diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index 8ad1988bee..7df5cbec22 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -109,6 +109,7 @@ __JS_ENUMERATE(toStringTag, to_string_tag) #define JS_ENUMERATE_REGEXP_FLAGS \ + __JS_ENUMERATE(hasIndices, has_indices, d) \ __JS_ENUMERATE(global, global, g) \ __JS_ENUMERATE(ignoreCase, ignore_case, i) \ __JS_ENUMERATE(multiline, multiline, m) \ diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index fc5f1b1dd8..44d6775786 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -789,7 +789,7 @@ NonnullRefPtr Parser::parse_regexp_literal() HashTable seen_flags; for (size_t i = 0; i < flags.length(); ++i) { auto flag = flags.substring_view(i, 1); - if (!flag.is_one_of("g", "i", "m", "s", "u", "y")) + if (!flag.is_one_of("d", "g", "i", "m", "s", "u", "y")) syntax_error(String::formatted("Invalid RegExp flag '{}'", flag), Position { flags_start.line, flags_start.column + i }); if (seen_flags.contains(*flag.characters_without_null_termination())) syntax_error(String::formatted("Repeated RegExp flag '{}'", flag), Position { flags_start.line, flags_start.column + i }); diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 42dcea4bdf..48ac2eb0db 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -188,6 +188,7 @@ namespace JS { P(globalThis) \ P(groups) \ P(has) \ + P(hasIndices) \ P(hasOwn) \ P(hasOwnProperty) \ P(hypot) \ diff --git a/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp b/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp index 749f477c2c..48cbfa41fe 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp @@ -16,7 +16,7 @@ namespace JS { static Flags options_from(GlobalObject& global_object, const String& flags) { auto& vm = global_object.vm(); - bool g = false, i = false, m = false, s = false, u = false, y = false; + bool d = false, g = false, i = false, m = false, s = false, u = false, y = false; Flags options { // JS regexps are all 'global' by default as per our definition, but the "global" flag enables "stateful". // FIXME: Enable 'BrowserExtended' only if in a browser context. @@ -26,6 +26,11 @@ static Flags options_from(GlobalObject& global_object, const String& flags) for (auto ch : flags) { switch (ch) { + case 'd': + if (d) + vm.throw_exception(global_object, ErrorType::RegExpObjectRepeatedFlag, ch); + d = true; + break; case 'g': if (g) vm.throw_exception(global_object, ErrorType::RegExpObjectRepeatedFlag, ch); diff --git a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp index 726d11dfd5..ae454019c2 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp @@ -224,6 +224,7 @@ static Value regexp_exec(GlobalObject& global_object, Object& regexp_object, Str return regexp_builtin_exec(global_object, static_cast(regexp_object), string); } +// 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 // 22.2.5.6 get RegExp.prototype.ignoreCase, https://tc39.es/ecma262/#sec-get-regexp.prototype.ignorecase diff --git a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.flags.js b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.flags.js index 9ccc0b614e..6d548ee935 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.flags.js +++ b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.flags.js @@ -1,5 +1,6 @@ test("basic functionality", () => { expect(/foo/.flags).toBe(""); + expect(/foo/d.flags).toBe("d"); expect(/foo/g.flags).toBe("g"); expect(/foo/i.flags).toBe("i"); expect(/foo/m.flags).toBe("m"); @@ -7,5 +8,5 @@ test("basic functionality", () => { expect(/foo/u.flags).toBe("u"); expect(/foo/y.flags).toBe("y"); // prettier-ignore - expect(/foo/sgimyu.flags).toBe("gimsuy"); + expect(/foo/dsgimyu.flags).toBe("dgimsuy"); });