diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp index 7efa100603..c03c874e5f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp @@ -16,6 +16,7 @@ #include "ecma-builtin-helpers.h" +#include "ecma-array-object.h" #include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-function-object.h" @@ -187,6 +188,88 @@ ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, /** < t return ret_value; } /* ecma_builtin_helper_get_to_locale_string_at_index */ + +/** + * The Object.keys and Object.getOwnPropertyName routine's common part. + * + * See also: + * ECMA-262 v5, 15.2.3.4 steps 2-5 + * ECMA-262 v5, 15.2.3.14 steps 3-6 + * + * @return completion value - Array of property names. + * Returned value must be freed with ecma_free_completion_value. + */ +ecma_completion_value_t +ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /** < object */ + bool only_enumerable_properties) /** < list enumerable properties? */ +{ + JERRY_ASSERT (obj_p != NULL); + + ecma_completion_value_t new_array = ecma_op_create_array_object (NULL, 0, false); + JERRY_ASSERT (ecma_is_completion_value_normal (new_array)); + ecma_object_t *new_array_p = ecma_get_object_from_completion_value (new_array); + + uint32_t index = 0; + + for (ecma_property_t *property_p = ecma_get_property_list (obj_p); + property_p != NULL; + property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p), index++) + { + ecma_string_t *property_name_p; + + if (property_p->type == ECMA_PROPERTY_NAMEDDATA) + { + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_data_property.name_p); + } + else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR) + { + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_accessor_property.name_p); + } + else + { + continue; + } + + if (only_enumerable_properties && !ecma_is_property_enumerable (property_p)) + { + continue; + } + + JERRY_ASSERT (property_name_p != NULL); + + ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); + + ecma_property_descriptor_t item_prop_desc = ecma_make_empty_property_descriptor (); + { + item_prop_desc.is_value_defined = true; + item_prop_desc.value = ecma_make_string_value (property_name_p); + + item_prop_desc.is_writable_defined = true; + item_prop_desc.is_writable = true; + + item_prop_desc.is_enumerable_defined = true; + item_prop_desc.is_enumerable = true; + + item_prop_desc.is_configurable_defined = true; + item_prop_desc.is_configurable = true; + } + + ecma_completion_value_t completion = ecma_op_object_define_own_property (new_array_p, + index_string_p, + &item_prop_desc, + false); + + JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)); + + ecma_free_completion_value (completion); + ecma_deref_ecma_string (index_string_p); + } + + return new_array; +} /* ecma_builtin_helper_object_get_properties */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index 54918129f0..39a6b97285 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -28,6 +28,8 @@ extern ecma_completion_value_t ecma_builtin_helper_object_to_string (const ecma_value_t this_arg); extern ecma_completion_value_t ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, uint32_t index); +extern ecma_completion_value_t ecma_builtin_helper_object_get_properties (ecma_object_t *obj, + bool only_enumerable_properties); /** * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp index c3a6d12530..6a62abb2b8 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp @@ -15,6 +15,8 @@ */ #include "ecma-alloc.h" +#include "ecma-array-object.h" +#include "ecma-builtin-helpers.h" #include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" @@ -128,10 +130,24 @@ ecma_builtin_object_object_get_prototype_of (ecma_value_t this_arg, /**< 'this' * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t -ecma_builtin_object_object_get_own_property_names (ecma_value_t this_arg, /**< 'this' argument */ +ecma_builtin_object_object_get_own_property_names (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { - ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg); + ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); + + if (!ecma_is_value_object (arg)) + { + /* 1. */ + ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); + } + else + { + ecma_object_t *obj_p = ecma_get_object_from_value (arg); + /* 2-5. */ + ret_value = ecma_builtin_helper_object_get_properties (obj_p, false); + } + + return ret_value; } /* ecma_builtin_object_object_get_own_property_names */ /** @@ -240,10 +256,24 @@ ecma_builtin_object_object_is_extensible (ecma_value_t this_arg, /**< 'this' arg * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t -ecma_builtin_object_object_keys (ecma_value_t this_arg, /**< 'this' argument */ +ecma_builtin_object_object_keys (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { - ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg); + ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); + + if (!ecma_is_value_object (arg)) + { + /* 1. */ + ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); + } + else + { + ecma_object_t *obj_p = ecma_get_object_from_value (arg); + /* 3-6. */ + ret_value = ecma_builtin_helper_object_get_properties (obj_p, true); + } + + return ret_value; } /* ecma_builtin_object_object_keys */ /** diff --git a/tests/jerry/object_get_own_property_names.js b/tests/jerry/object_get_own_property_names.js new file mode 100644 index 0000000000..f11ab40dcb --- /dev/null +++ b/tests/jerry/object_get_own_property_names.js @@ -0,0 +1,73 @@ +// Copyright 2015 Samsung Electronics Co., Ltd. +// Copyright 2015 University of Szeged. +// +// 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. + +// Test array +var arr = ['a', 'b', 'c']; +var props = Object.getOwnPropertyNames(arr); +// props should contain: 0,1,2,length and the order is not defined! +assert (props.indexOf("0") !== -1); +assert (props.indexOf("1") !== -1); +assert (props.indexOf("2") !== -1); +assert (props.indexOf("length") !== -1); +assert (props.length === 4); + +// Test object +var obj = {key1: 'a', key3: 'b', key2: 'c', key4: 'c', key5: ''}; +props = Object.getOwnPropertyNames(obj); +// props should contain: key1,key2,key3,key4,key5 and the order is not defined! +assert (props.indexOf("key1") !== -1); +assert (props.indexOf("key2") !== -1); +assert (props.indexOf("key3") !== -1); +assert (props.indexOf("key4") !== -1); +assert (props.indexOf("key5") !== -1); +assert (props.length === 5); + +var obj2 = {}; +Object.defineProperties(obj2, { + key_one: {enumerable: true, value: 'one'}, + key_two: {enumerable: false, value: 'two'}, +}); + +props = Object.getOwnPropertyNames(obj2); +// props should contain: key_one,key_two and the order is not defined! +assert (props.indexOf("key_one") !== -1); +assert (props.indexOf("key_two") !== -1); +assert (props.length === 2); + +// Test prototype chain +function Parent() {} +Parent.prototype.inheritedMethod = function() {}; + +function Child() { + this.prop = 5; + this.method = function() {}; +} +Child.prototype = new Parent; +Child.prototype.prototypeMethod = function() {}; + +props = Object.getOwnPropertyNames (new Child()); +// props should contain: prop,method and the order is not defined! +assert (props.indexOf("prop") !== -1); +assert (props.indexOf("method") !== -1); + +assert (props.length === 2); + +// Test non-object argument +try { + Object.getOwnPrototypeNames("hello"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/object_keys.js b/tests/jerry/object_keys.js new file mode 100644 index 0000000000..d860891e39 --- /dev/null +++ b/tests/jerry/object_keys.js @@ -0,0 +1,71 @@ +// Copyright 2015 Samsung Electronics Co., Ltd. +// Copyright 2015 University of Szeged. +// +// 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. + +// Test array +var arr = ['a', 'b', 'c']; +var props = Object.keys(arr); +// props should contain: 0,1,2 and the order is not defined! +assert (props.indexOf("0") !== -1); +assert (props.indexOf("1") !== -1); +assert (props.indexOf("2") !== -1); +assert (props.length === 3); + +// Test object +var obj = {key1: 'a', key3: 'b', key2: 'c', key4: 'c', key5: ''}; +props = Object.keys(obj); +// props should contain: key1,key2,key3,key4,key5 and the order is not defined! +assert (props.indexOf("key1") !== -1); +assert (props.indexOf("key2") !== -1); +assert (props.indexOf("key3") !== -1); +assert (props.indexOf("key4") !== -1); +assert (props.indexOf("key5") !== -1); +assert (props.length === 5); + +var obj2 = {}; +Object.defineProperties(obj2, { + key_one: {enumerable: true, value: 'one'}, + key_two: {enumerable: false, value: 'two'}, +}); + +props = Object.keys(obj2); +// props should contain: key_one +assert (props.indexOf("key_one") !== -1); +assert (props.indexOf("key_two") === -1); +assert (props.length === 1); + +// Test prototype chain +function Parent() {} +Parent.prototype.inheritedMethod = function() {}; + +function Child() { + this.prop = 5; + this.method = function() {}; +} +Child.prototype = new Parent; +Child.prototype.prototypeMethod = function() {}; + +props = Object.keys (new Child()); +// props should contain: prop,method and the order is not defined! +assert (props.indexOf("prop") !== -1); +assert (props.indexOf("method") !== -1); +assert (props.length === 2); + +// Test non-object argument +try { + Object.keys("hello"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +}