Commit 59e218c8 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[regexp] Don't propagate lookaround eats_at_least to surroundings

Lookarounds rewind the position after matching, and thus don't play
well with eats_at_least (EAL). This CL disables EAL propagation from
lookarounds.

In the future we could be a bit smarter by skipping over lookarounds
instead of resetting to 0.

Bug: v8:11290
Change-Id: I935400a7f9cda96d9c5a80e412ba7d04de70a84f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2808944Reviewed-by: 's avatarSeth Brenith <seth.brenith@microsoft.com>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73849}
parent c977b65b
......@@ -3533,14 +3533,23 @@ class EatsAtLeastPropagator : public AllStatic {
}
static void VisitAction(ActionNode* that) {
// POSITIVE_SUBMATCH_SUCCESS rewinds input, so we must not consider
// successor nodes for eats_at_least. SET_REGISTER_FOR_LOOP indicates a loop
// entry point, which means the loop body will run at least the minimum
// number of times before the continuation case can run. Otherwise the
// current node eats at least as much as its successor.
// - BEGIN_SUBMATCH and POSITIVE_SUBMATCH_SUCCESS wrap lookarounds.
// Lookarounds rewind input, so their eats_at_least value must not
// propagate to surroundings.
// TODO(jgruber): Instead of resetting EAL to 0 at lookaround boundaries,
// analysis should instead skip over the lookaround and look at whatever
// follows the lookaround. A simple solution would be to store a pointer to
// the associated POSITIVE_SUBMATCH_SUCCESS node in the BEGIN_SUBMATCH
// node, and use that during analysis.
// - SET_REGISTER_FOR_LOOP indicates a loop entry point, which means the
// loop body will run at least the minimum number of times before the
// continuation case can run. Otherwise the current node eats at least as
// much as its successor.
switch (that->action_type()) {
case ActionNode::BEGIN_SUBMATCH:
case ActionNode::POSITIVE_SUBMATCH_SUCCESS:
break; // Was already initialized to zero.
DCHECK(that->eats_at_least_info()->IsZero());
break;
case ActionNode::SET_REGISTER_FOR_LOOP:
that->set_eats_at_least_info(
that->on_success()->EatsAtLeastFromLoopEntry());
......
......@@ -109,6 +109,11 @@ struct EatsAtLeastInfo final {
}
}
bool IsZero() const {
return eats_at_least_from_possibly_start == 0 &&
eats_at_least_from_not_start == 0;
}
// Any successful match starting from the current node will consume at least
// this many characters. This does not necessarily mean that there is a
// possible match with exactly this many characters, but we generally try to
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
assertEquals("zzz".match(/(z(?=.)){2}/), ["zz", "z"]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment