From ac856cb96541f8165bbadbd4530b3d1ee7ed4395 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Fri, 29 Oct 2021 16:21:13 +0330 Subject: [PATCH] LibRegex: Don't ignore empty alternatives in append_alternation() Doing so would cause patterns like `(a|)` to not match the empty string. --- Tests/LibRegex/Regex.cpp | 1 + .../Libraries/LibRegex/RegexOptimizer.cpp | 22 ++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Tests/LibRegex/Regex.cpp b/Tests/LibRegex/Regex.cpp index 540c11d4ff2..31a22bdddf8 100644 --- a/Tests/LibRegex/Regex.cpp +++ b/Tests/LibRegex/Regex.cpp @@ -898,6 +898,7 @@ TEST_CASE(optimizer_atomic_groups) // Alternative fuse Tuple { "(abcfoo|abcbar|abcbaz).*x"sv, "abcbarx"sv, true }, Tuple { "(a|a)"sv, "a"sv, true }, + Tuple { "(a|)"sv, ""sv, true }, // Ensure that empty alternatives are not outright removed // ForkReplace shouldn't be applied where it would change the semantics Tuple { "(1+)\\1"sv, "11"sv, true }, Tuple { "(1+)1"sv, "11"sv, true }, diff --git a/Userland/Libraries/LibRegex/RegexOptimizer.cpp b/Userland/Libraries/LibRegex/RegexOptimizer.cpp index cd225f2d908..6519be9e270 100644 --- a/Userland/Libraries/LibRegex/RegexOptimizer.cpp +++ b/Userland/Libraries/LibRegex/RegexOptimizer.cpp @@ -436,13 +436,23 @@ void Regex::attempt_rewrite_loops_as_atomic_groups(BasicBlockList const& void Optimizer::append_alternation(ByteCode& target, ByteCode&& left, ByteCode&& right) { - if (left.is_empty()) { - target.extend(right); - return; - } + auto left_is_empty = left.is_empty(); + auto right_is_empty = right.is_empty(); + if (left_is_empty || right_is_empty) { + if (left_is_empty && right_is_empty) + return; - if (right.is_empty()) { - target.extend(left); + // ForkJump right (+ left.size() + 2 + right.size()) + // (left) + // Jump end (+ right.size()) + // (right) + // LABEL end + target.append(static_cast(OpCodeId::ForkJump)); + target.append(left.size() + 2 + right.size()); + target.extend(move(left)); + target.append(static_cast(OpCodeId::Jump)); + target.append(right.size()); + target.extend(move(right)); return; }