Selaa lähdekoodia

LibRegex: Do not continue searching input when the sticky bit is set

This partially reverts commit a962ee020a6310b2d7c7479aa058c15484127418.

When the sticky bit is set, the global bit should basically be ignored
except by external callers who want their own special behavior. For
example, RegExp.prototype [ @@match ] will use the global flag to
accumulate consecutive matches. But on the first failure, the regex
loop should break.
Timothy Flynn 3 vuotta sitten
vanhempi
commit
27d3de1f17

+ 8 - 0
Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.match.js

@@ -70,3 +70,11 @@ test("escaped code points", () => {
     expect(string.match(re).groups.𝓑𝓻𝓸𝔀𝓷).toBe("brown");
     expect(string.match(re).groups.𝓑𝓻𝓸𝔀𝓷).toBe("brown");
     expect(string.match(re).groups.𝓑𝓻𝓸𝔀𝓷).toBe("brown");
     expect(string.match(re).groups.𝓑𝓻𝓸𝔀𝓷).toBe("brown");
 });
 });
+
+test("sticky and global flag set", () => {
+    const string = "aaba";
+    expect(string.match(/a/)).toEqual(["a"]);
+    expect(string.match(/a/y)).toEqual(["a"]);
+    expect(string.match(/a/g)).toEqual(["a", "a", "a"]);
+    expect(string.match(/a/gy)).toEqual(["a", "a"]);
+});

+ 7 - 1
Userland/Libraries/LibRegex/RegexMatcher.cpp

@@ -180,6 +180,8 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona
 #endif
 #endif
 
 
     bool continue_search = input.regex_options.has_flag_set(AllFlags::Global) || input.regex_options.has_flag_set(AllFlags::Multiline);
     bool continue_search = input.regex_options.has_flag_set(AllFlags::Global) || input.regex_options.has_flag_set(AllFlags::Multiline);
+    if (input.regex_options.has_flag_set(AllFlags::Sticky))
+        continue_search = false;
 
 
     auto single_match_only = input.regex_options.has_flag_set(AllFlags::SingleMatch);
     auto single_match_only = input.regex_options.has_flag_set(AllFlags::SingleMatch);
 
 
@@ -280,7 +282,11 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona
                         break;
                         break;
                     continue;
                     continue;
                 }
                 }
-                if (state.string_position < view_length && !input.regex_options.has_flag_set(AllFlags::Internal_Stateful)) {
+                if (input.regex_options.has_flag_set(AllFlags::Internal_Stateful)) {
+                    append_match(input, state, view_index);
+                    break;
+                }
+                if (state.string_position < view_length) {
                     return { false, 0, {}, {}, {}, operations };
                     return { false, 0, {}, {}, {}, operations };
                 }
                 }