Skip to content

Commit b419eb6

Browse files
committed
Implement String.prototype.match
Added implementation for the String.prototype.match method. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
1 parent bcedc90 commit b419eb6

File tree

3 files changed

+344
-1
lines changed

3 files changed

+344
-1
lines changed

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

Lines changed: 241 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include "ecma-alloc.h"
18+
#include "ecma-array-object.h"
1819
#include "ecma-builtin-helpers.h"
1920
#include "ecma-builtins.h"
2021
#include "ecma-conversion.h"
@@ -331,6 +332,8 @@ ecma_builtin_string_prototype_object_locale_compare (ecma_value_t this_arg, /**<
331332
return ret_value;
332333
} /* ecma_builtin_string_prototype_object_locale_compare */
333334

335+
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
336+
334337
/**
335338
* The String.prototype object's 'match' routine
336339
*
@@ -344,8 +347,245 @@ static ecma_completion_value_t
344347
ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this argument */
345348
ecma_value_t arg) /**< routine's argument */
346349
{
347-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
350+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
351+
352+
/* 1. */
353+
ECMA_TRY_CATCH (this_check_coercible_value,
354+
ecma_op_check_object_coercible (this_arg),
355+
ret_value);
356+
357+
/* 2. */
358+
ECMA_TRY_CATCH (this_to_string_value,
359+
ecma_op_to_string (this_arg),
360+
ret_value);
361+
362+
ecma_value_t regexp_value = 0;
363+
/* 3. */
364+
if (ecma_is_value_object (arg)
365+
&& ecma_object_get_class_name (ecma_get_object_from_value (arg)) == LIT_MAGIC_STRING_REGEXP_UL)
366+
{
367+
regexp_value = ecma_copy_value (arg, true);
368+
}
369+
else
370+
{
371+
/* 4. */
372+
ecma_value_t regexp_arguments[1] = { arg };
373+
ECMA_TRY_CATCH (new_regexp_value,
374+
ecma_builtin_regexp_dispatch_construct (regexp_arguments, 1),
375+
ret_value);
376+
377+
regexp_value = ecma_copy_value (new_regexp_value, true);
378+
379+
ECMA_FINALIZE (new_regexp_value);
380+
}
381+
382+
if (ecma_is_completion_value_empty (ret_value))
383+
{
384+
JERRY_ASSERT (regexp_value != 0);
385+
ecma_object_t *regexp_obj_p = ecma_get_object_from_value (regexp_value);
386+
ecma_string_t *global_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL);
387+
388+
/* 5. */
389+
ECMA_TRY_CATCH (global_prop_value,
390+
ecma_op_object_get (regexp_obj_p, global_string_p),
391+
ret_value);
392+
393+
ECMA_TRY_CATCH (global_value,
394+
ecma_op_to_boolean (global_prop_value),
395+
ret_value);
396+
397+
ecma_value_t exec_arguments[1] = { this_to_string_value };
398+
399+
if (!ecma_is_completion_value_normal_true (global_value))
400+
{
401+
/* 7. */
402+
ret_value = ecma_builtin_regexp_prototype_dispatch_routine (LIT_MAGIC_STRING_EXEC,
403+
regexp_value,
404+
exec_arguments,
405+
1);
406+
}
407+
else
408+
{
409+
/* 8.a. */
410+
ecma_number_t *zero_number_p = ecma_alloc_number ();
411+
*zero_number_p = 0;
412+
413+
ecma_string_t *index_zero_string_p = ecma_new_ecma_string_from_uint32 (0);
414+
415+
ecma_string_t *last_index_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL);
416+
417+
ECMA_TRY_CATCH (put_value,
418+
ecma_op_object_put (regexp_obj_p,
419+
last_index_string_p,
420+
ecma_make_number_value (zero_number_p),
421+
true),
422+
ret_value);
423+
424+
/* 8.b. */
425+
ECMA_TRY_CATCH (new_array_value,
426+
ecma_op_create_array_object (NULL, 0, false),
427+
ret_value);
428+
429+
ecma_object_t *new_array_obj_p = ecma_get_object_from_value (new_array_value);
430+
431+
/* 8.c. */
432+
ecma_number_t previous_last_index = 0;
433+
/* 8.d. */
434+
uint32_t n = 0;
435+
/* 8.e. */
436+
bool last_match = true;
437+
438+
ecma_completion_value_t exec_result = ecma_make_empty_completion_value ();
439+
440+
/* 8.f. */
441+
while (last_match && ecma_is_completion_value_empty (exec_result))
442+
{
443+
/* 8.f.i. */
444+
ECMA_TRY_CATCH (exec_value,
445+
ecma_builtin_regexp_prototype_dispatch_routine (LIT_MAGIC_STRING_EXEC,
446+
regexp_value,
447+
exec_arguments,
448+
1),
449+
exec_result);
450+
451+
if (ecma_is_value_null (exec_value))
452+
{
453+
/* 8.f.ii. */
454+
last_match = false;
455+
}
456+
else
457+
{
458+
/* 8.f.iii. */
459+
ECMA_TRY_CATCH (this_index_value,
460+
ecma_op_object_get (regexp_obj_p, last_index_string_p),
461+
exec_result);
462+
463+
ECMA_TRY_CATCH (this_index_number,
464+
ecma_op_to_number (this_index_value),
465+
exec_result);
466+
467+
ecma_number_t this_index = *ecma_get_number_from_value (this_index_number);
468+
469+
/* 8.f.iii.2. */
470+
if (this_index == previous_last_index)
471+
{
472+
ecma_number_t *new_last_index_p = ecma_alloc_number ();
473+
*new_last_index_p = this_index + 1;
474+
/* 8.f.iii.2.a. */
475+
ECMA_TRY_CATCH (index_put_value,
476+
ecma_op_object_put (regexp_obj_p,
477+
last_index_string_p,
478+
ecma_make_number_value (new_last_index_p),
479+
true),
480+
exec_result);
481+
482+
/* 8.f.iii.2.b. */
483+
previous_last_index = this_index + 1;
484+
485+
ECMA_FINALIZE (index_put_value);
486+
487+
ecma_dealloc_number (new_last_index_p);
488+
}
489+
else
490+
{
491+
/* 8.f.iii.3. */
492+
previous_last_index = this_index;
493+
}
494+
495+
if (ecma_is_completion_value_empty (exec_result))
496+
{
497+
/* 8.f.iii.4. */
498+
JERRY_ASSERT (ecma_is_value_object (exec_value));
499+
ecma_object_t *exec_obj_p = ecma_get_object_from_value (exec_value);
500+
501+
ECMA_TRY_CATCH (match_string_value,
502+
ecma_op_object_get (exec_obj_p, index_zero_string_p),
503+
exec_result);
504+
505+
/* 8.f.iii.5. */
506+
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
507+
{
508+
prop_desc.is_value_defined = true;
509+
prop_desc.value = match_string_value;
510+
511+
prop_desc.is_writable_defined = true;
512+
prop_desc.is_writable = true;
513+
514+
prop_desc.is_enumerable_defined = true;
515+
prop_desc.is_enumerable = false;
516+
517+
prop_desc.is_configurable_defined = true;
518+
prop_desc.is_configurable = true;
519+
}
520+
521+
ecma_string_t *current_index_str_p = ecma_new_ecma_string_from_uint32 (n);
522+
523+
ecma_completion_value_t completion = ecma_op_object_define_own_property (new_array_obj_p,
524+
current_index_str_p,
525+
&prop_desc,
526+
false);
527+
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));
528+
529+
ecma_deref_ecma_string (current_index_str_p);
530+
531+
/* 8.f.iii.6. */
532+
n++;
533+
534+
ECMA_FINALIZE (match_string_value);
535+
}
536+
537+
ECMA_FINALIZE (this_index_number);
538+
539+
ECMA_FINALIZE (this_index_value);
540+
}
541+
542+
ECMA_FINALIZE (exec_value);
543+
}
544+
545+
if (ecma_is_completion_value_empty (exec_result))
546+
{
547+
if (n == 0)
548+
{
549+
/* 8.g. */
550+
ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_NULL);
551+
}
552+
else
553+
{
554+
/* 8.h. */
555+
ret_value = ecma_make_normal_completion_value (ecma_copy_value (new_array_value, true));
556+
}
557+
}
558+
else
559+
{
560+
ret_value = exec_result;
561+
}
562+
563+
564+
ECMA_FINALIZE (new_array_value);
565+
566+
ECMA_FINALIZE (put_value);
567+
568+
ecma_deref_ecma_string (last_index_string_p);
569+
ecma_deref_ecma_string (index_zero_string_p);
570+
ecma_dealloc_number (zero_number_p);
571+
}
572+
573+
ECMA_FINALIZE (global_value);
574+
575+
ECMA_FINALIZE (global_prop_value);
576+
577+
ecma_deref_ecma_string (global_string_p);
578+
579+
ecma_free_value (regexp_value, true);
580+
}
581+
582+
ECMA_FINALIZE (this_to_string_value);
583+
584+
ECMA_FINALIZE (this_check_coercible_value);
585+
586+
return ret_value;
348587
} /* ecma_builtin_string_prototype_object_match */
588+
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
349589

350590
/**
351591
* The String.prototype object's 'replace' routine

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,11 @@ ROUTINE (LIT_MAGIC_STRING_LAST_INDEX_OF_UL, ecma_builtin_string_prototype_object
6767
ROUTINE (LIT_MAGIC_STRING_CHAR_AT_UL, ecma_builtin_string_prototype_object_char_at, 1, 1)
6868
ROUTINE (LIT_MAGIC_STRING_CHAR_CODE_AT_UL, ecma_builtin_string_prototype_object_char_code_at, 1, 1)
6969
ROUTINE (LIT_MAGIC_STRING_LOCALE_COMPARE_UL, ecma_builtin_string_prototype_object_locale_compare, 1, 1)
70+
71+
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
7072
ROUTINE (LIT_MAGIC_STRING_MATCH, ecma_builtin_string_prototype_object_match, 1, 1)
73+
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
74+
7175
ROUTINE (LIT_MAGIC_STRING_REPLACE, ecma_builtin_string_prototype_object_replace, 2, 2)
7276
ROUTINE (LIT_MAGIC_STRING_SEARCH, ecma_builtin_string_prototype_object_search, 1, 1)
7377
ROUTINE (LIT_MAGIC_STRING_SPLIT, ecma_builtin_string_prototype_object_split, 2, 2)

tests/jerry/string-prototype-match.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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.match, 'length').configurable === false);
18+
assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').enumerable === false);
19+
assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').writable === false);
20+
21+
function match_equals (match_result, expected)
22+
{
23+
if (match_result.length !== expected.length)
24+
{
25+
return false;
26+
}
27+
28+
for(var i = 0; i < expected.length; i++)
29+
{
30+
if (match_result[i] !== expected[i])
31+
{
32+
return false;
33+
}
34+
}
35+
36+
return true;
37+
}
38+
39+
assert (match_equals ("hello".match("o"), ["o"]));
40+
assert ("hello".match(/ /g) == void 0);
41+
42+
assert (match_equals ("hello".match(/o/), ["o"]));
43+
44+
assert (match_equals ("hello".match(/l/), ["l"]));
45+
assert (match_equals ("hello".match(/l/g), ["l", "l"]));
46+
47+
assert ("".match(/a/g) == void 0);
48+
49+
assert ("".match() !== void 0 );
50+
// FIXME: uncomment when #435 landed.
51+
//assert (match_equals ("".match(), [""]));
52+
//assert (match_equals ("".match(undefined), [""]));
53+
assert (match_equals ("".match(""), [""]));
54+
55+
assert (match_equals ("test 1, test 2, test 3, test 45".match(/[0-9]+/g), ["1", "2", "3", "45"]));
56+
57+
var re = new RegExp("", "g");
58+
assert (match_equals ("a".match(re), ["", ""]));
59+
60+
61+
/* Check Object coercible */
62+
try {
63+
String.prototype.match.call(undefined, "");
64+
assert (false);
65+
}
66+
catch (e)
67+
{
68+
assert (e instanceof TypeError);
69+
}
70+
71+
/* Check toString conversion */
72+
try {
73+
var obj = { toString: function() { throw new ReferenceError("foo"); } };
74+
String.prototype.match.call(obj, "");
75+
assert (false);
76+
}
77+
catch (e)
78+
{
79+
assert (e instanceof ReferenceError);
80+
assert (e.message === "foo");
81+
}
82+
83+
/* Check Invalid RegExp */
84+
try {
85+
var obj = { toString: function() { throw new ReferenceError("foo"); } };
86+
"".match (obj);
87+
assert (false);
88+
}
89+
catch (e)
90+
{
91+
assert (e instanceof ReferenceError);
92+
assert (e.message === "foo");
93+
}
94+
95+
/* Check if lastIndex is set to 0 on start */
96+
var re = /a/g;
97+
re.lastIndex = 3;
98+
99+
assert (match_equals ("a".match(re), ["a"]));

0 commit comments

Comments
 (0)