From 65003241e40cb51605a0e0fcfb5203356af79b6a Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 6 Jul 2021 11:09:46 -0400 Subject: [PATCH] LibRegex: Allow dollar signs in ECMA262 named capture groups Fixes 1 test262 test. --- Tests/LibRegex/Regex.cpp | 21 +++++++++++++++++++ .../String/String.prototype.replace.js | 3 +++ Userland/Libraries/LibRegex/RegexParser.cpp | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Tests/LibRegex/Regex.cpp b/Tests/LibRegex/Regex.cpp index 9656608571..20581b3a8f 100644 --- a/Tests/LibRegex/Regex.cpp +++ b/Tests/LibRegex/Regex.cpp @@ -422,6 +422,27 @@ TEST_CASE(named_capture_group) EXPECT_EQ(result.named_capture_group_matches.at(1).ensure("Test").view, "0"); } +TEST_CASE(ecma262_named_capture_group_with_dollar_sign) +{ + Regex re("[a-zA-Z]*=(?<$Test$>[0-9]*)"); + RegexResult result; + + if constexpr (REGEX_DEBUG) { + RegexDebug regex_dbg(stderr); + regex_dbg.print_raw_bytecode(re); + regex_dbg.print_header(); + regex_dbg.print_bytecode(re); + } + + String haystack = "[Window]\nOpacity=255\nAudibleBeep=0\n"; + EXPECT_EQ(re.search(haystack, result, ECMAScriptFlags::Multiline), true); + EXPECT_EQ(result.count, 2u); + EXPECT_EQ(result.matches.at(0).view, "Opacity=255"); + EXPECT_EQ(result.named_capture_group_matches.at(0).ensure("$Test$").view, "255"); + EXPECT_EQ(result.matches.at(1).view, "AudibleBeep=0"); + EXPECT_EQ(result.named_capture_group_matches.at(1).ensure("$Test$").view, "0"); +} + TEST_CASE(a_star) { Regex re("a*"); diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.replace.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.replace.js index 16d481c9f8..90e306bccb 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.replace.js +++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.replace.js @@ -138,6 +138,9 @@ test("replacement with substitution", () => { expect("abc".replace(/(?a)b(?c)/, "$")).toBe("a"); expect("abc".replace(/(?a)b(?c)/, "$")).toBe("c"); expect("abc".replace(/(?a)b(?c)/, "$b$")).toBe("cba"); + + expect(/(?<𝒜>b)/u[Symbol.replace]("abc", "d$<𝒜>$`")).toBe("adbac"); + expect(/(?<$𐒤>b)/gu[Symbol.replace]("abc", "$'$<$𐒤>d")).toBe("acbdc"); }); test("replacement with substitution and 'groups' coerced to an object", () => { diff --git a/Userland/Libraries/LibRegex/RegexParser.cpp b/Userland/Libraries/LibRegex/RegexParser.cpp index 1c6a78b072..a3a271036f 100644 --- a/Userland/Libraries/LibRegex/RegexParser.cpp +++ b/Userland/Libraries/LibRegex/RegexParser.cpp @@ -1625,7 +1625,7 @@ StringView ECMA262Parser::read_capture_group_specifier(bool take_starting_angle_ auto start_token = m_parser_state.current_token; size_t offset = 0; - while (match(TokenType::Char)) { + while (match(TokenType::Char) || match(TokenType::Dollar)) { auto c = m_parser_state.current_token.value(); if (c == ">") break;