mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 07:27:45 +00:00
LibJS: Define RegExp.prototype methods in spec order
This commit is contained in:
parent
7ea85ed10b
commit
968f6e2432
2 changed files with 100 additions and 101 deletions
|
@ -55,27 +55,6 @@ RegExpPrototype::~RegExpPrototype()
|
|||
{
|
||||
}
|
||||
|
||||
// 22.2.5.2.3 AdvanceStringIndex ( S, index, unicode ), https://tc39.es/ecma262/#sec-advancestringindex
|
||||
size_t advance_string_index(Utf16View const& string, size_t index, bool unicode)
|
||||
{
|
||||
// 1. Assert: index ≤ 2^53 - 1.
|
||||
|
||||
// 2. If unicode is false, return index + 1.
|
||||
if (!unicode)
|
||||
return index + 1;
|
||||
|
||||
// 3. Let length be the number of code units in S.
|
||||
// 4. If index + 1 ≥ length, return index + 1.
|
||||
if (index + 1 >= string.length_in_code_units())
|
||||
return index + 1;
|
||||
|
||||
// 5. Let cp be ! CodePointAt(S, index).
|
||||
auto code_point = code_point_at(string, index);
|
||||
|
||||
// 6. Return index + cp.[[CodeUnitCount]].
|
||||
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)
|
||||
{
|
||||
|
@ -426,6 +405,27 @@ ThrowCompletionOr<Value> regexp_exec(GlobalObject& global_object, Object& regexp
|
|||
return regexp_builtin_exec(global_object, static_cast<RegExpObject&>(regexp_object), move(string));
|
||||
}
|
||||
|
||||
// 22.2.5.2.3 AdvanceStringIndex ( S, index, unicode ), https://tc39.es/ecma262/#sec-advancestringindex
|
||||
size_t advance_string_index(Utf16View const& string, size_t index, bool unicode)
|
||||
{
|
||||
// 1. Assert: index ≤ 2^53 - 1.
|
||||
|
||||
// 2. If unicode is false, return index + 1.
|
||||
if (!unicode)
|
||||
return index + 1;
|
||||
|
||||
// 3. Let length be the number of code units in S.
|
||||
// 4. If index + 1 ≥ length, return index + 1.
|
||||
if (index + 1 >= string.length_in_code_units())
|
||||
return index + 1;
|
||||
|
||||
// 5. Let cp be ! CodePointAt(S, index).
|
||||
auto code_point = code_point_at(string, index);
|
||||
|
||||
// 6. Return index + cp.[[CodeUnitCount]].
|
||||
return index + code_point.code_unit_count;
|
||||
}
|
||||
|
||||
// 1.1.4.3 get RegExp.prototype.hasIndices, https://tc39.es/proposal-regexp-match-indices/#sec-get-regexp.prototype.hasIndices
|
||||
// 22.2.5.3 get RegExp.prototype.dotAll, https://tc39.es/ecma262/#sec-get-regexp.prototype.dotAll
|
||||
// 22.2.5.5 get RegExp.prototype.global, https://tc39.es/ecma262/#sec-get-regexp.prototype.global
|
||||
|
@ -455,6 +455,20 @@ ThrowCompletionOr<Value> regexp_exec(GlobalObject& global_object, Object& regexp
|
|||
JS_ENUMERATE_REGEXP_FLAGS
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
// 22.2.5.2 RegExp.prototype.exec ( string ), https://tc39.es/ecma262/#sec-regexp.prototype.exec
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::exec)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(R, [[RegExpMatcher]]).
|
||||
auto* regexp_object = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. Let S be ? ToString(string).
|
||||
auto string = TRY(vm.argument(0).to_utf16_string(global_object));
|
||||
|
||||
// 4. Return ? RegExpBuiltinExec(R, S).
|
||||
return TRY(regexp_builtin_exec(global_object, *regexp_object, move(string)));
|
||||
}
|
||||
|
||||
// 22.2.5.4 get RegExp.prototype.flags, https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::flags)
|
||||
{
|
||||
|
@ -489,81 +503,6 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::flags)
|
|||
return js_string(vm, builder.to_string());
|
||||
}
|
||||
|
||||
// 22.2.5.12 get RegExp.prototype.source, https://tc39.es/ecma262/#sec-get-regexp.prototype.source
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::source)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
auto* regexp_object = TRY(this_object(global_object));
|
||||
|
||||
// 3. If R does not have an [[OriginalSource]] internal slot, then
|
||||
if (!is<RegExpObject>(regexp_object)) {
|
||||
// a. If SameValue(R, %RegExp.prototype%) is true, return "(?:)".
|
||||
if (same_value(regexp_object, global_object.regexp_prototype()))
|
||||
return js_string(vm, "(?:)");
|
||||
|
||||
// b. Otherwise, throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::NotAnObjectOfType, "RegExp");
|
||||
}
|
||||
|
||||
// 4. Assert: R has an [[OriginalFlags]] internal slot.
|
||||
// 5. Let src be R.[[OriginalSource]].
|
||||
// 6. Let flags be R.[[OriginalFlags]].
|
||||
// 7. Return EscapeRegExpPattern(src, flags).
|
||||
return js_string(vm, static_cast<RegExpObject&>(*regexp_object).escape_regexp_pattern());
|
||||
}
|
||||
|
||||
// 22.2.5.2 RegExp.prototype.exec ( string ), https://tc39.es/ecma262/#sec-regexp.prototype.exec
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::exec)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(R, [[RegExpMatcher]]).
|
||||
auto* regexp_object = TRY(typed_this_object(global_object));
|
||||
|
||||
// 3. Let S be ? ToString(string).
|
||||
auto string = TRY(vm.argument(0).to_utf16_string(global_object));
|
||||
|
||||
// 4. Return ? RegExpBuiltinExec(R, S).
|
||||
return TRY(regexp_builtin_exec(global_object, *regexp_object, move(string)));
|
||||
}
|
||||
|
||||
// 22.2.5.15 RegExp.prototype.test ( S ), https://tc39.es/ecma262/#sec-regexp.prototype.test
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::test)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
auto* regexp_object = TRY(this_object(global_object));
|
||||
|
||||
// 3. Let string be ? ToString(S).
|
||||
auto string = TRY(vm.argument(0).to_utf16_string(global_object));
|
||||
|
||||
// 4. Let match be ? RegExpExec(R, string).
|
||||
auto match = TRY(regexp_exec(global_object, *regexp_object, move(string)));
|
||||
|
||||
// 5. If match is not null, return true; else return false.
|
||||
return Value(!match.is_null());
|
||||
}
|
||||
|
||||
// 22.2.5.16 RegExp.prototype.toString ( ), https://tc39.es/ecma262/#sec-regexp.prototype.tostring
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::to_string)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
auto* regexp_object = TRY(this_object(global_object));
|
||||
|
||||
// 3. Let pattern be ? ToString(? Get(R, "source")).
|
||||
auto source_attr = TRY(regexp_object->get(vm.names.source));
|
||||
auto pattern = TRY(source_attr.to_string(global_object));
|
||||
|
||||
// 4. Let flags be ? ToString(? Get(R, "flags")).
|
||||
auto flags_attr = TRY(regexp_object->get(vm.names.flags));
|
||||
auto flags = TRY(flags_attr.to_string(global_object));
|
||||
|
||||
// 5. Let result be the string-concatenation of "/", pattern, "/", and flags.
|
||||
// 6. Return result.
|
||||
return js_string(vm, String::formatted("/{}/{}", pattern, flags));
|
||||
}
|
||||
|
||||
// 22.2.5.7 RegExp.prototype [ @@match ] ( string ), https://tc39.es/ecma262/#sec-regexp.prototype-@@match
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match)
|
||||
{
|
||||
|
@ -905,6 +844,30 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_search)
|
|||
return TRY(result.get(global_object, vm.names.index));
|
||||
}
|
||||
|
||||
// 22.2.5.12 get RegExp.prototype.source, https://tc39.es/ecma262/#sec-get-regexp.prototype.source
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::source)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
auto* regexp_object = TRY(this_object(global_object));
|
||||
|
||||
// 3. If R does not have an [[OriginalSource]] internal slot, then
|
||||
if (!is<RegExpObject>(regexp_object)) {
|
||||
// a. If SameValue(R, %RegExp.prototype%) is true, return "(?:)".
|
||||
if (same_value(regexp_object, global_object.regexp_prototype()))
|
||||
return js_string(vm, "(?:)");
|
||||
|
||||
// b. Otherwise, throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::NotAnObjectOfType, "RegExp");
|
||||
}
|
||||
|
||||
// 4. Assert: R has an [[OriginalFlags]] internal slot.
|
||||
// 5. Let src be R.[[OriginalSource]].
|
||||
// 6. Let flags be R.[[OriginalFlags]].
|
||||
// 7. Return EscapeRegExpPattern(src, flags).
|
||||
return js_string(vm, static_cast<RegExpObject&>(*regexp_object).escape_regexp_pattern());
|
||||
}
|
||||
|
||||
// 22.2.5.13 RegExp.prototype [ @@split ] ( string, limit ), https://tc39.es/ecma262/#sec-regexp.prototype-@@split
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split)
|
||||
{
|
||||
|
@ -1062,6 +1025,43 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split)
|
|||
return array;
|
||||
}
|
||||
|
||||
// 22.2.5.15 RegExp.prototype.test ( S ), https://tc39.es/ecma262/#sec-regexp.prototype.test
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::test)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
auto* regexp_object = TRY(this_object(global_object));
|
||||
|
||||
// 3. Let string be ? ToString(S).
|
||||
auto string = TRY(vm.argument(0).to_utf16_string(global_object));
|
||||
|
||||
// 4. Let match be ? RegExpExec(R, string).
|
||||
auto match = TRY(regexp_exec(global_object, *regexp_object, move(string)));
|
||||
|
||||
// 5. If match is not null, return true; else return false.
|
||||
return Value(!match.is_null());
|
||||
}
|
||||
|
||||
// 22.2.5.16 RegExp.prototype.toString ( ), https://tc39.es/ecma262/#sec-regexp.prototype.tostring
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::to_string)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
auto* regexp_object = TRY(this_object(global_object));
|
||||
|
||||
// 3. Let pattern be ? ToString(? Get(R, "source")).
|
||||
auto source_attr = TRY(regexp_object->get(vm.names.source));
|
||||
auto pattern = TRY(source_attr.to_string(global_object));
|
||||
|
||||
// 4. Let flags be ? ToString(? Get(R, "flags")).
|
||||
auto flags_attr = TRY(regexp_object->get(vm.names.flags));
|
||||
auto flags = TRY(flags_attr.to_string(global_object));
|
||||
|
||||
// 5. Let result be the string-concatenation of "/", pattern, "/", and flags.
|
||||
// 6. Return result.
|
||||
return js_string(vm, String::formatted("/{}/{}", pattern, flags));
|
||||
}
|
||||
|
||||
// B.2.4.1 RegExp.prototype.compile ( pattern, flags ), https://tc39.es/ecma262/#sec-regexp.prototype.compile
|
||||
JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::compile)
|
||||
{
|
||||
|
|
|
@ -24,17 +24,16 @@ public:
|
|||
virtual ~RegExpPrototype() override;
|
||||
|
||||
private:
|
||||
JS_DECLARE_NATIVE_FUNCTION(flags);
|
||||
JS_DECLARE_NATIVE_FUNCTION(source);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(exec);
|
||||
JS_DECLARE_NATIVE_FUNCTION(test);
|
||||
JS_DECLARE_NATIVE_FUNCTION(to_string);
|
||||
JS_DECLARE_NATIVE_FUNCTION(flags);
|
||||
JS_DECLARE_NATIVE_FUNCTION(symbol_match);
|
||||
JS_DECLARE_NATIVE_FUNCTION(symbol_match_all);
|
||||
JS_DECLARE_NATIVE_FUNCTION(symbol_replace);
|
||||
JS_DECLARE_NATIVE_FUNCTION(symbol_search);
|
||||
JS_DECLARE_NATIVE_FUNCTION(source);
|
||||
JS_DECLARE_NATIVE_FUNCTION(symbol_split);
|
||||
JS_DECLARE_NATIVE_FUNCTION(test);
|
||||
JS_DECLARE_NATIVE_FUNCTION(to_string);
|
||||
JS_DECLARE_NATIVE_FUNCTION(compile);
|
||||
|
||||
#define __JS_ENUMERATE(_, flag_name, ...) \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue