[regexp] Implement regexp groups as wrapper.

Non-capturing groups so far did not have any effect, so we elided
them in the regexp parser. However, they do affect how lookarounds
are parsed: in unicode mode, lookarounds are not quantifiable. They
are however if wrapped in a group.

BUG=v8:5845

Review-Url: https://codereview.chromium.org/2636883002
Cr-Commit-Position: refs/heads/master@{#42436}
This commit is contained in:
yangguo 2017-01-18 00:14:59 -08:00 committed by Commit bot
parent 2851866cfe
commit 92acec568c
5 changed files with 39 additions and 5 deletions

View File

@ -264,6 +264,12 @@ void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
return NULL;
}
void* RegExpUnparser::VisitGroup(RegExpGroup* that, void* data) {
os_ << "(?: ";
that->body()->Accept(this, data);
os_ << ")";
return NULL;
}
void* RegExpUnparser::VisitLookaround(RegExpLookaround* that, void* data) {
os_ << "(";

View File

@ -21,12 +21,12 @@ namespace internal {
VISIT(Atom) \
VISIT(Quantifier) \
VISIT(Capture) \
VISIT(Group) \
VISIT(Lookaround) \
VISIT(BackReference) \
VISIT(Empty) \
VISIT(Text)
#define FORWARD_DECLARE(Name) class RegExp##Name;
FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE)
#undef FORWARD_DECLARE
@ -440,6 +440,26 @@ class RegExpCapture final : public RegExpTree {
const ZoneVector<uc16>* name_;
};
class RegExpGroup final : public RegExpTree {
public:
explicit RegExpGroup(RegExpTree* body) : body_(body) {}
void* Accept(RegExpVisitor* visitor, void* data) override;
RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) override {
return body_->ToNode(compiler, on_success);
}
RegExpGroup* AsGroup() override;
bool IsAnchoredAtStart() override { return body_->IsAnchoredAtStart(); }
bool IsAnchoredAtEnd() override { return body_->IsAnchoredAtEnd(); }
bool IsGroup() override;
int min_match() override { return body_->min_match(); }
int max_match() override { return body_->max_match(); }
Interval CaptureRegisters() override { return body_->CaptureRegisters(); }
RegExpTree* body() { return body_; }
private:
RegExpTree* body_;
};
class RegExpLookaround final : public RegExpTree {
public:

View File

@ -216,7 +216,9 @@ RegExpTree* RegExpParser::ParseDisjunction() {
RegExpCapture* capture = GetCapture(capture_index);
capture->set_body(body);
body = capture;
} else if (group_type != GROUPING) {
} else if (group_type == GROUPING) {
body = new (zone()) RegExpGroup(body);
} else {
DCHECK(group_type == POSITIVE_LOOKAROUND ||
group_type == NEGATIVE_LOOKAROUND);
bool is_positive = (group_type == POSITIVE_LOOKAROUND);

View File

@ -199,8 +199,8 @@ void TestRegExpParser(bool lookbehind) {
CheckParseEq("xyz{1,}?", "(: 'xy' (# 1 - n 'z'))");
CheckParseEq("a\\fb\\nc\\rd\\te\\vf", "'a\\x0cb\\x0ac\\x0dd\\x09e\\x0bf'");
CheckParseEq("a\\nb\\bc", "(: 'a\\x0ab' @b 'c')");
CheckParseEq("(?:foo)", "'foo'");
CheckParseEq("(?: foo )", "' foo '");
CheckParseEq("(?:foo)", "(?: 'foo')");
CheckParseEq("(?: foo )", "(?: ' foo ')");
CheckParseEq("(foo|bar|baz)", "(^ (| 'foo' 'bar' 'baz'))");
CheckParseEq("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')");
CheckParseEq("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')");
@ -294,7 +294,7 @@ void TestRegExpParser(bool lookbehind) {
CheckParseEq("(?!\\1(a\\1)\\1)\\1",
"(: (-> - (: (<- 1) (^ 'a') (<- 1))) (<- 1))");
CheckParseEq("\\1\\2(a(?:\\1(b\\1\\2))\\2)\\1",
"(: (<- 1) (<- 2) (^ (: 'a' (^ 'b') (<- 2))) (<- 1))");
"(: (<- 1) (<- 2) (^ (: 'a' (?: (^ 'b')) (<- 2))) (<- 1))");
if (lookbehind) {
CheckParseEq("\\1\\2(a(?<=\\1(b\\1\\2))\\2)\\1",
"(: (<- 1) (<- 2) (^ (: 'a' (<- + (^ 'b')) (<- 2))) (<- 1))");

View File

@ -0,0 +1,6 @@
// Copyright 2017 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.
assertDoesNotThrow('/(?:(?=(foo)))?/u.exec("foo")');
assertThrows('/(?=(foo))?/u.exec("foo")');