Skip to content

Commit cf70fc2

Browse files
szledandbatyai
authored andcommitted
Implemented Array.prototype.concat()
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai [email protected] JerryScript-DCO-1.0-Signed-off-by: Szilard Ledan [email protected]
1 parent dd94064 commit cf70fc2

File tree

3 files changed

+206
-0
lines changed

3 files changed

+206
-0
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,149 @@ ecma_builtin_array_prototype_helper_set_length (ecma_object_t *object, /**< obje
7676
return ret_value;
7777
} /* ecma_builtin_array_prototype_helper_set_length */
7878

79+
/**
80+
* The Array.prototype object's 'concat' routine
81+
*
82+
* See also:
83+
* ECMA-262 v5, 15.4.4.4
84+
*
85+
* @return completion value
86+
* Returned value must be freed with ecma_free_completion_value.
87+
*/
88+
static ecma_completion_value_t
89+
ecma_builtin_array_prototype_object_concat (ecma_value_t this_arg, /**< this argument */
90+
const ecma_value_t args[], /**< arguments list */
91+
ecma_length_t args_number) /**< number of arguments */
92+
{
93+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
94+
/* 1. */
95+
ECMA_TRY_CATCH (obj_this,
96+
ecma_op_to_object (this_arg),
97+
ret_value);
98+
99+
ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
100+
ecma_string_t *magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH);
101+
102+
ECMA_TRY_CATCH (len_value,
103+
ecma_op_object_get (obj_p, magic_string_length_p),
104+
ret_value);
105+
106+
ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
107+
108+
uint32_t len = ecma_number_to_uint32 (len_number);
109+
110+
uint32_t new_array_index = 0;
111+
112+
/* 2. */
113+
ecma_completion_value_t new_array = ecma_op_create_array_object (0, 0, false);
114+
ecma_object_t *new_array_p = ecma_get_object_from_completion_value (new_array);
115+
116+
117+
for (uint32_t index = 0;
118+
index < len && ecma_is_completion_value_empty (ret_value);
119+
index++, new_array_index++)
120+
{
121+
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
122+
ECMA_TRY_CATCH (get_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
123+
124+
/* Using [[Put]] is equvalent to [[DefineOwnProperty]] in this case, so we use it for simplicity. */
125+
ecma_completion_value_t put_comp = ecma_op_object_put (new_array_p,
126+
index_string_p,
127+
get_value,
128+
false);
129+
JERRY_ASSERT (ecma_is_completion_value_normal (put_comp));
130+
ecma_free_completion_value (put_comp);
131+
132+
ECMA_FINALIZE (get_value);
133+
ecma_deref_ecma_string (index_string_p);
134+
}
135+
136+
for (uint32_t arg_index = 0;
137+
arg_index < args_number && ecma_is_completion_value_empty (ret_value);
138+
arg_index++)
139+
{
140+
/* 5.b */
141+
if (ecma_is_value_object (args[arg_index]) &&
142+
(ecma_get_object_type (ecma_get_object_from_value (args[arg_index])) == ECMA_OBJECT_TYPE_ARRAY))
143+
{
144+
/* 5.b.ii */
145+
ECMA_TRY_CATCH (arg_len_value,
146+
ecma_op_object_get (ecma_get_object_from_value (args[arg_index]),
147+
magic_string_length_p),
148+
ret_value);
149+
ECMA_OP_TO_NUMBER_TRY_CATCH (arg_len_number, len_value, ret_value);
150+
151+
uint32_t arg_len = ecma_number_to_uint32 (arg_len_number);
152+
153+
for (uint32_t array_index = 0;
154+
array_index < arg_len && ecma_is_completion_value_empty (ret_value);
155+
array_index++, new_array_index++)
156+
{
157+
ecma_string_t *array_index_string_p = ecma_new_ecma_string_from_uint32 (array_index);
158+
159+
/* 5.b.iii.2 */
160+
if (ecma_op_object_get_property (ecma_get_object_from_value (args[arg_index]),
161+
array_index_string_p) != NULL)
162+
{
163+
ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 (new_array_index);
164+
165+
ECMA_TRY_CATCH (get_value,
166+
ecma_op_object_get (ecma_get_object_from_value (args[arg_index]),
167+
array_index_string_p),
168+
ret_value);
169+
170+
/* Using [[Put]] is equvalent to [[DefineOwnProperty]] in this case, so we use it for simplicity. */
171+
ecma_completion_value_t put_comp = ecma_op_object_put (new_array_p,
172+
new_array_index_string_p,
173+
get_value,
174+
false);
175+
JERRY_ASSERT (ecma_is_completion_value_normal (put_comp));
176+
ecma_free_completion_value (put_comp);
177+
178+
ECMA_FINALIZE (get_value);
179+
ecma_deref_ecma_string (new_array_index_string_p);
180+
}
181+
182+
ecma_deref_ecma_string (array_index_string_p);
183+
}
184+
185+
ECMA_OP_TO_NUMBER_FINALIZE (len_number);
186+
ECMA_FINALIZE (arg_len_value);
187+
}
188+
else
189+
{
190+
ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 (new_array_index);
191+
192+
/* Using [[Put]] is equvalent to [[DefineOwnProperty]] in this case, so we use it for simplicity. */
193+
ecma_completion_value_t put_comp = ecma_op_object_put (new_array_p,
194+
new_array_index_string_p,
195+
args[arg_index],
196+
false);
197+
JERRY_ASSERT (ecma_is_completion_value_normal (put_comp));
198+
ecma_free_completion_value (put_comp);
199+
200+
ecma_deref_ecma_string (new_array_index_string_p);
201+
new_array_index++;
202+
}
203+
}
204+
205+
if (ecma_is_completion_value_empty (ret_value))
206+
{
207+
ret_value = new_array;
208+
}
209+
else
210+
{
211+
ecma_free_completion_value (new_array);
212+
}
213+
214+
ECMA_OP_TO_NUMBER_FINALIZE (len_number);
215+
ECMA_FINALIZE (len_value);
216+
ecma_deref_ecma_string (magic_string_length_p);
217+
ECMA_FINALIZE (obj_this);
218+
219+
return ret_value;
220+
}
221+
79222
/**
80223
* The Array.prototype object's 'forEach' routine
81224
*

jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ NUMBER_VALUE (ECMA_MAGIC_STRING_LENGTH,
5959
/* Routine properties:
6060
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
6161
ROUTINE (ECMA_MAGIC_STRING_FOR_EACH_UL, ecma_builtin_array_prototype_object_for_each, 2, 1)
62+
ROUTINE (ECMA_MAGIC_STRING_CONCAT, ecma_builtin_array_prototype_object_concat, NON_FIXED, 1)
6263
ROUTINE (ECMA_MAGIC_STRING_JOIN, ecma_builtin_array_prototype_join, 1, 1)
6364
ROUTINE (ECMA_MAGIC_STRING_TO_STRING_UL, ecma_builtin_array_prototype_object_to_string, 0, 0)
6465
ROUTINE (ECMA_MAGIC_STRING_POP, ecma_builtin_array_prototype_object_pop, 0, 0)

tests/jerry/array_prototype_concat.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2015 Samsung Electronics Co., Ltd.
2+
// Copyright 2015 University of Szeged.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
var array = ["foo", [], Infinity, 4]
17+
var new_arr = array.concat();
18+
19+
assert(new_arr.length === array.length)
20+
for (i = 0; i < array.length; i++) {
21+
assert(array[i] === new_arr[i]);
22+
}
23+
24+
var obj = {};
25+
var arr1 = ["Apple", 6, "Peach"];
26+
var arr2 = [obj, "Cherry", "Grape"];
27+
28+
var new_array = arr1.concat(arr2, obj, 1);
29+
30+
assert(new_array.length === 8);
31+
assert(new_array[0] === "Apple");
32+
assert(new_array[1] === 6);
33+
assert(new_array[2] === "Peach");
34+
assert(new_array[3] === obj);
35+
assert(new_array[4] === "Cherry");
36+
assert(new_array[5] === "Grape");
37+
assert(new_array[6] === obj);
38+
assert(new_array[7] === 1);
39+
40+
// Checking behavior when unable to get length
41+
var obj = { concat : Array.prototype.concat }
42+
Object.defineProperty(obj, 'length', { 'get' : function () {throw new ReferenceError ("foo"); } });
43+
44+
try {
45+
obj.concat();
46+
assert(false);
47+
} catch (e) {
48+
assert(e.message === "foo");
49+
assert(e instanceof ReferenceError);
50+
}
51+
52+
// Checking behavior when unable to get element
53+
var obj = { concat : Array.prototype.concat, length : 1 }
54+
Object.defineProperty(obj, '0', { 'get' : function () {throw new ReferenceError ("foo"); } });
55+
56+
try {
57+
obj.concat();
58+
assert(false);
59+
} catch (e) {
60+
assert(e.message === "foo");
61+
assert(e instanceof ReferenceError);
62+
}

0 commit comments

Comments
 (0)