From 6cc9848afc00614f56bd8e6fff07d3b94b3a48bb Mon Sep 17 00:00:00 2001 From: Szilagyi Adam Date: Tue, 10 Dec 2019 14:30:59 +0100 Subject: [PATCH] Implement Array.of method (#3418) The algorithm is based on ECMA-262 v6, 22.1.2.3 JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu --- .../ecma/builtin-objects/ecma-builtin-array.c | 69 ++++++++++++++++++ .../builtin-objects/ecma-builtin-array.inc.h | 1 + jerry-core/lit/lit-magic-strings.inc.h | 6 +- tests/jerry/es2015/array-of.js | 72 +++++++++++++++++++ 4 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 tests/jerry/es2015/array-of.js diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c index cea68674a..9f7504ea6 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c @@ -391,6 +391,75 @@ cleanup: ecma_deref_object (array_like_obj_p); return ret_value; } /* ecma_builtin_array_object_from */ + +/** + * The Array object's 'of' routine + * + * See also: + * ECMA-262 v6, 22.1.2.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_array_object_of (ecma_value_t this_arg, /**< 'this' argument */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + if (!ecma_is_constructor (this_arg)) + { + return ecma_op_create_array_object (arguments_list_p, arguments_list_len, false); + } + + ecma_value_t len = ecma_make_uint32_value (arguments_list_len); + + ecma_value_t ret_val = ecma_op_function_construct (ecma_get_object_from_value (this_arg), + ECMA_VALUE_UNDEFINED, + &len, + 1); + + if (ECMA_IS_VALUE_ERROR (ret_val)) + { + ecma_free_value (len); + return ret_val; + } + + uint32_t k = 0; + ecma_object_t *obj_p = ecma_get_object_from_value (ret_val); + const uint32_t prop_status_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; + + while (k < arguments_list_len) + { + ecma_value_t define_status = ecma_builtin_helper_def_prop_by_index (obj_p, + k, + arguments_list_p[k], + prop_status_flags); + + if (ECMA_IS_VALUE_ERROR (define_status)) + { + ecma_free_value (len); + ecma_deref_object (obj_p); + return define_status; + } + + k++; + } + + ret_val = ecma_op_object_put (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), + len, + true); + + ecma_free_value (len); + + if (ECMA_IS_VALUE_ERROR (ret_val)) + { + ecma_deref_object (obj_p); + return ret_val; + } + + return ecma_make_object_value (obj_p); +} /* ecma_builtin_array_object_of */ #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h index bd980fbbf..013aa683e 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h @@ -42,6 +42,7 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, ROUTINE (LIT_MAGIC_STRING_IS_ARRAY_UL, ecma_builtin_array_object_is_array, 1, 1) #if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_FROM, ecma_builtin_array_object_from, NON_FIXED, 1) +ROUTINE (LIT_MAGIC_STRING_OF, ecma_builtin_array_object_of, NON_FIXED, 0) #endif /* ENABLED (JERRY_ES2015) */ #endif /* !(ENABLED (JERRY_BUILTIN_ARRAY)) */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 898444070..6891e722c 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -38,7 +38,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PI_U, "PI") #if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS, "is") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_OF, "of") #endif #if ENABLED (JERRY_BUILTIN_MATH) @@ -813,7 +814,8 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (1, LIT_MAGIC_STRING_SPACE_CHAR) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_PI_U) #elif ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_IS) -#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#elif ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_OF) #elif ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_LN2_U) diff --git a/tests/jerry/es2015/array-of.js b/tests/jerry/es2015/array-of.js new file mode 100644 index 000000000..00b862fda --- /dev/null +++ b/tests/jerry/es2015/array-of.js @@ -0,0 +1,72 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// 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 with regular inputs +var array1 = Array.of(1, 2, 3, 4, 5); +assert(array1.length === 5); +assert(array1[2] === 3); + +// Test with no input +var array2 = Array.of(); +assert(array2.length === 0); +assert(array2[0] === undefined); + +// Test when an input is another array +var array3 = Array.of(array1, 6, 7); +assert(array3.length === 3); +assert(array3[0] instanceof Array); +assert(array3[0][3] === 4); +assert(array3[2] === 7); + +// Test with undefined +var array4 = Array.of(undefined); +assert(array4.length === 1); +assert(array4[0] === undefined); + +// Test when input is an object +var obj = { + 0: 0, + 1: 1 +}; + +var array5 = Array.of(obj, 2, 3); +assert(array5[0] instanceof Object); +assert(array5[0][0] === 0); +assert(array5[0][1] === 1); +assert(array5[2] === 3); + +// Test with array holes +var array6 = Array.of.apply(null, [,,undefined]); +assert(array6.length === 3); +assert(array6[0] === undefined); + +// Test with another class +var hits = 0; +function Test() { + hits++; +} +Test.of = Array.of; + +hits = 0; +var array6 = Test.of(1, 2); +assert(hits === 1); +assert(array6.length === 2); +assert(array6[1] === 2); + +// Test superficial features +var desc = Object.getOwnPropertyDescriptor(Array, "of"); +assert(desc.configurable === true); +assert(desc.writable === true); +assert(desc.enumerable === false); +assert(Array.of.length === 0);