Skip to content

Commit 69a2739

Browse files
committed
Implement String.prototype.substring()
JerryScript-DCO-1.0-Signed-off-by: Laszlo Vidacs [email protected]
1 parent e027b4d commit 69a2739

File tree

2 files changed

+232
-1
lines changed

2 files changed

+232
-1
lines changed

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

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,130 @@ ecma_builtin_string_prototype_object_substring (ecma_value_t this_arg, /**< this
421421
ecma_value_t arg1, /**< routine's first argument */
422422
ecma_value_t arg2) /**< routine's second argument */
423423
{
424-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg1, arg2);
424+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
425+
426+
/* 1 */
427+
ECMA_TRY_CATCH (check_coercible_val,
428+
ecma_op_check_object_coercible (this_arg),
429+
ret_value);
430+
431+
/* 2 */
432+
ECMA_TRY_CATCH (to_string_val,
433+
ecma_op_to_string (this_arg),
434+
ret_value);
435+
436+
/* 3 */
437+
ecma_string_t *original_string_p = ecma_get_string_from_value (to_string_val);
438+
439+
JERRY_ASSERT (ecma_string_get_length (original_string_p) >= 0);
440+
441+
const uint32_t len = (uint32_t) ecma_string_get_length (original_string_p);
442+
443+
/* 4, 6 */
444+
ECMA_OP_TO_NUMBER_TRY_CATCH (start_num,
445+
arg1,
446+
ret_value);
447+
448+
uint32_t start = 0, end = len;
449+
450+
if (ecma_number_is_nan (start_num) || ecma_number_is_negative (start_num))
451+
{
452+
start = 0;
453+
}
454+
else
455+
{
456+
if (ecma_number_is_infinity (start_num))
457+
{
458+
start = len;
459+
}
460+
else
461+
{
462+
start = ecma_number_to_uint32 (start_num);
463+
464+
if (start > len)
465+
{
466+
start = len;
467+
}
468+
}
469+
}
470+
471+
/* 5, 7 */
472+
if (ecma_is_value_undefined (arg2))
473+
{
474+
end = len;
475+
}
476+
else
477+
{
478+
ECMA_OP_TO_NUMBER_TRY_CATCH (end_num,
479+
arg2,
480+
ret_value);
481+
482+
if (ecma_number_is_nan (end_num) || ecma_number_is_negative (end_num))
483+
{
484+
end = 0;
485+
}
486+
else
487+
{
488+
if (ecma_number_is_infinity (end_num))
489+
{
490+
end = len;
491+
}
492+
else
493+
{
494+
end = ecma_number_to_uint32 (end_num);
495+
496+
if (end > len)
497+
{
498+
end = len;
499+
}
500+
}
501+
}
502+
503+
ECMA_OP_TO_NUMBER_FINALIZE (end_num);
504+
}
505+
506+
if (ecma_is_completion_value_empty (ret_value))
507+
{
508+
JERRY_ASSERT (start <= len && end <= len);
509+
510+
/* 8 */
511+
uint32_t from = start < end ? start : end;
512+
513+
/* 9 */
514+
uint32_t to = start > end ? start : end;
515+
516+
/* 10 */
517+
/* Workaround: avoid repeated call of ecma_string_get_char_at_pos() because its overhead */
518+
uint32_t zt_str_size = (uint32_t) sizeof (ecma_char_t) * (len + 1);
519+
ecma_char_t *original_zt_str_p = (ecma_char_t*) mem_heap_alloc_block (zt_str_size,
520+
MEM_HEAP_ALLOC_SHORT_TERM);
521+
ecma_string_to_zt_string (original_string_p, original_zt_str_p, (ssize_t) zt_str_size);
522+
523+
uint32_t new_len = to - from;
524+
525+
MEM_DEFINE_LOCAL_ARRAY (new_str_buffer, new_len + 1, ecma_char_t);
526+
527+
for (uint32_t idx = 0; idx < new_len; ++idx)
528+
{
529+
new_str_buffer[idx] = original_zt_str_p[idx + from];
530+
}
531+
532+
new_str_buffer[new_len] = '\0';
533+
ecma_string_t *new_str_p = ecma_new_ecma_string ((ecma_char_t *) new_str_buffer);
534+
535+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (new_str_p));
536+
537+
MEM_FINALIZE_LOCAL_ARRAY (new_str_buffer);
538+
539+
mem_heap_free_block (original_zt_str_p);
540+
}
541+
542+
ECMA_OP_TO_NUMBER_FINALIZE (start_num);
543+
544+
ECMA_FINALIZE (to_string_val);
545+
ECMA_FINALIZE (check_coercible_val);
546+
547+
return ret_value;
425548
} /* ecma_builtin_string_prototype_object_substring */
426549

