diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index 6a65fa75d..7b3ff023f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -71,6 +71,7 @@ enum ECMA_ARRAY_PROTOTYPE_REDUCE, ECMA_ARRAY_PROTOTYPE_REDUCE_RIGHT, ECMA_ARRAY_PROTOTYPE_FIND, + ECMA_ARRAY_PROTOTYPE_FIND_INDEX, ECMA_ARRAY_PROTOTYPE_ENTRIES, ECMA_ARRAY_PROTOTYPE_VALUES, ECMA_ARRAY_PROTOTYPE_KEYS, @@ -1995,10 +1996,11 @@ ecma_builtin_array_reduce_from (ecma_value_t callbackfn, /**< routine's 1st argu #if ENABLED (JERRY_ES2015_BUILTIN) /** - * The Array.prototype object's 'find' routine + * The Array.prototype object's 'find' and 'findIndex' routine * * See also: * ECMA-262 v6, 22.1.3.8 + * ECMA-262 v6, 22.1.3.9 * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -2007,6 +2009,8 @@ static ecma_value_t ecma_builtin_array_prototype_object_find (ecma_value_t predicate, /**< callback function */ ecma_value_t predicate_this_arg, /**< this argument for * invoke predicate */ + bool is_find, /**< true - find routine + * false - findIndex routine */ ecma_object_t *obj_p, /**< array object */ uint32_t len) /**< array object's length */ { @@ -2034,7 +2038,7 @@ ecma_builtin_array_prototype_object_find (ecma_value_t predicate, /**< callback if (ecma_is_value_found (get_value)) { /* 8.d - 8.e */ - uint32_t current_index = ecma_make_uint32_value (index); + ecma_value_t current_index = ecma_make_uint32_value (index); ecma_value_t call_args[] = { get_value, current_index, ecma_make_object_value (obj_p) }; @@ -2043,7 +2047,7 @@ ecma_builtin_array_prototype_object_find (ecma_value_t predicate, /**< callback if (ecma_op_to_boolean (call_value)) { /* 8.f */ - ret_value = ecma_copy_value (get_value); + ret_value = is_find ? ecma_copy_value (get_value) : current_index; } ECMA_FINALIZE (call_value); @@ -2057,7 +2061,7 @@ ecma_builtin_array_prototype_object_find (ecma_value_t predicate, /**< callback if (ecma_is_value_empty (ret_value)) { /* 9. */ - ret_value = ECMA_VALUE_UNDEFINED; + ret_value = is_find ? ECMA_VALUE_UNDEFINED : ecma_make_integer_value (-1); } return ret_value; @@ -2303,9 +2307,11 @@ ecma_builtin_array_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< } #if ENABLED (JERRY_ES2015_BUILTIN) case ECMA_ARRAY_PROTOTYPE_FIND: + case ECMA_ARRAY_PROTOTYPE_FIND_INDEX: { ret_value = ecma_builtin_array_prototype_object_find (routine_arg_1, routine_arg_2, + builtin_routine_id == ECMA_ARRAY_PROTOTYPE_FIND, obj_p, length); break; diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h index 04c3e4d88..ad86d85e7 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h @@ -64,6 +64,7 @@ ROUTINE (LIT_MAGIC_STRING_REDUCE, ECMA_ARRAY_PROTOTYPE_REDUCE, NON_FIXED, 1) ROUTINE (LIT_MAGIC_STRING_REDUCE_RIGHT_UL, ECMA_ARRAY_PROTOTYPE_REDUCE_RIGHT, NON_FIXED, 1) #if ENABLED (JERRY_ES2015_BUILTIN) ROUTINE (LIT_MAGIC_STRING_FIND, ECMA_ARRAY_PROTOTYPE_FIND, 2, 1) +ROUTINE (LIT_MAGIC_STRING_FIND_INDEX, ECMA_ARRAY_PROTOTYPE_FIND_INDEX, 2, 1) #endif /* ENABLED (JERRY_ES2015_BUILTIN) */ #if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) ROUTINE (LIT_MAGIC_STRING_ENTRIES, ECMA_ARRAY_PROTOTYPE_ENTRIES, 0, 0) diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c index bd46a52b9..8aee29f3f 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c @@ -1501,19 +1501,18 @@ ecma_builtin_typedarray_prototype_sort (ecma_value_t this_arg, /**< this argumen } /* ecma_builtin_typedarray_prototype_sort */ /** - * The %TypedArray%.prototype object's 'find' routine - * - * See also: - * ECMA-262 v6, 22.2.3.10 + * The %TypedArray%.prototype object's 'find' and 'findIndex' routine helper * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_typedarray_prototype_find (ecma_value_t this_arg, /**< this argument */ - ecma_value_t predicate, /**< callback function */ - ecma_value_t predicate_this_arg) /**< this argument for - * invoke predicate */ +ecma_builtin_typedarray_prototype_find_helper (ecma_value_t this_arg, /**< this argument */ + ecma_value_t predicate, /**< callback function */ + ecma_value_t predicate_this_arg, /**< this argument for + * invoke predicate */ + bool is_find) /**< true - find routine + * false - findIndex routine */ { if (!ecma_is_typedarray (this_arg)) { @@ -1544,7 +1543,7 @@ ecma_builtin_typedarray_prototype_find (ecma_value_t this_arg, /**< this argumen ecma_number_t element_num = ecma_get_typedarray_element (typedarray_buffer_p + byte_index, class_id); ecma_value_t element_value = ecma_make_number_value (element_num); - ecma_value_t call_args[] = { element_value, ecma_make_uint32_value (buffer_index++), this_arg }; + ecma_value_t call_args[] = { element_value, ecma_make_uint32_value (buffer_index), this_arg }; ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3); @@ -1559,15 +1558,51 @@ ecma_builtin_typedarray_prototype_find (ecma_value_t this_arg, /**< this argumen if (call_result) { - return element_value; + return is_find ? element_value : ecma_make_uint32_value (buffer_index); } - + buffer_index++; ecma_free_value (element_value); } - return ECMA_VALUE_UNDEFINED; + return is_find ? ECMA_VALUE_UNDEFINED : ecma_make_integer_value (-1); +} /* ecma_builtin_typedarray_prototype_find_helper */ + +/** + * The %TypedArray%.prototype object's 'find' routine + * + * See also: + * ECMA-262 v6, 22.2.3.10 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_typedarray_prototype_find (ecma_value_t this_arg, /**< this argument */ + ecma_value_t predicate, /**< callback function */ + ecma_value_t predicate_this_arg) /**< this argument for + * invoke predicate */ +{ + return ecma_builtin_typedarray_prototype_find_helper (this_arg, predicate, predicate_this_arg, true); } /* ecma_builtin_typedarray_prototype_find */ +/** + * The %TypedArray%.prototype object's 'findIndex' routine + * + * See also: + * ECMA-262 v6, 22.2.3.11 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_typedarray_prototype_find_index (ecma_value_t this_arg, /**< this argument */ + ecma_value_t predicate, /**< callback function */ + ecma_value_t predicate_this_arg) /**< this argument for + * invoke predicate */ +{ + return ecma_builtin_typedarray_prototype_find_helper (this_arg, predicate, predicate_this_arg, false); +} /* ecma_builtin_typedarray_prototype_find_index */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h index 5f5809573..ea3f25ba0 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h @@ -69,6 +69,7 @@ ROUTINE (LIT_MAGIC_STRING_SUBARRAY, ecma_builtin_typedarray_prototype_subarray, ROUTINE (LIT_MAGIC_STRING_FILL, ecma_builtin_typedarray_prototype_fill, 3, 1) ROUTINE (LIT_MAGIC_STRING_SORT, ecma_builtin_typedarray_prototype_sort, 1, 1) ROUTINE (LIT_MAGIC_STRING_FIND, ecma_builtin_typedarray_prototype_find, 2, 1) +ROUTINE (LIT_MAGIC_STRING_FIND_INDEX, ecma_builtin_typedarray_prototype_find_index, 2, 1) #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 04ba63732..6df47ff69 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -477,6 +477,10 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNDEFINED_UL, "Undefined") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARGUMENTS, "arguments") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DECODE_URI, "decodeURI") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENCODE_URI, "encodeURI") +#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FIND_INDEX, "findIndex") +#endif #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_DAY_UL, "getUTCDay") #endif diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index db8369523..92e6d1719 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -211,6 +211,7 @@ LIT_MAGIC_STRING_UNDEFINED_UL = "Undefined" LIT_MAGIC_STRING_ARGUMENTS = "arguments" LIT_MAGIC_STRING_DECODE_URI = "decodeURI" LIT_MAGIC_STRING_ENCODE_URI = "encodeURI" +LIT_MAGIC_STRING_FIND_INDEX = "findIndex" LIT_MAGIC_STRING_GET_UTC_DAY_UL = "getUTCDay" LIT_MAGIC_STRING_GET_UINT16_UL = "getUint16" LIT_MAGIC_STRING_GET_UINT32_UL = "getUint32" diff --git a/tests/jerry/es2015/array-prototype-find-index.js b/tests/jerry/es2015/array-prototype-find-index.js new file mode 100644 index 000000000..8a763144c --- /dev/null +++ b/tests/jerry/es2015/array-prototype-find-index.js @@ -0,0 +1,155 @@ +// 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. + +var arrow_is_available = false; + +try { + assert (eval ("(f => 5) ()") === 5); + arrow_is_available = true; +} catch (e) { + assert (e instanceof SyntaxError); +} + +var array1 = [5, 12, 0, 8, 130, 44]; + +function bigger_than_10 (element) { + return element > 10; +} + +assert (array1.findIndex (bigger_than_10) === 1); + +function less_than_0 (element) { + if (element == 0) { + throw new Error ("zero"); + } + return element < 0; +} + +try { + array1.findIndex (less_than_0); + assert (false); +} catch (e) { + assert (e instanceof Error); + assert (e.message === "zero"); +} + +var inventory = [ + {name: 'apples', quantity: 2}, + {name: 'bananas', quantity: 0}, + {name: 'cherries', quantity: 5} +]; + +function isCherries (fruit) { + return fruit.name === 'cherries'; +} + +assert (JSON.stringify (inventory.findIndex (isCherries)) === "2"); + +if (arrow_is_available) { + assert (eval ("inventory.findIndex (fruit => fruit.name === 'bananas')") === 1); +} + +/* Test the callback function arguments */ +var src_array = [4, 6, 8, 12]; +var array_index = 0; + +function isPrime (element, index, array) { + assert (array_index++ === index); + assert (array === src_array) + assert (element === array[index]); + + var start = 2; + while (start <= Math.sqrt (element)) { + if (element % start++ < 1) { + return false; + } + } + return element > 1; +} + +assert (src_array.findIndex (isPrime) === -1); + +src_array = [4, 5, 8, 12]; +array_index = 0; +assert (src_array.findIndex (isPrime) === 1); + +// Checking behavior when the given object is not %Array% +try { + Array.prototype.findIndex.call (5); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +// Checking behavior when unable to get length +var obj = {}; +Object.defineProperty (obj, 'length', { 'get' : function () { throw new ReferenceError ("foo"); } }); +obj.findIndex = Array.prototype.findIndex; + +try { + obj.findIndex (); + assert (false); +} catch (e) { + assert (e.message === "foo"); + assert (e instanceof ReferenceError); +} + +var data = { 0: 1, 2: -3, 3: "string" } +assert (Array.prototype.findIndex.call (data, function (e) { return e < 5; }) === -1); + +// Checking behavior when unable to get element +var obj = {} +obj.length = 1; +Object.defineProperty (obj, '0', { 'get' : function () { throw new ReferenceError ("foo"); } }); +obj.findIndex = Array.prototype.findIndex; + +try { + obj.findIndex (function () { return undefined; }); + assert (false); +} catch (e) { + assert (e.message === "foo"); + assert (e instanceof ReferenceError); +} + +// Checking behavior when the first argument is not a callback +var array = [1, 2, 3]; + +try { + array.findIndex (5); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +// Checking behavior when the first argument does not exist +try { + array.findIndex (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +// Checking behavior when there are more than 2 arguments +assert (array.findIndex (function (e) { return e < 2 }, {}, 8, 4, 5, 6, 6) === 0); + +function func (element) { + return element > 8; +} + +/* ES v6.0 22.1.3.9.8.c + Checking behavior when the first element deletes the second */ + function f() { delete arr[1]; }; + var arr = [0, 1, 2, 3]; + Object.defineProperty(arr, '0', { 'get' : f }); + Array.prototype.findIndex.call(arr, func); diff --git a/tests/jerry/es2015/typedArray-find-index.js b/tests/jerry/es2015/typedArray-find-index.js new file mode 100644 index 000000000..cb54de996 --- /dev/null +++ b/tests/jerry/es2015/typedArray-find-index.js @@ -0,0 +1,116 @@ +// 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. + +var arrow_is_available = false; + +try { + assert (eval ("(f => 5) ()") === 5); + arrow_is_available = true; +} catch (e) { + assert (e instanceof SyntaxError); +} + +var typedArrayTypes = [Int8Array, + Uint8Array, + Uint8ClampedArray, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array]; + + +typedArrayTypes.forEach (function (TypedArray) { + + var array1 = new TypedArray ([5, 12, 0, 8, 120, 44]); + + function bigger_than_10 (element) { + return element > 10; + } + + assert (array1.findIndex (bigger_than_10) === 1); + + function less_than_0 (element) { + if (element == 0) { + throw new Error ("zero"); + } + return element < 0; + } + + try { + array1.findIndex (less_than_0); + assert (false); + } catch (e) { + assert (e instanceof Error); + assert (e.message === "zero"); + } + + if (arrow_is_available) { + assert (eval ("array1.findIndex (e => e > 100)") === 4); + } + + /* Test the callback function arguments */ + var src_array = new TypedArray ([4, 6, 8, 12]); + var array_index = 0; + + function isPrime (element, index, array) { + assert (array_index++ === index); + assert (array === src_array) + assert (element === array[index]); + + var start = 2; + while (start <= Math.sqrt (element)) { + if (element % start++ < 1) { + return false; + } + } + return element > 1; + } + + assert (src_array.findIndex (isPrime) === -1); + + src_array = new TypedArray ([4, 5, 8, 12]); + array_index = 0; + assert (src_array.findIndex (isPrime) === 1); + + // Checking behavior when the given object is not %TypedArray% + try { + TypedArray.prototype.findIndex.call (5); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + // Checking behavior when the first argument is not a callback + var array = new TypedArray ([1, 2, 3]); + + try { + array.findIndex (5); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + // Checking behavior when the first argument does not exist + try { + array.findIndex (); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + // Checking behavior when there are more than 2 arguments + assert (array.findIndex (function (e) { return e < 2 }, {}, 8, 4, 5, 6, 6) === 0); +})