소스 검색

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.
Ali Mohammad Pur 2 년 전
부모
커밋
bcfbe0fbf7
2개의 변경된 파일25개의 추가작업 그리고 3개의 파일을 삭제
  1. 24 1
      Userland/Libraries/LibJS/Runtime/RegExpObject.cpp
  2. 1 2
      Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.source.js

+ 24 - 1
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

+ 1 - 2
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");
 });