diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index b87d47fcb..38e187dd9 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -462,6 +462,19 @@ typedef float ecma_number_t; */ #define ECMA_NUMBER_ONE ((ecma_number_t) 1) +/** + * Maximum number of characters in string representation of ecma-number + */ +#define ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER 512 + +/** + * Maximum value of valid array index + * + * See also: + * ECMA-262 v5, 15.4 + */ +#define ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX ((uint32_t) (-1)) + /** * Description of arrays'/strings' length */ diff --git a/src/libecmaoperations/ecma-array-object.c b/src/libecmaoperations/ecma-array-object.c new file mode 100644 index 000000000..2a663f05e --- /dev/null +++ b/src/libecmaoperations/ecma-array-object.c @@ -0,0 +1,261 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-alloc.h" +#include "ecma-array-object.h" +#include "ecma-exceptions.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-magic-strings.h" +#include "ecma-number-arithmetic.h" +#include "ecma-objects.h" +#include "ecma-objects-general.h" + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmaarrayobject ECMA Array object related routines + * @{ + */ + +/** + * Reject sequence + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +static ecma_completion_value_t +ecma_reject (bool is_throw) /**< Throw flag */ +{ + if (is_throw) + { + return ecma_make_throw_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); + } + else + { + return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); + } +} /* ecma_reject */ + +/** + * [[DefineOwnProperty]] ecma array object's operation + * + * See also: + * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 + * ECMA-262 v5, 15.4.5.1 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_completion_value_t +ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the object */ + const ecma_char_t *property_name_p, /**< property name */ + ecma_property_descriptor_t property_desc, /**< property descriptor */ + bool is_throw) /**< flag that controls failure handling */ +{ + JERRY_ASSERT (obj_p->u.object.type == ECMA_OBJECT_TYPE_ARRAY); + + const ecma_char_t* magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH); + + // 1. + ecma_property_t *len_prop_p = ecma_op_object_get_own_property (obj_p, magic_string_length_p); + JERRY_ASSERT (len_prop_p != NULL && len_prop_p->type == ECMA_PROPERTY_NAMEDDATA); + + // 2. + ecma_value_t old_len_value = len_prop_p->u.named_data_property.value; + + JERRY_ASSERT (old_len_value.value_type == ECMA_TYPE_NUMBER); + + ecma_number_t *num_p = ECMA_GET_POINTER (old_len_value.value); + uint32_t old_len_uint32 = ecma_number_to_uint32 (*num_p); + + // 3. + if (ecma_compare_zt_string_to_zt_string (property_name_p, magic_string_length_p) == 0) + { + // a. + if (!property_desc.is_value_defined) + { + // i. + return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc, is_throw); + } + + ecma_completion_value_t ret_value = ecma_make_empty_completion_value(); + + // c. + ecma_completion_value_t completion = ecma_op_to_number (property_desc.value); + if (ecma_is_completion_value_throw (completion) ) + { + ret_value = completion; + } + else + { + JERRY_ASSERT (ecma_is_completion_value_normal (completion) + && completion.value.value_type == ECMA_TYPE_NUMBER); + + ecma_number_t *new_len_num_p = ECMA_GET_POINTER (completion.value.value); + + uint32_t new_len_uint32 = ecma_number_to_uint32 (*new_len_num_p); + + // d. + if (ecma_uint32_to_number (new_len_uint32) != *new_len_num_p) + { + ret_value = ecma_make_throw_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); + } + else + { + // b., e. + ecma_property_descriptor_t new_len_property_desc = property_desc; + new_len_property_desc.value = ecma_make_number_value (new_len_num_p); + + // f. + if ( new_len_uint32 >= old_len_uint32 ) + { + // i. + ret_value = ecma_op_general_object_define_own_property (obj_p, + magic_string_length_p, + new_len_property_desc, + is_throw); + } + else + { + // g. + if (len_prop_p->u.named_data_property.writable == ECMA_PROPERTY_NOT_WRITABLE) + { + ret_value = ecma_reject (is_throw); + } + else + { + // h. + bool new_writable; + if (!new_len_property_desc.is_writable_defined + || new_len_property_desc.writable == ECMA_PROPERTY_WRITABLE) + { + new_writable = true; + } + else + { + // ii. + new_writable = false; + + // iii. + new_len_property_desc.is_writable_defined = true; + new_len_property_desc.writable = ECMA_PROPERTY_WRITABLE; + } + + // j. + ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, + magic_string_length_p, + new_len_property_desc, + is_throw); + + /* Handling normal false and throw values */ + if (!ecma_is_completion_value_normal_true (succeeded)) + { + // k. + ret_value = completion; + } + + // l. + while (new_len_uint32 < old_len_uint32) + { + JERRY_UNIMPLEMENTED(); + } + + // m. + if (!new_writable) + { + ecma_property_descriptor_t prop_desc_not_writable = ecma_make_empty_property_descriptor(); + + prop_desc_not_writable.is_writable_defined = true; + prop_desc_not_writable.writable = ECMA_PROPERTY_NOT_WRITABLE; + + ecma_completion_value_t completion_set_not_writable = ecma_op_general_object_define_own_property (obj_p, + magic_string_length_p, + prop_desc_not_writable, + false); + JERRY_ASSERT (ecma_is_completion_value_normal_true (completion_set_not_writable)); + } + + ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); + } + } + } + + ecma_free_completion_value (completion); + } + + return ret_value; + } + else + { + // 4.a. + ecma_number_t number = ecma_zt_string_to_number (property_name_p); + uint32_t index = ecma_number_to_uint32 (number); + + if (index >= ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX + || ecma_uint32_to_number (index) != number) + { + // 5. + return ecma_op_general_object_define_own_property (obj_p, + property_name_p, + property_desc, + false); + } + + // 4. + + // b. + if (index >= old_len_uint32 + && len_prop_p->u.named_data_property.writable == ECMA_PROPERTY_NOT_WRITABLE) + { + return ecma_reject(is_throw); + } + + // c. + ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, + property_name_p, + property_desc, + false); + // d. + JERRY_ASSERT (ecma_is_completion_value_normal_true (succeeded) + || ecma_is_completion_value_normal_false (succeeded)); + + if (ecma_is_completion_value_normal_false (succeeded)) + { + return ecma_reject (is_throw); + } + + // e. + if (index >= old_len_uint32) + { + // i., ii. + ecma_number_t *num_p = ecma_alloc_number(); + *num_p = ecma_op_number_add (ecma_uint32_to_number (index), ECMA_NUMBER_ONE); + + ecma_free_value (len_prop_p->u.named_data_property.value, false); + len_prop_p->u.named_data_property.value = ecma_make_number_value (num_p); + } + + // f. + return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); + } + + JERRY_UNREACHABLE(); +} /* ecma_op_array_object_define_own_property */ + +/** + * @} + * @} + */ diff --git a/src/libecmaoperations/ecma-array-object.h b/src/libecmaoperations/ecma-array-object.h new file mode 100644 index 000000000..259d475bf --- /dev/null +++ b/src/libecmaoperations/ecma-array-object.h @@ -0,0 +1,39 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_ARRAY_OBJECT_H +#define ECMA_ARRAY_OBJECT_H + +#include "ecma-globals.h" + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmaarrayobject ECMA Array object related routines + * @{ + */ + +extern ecma_completion_value_t +ecma_op_array_object_define_own_property (ecma_object_t *obj_p, + const ecma_char_t *property_name_p, + ecma_property_descriptor_t property_desc, + bool is_throw); + +/** + * @} + * @} + */ + +#endif /* !ECMA_ARRAY_OBJECT_H */ diff --git a/src/libecmaoperations/ecma-conversion.c b/src/libecmaoperations/ecma-conversion.c index e37d5db4f..76f4b5789 100644 --- a/src/libecmaoperations/ecma-conversion.c +++ b/src/libecmaoperations/ecma-conversion.c @@ -314,6 +314,65 @@ ecma_op_to_object (ecma_value_t value) /**< ecma-value */ JERRY_UNIMPLEMENTED_REF_UNUSED_VARS(value); } /* ecma_op_to_object */ +/** + * ECMA-defined conversion of string (zero-terminated) to Number. + * + * See also: + * ECMA-262 v5, 9.6 + * + * @return ecma-number + */ +ecma_number_t +ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string */ +{ + FIXME (Implement according to ECMA); + + ecma_number_t ret_value = 0; + while (*str_p != '\0') + { + if (*str_p >= '0' && *str_p <= '9') + { + ret_value *= 10; + ret_value += (ecma_number_t) (*str_p - '0'); + } + else + { + JERRY_UNIMPLEMENTED(); + } + } + + return ret_value; +} /* ecma_zt_string_to_number */ + +/** + * ECMA-defined conversion of UInt32 value to Number value + * + * @return number - result of conversion. + */ +ecma_number_t +ecma_uint32_to_number (uint32_t value) /**< unsigned 32-bit integer value */ +{ + TODO(Implement according to ECMA); + + return (ecma_number_t) value; +} /* ecma_uint32_to_number */ + +/** + * ECMA-defined conversion of Number value to Uint32 value + * + * See also: + * ECMA-262 v5, 9.6 + * + * @return number - result of conversion. + */ +uint32_t +ecma_number_to_uint32 (ecma_number_t value) /**< unsigned 32-bit integer value */ +{ + TODO(Implement according to ECMA); + + return (uint32_t) value; +} /* ecma_number_to_uint32 */ + /** * @} * @} diff --git a/src/libecmaoperations/ecma-conversion.h b/src/libecmaoperations/ecma-conversion.h index be1ef4a86..7b11e7e5e 100644 --- a/src/libecmaoperations/ecma-conversion.h +++ b/src/libecmaoperations/ecma-conversion.h @@ -46,6 +46,9 @@ extern ecma_completion_value_t ecma_op_to_primitive (ecma_value_t value, ecma_pr extern ecma_completion_value_t ecma_op_to_boolean (ecma_value_t value); extern ecma_completion_value_t ecma_op_to_number (ecma_value_t value); extern ecma_completion_value_t ecma_op_to_object (ecma_value_t value); +extern ecma_number_t ecma_zt_string_to_number (const ecma_char_t *str_p); +extern uint32_t ecma_number_to_uint32 (ecma_number_t value); +extern ecma_number_t ecma_uint32_to_number (uint32_t value); /** * @} diff --git a/src/libecmaoperations/ecma-magic-strings.c b/src/libecmaoperations/ecma-magic-strings.c index 1164830c6..4d9beb058 100644 --- a/src/libecmaoperations/ecma-magic-strings.c +++ b/src/libecmaoperations/ecma-magic-strings.c @@ -40,6 +40,7 @@ ecma_get_magic_string (ecma_magic_string_id_t id) /**< magic string id */ case ECMA_MAGIC_STRING_CONSTRUCTOR: return (ecma_char_t*) "constructor"; case ECMA_MAGIC_STRING_CALLER: return (ecma_char_t*) "caller"; case ECMA_MAGIC_STRING_UNDEFINED: return (ecma_char_t*) "undefined"; + case ECMA_MAGIC_STRING_LENGTH: return (ecma_char_t*) "length"; } JERRY_UNREACHABLE(); diff --git a/src/libecmaoperations/ecma-magic-strings.h b/src/libecmaoperations/ecma-magic-strings.h index d4222e011..307c60435 100644 --- a/src/libecmaoperations/ecma-magic-strings.h +++ b/src/libecmaoperations/ecma-magic-strings.h @@ -35,7 +35,8 @@ typedef enum ECMA_MAGIC_STRING_PROTOTYPE, /**< "prototype" */ ECMA_MAGIC_STRING_CONSTRUCTOR, /**< "constructor" */ ECMA_MAGIC_STRING_CALLER, /**< "caller" */ - ECMA_MAGIC_STRING_UNDEFINED /**< undefined */ + ECMA_MAGIC_STRING_UNDEFINED,/**< undefined */ + ECMA_MAGIC_STRING_LENGTH /**< length */ } ecma_magic_string_id_t; extern const ecma_char_t* ecma_get_magic_string (ecma_magic_string_id_t id); diff --git a/src/libecmaoperations/ecma-objects-general.c b/src/libecmaoperations/ecma-objects-general.c index cf1217d3b..0d5965eee 100644 --- a/src/libecmaoperations/ecma-objects-general.c +++ b/src/libecmaoperations/ecma-objects-general.c @@ -47,7 +47,7 @@ ecma_reject (bool is_throw) /**< Throw flag */ } /* ecma_reject */ /** - * [[Get]] ecma object's operation + * [[Get]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -102,7 +102,7 @@ ecma_op_general_object_get (ecma_object_t *obj_p, /**< the object */ } /* ecma_op_general_object_get */ /** - * [[GetOwnProperty]] ecma object's operation + * [[GetOwnProperty]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -122,7 +122,7 @@ ecma_op_general_object_get_own_property (ecma_object_t *obj_p, /**< the object * } /* ecma_op_general_object_get_own_property */ /** - * [[GetProperty]] ecma object's operation + * [[GetProperty]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -162,7 +162,7 @@ ecma_op_general_object_get_property (ecma_object_t *obj_p, /**< the object */ } /* ecma_op_general_object_get_property */ /** - * [[Put]] ecma object's operation + * [[Put]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -265,7 +265,7 @@ ecma_op_general_object_put (ecma_object_t *obj_p, /**< the object */ } /* ecma_op_general_object_put */ /** - * [[CanPut]] ecma object's operation + * [[CanPut]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -364,7 +364,7 @@ ecma_op_general_object_can_put (ecma_object_t *obj_p, /**< the object */ } /* ecma_op_general_object_can_put */ /** - * [[HasProperty]] ecma object's operation + * [[HasProperty]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -386,7 +386,7 @@ ecma_op_general_object_has_property (ecma_object_t *obj_p, /**< the object */ } /* ecma_op_general_object_has_property */ /** - * [[Delete]] ecma object's operation + * [[Delete]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -448,7 +448,7 @@ ecma_op_general_object_delete (ecma_object_t *obj_p, /**< the object */ } /* ecma_op_general_object_delete */ /** - * [[DefaultValue]] ecma object's operation + * [[DefaultValue]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 @@ -467,7 +467,7 @@ ecma_op_general_object_default_value (ecma_object_t *obj_p, /**< the object */ } /* ecma_op_general_object_default_value */ /** - * [[DefineOwnProperty]] ecma object's operation + * [[DefineOwnProperty]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8