From 404b30f488d8c82fbf0d484b62c766830f894de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20B=C3=A1tyai?= Date: Thu, 14 May 2015 17:28:45 +0200 Subject: [PATCH] Implemented Array.prototype.indexOf(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com --- .../ecma-builtin-array-prototype.cpp | 131 ++++++++++++++++++ .../ecma-builtin-array-prototype.inc.h | 1 + tests/jerry/array_prototype_indexof.js | 66 +++++++++ 3 files changed, 198 insertions(+) create mode 100644 tests/jerry/array_prototype_indexof.js diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp index 28f873aad0..b7b53ad3cf 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp @@ -15,6 +15,7 @@ #include "ecma-alloc.h" #include "ecma-builtins.h" +#include "ecma-comparison.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-gc.h" @@ -266,6 +267,136 @@ ecma_builtin_array_prototype_object_push (ecma_value_t this_arg, /**< this argum return ret_value; } /* ecma_builtin_array_prototype_object_push */ +/** + * The Array.prototype object's 'indexOf' routine + * + * See also: + * ECMA-262 v5, 15.4.4.14 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value. + */ +static ecma_completion_value_t +ecma_builtin_array_prototype_object_index_of (ecma_value_t this_arg, /**< this argument */ + ecma_value_t arg1, /**< searchElement */ + ecma_value_t arg2) /**< fromIndex */ +{ + ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); + + /* 1. */ + ECMA_TRY_CATCH (obj_this, + ecma_op_to_object (this_arg), + ret_value); + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); + ecma_string_t *magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH); + + /* 2. */ + ECMA_TRY_CATCH (len_value, + ecma_op_object_get (obj_p, magic_string_length_p), + ret_value); + + ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value); + + /* 3. */ + uint32_t len = ecma_number_to_uint32 (len_number); + + ecma_number_t* num_p = ecma_alloc_number (); + *num_p = ecma_int32_to_number (-1); + + /* 4. */ + if (len == 0) + { + ret_value = ecma_make_normal_completion_value (ecma_make_number_value (num_p)); + } + else + { + /* 5. */ + ECMA_OP_TO_NUMBER_TRY_CATCH (arg_from_idx, arg2, ret_value); + + int32_t from_idx_int = ecma_number_to_int32 (arg_from_idx); + + /* 6. */ + if (from_idx_int > 0 && (uint32_t) from_idx_int >= len) + { + ret_value = ecma_make_normal_completion_value (ecma_make_number_value (num_p)); + } + else + { + uint32_t k; + + /* 7 */ + if (from_idx_int >= 0) + { + k = (uint32_t) from_idx_int; + } + /* 8. */ + else + { + from_idx_int = -from_idx_int; + + /* As opposed to the standard, we prevent k from being negative, so that we can use an uint32 */ + if ((uint32_t) from_idx_int < len) + { + /* 8.a */ + k = len - (uint32_t) from_idx_int; + } + /* If k would've been negative */ + else + { + /* 8.b */ + k = 0; + } + + } + JERRY_ASSERT (k < len); + + for (; k < len && *num_p < 0 && ecma_is_completion_value_empty (ret_value); k++) + { + ecma_string_t *idx_str_p = ecma_new_ecma_string_from_uint32 (k); + + /* 9.a */ + if (ecma_op_object_get_property (obj_p, idx_str_p) != NULL) + { + /* 9.b.i */ + ECMA_TRY_CATCH (get_value, ecma_op_object_get (obj_p, idx_str_p), ret_value); + + /* 9.b.ii */ + if (ecma_op_strict_equality_compare (arg1, get_value)) + { + *num_p = ecma_uint32_to_number (k); + } + + ECMA_FINALIZE (get_value); + } + + ecma_deref_ecma_string (idx_str_p); + } + + if (ecma_is_completion_value_empty (ret_value)) + { + ret_value = ecma_make_normal_completion_value (ecma_make_number_value (num_p)); + } + else + { + ecma_dealloc_number (num_p); + } + } + + ECMA_OP_TO_NUMBER_FINALIZE (arg_from_idx); + } + + ECMA_OP_TO_NUMBER_FINALIZE (len_number); + + ECMA_FINALIZE (len_value); + + ecma_deref_ecma_string (magic_string_length_p); + + ECMA_FINALIZE (obj_this); + + return ret_value; +} /* ecma_builtin_array_prototype_object_index_of */ + /** * @} * @} 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 dd7609f7ad..fe94267e40 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 @@ -61,6 +61,7 @@ NUMBER_VALUE (ECMA_MAGIC_STRING_LENGTH, ROUTINE (ECMA_MAGIC_STRING_TO_STRING_UL, ecma_builtin_array_prototype_object_to_string, 0, 0) ROUTINE (ECMA_MAGIC_STRING_POP, ecma_builtin_array_prototype_object_pop, 0, 0) ROUTINE (ECMA_MAGIC_STRING_PUSH, ecma_builtin_array_prototype_object_push, NON_FIXED, 1) +ROUTINE (ECMA_MAGIC_STRING_INDEX_OF_UL, ecma_builtin_array_prototype_object_index_of, 2, 1) #undef OBJECT_ID #undef SIMPLE_VALUE diff --git a/tests/jerry/array_prototype_indexof.js b/tests/jerry/array_prototype_indexof.js new file mode 100644 index 0000000000..15511c6b0b --- /dev/null +++ b/tests/jerry/array_prototype_indexof.js @@ -0,0 +1,66 @@ +// 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. + +var obj = {}; +var array = ["foo", 19, "bar", obj, "foo", 29, "baz"]; + +var index = array.indexOf("foo"); +assert(index === 0); +assert(array[index] === "foo"); + +assert(array.indexOf("foo", 1) === 4); +assert(array.indexOf("foo", 5) === -1); + +var index = array.indexOf("baz"); +assert(index === 6); +assert(array[index] === "baz"); + +assert(array.indexOf("baz", 7) === -1); + +var index = array.indexOf(obj); +assert(index === 3); +assert(array[index] === obj); + +// Checking behavior when length is zero +var obj = { indexOf : Array.prototype.indexOf, length : 0 }; +assert(obj.indexOf("foo") === -1); + +// Checking behavior when start index >= length +var arr = [11, 22, 33, 44]; +assert(arr.indexOf(44, 4) === -1); + +// Checking behavior when unable to get length +var obj = { indexOf : Array.prototype.indexOf} +Object.defineProperty(obj, 'length', { 'get' : function () { throw new ReferenceError ("foo"); } }); + +try { + obj.indexOf("bar"); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +} + +// Checking behavior when unable to get element +var obj = { indexOf : Array.prototype.indexOf, length : 1} +Object.defineProperty(obj, '0', { 'get' : function () { throw new ReferenceError ("foo"); } }); + +try { + obj.indexOf("bar"); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +}