Skip to content

Commit cc21cc3

Browse files
committed
Implement Array.prototype.join
JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
1 parent 137c5f3 commit cc21cc3

File tree

6 files changed

+321
-0
lines changed

6 files changed

+321
-0
lines changed

jerry-core/ecma/base/ecma-magic-strings.inc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ ECMA_MAGIC_STRING_DEF (ECMA_MAGIC_STRING_MESSAGE, "message")
205205
ECMA_MAGIC_STRING_DEF (ECMA_MAGIC_STRING_LEFT_SQUARE_CHAR, "[")
206206
ECMA_MAGIC_STRING_DEF (ECMA_MAGIC_STRING_RIGHT_SQUARE_CHAR, "]")
207207
ECMA_MAGIC_STRING_DEF (ECMA_MAGIC_STRING_COLON_CHAR, ":")
208+
ECMA_MAGIC_STRING_DEF (ECMA_MAGIC_STRING_COMMA_CHAR, ",")
208209
ECMA_MAGIC_STRING_DEF (ECMA_MAGIC_STRING_SPACE_CHAR, " ")
209210
ECMA_MAGIC_STRING_DEF (ECMA_MAGIC_STRING__EMPTY, "")
210211

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

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "ecma-alloc.h"
1717
#include "ecma-array-object.h"
18+
#include "ecma-array-prototype.h"
1819
#include "ecma-builtins.h"
1920
#include "ecma-comparison.h"
2021
#include "ecma-conversion.h"
@@ -168,6 +169,108 @@ ecma_builtin_array_prototype_object_for_each (ecma_value_t this_arg, /**< this a
168169
return ret_value;
169170
} /* ecma_builtin_array_prototype_object_for_each */
170171

172+
/**
173+
* The Array.prototype object's 'join' routine
174+
*
175+
* See also:
176+
* ECMA-262 v5, 15.4.4.5
177+
*
178+
* @return completion value
179+
* Returned value must be freed with ecma_free_completion_value.
180+
*/
181+
static ecma_completion_value_t
182+
ecma_builtin_array_prototype_join (const ecma_value_t this_arg, /**< this argument */
183+
const ecma_value_t separator_arg) /** < separator argument */
184+
{
185+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
186+
187+
/* 1. */
188+
ECMA_TRY_CATCH (obj_value,
189+
ecma_op_to_object (this_arg),
190+
ret_value);
191+
192+
ecma_object_t *obj_p = ecma_get_object_from_value (obj_value);
193+
194+
ecma_string_t *length_magic_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH);
195+
196+
/* 2. */
197+
ECMA_TRY_CATCH (length_value,
198+
ecma_op_object_get (obj_p, length_magic_string_p),
199+
ret_value);
200+
201+
ecma_number_t *length_p = ecma_get_number_from_value (length_value);
202+
203+
/* 3. */
204+
uint32_t length = ecma_number_to_uint32 (*length_p);
205+
206+
/* 4-5. */
207+
ECMA_TRY_CATCH (separator_value,
208+
ecma_op_array_get_separator_string (separator_arg),
209+
ret_value);
210+
211+
if (length == 0)
212+
{
213+
/* 6. */
214+
ecma_string_t *empty_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING__EMPTY);
215+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (empty_string_p));
216+
}
217+
else
218+
{
219+
ecma_string_t *separator_string_p = ecma_get_string_from_value (separator_value);
220+
221+
/* 7-8. */
222+
ECMA_TRY_CATCH (first_value,
223+
ecma_op_array_get_to_string_at_index (obj_p, 0),
224+
ret_value);
225+
226+
ecma_string_t *return_string_p = ecma_copy_or_ref_ecma_string (ecma_get_string_from_value (first_value));
227+
228+
/* 9-10. */
229+
for (uint32_t k = 1; ecma_is_completion_value_empty (ret_value) && (k < length); ++k)
230+
{
231+
/* 10.a */
232+
ecma_string_t *part_string_p = ecma_concat_ecma_strings (return_string_p, separator_string_p);
233+
234+
/* 10.b, 10.c */
235+
ECMA_TRY_CATCH (next_string_value,
236+
ecma_op_array_get_to_string_at_index (obj_p, k),
237+
ret_value);
238+
239+
ecma_string_t *next_string_p = ecma_get_string_from_value (next_string_value);
240+
241+
ecma_deref_ecma_string (return_string_p);
242+
243+
/* 10.d */
244+
return_string_p = ecma_concat_ecma_strings (part_string_p, next_string_p);
245+
246+
ECMA_FINALIZE (next_string_value);
247+
248+
ecma_deref_ecma_string (part_string_p);
249+
}
250+
251+
if (ecma_is_completion_value_empty (ret_value))
252+
{
253+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (return_string_p));
254+
}
255+
else
256+
{
257+
ecma_deref_ecma_string (return_string_p);
258+
}
259+
260+
ECMA_FINALIZE (first_value);
261+
}
262+
263+
ECMA_FINALIZE (separator_value);
264+
265+
ECMA_FINALIZE (length_value);
266+
267+
ecma_deref_ecma_string (length_magic_string_p);
268+
269+
ECMA_FINALIZE (obj_value);
270+
271+
return ret_value;
272+
} /* ecma_builtin_array_prototype_join */
273+
171274
/**
172275
* The Array.prototype object's 'toString' routine
173276
*

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_JOIN, ecma_builtin_array_prototype_join, 1, 1)
6263
ROUTINE (ECMA_MAGIC_STRING_TO_STRING_UL, ecma_builtin_array_prototype_object_to_string, 0, 0)
6364
ROUTINE (ECMA_MAGIC_STRING_POP, ecma_builtin_array_prototype_object_pop, 0, 0)
6465
ROUTINE (ECMA_MAGIC_STRING_PUSH, ecma_builtin_array_prototype_object_push, NON_FIXED, 1)
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
17+
#include "ecma-array-prototype.h"
18+
19+
#include "ecma-builtins.h"
20+
#include "ecma-conversion.h"
21+
#include "ecma-function-object.h"
22+
#include "ecma-exceptions.h"
23+
#include "ecma-helpers.h"
24+
#include "ecma-objects.h"
25+
#include "ecma-try-catch-macro.h"
26+
27+
/** \addtogroup ecma ECMA
28+
* @{
29+
*
30+
* \addtogroup ecmabuiltins
31+
* @{
32+
*
33+
* \addtogroup arrayprototype ECMA Array.prototype object built-in operations
34+
* @{
35+
*/
36+
37+
/**
38+
* The Array.prototype.toString's separator creation routine
39+
*
40+
* See also:
41+
* ECMA-262 v5.1, 15.4.4.2 4th step
42+
*
43+
* @return completion value
44+
* Returned value must be freed with ecma_free_completion_value.
45+
*/
46+
ecma_completion_value_t
47+
ecma_op_array_get_separator_string (ecma_value_t separator)
48+
{
49+
if (ecma_is_value_undefined (separator))
50+
{
51+
ecma_string_t *comma_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING_COMMA_CHAR);
52+
return ecma_make_normal_completion_value (ecma_make_string_value (comma_string_p));
53+
}
54+
else
55+
{
56+
return ecma_op_to_string (separator);
57+
}
58+
}
59+
60+
/**
61+
* The Array.prototype's 'toString' single element operation routine
62+
*
63+
* See also:
64+
* ECMA-262 v5.1, 15.4.4.2
65+
*
66+
* @return ecma_completion_value_t value
67+
* Returned value must be freed with ecma_free_completion_value.
68+
*/
69+
ecma_completion_value_t
70+
ecma_op_array_get_to_string_at_index (ecma_object_t *obj_p, /** < this object */
71+
uint32_t index) /** < array index */
72+
{
73+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
74+
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
75+
76+
ECMA_TRY_CATCH (index_value,
77+
ecma_op_object_get (obj_p, index_string_p),
78+
ret_value);
79+
80+
if (ecma_is_value_undefined (index_value)
81+
|| ecma_is_value_null (index_value))
82+
{
83+
ecma_string_t *empty_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING__EMPTY);
84+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (empty_string_p));
85+
}
86+
else
87+
{
88+
ret_value = ecma_op_to_string (index_value);
89+
}
90+
91+
ECMA_FINALIZE (index_value)
92+
93+
ecma_deref_ecma_string (index_string_p);
94+
95+
return ret_value;
96+
} /* ecma_op_array_get_to_string_at_index */
97+
98+
/**
99+
* @}
100+
* @}
101+
* @}
102+
*/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
17+
#ifndef ECMA_ARRAY_PROTOTYPE_H
18+
#define ECMA_ARRAY_PROTOTYPE_H
19+
20+
#include "ecma-globals.h"
21+
22+
/** \addtogroup ecma ECMA
23+
* @{
24+
*
25+
* \addtogroup ecmaarrayprototypeops ECMA array prototype's operations
26+
* @{
27+
*/
28+
29+
extern ecma_completion_value_t ecma_op_array_get_separator_string (ecma_value_t separator);
30+
extern ecma_completion_value_t ecma_op_array_get_to_string_at_index (ecma_object_t *obj_p, uint32_t index);
31+
32+
/**
33+
* @}
34+
* @}
35+
*/
36+
37+
#endif /* !ECMA_ARRAY_PROPERTY_H */

tests/jerry/array_prototype_join.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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+
assert ([].join() === "");
17+
assert ([1].join() === "1");
18+
assert ([1, 2].join() === "1,2");
19+
20+
21+
assert ([].join('--') === "");
22+
assert ([1].join("--") === "1");
23+
assert ([1, 2].join('--') === "1--2");
24+
25+
assert ([1,2,3].join({toString: function() { return "--"; }}) === "1--2--3");
26+
27+
28+
// Join should use 'length' to as the number of elements int the array.
29+
var lst = [1,2,3,4];
30+
lst.length = 3;
31+
assert (lst.join() === [1,2,3].join());
32+
33+
// Checking behavior when unable to get length.
34+
var obj = {};
35+
Object.defineProperty(obj, 'length', { 'get' : function () {throw new ReferenceError ("foo"); } });
36+
obj.join = Array.prototype.join;
37+
38+
try {
39+
obj.join();
40+
// Should not be reached.
41+
assert (false);
42+
} catch (e) {
43+
assert (e.message === "foo");
44+
assert (e instanceof ReferenceError);
45+
}
46+
47+
// Check join argument fail.
48+
try {
49+
[1,2,3].join({toString: function() { throw new ReferenceError ("foo"); }});
50+
// Should not be reached.
51+
assert (false);
52+
} catch (e) {
53+
assert (e.message === "foo");
54+
assert (e instanceof ReferenceError);
55+
}
56+
57+
// Check single join element fail.
58+
try {
59+
[1, 2, {toString: function() { throw new ReferenceError ("foo"); }}, 4].join();
60+
// Should not be reached.
61+
assert (false);
62+
} catch (e) {
63+
assert (e.message === "foo");
64+
assert (e instanceof ReferenceError);
65+
}
66+
67+
// Check join on different object.
68+
var obj_2 = {};
69+
obj_2.length = 3;
70+
obj_2[0] = 1;
71+
obj_2[1] = 2;
72+
obj_2[2] = 3;
73+
obj_2[3] = 4;
74+
75+
obj_2.join = Array.prototype.join;
76+
77+
assert (obj_2.join() === "1,2,3");

0 commit comments

Comments
 (0)