1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:27:35 +00:00

LibRegex: Give the bytecode a chance to run when there's no input

Fixes #4246
Also adds a test case.
This commit is contained in:
AnotherTest 2020-11-29 23:44:48 +03:30 committed by Andreas Kling
parent ab2c646d5d
commit 8cada744df
2 changed files with 29 additions and 0 deletions

View file

@ -27,6 +27,7 @@
#include "RegexMatcher.h" #include "RegexMatcher.h"
#include "RegexDebug.h" #include "RegexDebug.h"
#include "RegexParser.h" #include "RegexParser.h"
#include <AK/ScopedValueRollback.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
@ -153,6 +154,33 @@ RegexResult Matcher<Parser>::match(const Vector<RegexStringView> views, Optional
auto view_length = view.length(); auto view_length = view.length();
size_t view_index = m_pattern.start_offset; size_t view_index = m_pattern.start_offset;
state.string_position = view_index; state.string_position = view_index;
if (view_index == view_length && m_pattern.parser_result.match_length_minimum == 0) {
// Run the code until it tries to consume something.
// This allows non-consuming code to run on empty strings, for instance
// e.g. "Exit"
MatchOutput temp_output { output };
input.column = match_count;
input.match_index = match_count;
state.string_position = view_index;
state.instruction_position = 0;
auto success = execute(input, state, temp_output, 0);
// This success is acceptable only if it doesn't read anything from the input (input length is 0).
if (state.string_position <= view_index) {
if (success.value()) {
output = move(temp_output);
if (!match_count) {
// Nothing was *actually* matched, so append an empty match.
append_match(input, state, output, view_index);
++match_count;
}
}
}
}
for (; view_index < view_length; ++view_index) { for (; view_index < view_length; ++view_index) {
auto& match_length_minimum = m_pattern.parser_result.match_length_minimum; auto& match_length_minimum = m_pattern.parser_result.match_length_minimum;
// FIXME: More performant would be to know the remaining minimum string // FIXME: More performant would be to know the remaining minimum string

View file

@ -535,6 +535,7 @@ TEST_CASE(ECMA262_match)
{ "bar.*(?<=foo)", "barbar", false }, { "bar.*(?<=foo)", "barbar", false },
{ "bar.*(?<!foo)", "barbar", true }, { "bar.*(?<!foo)", "barbar", true },
{ "((...)X)+", "fooXbarXbazX", true }, { "((...)X)+", "fooXbarXbazX", true },
{ "(?:)", "", true },
}; };
for (auto& test : tests) { for (auto& test : tests) {