427550
/**
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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+
// check properties
17+
assert(Object.getOwnPropertyDescriptor(String.prototype.substring, 'length').configurable === false);
18+
19+
assert(Object.getOwnPropertyDescriptor(String.prototype.substring, 'length').enumerable === false);
20+
21+
assert(Object.getOwnPropertyDescriptor(String.prototype.substring, 'length').writable === false);
22+
23+
assert(String.prototype.substring.length === 2);
24+
25+
assert(String.prototype.substring.call(new String()) === "");
26+
27+
assert(String.prototype.substring.call({}) === "[object Object]");
28+
29+
// check this is undefined
30+
try {
31+
String.prototype.substring.call(undefined);
32+
assert(false);
33+
} catch(e) {
34+
assert(e instanceof TypeError);
35+
}
36+
37+
// check this is null
38+
try {
39+
String.prototype.substring.call(null);
40+
assert(false);
41+
} catch(e) {
42+
assert(e instanceof TypeError);
43+
}
44+
45+
// simple checks
46+
assert("hello world!".substring(0, 11) === "hello world");
47+
48+
assert("hello world!".substring(11, 0) === "hello world");
49+
50+
assert("hello world!".substring(0, 12) === "hello world!");
51+
52+
assert("hello world!".substring(12, 0) === "hello world!");
53+
54+
// check NaN
55+
assert("hello world!".substring(NaN, 12) === "hello world!");
56+
57+
// check NaN
58+
assert("hello world!".substring(2, NaN) === "he");
59+
60+
// check and undefined
61+
assert("hello world!".substring(2, undefined) === "llo world!");
62+
63+
// check negative
64+
assert("hello world!".substring(-1,8) === "hello wo");
65+
66+
// check negative
67+
assert("hello\tworld!".substring(5,-8) === "hello");
68+
69+
// check negative
70+
assert("hello world!".substring(-1,-8) === "");
71+
72+
// check ranges
73+
assert("hello world!".substring(-1,10000) === "hello world!");
74+
75+
assert("hello world!".substring(10000,1000000) === "");
76+
77+
assert("hello world!".substring(100000,1) === "ello world!");
78+
79+
// check integer conversion
80+
assert("hello world!".substring(undefined, 5) === "hello");
81+
82+
assert("hello world!".substring(undefined, "bar") === "");
83+
84+
assert("hello world!".substring(2, true) === "e");
85+
86+
assert("hello world!".substring(2, false) === "he");
87+
88+
assert("hello world!".substring(5, obj) === " world!");
89+
90+
// check other objects
91+
var obj = { substring : String.prototype.substring }
92+
93+
obj.toString = function() {
94+
return "Iam";
95+
}
96+
assert(obj.substring(100000,1) === "am");
97+
98+
obj.toString = function() {
99+
throw new ReferenceError ("foo");
100+
};
101+
102+
try {
103+
assert(obj.substring(100000,1));
104+
assert(false);
105+
} catch (e) {
106+
assert(e.message === "foo");
107+
assert(e instanceof ReferenceError);
108+
}

0 commit comments

Comments
 (0)