mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-10 18:10:56 +09:00
LibJS: Add spec comments to RegExp.prototype [ @@match ]
In doing so, this fixes a few minor issues: 1. We were accessing the "unicode" and "lastIndex" properties out of order. This is somewhat frequently tested by test262, but not in this case. 2. We were doing a Value::to_object() followed by Object::get(), rather than just Value::get() as the spec dictates. 3. We were TRYing a step (CreateDataPropertyOrThrow) that should never fail, and should have been a MUST.
This commit is contained in:
parent
26294a2d27
commit
5eb4d2e96e
Notes:
sideshowbarker
2024-07-17 22:30:56 +09:00
Author: https://github.com/trflynn89
Commit: 5eb4d2e96e
Pull-request: https://github.com/SerenityOS/serenity/pull/11334
Reviewed-by: https://github.com/davidot ✅
Reviewed-by: https://github.com/linusg ✅
1 changed files with 42 additions and 9 deletions
|
@ -68,14 +68,19 @@ size_t advance_string_index(Utf16View const& string, size_t index, bool unicode)
|
|||
return index + code_point.code_unit_count;
|
||||
}
|
||||
|
||||
// Non-standard abstraction around steps used by multiple prototypes.
|
||||
static ThrowCompletionOr<void> increment_last_index(GlobalObject& global_object, Object& regexp_object, Utf16View const& string, bool unicode)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))).
|
||||
auto last_index_value = TRY(regexp_object.get(vm.names.lastIndex));
|
||||
auto last_index = TRY(last_index_value.to_length(global_object));
|
||||
|
||||
// Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
|
||||
last_index = advance_string_index(string, last_index, unicode);
|
||||
|
||||
// Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true).
|
||||
TRY(regexp_object.set(vm.names.lastIndex, Value(last_index), Object::ShouldThrowExceptions::Yes));
|
||||
return {};
|
||||
}
|
||||
|
@ -357,40 +362,68 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::to_string)
|
|||
// 22.2.5.7 RegExp.prototype [ @@match ] ( string ), https://tc39.es/ecma262/#sec-regexp.prototype-@@match
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match)
|
||||
{
|
||||
// 1. Let rx be the this value.
|
||||
// 2. If Type(rx) is not Object, throw a TypeError exception.
|
||||
auto* regexp_object = TRY(this_object(global_object));
|
||||
|
||||
// 3. Let S be ? ToString(string).
|
||||
auto string = TRY(vm.argument(0).to_utf16_string(global_object));
|
||||
|
||||
// 4. Let global be ! ToBoolean(? Get(rx, "global")).
|
||||
bool global = TRY(regexp_object->get(vm.names.global)).to_boolean();
|
||||
|
||||
if (!global)
|
||||
// 5. If global is false, then
|
||||
if (!global) {
|
||||
// a. Return ? RegExpExec(rx, S).
|
||||
return TRY(regexp_exec(global_object, *regexp_object, move(string)));
|
||||
}
|
||||
|
||||
// 6. Else,
|
||||
// a. Assert: global is true.
|
||||
|
||||
// b. Let fullUnicode be ! ToBoolean(? Get(rx, "unicode")).
|
||||
bool full_unicode = TRY(regexp_object->get(vm.names.unicode)).to_boolean();
|
||||
|
||||
// c. Perform ? Set(rx, "lastIndex", +0𝔽, true).
|
||||
TRY(regexp_object->set(vm.names.lastIndex, Value(0), Object::ShouldThrowExceptions::Yes));
|
||||
|
||||
// d. Let A be ! ArrayCreate(0).
|
||||
auto* array = MUST(Array::create(global_object, 0));
|
||||
|
||||
bool unicode = TRY(regexp_object->get(vm.names.unicode)).to_boolean();
|
||||
|
||||
// e. Let n be 0.
|
||||
size_t n = 0;
|
||||
|
||||
// f. Repeat,
|
||||
while (true) {
|
||||
// i. Let result be ? RegExpExec(rx, S).
|
||||
auto result = TRY(regexp_exec(global_object, *regexp_object, string));
|
||||
|
||||
// ii. If result is null, then
|
||||
if (result.is_null()) {
|
||||
// 1. If n = 0, return null.
|
||||
if (n == 0)
|
||||
return js_null();
|
||||
|
||||
// 2. Return A.
|
||||
return array;
|
||||
}
|
||||
|
||||
auto* result_object = TRY(result.to_object(global_object));
|
||||
auto match_object = TRY(result_object->get(0));
|
||||
auto match_str = TRY(match_object.to_string(global_object));
|
||||
// iii. Else,
|
||||
|
||||
TRY(array->create_data_property_or_throw(n, js_string(vm, match_str)));
|
||||
// 1. Let matchStr be ? ToString(? Get(result, "0")).
|
||||
auto match_value = TRY(result.get(global_object, 0));
|
||||
auto match_str = TRY(match_value.to_string(global_object));
|
||||
|
||||
if (match_str.is_empty())
|
||||
TRY(increment_last_index(global_object, *regexp_object, string.view(), unicode));
|
||||
// 2. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), matchStr).
|
||||
MUST(array->create_data_property_or_throw(n, js_string(vm, match_str)));
|
||||
|
||||
// 3. If matchStr is the empty String, then
|
||||
if (match_str.is_empty()) {
|
||||
// Stepsp 3a-3c are implemented by increment_last_index.
|
||||
TRY(increment_last_index(global_object, *regexp_object, string.view(), full_unicode));
|
||||
}
|
||||
|
||||
// 4. Set n to n + 1.
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue