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 becc07cdba..da5b56de21 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp @@ -663,6 +663,103 @@ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /**< t return ret_value; } /* ecma_builtin_array_prototype_object_last_index_of */ +/** + * The Array.prototype object's 'reverse' routine + * + * See also: + * ECMA-262 v5, 15.4.4.8 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value. + */ +static ecma_completion_value_t +ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg) /**< this argument */ +{ + 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); + + /* 4. */ + uint32_t middle = len / 2; + + /* 5. and 6. */ + for (uint32_t lower = 0; lower < middle && ecma_is_completion_value_empty (ret_value); lower++) + { + /* 6.a */ + uint32_t upper = len - lower - 1; + /* 6.b and 6.c */ + ecma_string_t *upper_str_p = ecma_new_ecma_string_from_uint32 (upper); + ecma_string_t *lower_str_p = ecma_new_ecma_string_from_uint32 (lower); + + /* 6.d and 6.e */ + ECMA_TRY_CATCH (lower_value, ecma_op_object_get (obj_p, lower_str_p), ret_value); + ECMA_TRY_CATCH (upper_value, ecma_op_object_get (obj_p, upper_str_p), ret_value); + + /* 6.f and 6.g */ + bool lower_exist = (ecma_op_object_get_property (obj_p, lower_str_p) != NULL); + bool upper_exist = (ecma_op_object_get_property (obj_p, upper_str_p) != NULL); + + /* 6.h */ + if (lower_exist && upper_exist) + { + ECMA_TRY_CATCH (outer_put_value, ecma_op_object_put (obj_p, lower_str_p, upper_value, true), ret_value); + ECMA_TRY_CATCH (inner_put_value, ecma_op_object_put (obj_p, upper_str_p, lower_value, true), ret_value); + ECMA_FINALIZE (inner_put_value); + ECMA_FINALIZE (outer_put_value); + } + /* 6.i */ + else if (!lower_exist && upper_exist) + { + ECMA_TRY_CATCH (put_value, ecma_op_object_put (obj_p, lower_str_p, upper_value, true), ret_value); + ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, upper_str_p, true), ret_value); + ECMA_FINALIZE (del_value); + ECMA_FINALIZE (put_value); + } + /* 6.j */ + else if (lower_exist && !upper_exist) + { + ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, lower_str_p, true), ret_value); + ECMA_TRY_CATCH (put_value, ecma_op_object_put (obj_p, upper_str_p, lower_value, true), ret_value); + ECMA_FINALIZE (put_value); + ECMA_FINALIZE (del_value); + } + + ECMA_FINALIZE (upper_value); + ECMA_FINALIZE (lower_value); + ecma_deref_ecma_string (lower_str_p); + ecma_deref_ecma_string (upper_str_p); + } + + if (ecma_is_completion_value_empty (ret_value)) + { + /* 7. */ + ret_value = ecma_make_normal_completion_value (ecma_copy_value (obj_this, true)); + } + + 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_reverse */ + /** * The Array.prototype object's 'shift' routine * 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 b17cc6a786..d78402aba4 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 (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) ROUTINE (ECMA_MAGIC_STRING_LAST_INDEX_OF_UL, ecma_builtin_array_prototype_object_last_index_of, 2, 1) +ROUTINE (ECMA_MAGIC_STRING_REVERSE, ecma_builtin_array_prototype_object_reverse, 0, 0) ROUTINE (ECMA_MAGIC_STRING_SHIFT, ecma_builtin_array_prototype_object_shift, 0, 0) ROUTINE (ECMA_MAGIC_STRING_UNSHIFT, ecma_builtin_array_prototype_object_unshift, NON_FIXED, 1) ROUTINE (ECMA_MAGIC_STRING_SLICE, ecma_builtin_array_prototype_object_slice, 2, 2) diff --git a/tests/jerry/array_prototype_reverse.js b/tests/jerry/array_prototype_reverse.js new file mode 100644 index 0000000000..8518590b43 --- /dev/null +++ b/tests/jerry/array_prototype_reverse.js @@ -0,0 +1,46 @@ +// 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 array = [4, 3, 2, 1, 0] + +array.reverse(); + +for (i = 0; i < array.length; i++) { + assert(array[i] === i); +} + +// Checking behavior when unable to get length +var obj = { reverse : Array.prototype.reverse }; +Object.defineProperty(obj, 'length', { 'get' : function () {throw new ReferenceError ("foo"); } }); + +try { + obj.reverse(); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +} + +// Checking behavior when unable to get element +var obj = { reverse : Array.prototype.reverse, length : 3 }; +Object.defineProperty(obj, '0', { 'get' : function () {throw new ReferenceError ("foo"); } }); + +try { + obj.reverse(); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +}