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
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "ecma-alloc.h"
|
||||
#include "ecma-array-object.h"
|
||||
#include "ecma-builtin-helpers.h"
|
||||
#include "ecma-builtins.h"
|
||||
#include "ecma-conversion.h"
|
||||
@@ -383,6 +384,8 @@ ecma_builtin_string_prototype_object_locale_compare (ecma_value_t this_arg, /**<
|
||||
return ret_value;
|
||||
} /* ecma_builtin_string_prototype_object_locale_compare */
|
||||
|
||||
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
|
||||
|
||||
/**
|
||||
* The String.prototype object's 'match' routine
|
||||
*
|
||||
@@ -396,8 +399,236 @@ static ecma_completion_value_t
|
||||
ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this argument */
|
||||
ecma_value_t arg) /**< routine's argument */
|
||||
{
|
||||
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
/* 1. */
|
||||
ECMA_TRY_CATCH (this_check_coercible_value,
|
||||
ecma_op_check_object_coercible (this_arg),
|
||||
ret_value);
|
||||
|
||||
/* 2. */
|
||||
ECMA_TRY_CATCH (this_to_string_value,
|
||||
ecma_op_to_string (this_arg),
|
||||
ret_value);
|
||||
|
||||
ecma_value_t regexp_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
|
||||
/* 3. */
|
||||
if (ecma_is_value_object (arg)
|
||||
&& ecma_object_get_class_name (ecma_get_object_from_value (arg)) == LIT_MAGIC_STRING_REGEXP_UL)
|
||||
{
|
||||
regexp_value = ecma_copy_value (arg, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 4. */
|
||||
ecma_value_t regexp_arguments[1] = { arg };
|
||||
ECMA_TRY_CATCH (new_regexp_value,
|
||||
ecma_builtin_regexp_dispatch_construct (regexp_arguments, 1),
|
||||
ret_value);
|
||||
|
||||
regexp_value = ecma_copy_value (new_regexp_value, true);
|
||||
|
||||
ECMA_FINALIZE (new_regexp_value);
|
||||
}
|
||||
|
||||
if (ecma_is_completion_value_empty (ret_value))
|
||||
{
|
||||
JERRY_ASSERT (!ecma_is_value_empty (regexp_value));
|
||||
ecma_object_t *regexp_obj_p = ecma_get_object_from_value (regexp_value);
|
||||
ecma_string_t *global_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL);
|
||||
|
||||
/* 5. */
|
||||
ECMA_TRY_CATCH (global_value,
|
||||
ecma_op_object_get (regexp_obj_p, global_string_p),
|
||||
ret_value);
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_boolean (global_value));
|
||||
|
||||
ecma_value_t exec_arguments[1] = { this_to_string_value };
|
||||
|
||||
if (!ecma_is_value_true (global_value))
|
||||
{
|
||||
/* 7. */
|
||||
ret_value = ecma_builtin_regexp_prototype_dispatch_routine (LIT_MAGIC_STRING_EXEC,
|
||||
regexp_value,
|
||||
exec_arguments,
|
||||
1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 8.a. */
|
||||
ecma_number_t *zero_number_p = ecma_alloc_number ();
|
||||
*zero_number_p = 0;
|
||||
|
||||
ecma_string_t *index_zero_string_p = ecma_new_ecma_string_from_uint32 (0);
|
||||
|
||||
ecma_string_t *last_index_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL);
|
||||
|
||||
ECMA_TRY_CATCH (put_value,
|
||||
ecma_op_object_put (regexp_obj_p,
|
||||
last_index_string_p,
|
||||
ecma_make_number_value (zero_number_p),
|
||||
true),
|
||||
ret_value);
|
||||
|
||||
/* 8.b. */
|
||||
ECMA_TRY_CATCH (new_array_value,
|
||||
ecma_op_create_array_object (NULL, 0, false),
|
||||
ret_value);
|
||||
|
||||
ecma_object_t *new_array_obj_p = ecma_get_object_from_value (new_array_value);
|
||||
|
||||
/* 8.c. */
|
||||
ecma_number_t previous_last_index = 0;
|
||||
/* 8.d. */
|
||||
uint32_t n = 0;
|
||||
/* 8.e. */
|
||||
bool last_match = true;
|
||||
|
||||
//ecma_completion_value_t exec_result = ecma_make_empty_completion_value ();
|
||||
|
||||
/* 8.f. */
|
||||
while (last_match && ecma_is_completion_value_empty (ret_value))
|
||||
{
|
||||
/* 8.f.i. */
|
||||
ECMA_TRY_CATCH (exec_value,
|
||||
ecma_builtin_regexp_prototype_dispatch_routine (LIT_MAGIC_STRING_EXEC,
|
||||
regexp_value,
|
||||
exec_arguments,
|
||||
1),
|
||||
ret_value);
|
||||
|
||||
if (ecma_is_value_null (exec_value))
|
||||
{
|
||||
/* 8.f.ii. */
|
||||
last_match = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 8.f.iii. */
|
||||
ECMA_TRY_CATCH (this_index_value,
|
||||
ecma_op_object_get (regexp_obj_p, last_index_string_p),
|
||||
ret_value);
|
||||
|
||||
ECMA_TRY_CATCH (this_index_number,
|
||||
ecma_op_to_number (this_index_value),
|
||||
ret_value);
|
||||
|
||||
ecma_number_t this_index = *ecma_get_number_from_value (this_index_number);
|
||||
|
||||
/* 8.f.iii.2. */
|
||||
if (this_index == previous_last_index)
|
||||
{
|
||||
ecma_number_t *new_last_index_p = ecma_alloc_number ();
|
||||
*new_last_index_p = this_index + 1;
|
||||
/* 8.f.iii.2.a. */
|
||||
ECMA_TRY_CATCH (index_put_value,
|
||||
ecma_op_object_put (regexp_obj_p,
|
||||
last_index_string_p,
|
||||
ecma_make_number_value (new_last_index_p),
|
||||
true),
|
||||
ret_value);
|
||||
|
||||
/* 8.f.iii.2.b. */
|
||||
previous_last_index = this_index + 1;
|
||||
|
||||
ECMA_FINALIZE (index_put_value);
|
||||
|
||||
ecma_dealloc_number (new_last_index_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 8.f.iii.3. */
|
||||
previous_last_index = this_index;
|
||||
}
|
||||
|
||||
if (ecma_is_completion_value_empty (ret_value))
|
||||
{
|
||||
/* 8.f.iii.4. */
|
||||
JERRY_ASSERT (ecma_is_value_object (exec_value));
|
||||
ecma_object_t *exec_obj_p = ecma_get_object_from_value (exec_value);
|
||||
|
||||
ECMA_TRY_CATCH (match_string_value,
|
||||
ecma_op_object_get (exec_obj_p, index_zero_string_p),
|
||||
ret_value);
|
||||
|
||||
/* 8.f.iii.5. */
|
||||
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
|
||||
{
|
||||
prop_desc.is_value_defined = true;
|
||||
prop_desc.value = match_string_value;
|
||||
|
||||
prop_desc.is_writable_defined = true;
|
||||
prop_desc.is_writable = true;
|
||||
|
||||
prop_desc.is_enumerable_defined = true;
|
||||
prop_desc.is_enumerable = true;
|
||||
|
||||
prop_desc.is_configurable_defined = true;
|
||||
prop_desc.is_configurable = true;
|
||||
}
|
||||
|
||||
ecma_string_t *current_index_str_p = ecma_new_ecma_string_from_uint32 (n);
|
||||
|
||||
ecma_completion_value_t completion = ecma_op_object_define_own_property (new_array_obj_p,
|
||||
current_index_str_p,
|
||||
&prop_desc,
|
||||
false);
|
||||
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));
|
||||
|
||||
ecma_deref_ecma_string (current_index_str_p);
|
||||
|
||||
/* 8.f.iii.6. */
|
||||
n++;
|
||||
|
||||
ECMA_FINALIZE (match_string_value);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (this_index_number);
|
||||
|
||||
ECMA_FINALIZE (this_index_value);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (exec_value);
|
||||
}
|
||||
|
||||
if (ecma_is_completion_value_empty (ret_value))
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
/* 8.g. */
|
||||
ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 8.h. */
|
||||
ret_value = ecma_make_normal_completion_value (ecma_copy_value (new_array_value, true));
|
||||
}
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (new_array_value);
|
||||
|
||||
ECMA_FINALIZE (put_value);
|
||||
|
||||
ecma_deref_ecma_string (last_index_string_p);
|
||||
ecma_deref_ecma_string (index_zero_string_p);
|
||||
ecma_dealloc_number (zero_number_p);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (global_value);
|
||||
|
||||
ecma_deref_ecma_string (global_string_p);
|
||||
|
||||
ecma_free_value (regexp_value, true);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (this_to_string_value);
|
||||
|
||||
ECMA_FINALIZE (this_check_coercible_value);
|
||||
|
||||
return ret_value;
|
||||
} /* ecma_builtin_string_prototype_object_match */
|
||||
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
|
||||
|
||||
/**
|
||||
* The String.prototype object's 'replace' routine
|
||||
|
||||
@@ -67,7 +67,11 @@ ROUTINE (LIT_MAGIC_STRING_LAST_INDEX_OF_UL, ecma_builtin_string_prototype_object
|
||||
ROUTINE (LIT_MAGIC_STRING_CHAR_AT_UL, ecma_builtin_string_prototype_object_char_at, 1, 1)
|
||||
ROUTINE (LIT_MAGIC_STRING_CHAR_CODE_AT_UL, ecma_builtin_string_prototype_object_char_code_at, 1, 1)
|
||||
ROUTINE (LIT_MAGIC_STRING_LOCALE_COMPARE_UL, ecma_builtin_string_prototype_object_locale_compare, 1, 1)
|
||||
|
||||
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
|
||||
ROUTINE (LIT_MAGIC_STRING_MATCH, ecma_builtin_string_prototype_object_match, 1, 1)
|
||||
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
|
||||
|
||||
ROUTINE (LIT_MAGIC_STRING_REPLACE, ecma_builtin_string_prototype_object_replace, 2, 2)
|
||||
ROUTINE (LIT_MAGIC_STRING_SEARCH, ecma_builtin_string_prototype_object_search, 1, 1)
|
||||
ROUTINE (LIT_MAGIC_STRING_SPLIT, ecma_builtin_string_prototype_object_split, 2, 2)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// 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.
|
||||
|
||||
// check properties
|
||||
assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').configurable === false);
|
||||
assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').enumerable === false);
|
||||
assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').writable === false);
|
||||
|
||||
function match_equals (match_result, expected)
|
||||
{
|
||||
if (match_result.length !== expected.length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(var i = 0; i < expected.length; i++)
|
||||
{
|
||||
if (match_result[i] !== expected[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
assert (match_equals ("hello".match("o"), ["o"]));
|
||||
assert ("hello".match(/ /g) == void 0);
|
||||
|
||||
assert (match_equals ("hello".match(/o/), ["o"]));
|
||||
|
||||
assert (match_equals ("hello".match(/l/), ["l"]));
|
||||
assert (match_equals ("hello".match(/l/g), ["l", "l"]));
|
||||
|
||||
assert ("".match(/a/g) == void 0);
|
||||
|
||||
assert ("".match() !== void 0 );
|
||||
// FIXME: uncomment when #435 landed.
|
||||
//assert (match_equals ("".match(), [""]));
|
||||
//assert (match_equals ("".match(undefined), [""]));
|
||||
assert (match_equals ("".match(""), [""]));
|
||||
|
||||
assert (match_equals ("test 1, test 2, test 3, test 45".match(/[0-9]+/g), ["1", "2", "3", "45"]));
|
||||
|
||||
var re = new RegExp("", "g");
|
||||
assert (match_equals ("a".match(re), ["", ""]));
|
||||
|
||||
|
||||
/* Check Object coercible */
|
||||
try {
|
||||
String.prototype.match.call(undefined, "");
|
||||
assert (false);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
/* Check toString conversion */
|
||||
try {
|
||||
var obj = { toString: function() { throw new ReferenceError("foo"); } };
|
||||
String.prototype.match.call(obj, "");
|
||||
assert (false);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assert (e instanceof ReferenceError);
|
||||
assert (e.message === "foo");
|
||||
}
|
||||
|
||||
/* Check Invalid RegExp */
|
||||
try {
|
||||
var obj = { toString: function() { throw new ReferenceError("foo"); } };
|
||||
"".match (obj);
|
||||
assert (false);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assert (e instanceof ReferenceError);
|
||||
assert (e.message === "foo");
|
||||
}
|
||||
|
||||
/* Check if lastIndex is set to 0 on start */
|
||||
var re = /a/g;
|
||||
re.lastIndex = 3;
|
||||
|
||||
assert (match_equals ("a".match(re), ["a"]));
|
||||
Reference in New Issue
Block a user