diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2023-02-15 17:55:13 +0330 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-02-16 21:03:19 +0100 |
commit | bcfbe0fbf7465ed6706d806b69c5eaa2dcfc6325 (patch) | |
tree | ddd3ae95f9d6b484014fc7f4953da76c9b5f9ab9 /Userland/Libraries/LibJS | |
parent | a8bcb901c0bbe023364e852796e900fa58bcac45 (diff) | |
download | serenity-bcfbe0fbf7465ed6706d806b69c5eaa2dcfc6325.zip |
LibJS: Manually loop over escaped regex pattern instead of ::replace()
This makes it ever-so-slightly faster, but more importantly, it fixes
the bug where a `/\//` regex's `source` property would return `\\/`
("\\\\/") instead of `\/` due to the existing '/' -> '\/' replace()
call.
Diffstat (limited to 'Userland/Libraries/LibJS')
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/RegExpObject.cpp | 25 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.source.js | 3 |
2 files changed, 25 insertions, 3 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp b/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp index 74b52e3000..40c7a6638f 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpObject.cpp @@ -248,8 +248,31 @@ DeprecatedString RegExpObject::escape_regexp_pattern() const // 3. Return S. if (m_pattern.is_empty()) return "(?:)"; + // FIXME: Check the 'u' and 'v' flags and escape accordingly - return m_pattern.replace("\n"sv, "\\n"sv, ReplaceMode::All).replace("\r"sv, "\\r"sv, ReplaceMode::All).replace(LINE_SEPARATOR_STRING, "\\u2028"sv, ReplaceMode::All).replace(PARAGRAPH_SEPARATOR_STRING, "\\u2029"sv, ReplaceMode::All).replace("/"sv, "\\/"sv, ReplaceMode::All); + StringBuilder builder; + auto pattern = Utf8View { m_pattern }; + auto escaped = false; + for (auto code_point : pattern) { + if (escaped) { + escaped = false; + builder.append_code_point('\\'); + builder.append_code_point(code_point); + continue; + } + + if (code_point == '\\') { + escaped = true; + continue; + } + + if (code_point == '\r' || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR || code_point == '/') { + builder.append_code_point('\\'); + } + builder.append_code_point(code_point); + } + + return builder.to_deprecated_string(); } // 22.2.3.2.4 RegExpCreate ( P, F ), https://tc39.es/ecma262/#sec-regexpcreate diff --git a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.source.js b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.source.js index 4f0e14297f..3992c7c1db 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.source.js +++ b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.source.js @@ -3,6 +3,5 @@ test("basic functionality", () => { expect(RegExp().source).toBe("(?:)"); expect(/test/.source).toBe("test"); expect(/\n/.source).toBe("\\n"); - // FIXME: RegExp parse doesn't parse \/ :( - // expect(/foo\/bar/.source).toBe("foo\\/bar"); + expect(/foo\/bar/.source).toBe("foo\\/bar"); }); |