mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:07:36 +00:00
LibJS: Implement global RegExp.prototype.match
Also rename the 'rx' variable to 'regexp_object' to match other RegExp methods.
This commit is contained in:
parent
b6b5adb47d
commit
2d0589f93c
2 changed files with 73 additions and 17 deletions
|
@ -82,6 +82,24 @@ static String escape_regexp_pattern(const RegExpObject& regexp_object)
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void increment_last_index(GlobalObject& global_object, Object& regexp_object)
|
||||||
|
{
|
||||||
|
auto& vm = global_object.vm();
|
||||||
|
|
||||||
|
auto last_index_value = regexp_object.get(vm.names.lastIndex);
|
||||||
|
if (vm.exception())
|
||||||
|
return;
|
||||||
|
auto last_index = last_index_value.to_length(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// FIXME: Implement AdvanceStringIndex to take Unicode code points into account - https://tc39.es/ecma262/#sec-advancestringindex
|
||||||
|
// Once implemented, step (8a) of the @@replace algorithm must also be implemented.
|
||||||
|
++last_index;
|
||||||
|
|
||||||
|
regexp_object.set(vm.names.lastIndex, Value(last_index), true);
|
||||||
|
}
|
||||||
|
|
||||||
static RegexResult do_match(const Regex<ECMA262>& re, const StringView& subject)
|
static RegexResult do_match(const Regex<ECMA262>& re, const StringView& subject)
|
||||||
{
|
{
|
||||||
auto result = re.match(subject);
|
auto result = re.match(subject);
|
||||||
|
@ -302,28 +320,68 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::to_string)
|
||||||
// 22.2.5.7 RegExp.prototype [ @@match ] ( string ), https://tc39.es/ecma262/#sec-regexp.prototype-@@match
|
// 22.2.5.7 RegExp.prototype [ @@match ] ( string ), https://tc39.es/ecma262/#sec-regexp.prototype-@@match
|
||||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match)
|
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match)
|
||||||
{
|
{
|
||||||
auto* rx = regexp_object_from(vm, global_object);
|
auto* regexp_object = regexp_object_from(vm, global_object);
|
||||||
if (!rx)
|
if (!regexp_object)
|
||||||
return {};
|
return {};
|
||||||
auto s = vm.argument(0).to_string(global_object);
|
auto s = vm.argument(0).to_string(global_object);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
auto global_value = rx->get(vm.names.global);
|
|
||||||
|
auto global_value = regexp_object->get(vm.names.global);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
bool global = global_value.to_boolean();
|
bool global = global_value.to_boolean();
|
||||||
|
|
||||||
if (!global) {
|
if (!global) {
|
||||||
auto result = regexp_exec(global_object, *rx, s);
|
auto result = regexp_exec(global_object, *regexp_object, s);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This should exec the RegExp repeatedly while updating "lastIndex"
|
regexp_object->set(vm.names.lastIndex, Value(0), true);
|
||||||
auto result = regexp_exec(global_object, *rx, s);
|
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
return result;
|
|
||||||
|
auto* array = Array::create(global_object, 0);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
auto result = regexp_exec(global_object, *regexp_object, s);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (result.is_null()) {
|
||||||
|
if (n == 0)
|
||||||
|
return js_null();
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* result_object = result.to_object(global_object);
|
||||||
|
if (!result_object)
|
||||||
|
return {};
|
||||||
|
auto match_object = result_object->get(0);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
auto match_str = match_object.to_string(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
array->create_data_property_or_throw(n, js_string(vm, match_str));
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (match_str.is_empty()) {
|
||||||
|
increment_last_index(global_object, *regexp_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
++n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 22.2.5.10 RegExp.prototype [ @@replace ] ( string, replaceValue ), https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
|
// 22.2.5.10 RegExp.prototype [ @@replace ] ( string, replaceValue ), https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
|
||||||
|
@ -380,20 +438,12 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_replace)
|
||||||
auto match_object = result_object->get(0);
|
auto match_object = result_object->get(0);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
String match_str = match_object.to_string(global_object);
|
String match_str = match_object.to_string(global_object);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (match_str.is_empty()) {
|
if (match_str.is_empty()) {
|
||||||
// FIXME: Implement AdvanceStringIndex to take Unicode code points into account - https://tc39.es/ecma262/#sec-advancestringindex
|
increment_last_index(global_object, *regexp_object);
|
||||||
// Once implemented, step (8a) of the @@replace algorithm must also be implemented.
|
|
||||||
auto last_index = regexp_object->get(vm.names.lastIndex);
|
|
||||||
if (vm.exception())
|
|
||||||
return {};
|
|
||||||
auto this_index = last_index.to_length(global_object);
|
|
||||||
if (vm.exception())
|
|
||||||
return {};
|
|
||||||
regexp_object->set(vm.names.lastIndex, Value(this_index + 1), true);
|
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,12 @@ test("basic functionality", () => {
|
||||||
|
|
||||||
expect("hello friends".match(/hello/)).not.toBeNull();
|
expect("hello friends".match(/hello/)).not.toBeNull();
|
||||||
expect("hello friends".match(/enemies/)).toBeNull();
|
expect("hello friends".match(/enemies/)).toBeNull();
|
||||||
|
|
||||||
|
expect("aaa".match(/a/)).toEqual(["a"]);
|
||||||
|
expect("aaa".match(/a/g)).toEqual(["a", "a", "a"]);
|
||||||
|
|
||||||
|
expect("aaa".match(/b/)).toBeNull();
|
||||||
|
expect("aaa".match(/b/g)).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override exec with function", () => {
|
test("override exec with function", () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue