diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index a416f27f9..40464cfd6 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -188,50 +188,6 @@ typedef enum ECMA_PROPERTY_CONFIGURABLE /**< property's 'Configurable' attribute is true */ } ecma_property_configurable_value_t; -/** - * Description of ECMA property descriptor - * - * See also: ECMA-262 v5, 8.10. - */ -typedef struct -{ - /** Is [[Value]] defined? */ - unsigned int is_value_defined : 1; - - /** Is [[Get]] defined? */ - unsigned int is_get_defined : 1; - - /** Is [[Set]] defined? */ - unsigned int is_set_defined : 1; - - /** Is [[Writable]] defined? */ - unsigned int is_writable_defined : 1; - - /** Is [[Enumerable]] defined? */ - unsigned int is_enumerable_defined : 1; - - /** Is [[Configurable]] defined? */ - unsigned int is_configurable_defined : 1; - - /** [[Value]] */ - ecma_value_t value; - - /** [[Get]] */ - ecma_value_t get; - - /** [[Set]] */ - ecma_value_t set; - - /** [[Writable]] */ - ecma_property_writable_value_t writable; - - /** [[Enumerable]] */ - ecma_property_enumerable_value_t enumerable; - - /** [[Configurable]] */ - ecma_property_configurable_value_t configurable; -} ecma_property_descriptor_t; - /** * Description of ecma-property */ @@ -393,6 +349,54 @@ typedef struct ecma_object_t { ecma_gc_info_t GCInfo; } __packed ecma_object_t; +/** + * Description of ECMA property descriptor + * + * See also: ECMA-262 v5, 8.10. + * + * Note: + * If a component of descriptor is undefined then corresponding + * field should contain it's default value. + */ +typedef struct +{ + /** Is [[Value]] defined? */ + unsigned int is_value_defined : 1; + + /** Is [[Get]] defined? */ + unsigned int is_get_defined : 1; + + /** Is [[Set]] defined? */ + unsigned int is_set_defined : 1; + + /** Is [[Writable]] defined? */ + unsigned int is_writable_defined : 1; + + /** Is [[Enumerable]] defined? */ + unsigned int is_enumerable_defined : 1; + + /** Is [[Configurable]] defined? */ + unsigned int is_configurable_defined : 1; + + /** [[Value]] */ + ecma_value_t value; + + /** [[Get]] */ + ecma_object_t* get_p; + + /** [[Set]] */ + ecma_object_t* set_p; + + /** [[Writable]] */ + ecma_property_writable_value_t writable; + + /** [[Enumerable]] */ + ecma_property_enumerable_value_t enumerable; + + /** [[Configurable]] */ + ecma_property_configurable_value_t configurable; +} ecma_property_descriptor_t; + /** * Description of an ecma-character */ diff --git a/src/libecmaobjects/ecma-helpers.c b/src/libecmaobjects/ecma-helpers.c index 199c8f5cf..3b5148f8b 100644 --- a/src/libecmaobjects/ecma-helpers.c +++ b/src/libecmaobjects/ecma-helpers.c @@ -208,11 +208,11 @@ ecma_get_internal_property(ecma_object_t *object_p, /**< object descriptor */ * @return pointer to newly created property */ ecma_property_t* -ecma_create_named_property(ecma_object_t *obj_p, /**< object */ - ecma_char_t *name_p, /**< property name */ - ecma_property_writable_value_t writable, /**< 'writable' attribute */ - ecma_property_enumerable_value_t enumerable, /**< 'enumerable' attribute */ - ecma_property_configurable_value_t configurable) /**< 'configurable' attribute */ +ecma_create_named_data_property(ecma_object_t *obj_p, /**< object */ + ecma_char_t *name_p, /**< property name */ + ecma_property_writable_value_t writable, /**< 'writable' attribute */ + ecma_property_enumerable_value_t enumerable, /**< 'enumerable' attribute */ + ecma_property_configurable_value_t configurable) /**< 'configurable' attribute */ { JERRY_ASSERT( obj_p != NULL && name_p != NULL ); @@ -232,7 +232,40 @@ ecma_create_named_property(ecma_object_t *obj_p, /**< object */ ecma_set_pointer( obj_p->properties_p, prop); return prop; -} /* ecma_create_named_property */ +} /* ecma_create_named_data_property */ + +/** + * Create named accessor property with given name, attributes, getter and setter. + * + * @return pointer to newly created property + */ +ecma_property_t* +ecma_create_named_accessor_property(ecma_object_t *obj_p, /**< object */ + ecma_char_t *name_p, /**< property name */ + ecma_object_t *get_p, /**< getter */ + ecma_object_t *set_p, /**< setter */ + ecma_property_enumerable_value_t enumerable, /**< 'enumerable' attribute */ + ecma_property_configurable_value_t configurable) /**< 'configurable' attribute */ +{ + JERRY_ASSERT( obj_p != NULL && name_p != NULL ); + + ecma_property_t *prop_p = ecma_alloc_property(); + + prop_p->type = ECMA_PROPERTY_NAMEDACCESSOR; + + ecma_set_pointer( prop_p->u.named_accessor_property.name_p, ecma_new_ecma_string( name_p)); + + ecma_set_pointer( prop_p->u.named_accessor_property.get_p, get_p); + ecma_set_pointer( prop_p->u.named_accessor_property.set_p, set_p); + + prop_p->u.named_accessor_property.enumerable = enumerable; + prop_p->u.named_accessor_property.configurable = configurable; + + ecma_set_pointer( prop_p->next_property_p, ecma_get_pointer( obj_p->properties_p)); + ecma_set_pointer( obj_p->properties_p, prop_p); + + return prop_p; +} /* ecma_create_named_accessor_property */ /** * Find named data property or named access property in specified object. @@ -700,96 +733,6 @@ ecma_free_array( ecma_array_first_chunk_t *first_chunk_p) /**< first chunk of th } } /* ecma_free_array */ -/** - * ECMA property descriptor constructor. - * - * @return ecma property descriptor - */ -ecma_property_descriptor_t -ecma_make_property_descriptor( bool is_value_defined, /**< is [[Value]] defined */ - bool is_get_defined, /**< is [[Get]] defined */ - bool is_set_defined, /**< is [[Set]] defined */ - bool is_writable_defined, /**< is [[Writable]] defined */ - bool is_enumerable_defined, /**< is [[Enumerable]] defined */ - bool is_configurable_defined, /**< is [[Configurable]] defined */ - ecma_value_t value, /**< [[Value]] */ - ecma_value_t get, /**< [[Get]] */ - ecma_value_t set, /**< [[Set]] */ - ecma_property_writable_value_t writable, /**< [[Writable]] */ - ecma_property_enumerable_value_t enumerable, /**< [[Enumerable]] */ - ecma_property_configurable_value_t configurable) /**< [[Configurable]] */ -{ - ecma_property_descriptor_t prop_desc; - - prop_desc.is_value_defined = is_value_defined; - prop_desc.is_get_defined = is_get_defined; - prop_desc.is_set_defined = is_set_defined; - prop_desc.is_writable_defined = is_writable_defined; - prop_desc.is_enumerable_defined = is_enumerable_defined; - prop_desc.is_configurable_defined = is_configurable_defined; - - if ( prop_desc.is_value_defined ) - { - prop_desc.value = value; - } - - if ( prop_desc.is_get_defined ) - { - prop_desc.get = get; - } - - if ( prop_desc.is_set_defined ) - { - prop_desc.set = set; - } - - if ( prop_desc.is_writable_defined ) - { - prop_desc.writable = writable; - } - - if ( prop_desc.is_enumerable_defined ) - { - prop_desc.enumerable = enumerable; - } - - if ( prop_desc.is_configurable_defined ) - { - prop_desc.configurable = configurable; - } - - return prop_desc; -} /* ecma_make_property_descriptor */ - -/** - * Free the ecma property descriptor. - */ -void -ecma_free_property_descriptor( ecma_property_descriptor_t prop_desc) /**< ECMA property descriptor */ -{ - if ( prop_desc.is_value_defined ) - { - ecma_free_value( prop_desc.value); - } - - if ( prop_desc.is_get_defined ) - { - ecma_free_value( prop_desc.get); - } - - if ( prop_desc.is_set_defined ) - { - ecma_free_value( prop_desc.set); - } - - prop_desc.is_value_defined = false; - prop_desc.is_get_defined = false; - prop_desc.is_set_defined = false; - prop_desc.is_writable_defined = false; - prop_desc.is_enumerable_defined = false; - prop_desc.is_configurable_defined = false; -} /* ecma_free_property_descriptor */ - /** * @} * @} diff --git a/src/libecmaobjects/ecma-helpers.h b/src/libecmaobjects/ecma-helpers.h index 7e6472c64..70e608363 100644 --- a/src/libecmaobjects/ecma-helpers.h +++ b/src/libecmaobjects/ecma-helpers.h @@ -77,7 +77,8 @@ extern ecma_property_t* ecma_create_internal_property(ecma_object_t *object_p, e extern ecma_property_t* ecma_find_internal_property(ecma_object_t *object_p, ecma_internal_property_id_t property_id); extern ecma_property_t* ecma_get_internal_property(ecma_object_t *object_p, ecma_internal_property_id_t property_id); -extern ecma_property_t *ecma_create_named_property(ecma_object_t *obj_p, ecma_char_t *name_p, ecma_property_writable_value_t writable, ecma_property_enumerable_value_t enumerable, ecma_property_configurable_value_t configurable); +extern ecma_property_t *ecma_create_named_data_property(ecma_object_t *obj_p, ecma_char_t *name_p, ecma_property_writable_value_t writable, ecma_property_enumerable_value_t enumerable, ecma_property_configurable_value_t configurable); +extern ecma_property_t *ecma_create_named_accessor_property(ecma_object_t *obj_p, ecma_char_t *name_p, ecma_object_t *get_p, ecma_object_t *set_p, ecma_property_enumerable_value_t enumerable, ecma_property_configurable_value_t configurable); extern ecma_property_t *ecma_find_named_property(ecma_object_t *obj_p, ecma_char_t *name_p); extern ecma_property_t *ecma_get_named_property(ecma_object_t *obj_p, ecma_char_t *name_p); extern ecma_property_t *ecma_get_named_data_property(ecma_object_t *obj_p, ecma_char_t *name_p); @@ -96,21 +97,6 @@ extern bool ecma_compare_zt_string_to_ecma_string( const ecma_char_t *string_p, extern bool ecma_compare_ecma_string_to_ecma_string(const ecma_array_first_chunk_t *string1_p, const ecma_array_first_chunk_t *string2_p); extern void ecma_free_array( ecma_array_first_chunk_t *first_chunk_p); -extern ecma_property_descriptor_t ecma_make_property_descriptor( bool is_value_defined, - bool is_get_defined, - bool is_set_defined, - bool is_writable_defined, - bool is_enumerable_defined, - bool is_configurable_defined, - ecma_value_t value, - ecma_value_t get, - ecma_value_t set, - ecma_property_writable_value_t writable, - ecma_property_enumerable_value_t enumerable, - ecma_property_configurable_value_t configurable); - -extern void ecma_free_property_descriptor( ecma_property_descriptor_t prop_desc); - #endif /* !JERRY_ECMA_HELPERS_H */ /** diff --git a/src/libecmaoperations/ecma-conversion.c b/src/libecmaoperations/ecma-conversion.c index 0d0b0778f..678670e5a 100644 --- a/src/libecmaoperations/ecma-conversion.c +++ b/src/libecmaoperations/ecma-conversion.c @@ -74,6 +74,79 @@ ecma_op_check_object_coercible( ecma_value_t value) /**< ecma-value */ return ecma_make_empty_completion_value(); } /* ecma_op_check_object_coercible */ +/** + * SameValue operation. + * + * See also: + * ECMA-262 v5, 9.12 + * + * @return true - if the value are same according to ECMA-defined SameValue algorithm, + * false - otherwise. + */ +bool +ecma_op_same_value( ecma_value_t x, /**< ecma-value */ + ecma_value_t y) /**< ecma-value */ +{ + const bool is_x_undefined = ecma_is_value_undefined( x); + const bool is_x_null = ecma_is_value_null( x); + const bool is_x_boolean = ecma_is_value_boolean( x); + const bool is_x_number = ( x.value_type == ECMA_TYPE_NUMBER ); + const bool is_x_string = ( x.value_type == ECMA_TYPE_STRING ); + const bool is_x_object = ( x.value_type == ECMA_TYPE_OBJECT ); + + const bool is_y_undefined = ecma_is_value_undefined( y); + const bool is_y_null = ecma_is_value_null( y); + const bool is_y_boolean = ecma_is_value_boolean( y); + const bool is_y_number = ( y.value_type == ECMA_TYPE_NUMBER ); + const bool is_y_string = ( y.value_type == ECMA_TYPE_STRING ); + const bool is_y_object = ( y.value_type == ECMA_TYPE_OBJECT ); + + const bool is_types_equal = ( ( is_x_undefined && is_y_undefined ) + || ( is_x_null && is_y_null ) + || ( is_x_boolean && is_y_boolean ) + || ( is_x_number && is_y_number ) + || ( is_x_string && is_y_string ) + || ( is_x_object && is_y_object ) ); + + if ( !is_types_equal ) + { + return false; + } + + if ( is_x_undefined + || is_x_null ) + { + return true; + } + + if ( is_x_number ) + { + TODO( Implement according to ECMA ); + + ecma_number_t *x_num_p = (ecma_number_t*)ecma_get_pointer( x.value); + ecma_number_t *y_num_p = (ecma_number_t*)ecma_get_pointer( y.value); + + return ( *x_num_p == *y_num_p ); + } + + if ( is_x_string ) + { + ecma_array_first_chunk_t* x_str_p = (ecma_array_first_chunk_t*)( ecma_get_pointer(x.value) ); + ecma_array_first_chunk_t* y_str_p = (ecma_array_first_chunk_t*)( ecma_get_pointer(y.value) ); + + return ecma_compare_ecma_string_to_ecma_string( x_str_p, y_str_p); + } + + if ( is_x_boolean ) + { + return ( ecma_is_value_true( x) == ecma_is_value_true( y) ); + } + + JERRY_ASSERT( is_x_object ); + + return ( ecma_get_pointer( x.value) == ecma_get_pointer( y.value) ); +} /* ecma_op_same_value */ + /** * ToPrimitive operation. * diff --git a/src/libecmaoperations/ecma-conversion.h b/src/libecmaoperations/ecma-conversion.h index 6a85163fd..8d3bc1b9d 100644 --- a/src/libecmaoperations/ecma-conversion.h +++ b/src/libecmaoperations/ecma-conversion.h @@ -41,6 +41,7 @@ typedef enum } ecma_preferred_type_hint_t; extern ecma_completion_value_t ecma_op_check_object_coercible( ecma_value_t value); +extern bool ecma_op_same_value( ecma_value_t x, ecma_value_t y); extern ecma_completion_value_t ecma_op_to_primitive( ecma_value_t value, ecma_preferred_type_hint_t preferred_type); 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); diff --git a/src/libecmaoperations/ecma-lex-env.c b/src/libecmaoperations/ecma-lex-env.c index dbc421ea2..1ee14312b 100644 --- a/src/libecmaoperations/ecma-lex-env.c +++ b/src/libecmaoperations/ecma-lex-env.c @@ -90,12 +90,12 @@ ecma_op_create_mutable_binding(ecma_object_t *lex_env_p, /**< lexical environmen { JERRY_ASSERT( ecma_is_completion_value_normal_false( ecma_op_has_binding( lex_env_p, name_p)) ); - ecma_create_named_property( lex_env_p, - name_p, - ECMA_PROPERTY_WRITABLE, - ECMA_PROPERTY_NOT_ENUMERABLE, - is_deletable ? ECMA_PROPERTY_CONFIGURABLE - : ECMA_PROPERTY_NOT_CONFIGURABLE); + ecma_create_named_data_property( lex_env_p, + name_p, + ECMA_PROPERTY_WRITABLE, + ECMA_PROPERTY_NOT_ENUMERABLE, + is_deletable ? ECMA_PROPERTY_CONFIGURABLE + : ECMA_PROPERTY_NOT_CONFIGURABLE); break; @@ -316,11 +316,11 @@ ecma_op_create_immutable_binding(ecma_object_t *lex_env_p, /**< lexical environm * Warning: * Whether immutable bindings are deletable seems not to be defined by ECMA v5. */ - ecma_property_t *prop_p = ecma_create_named_property( lex_env_p, - name_p, - ECMA_PROPERTY_NOT_WRITABLE, - ECMA_PROPERTY_NOT_ENUMERABLE, - ECMA_PROPERTY_NOT_CONFIGURABLE); + ecma_property_t *prop_p = ecma_create_named_data_property( lex_env_p, + name_p, + ECMA_PROPERTY_NOT_WRITABLE, + ECMA_PROPERTY_NOT_ENUMERABLE, + ECMA_PROPERTY_NOT_CONFIGURABLE); JERRY_ASSERT( ecma_is_value_undefined( prop_p->u.named_data_property.value ) ); diff --git a/src/libecmaoperations/ecma-objects-properties.c b/src/libecmaoperations/ecma-objects-properties.c index 104549285..4648406d5 100644 --- a/src/libecmaoperations/ecma-objects-properties.c +++ b/src/libecmaoperations/ecma-objects-properties.c @@ -13,7 +13,9 @@ * limitations under the License. */ +#include "ecma-exceptions.h" #include "ecma-globals.h" +#include "ecma-helpers.h" #include "ecma-objects-properties.h" /** \addtogroup ecma ---TODO--- @@ -34,9 +36,53 @@ */ ecma_completion_value_t ecma_op_object_get( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p) /**< property name */ + ecma_char_t *property_name_p) /**< property name */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + /* + * ECMA-262 v5, 8.12.3 + * + * Common implementation of operation for objects other than Host, Function or Arguments objects. + */ + + // 1. + const ecma_property_t* prop_p = ecma_op_object_get_property( obj_p, property_name_p); + + // 2. + if ( prop_p == NULL ) + { + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_UNDEFINED); + } + + // 3. + if ( prop_p->type == ECMA_PROPERTY_NAMEDDATA ) + { + return ecma_make_completion_value( ECMA_COMPLETION_TYPE_NORMAL, + ecma_copy_value( prop_p->u.named_data_property.value), + ECMA_TARGET_ID_RESERVED); + } + else + { + // 4. + ecma_object_t *getter = ecma_get_pointer( prop_p->u.named_accessor_property.get_p); + + // 5. + if ( getter == NULL ) + { + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_UNDEFINED); + } + else + { + /* + * Return result of O.[[Call]]; + */ + JERRY_UNIMPLEMENTED(); + } + } + + JERRY_UNREACHABLE(); } /* ecma_op_object_get */ /** @@ -46,13 +92,22 @@ ecma_op_object_get( ecma_object_t *obj_p, /**< the object */ * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * * @return pointer to a property - if it exists, - * NULL - otherwise. + * NULL (i.e. ecma-undefined) - otherwise. */ ecma_property_t* ecma_op_object_get_own_property( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p) /**< property name */ + ecma_char_t *property_name_p) /**< property name */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + /* + * ECMA-262 v5, 8.12.2 + * + * Common implementation of operation for objects other than Host, Function or Arguments objects. + */ + + return ecma_find_named_property( obj_p, property_name_p); } /* ecma_op_object_get_own_property */ /** @@ -62,13 +117,42 @@ ecma_op_object_get_own_property( ecma_object_t *obj_p, /**< the object */ * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * * @return pointer to a property - if it exists, - * NULL - otherwise. + * NULL (i.e. ecma-undefined) - otherwise. */ ecma_property_t* ecma_op_object_get_property( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p) /**< property name */ + ecma_char_t *property_name_p) /**< property name */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + /* + * ECMA-262 v5, 8.12.2 + * + * Common implementation of operation for objects other than Host, Function or Arguments objects. + */ + + // 1. + ecma_property_t *prop_p = ecma_op_object_get_own_property( obj_p, property_name_p); + + // 2. + if ( prop_p != NULL ) + { + return prop_p; + } + + // 3. + ecma_object_t *prototype_p = ecma_get_pointer( obj_p->u.object.prototype_object_p); + + // 4., 5. + if ( prototype_p != NULL ) + { + return ecma_op_object_get_property( prototype_p, property_name_p); + } + else + { + return NULL; + } } /* ecma_op_object_get_property */ /** @@ -82,11 +166,112 @@ ecma_op_object_get_property( ecma_object_t *obj_p, /**< the object */ */ ecma_completion_value_t ecma_op_object_put( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p, /**< property name */ + ecma_char_t *property_name_p, /**< property name */ ecma_value_t value, /**< ecma-value */ bool is_throw) /**< flag that controls failure handling */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p, value, is_throw); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + // 1. + if ( !ecma_op_object_can_put( obj_p, property_name_p) ) + { + if ( is_throw ) + { + // a. + return ecma_make_throw_value( ecma_new_standard_error( ECMA_ERROR_TYPE)); + } + else + { + // b. + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_FALSE); + } + } + + // 2. + ecma_property_t *own_desc_p = ecma_op_object_get_own_property( obj_p, property_name_p); + + // 3. + if ( own_desc_p->type == ECMA_PROPERTY_NAMEDDATA ) + { + // a. + ecma_property_descriptor_t value_desc = (ecma_property_descriptor_t) { + .is_value_defined = true, + .value = value, + + .is_get_defined = false, + .get_p = NULL, + + .is_set_defined = false, + .set_p = NULL, + + .is_writable_defined = false, + .writable = ECMA_PROPERTY_NOT_WRITABLE, + + .is_enumerable_defined = false, + .enumerable = ECMA_PROPERTY_NOT_ENUMERABLE, + + .is_configurable_defined = false, + .configurable = ECMA_PROPERTY_NOT_CONFIGURABLE, + }; + + // b., c. + return ecma_op_object_define_own_property( obj_p, + property_name_p, + value_desc, + is_throw); + } + + // 4. + ecma_property_t *desc_p = ecma_op_object_get_property( obj_p, property_name_p); + + // 5. + if ( desc_p->type == ECMA_PROPERTY_NAMEDACCESSOR ) + { + // a. + ecma_object_t *setter_p = ecma_get_pointer( desc_p->u.named_accessor_property.set_p); + + JERRY_ASSERT( setter_p != NULL ); + + // b. + /* + * setter_p->[[Call]]( obj_p, value); + */ + JERRY_UNIMPLEMENTED(); + } + else + { + // 6. + + // a. + ecma_property_descriptor_t new_desc = (ecma_property_descriptor_t) { + .is_value_defined = true, + .value = value, + + .is_get_defined = false, + .get_p = NULL, + + .is_set_defined = false, + .set_p = NULL, + + .is_writable_defined = true, + .writable = ECMA_PROPERTY_WRITABLE, + + .is_enumerable_defined = true, + .enumerable = ECMA_PROPERTY_ENUMERABLE, + + .is_configurable_defined = true, + .configurable = ECMA_PROPERTY_CONFIGURABLE + }; + + // b. + return ecma_op_object_define_own_property( obj_p, + property_name_p, + new_desc, + is_throw); + } + + JERRY_UNREACHABLE(); } /* ecma_op_object_put */ /** @@ -100,9 +285,97 @@ ecma_op_object_put( ecma_object_t *obj_p, /**< the object */ */ bool ecma_op_object_can_put( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p) /**< property name */ + ecma_char_t *property_name_p) /**< property name */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + /* + * ECMA-262 v5, 8.12.2 + * + * Common implementation of operation for objects other than Host, Function or Arguments objects. + */ + + // 1. + ecma_property_t *prop_p = ecma_op_object_get_own_property( obj_p, property_name_p); + + // 2. + if ( prop_p != NULL ) + { + // a. + if ( prop_p->type == ECMA_PROPERTY_NAMEDACCESSOR ) + { + ecma_object_t *setter_p = ecma_get_pointer( prop_p->u.named_accessor_property.set_p); + + // i. + if ( setter_p == NULL ) + { + return false; + } + + // ii. + return true; + } + else + { + // b. + + JERRY_ASSERT( prop_p->type == ECMA_PROPERTY_NAMEDDATA ); + + return ( prop_p->u.named_data_property.writable == ECMA_PROPERTY_WRITABLE ); + } + } + + // 3. + ecma_object_t *proto_p = ecma_get_pointer( obj_p->u.object.prototype_object_p); + + // 4. + if ( proto_p == NULL ) + { + return obj_p->u.object.extensible; + } + + // 5. + ecma_property_t *inherited_p = ecma_op_object_get_property( proto_p, property_name_p); + + // 6. + if ( inherited_p == NULL ) + { + return obj_p->u.object.extensible; + } + + // 7. + if ( inherited_p->type == ECMA_PROPERTY_NAMEDACCESSOR ) + { + ecma_object_t *setter_p = ecma_get_pointer( inherited_p->u.named_accessor_property.set_p); + + // a. + if ( setter_p == NULL ) + { + return false; + } + + // b. + return true; + } + else + { + // 8. + JERRY_ASSERT( inherited_p->type == ECMA_PROPERTY_NAMEDDATA ); + + // a. + if ( !obj_p->u.object.extensible ) + { + return false; + } + else + { + // b. + return ( inherited_p->u.named_data_property.writable == ECMA_PROPERTY_WRITABLE ); + } + } + + JERRY_UNREACHABLE(); } /* ecma_op_object_can_put */ /** @@ -116,9 +389,20 @@ ecma_op_object_can_put( ecma_object_t *obj_p, /**< the object */ */ bool ecma_op_object_has_property( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p) /**< property name */ + ecma_char_t *property_name_p) /**< property name */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + /* + * ECMA-262 v5, 8.12.2 + * + * Common implementation of operation for objects other than Host, Function or Arguments objects. + */ + + ecma_property_t *desc_p = ecma_op_object_get_property( obj_p, property_name_p); + + return ( desc_p != NULL ); } /* ecma_op_object_has_property */ /** @@ -132,10 +416,60 @@ ecma_op_object_has_property( ecma_object_t *obj_p, /**< the object */ */ ecma_completion_value_t ecma_op_object_delete( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p, /**< property name */ + ecma_char_t *property_name_p, /**< property name */ bool is_throw) /**< flag that controls failure handling */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p, is_throw); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + /* + * ECMA-262 v5, 8.12.2 + * + * Common implementation of operation for objects other than Host, Function or Arguments objects. + */ + + // 1. + ecma_property_t *desc_p = ecma_op_object_get_own_property( obj_p, property_name_p); + + // 2. + if ( desc_p == NULL ) + { + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_TRUE); + } + + // 3. + bool is_configurable; + if ( desc_p->type == ECMA_PROPERTY_NAMEDACCESSOR ) + { + is_configurable = desc_p->u.named_accessor_property.configurable; + } + else + { + JERRY_ASSERT( desc_p->type == ECMA_PROPERTY_NAMEDDATA ); + + is_configurable = desc_p->u.named_data_property.configurable; + } + + if ( is_configurable ) + { + // a. + ecma_delete_property( obj_p, desc_p); + + // b. + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_TRUE); + } + else if ( is_throw ) + { + // 4. + return ecma_make_throw_value( ecma_new_standard_error( ECMA_ERROR_TYPE)); + } + else + { + // 5. + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_FALSE); + } + + JERRY_UNREACHABLE(); } /* ecma_op_object_delete */ /** @@ -151,6 +485,8 @@ ecma_completion_value_t ecma_op_object_default_value( ecma_object_t *obj_p, /**< the object */ ecma_preferred_type_hint_t hint) /**< hint on preferred result type */ { + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, hint); } /* ecma_op_object_default_value */ @@ -165,11 +501,156 @@ ecma_op_object_default_value( ecma_object_t *obj_p, /**< the object */ */ ecma_completion_value_t ecma_op_object_define_own_property( ecma_object_t *obj_p, /**< the object */ - ecma_array_first_chunk_t *property_name_p, /**< property name */ + 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_UNIMPLEMENTED_REF_UNUSED_VARS( obj_p, property_name_p, property_desc, is_throw); + JERRY_ASSERT( obj_p != NULL && !obj_p->is_lexical_environment ); + JERRY_ASSERT( property_name_p != NULL ); + + const bool is_property_desc_generic_descriptor = ( !property_desc.is_value_defined + && !property_desc.is_writable_defined + && !property_desc.is_get_defined + && !property_desc.is_set_defined ); + const bool is_property_desc_data_descriptor = ( property_desc.is_value_defined + || property_desc.is_writable_defined ); + const bool is_property_desc_accessor_descriptor = ( property_desc.is_get_defined + || property_desc.is_set_defined ); + + // 1. + ecma_property_t *current_p = ecma_op_object_get_own_property( obj_p, property_name_p); + + // 2. + bool extensible = obj_p->u.object.extensible; + + if ( current_p == NULL ) + { + // 3. + if ( !extensible ) + { + // Reject + 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); + } + } + else + { + // 4. + + // a. + if ( is_property_desc_generic_descriptor + || is_property_desc_data_descriptor ) + { + ecma_create_named_data_property( obj_p, + property_name_p, + property_desc.writable, + property_desc.enumerable, + property_desc.configurable); + } + else + { + // b. + JERRY_ASSERT( is_property_desc_accessor_descriptor ); + + ecma_create_named_accessor_property( obj_p, + property_name_p, + property_desc.get_p, + property_desc.set_p, + property_desc.enumerable, + property_desc.configurable); + + } + + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_TRUE); + } + } + + // 5. + if ( is_property_desc_generic_descriptor + && !property_desc.is_enumerable_defined + && !property_desc.is_configurable_defined ) + { + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_TRUE); + } + + // 6. + const bool is_current_data_descriptor = ( current_p->type == ECMA_PROPERTY_NAMEDDATA ); + const bool is_current_accessor_descriptor = ( current_p->type == ECMA_PROPERTY_NAMEDACCESSOR ); + + JERRY_ASSERT( is_current_data_descriptor || is_current_accessor_descriptor ); + + bool is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = true; + if ( property_desc.is_value_defined ) + { + if ( !is_current_data_descriptor + || !ecma_op_same_value( property_desc.value, + current_p->u.named_data_property.value) ) + { + is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; + } + } + + if ( property_desc.is_writable_defined ) + { + if ( !is_current_data_descriptor + || property_desc.writable != current_p->u.named_data_property.writable ) + { + is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; + } + } + + if ( property_desc.is_get_defined ) + { + if ( !is_current_accessor_descriptor + || property_desc.get_p != ecma_get_pointer( current_p->u.named_accessor_property.get_p) ) + { + is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; + } + } + + if ( property_desc.is_set_defined ) + { + if ( !is_current_accessor_descriptor + || property_desc.set_p != ecma_get_pointer( current_p->u.named_accessor_property.set_p) ) + { + is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; + } + } + + if ( property_desc.is_enumerable_defined ) + { + if ( ( is_current_data_descriptor + && property_desc.enumerable != current_p->u.named_data_property.enumerable ) + || ( is_current_accessor_descriptor + && property_desc.configurable != current_p->u.named_accessor_property.enumerable ) ) + { + is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; + } + } + + if ( property_desc.is_configurable_defined ) + { + if ( ( is_current_data_descriptor + && property_desc.configurable != current_p->u.named_data_property.configurable ) + || ( is_current_accessor_descriptor + && property_desc.configurable != current_p->u.named_accessor_property.configurable ) ) + { + is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; + } + } + + if ( is_every_field_in_desc_also_occurs_in_current_desc_with_same_value ) + { + return ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_TRUE); + } + + // 7., ... + JERRY_UNIMPLEMENTED(); } /* ecma_op_object_define_own_property */ /** diff --git a/src/libecmaoperations/ecma-objects-properties.h b/src/libecmaoperations/ecma-objects-properties.h index a5f65a0a4..2a30d4a49 100644 --- a/src/libecmaoperations/ecma-objects-properties.h +++ b/src/libecmaoperations/ecma-objects-properties.h @@ -26,21 +26,21 @@ * @{ */ -extern ecma_completion_value_t ecma_op_object_get( ecma_object_t *obj_p, ecma_array_first_chunk_t *property_name_p); -extern ecma_property_t *ecma_op_object_get_own_property( ecma_object_t *obj_p, ecma_array_first_chunk_t *property_name_p); -extern ecma_property_t *ecma_op_object_get_property( ecma_object_t *obj_p, ecma_array_first_chunk_t *property_name_p); +extern ecma_completion_value_t ecma_op_object_get( ecma_object_t *obj_p, ecma_char_t *property_name_p); +extern ecma_property_t *ecma_op_object_get_own_property( ecma_object_t *obj_p, ecma_char_t *property_name_p); +extern ecma_property_t *ecma_op_object_get_property( ecma_object_t *obj_p, ecma_char_t *property_name_p); extern ecma_completion_value_t ecma_op_object_put( ecma_object_t *obj_p, - ecma_array_first_chunk_t *property_name_p, + ecma_char_t *property_name_p, ecma_value_t value, bool is_throw); -extern bool ecma_op_object_can_put( ecma_object_t *obj_p, ecma_array_first_chunk_t *property_name_p); -extern bool ecma_op_object_has_property( ecma_object_t *obj_p, ecma_array_first_chunk_t *property_name_p); +extern bool ecma_op_object_can_put( ecma_object_t *obj_p, ecma_char_t *property_name_p); +extern bool ecma_op_object_has_property( ecma_object_t *obj_p, ecma_char_t *property_name_p); extern ecma_completion_value_t ecma_op_object_delete( ecma_object_t *obj_p, - ecma_array_first_chunk_t *property_name_p, + ecma_char_t *property_name_p, bool is_throw); extern ecma_completion_value_t ecma_op_object_default_value( ecma_object_t *obj_p, ecma_preferred_type_hint_t hint); extern ecma_completion_value_t ecma_op_object_define_own_property( ecma_object_t *obj_p, - ecma_array_first_chunk_t *property_name_p, + ecma_char_t *property_name_p, ecma_property_descriptor_t property_desc, bool is_throw);