Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions harness/compareArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ function compareArray(a, b) {
return true;
}

assert.compareArray = function(actual, expected, message) {
assert(compareArray(actual, expected),
`Expected [${actual.join(", ")}] and [${expected.join(", ")}] to have the same contents. ${message}`);
}
27 changes: 27 additions & 0 deletions test/built-ins/RegExp/lookBehind/alternations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Alternations are tried left to right, and we do not backtrack into a lookbehind.
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray("xabcd".match(/.*(?<=(..|...|....))(.*)/), ["xabcd", "cd", ""], "#1");
assert.compareArray("xabcd".match(/.*(?<=(xx|...|....))(.*)/), ["xabcd", "bcd", ""], "#2");
assert.compareArray("xxabcd".match(/.*(?<=(xx|...))(.*)/), ["xxabcd", "bcd", ""], "#3");
assert.compareArray("xxabcd".match(/.*(?<=(xx|xxx))(.*)/), ["xxabcd", "xx", "abcd"], "#4");
29 changes: 29 additions & 0 deletions test/built-ins/RegExp/lookBehind/back-references-to-captures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Back references to captures inside the lookbehind.
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray("abcCd".match(/(?<=\1(\w))d/i), ["d", "C"], "#1");
assert.compareArray("abxxd".match(/(?<=\1([abx]))d/), ["d", "x"], "#2");
assert.compareArray("ababc".match(/(?<=\1(\w+))c/), ["c", "ab"], "#3");
assert.compareArray("ababbc".match(/(?<=\1(\w+))c/), ["c", "b"], "#4");
assert.sameValue("ababdc".match(/(?<=\1(\w+))c/), null, "#5");
assert.compareArray("ababc".match(/(?<=(\w+)\1)c/), ["c", "abab"], "#6");
43 changes: 43 additions & 0 deletions test/built-ins/RegExp/lookBehind/back-references.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Back references
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray("abb".match(/(.)(?<=(\1\1))/), ["b", "b", "bb"], "#1");
assert.compareArray("abB".match(/(.)(?<=(\1\1))/i), ["B", "B", "bB"], "#2");
assert.compareArray("aabAaBa".match(/((\w)\w)(?<=\1\2\1)/i), ["aB", "aB", "a"], "#3");
assert.compareArray("aabAaBa".match(/(\w(\w))(?<=\1\2\1)/i), ["Ba", "Ba", "a"], "#4");
assert.compareArray("abaBbAa".match(/(?=(\w))(?<=(\1))./i), ["b", "b", "B"], "#5");
assert.compareArray(" 'foo' ".match(/(?<=(.))(\w+)(?=\1)/), ["foo", "'", "foo"], "#6");
assert.compareArray(" \"foo\" ".match(/(?<=(.))(\w+)(?=\1)/), ["foo", "\"", "foo"], "#7");
assert.compareArray("abbb".match(/(.)(?<=\1\1\1)/), ["b", "b"], "#8");
assert.compareArray("fababab".match(/(..)(?<=\1\1\1)/), ["ab", "ab"], "#9");

assert.sameValue(" .foo\" ".match(/(?<=(.))(\w+)(?=\1)/), null, "#10");
assert.sameValue("ab".match(/(.)(?<=\1\1\1)/), null, "#11");
assert.sameValue("abb".match(/(.)(?<=\1\1\1)/), null, "#12");
assert.sameValue("ab".match(/(..)(?<=\1\1\1)/), null, "#13");
assert.sameValue("abb".match(/(..)(?<=\1\1\1)/), null, "#14");
assert.sameValue("aabb".match(/(..)(?<=\1\1\1)/), null, "#15");
assert.sameValue("abab".match(/(..)(?<=\1\1\1)/), null, "#16");
assert.sameValue("fabxbab".match(/(..)(?<=\1\1\1)/), null, "#17");
assert.sameValue("faxabab".match(/(..)(?<=\1\1\1)/), null, "#18");

25 changes: 25 additions & 0 deletions test/built-ins/RegExp/lookBehind/captures-negative.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: >
Captures inside negative lookbehind. (They never capture.)
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray("abcdef".match(/(?<!(^|[ab]))\w{2}/), ["de", undefined]);
34 changes: 34 additions & 0 deletions test/built-ins/RegExp/lookBehind/captures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: >
Capturing matches
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

var str = "abcdef";
assert.compareArray(str.match(/(?<=(c))def/), ["def", "c"], "#1");
assert.compareArray(str.match(/(?<=(\w{2}))def/), ["def", "bc"], "#2");
assert.compareArray(str.match(/(?<=(\w(\w)))def/), ["def", "bc", "c"], "#3");
assert.compareArray(str.match(/(?<=(\w){3})def/), ["def", "a"], "#4");
assert.compareArray(str.match(/(?<=(bc)|(cd))./), ["d", "bc", undefined], "#5");
assert.compareArray(str.match(/(?<=([ab]{1,2})\D|(abc))\w/), ["c", "a", undefined], "#6");
assert.compareArray(str.match(/\D(?<=([ab]+))(\w)/), ["ab", "a", "b"], "#7");
assert.compareArray(str.match(/(?<=b|c)\w/g), ["c", "d"], "#8");
assert.compareArray(str.match(/(?<=[b-e])\w{2}/g), ["cd", "ef"], "#9");
25 changes: 25 additions & 0 deletions test/built-ins/RegExp/lookBehind/do-not-backtrack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Do not backtrack into a lookbehind.
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
---*/

// The lookbehind captures "abc" so that \1 does not match. We do not backtrack
// to capture only "bc" in the lookbehind.
assert.sameValue("abcdbc".match(/(?<=([abc]+)).\1/), null);
26 changes: 26 additions & 0 deletions test/built-ins/RegExp/lookBehind/greedy-loop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Greedy loop
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray("abbbbbbc".match(/(?<=(b+))c/), ["c", "bbbbbb"], "#1");
assert.compareArray("ab1234c".match(/(?<=(b\d+))c/), ["c", "b1234"], "#2");
assert.compareArray("ab12b23b34c".match(/(?<=((?:b\d{2})+))c/), ["c", "b12b23b34"], "#3");
37 changes: 37 additions & 0 deletions test/built-ins/RegExp/lookBehind/misc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Misc RegExp lookbehind tests
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.sameValue("abcdef".match(/(?<=$abc)def/), null, "#1");
assert.sameValue("fno".match(/^f.o(?<=foo)$/), null, "#2");
assert.sameValue("foo".match(/^foo(?<!foo)$/), null, "#3");
assert.sameValue("foo".match(/^f.o(?<!foo)$/), null, "#4");

assert.compareArray("foo".match(/^foo(?<=foo)$/), ["foo"], "#5");
assert.compareArray("foo".match(/^f.o(?<=foo)$/), ["foo"], "#6");
assert.compareArray("fno".match(/^f.o(?<!foo)$/), ["fno"], "#7");
assert.compareArray("foooo".match(/^foooo(?<=fo+)$/), ["foooo"], "#8");
assert.compareArray("foooo".match(/^foooo(?<=fo*)$/), ["foooo"], "#9");
assert.compareArray(/(abc\1)/.exec("abc"), ["abc", "abc"], "#10");
assert.compareArray(/(abc\1)/.exec("abc\u1234"), ["abc", "abc"], "#11");
assert.compareArray(/(abc\1)/i.exec("abc"), ["abc", "abc"], "#12");
assert.compareArray(/(abc\1)/i.exec("abc\u1234"), ["abc", "abc"], "#13");
27 changes: 27 additions & 0 deletions test/built-ins/RegExp/lookBehind/mutual-recursive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Mutual recursive capture/back references
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray(/(?<=a(.\2)b(\1)).{4}/.exec("aabcacbc"), ["cacb", "a", ""], "#1");
assert.compareArray(/(?<=a(\2)b(..\1))b/.exec("aacbacb"), ["b", "ac", "ac"], "#2");
assert.compareArray(/(?<=(?:\1b)(aa))./.exec("aabaax"), ["x", "aa"], "#3");
assert.compareArray(/(?<=(?:\1|b)(aa))./.exec("aaaax"), ["x", "aa"], "#4");
32 changes: 32 additions & 0 deletions test/built-ins/RegExp/lookBehind/negative.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: RegExp negative lookbehind
info: |
The production Assertion :: (?<!Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a
Continuation c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful
MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is not failure, return failure.
d. Call c(x) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray("abcdef".match(/(?<!abc)\w\w\w/), ["abc"], "#1");
assert.compareArray("abcdef".match(/(?<!a.c)\w\w\w/), ["abc"], "#2");
assert.compareArray("abcdef".match(/(?<!a\wc)\w\w\w/), ["abc"], "#3");
assert.compareArray("abcdef".match(/(?<!a[a-z])\w\w\w/), ["abc"], "#4");
assert.compareArray("abcdef".match(/(?<!a[a-z]{2})\w\w\w/), ["abc"], "#5");
assert.sameValue("abcdef".match(/(?<!abc)def/), null, "#6");
assert.sameValue("abcdef".match(/(?<!a.c)def/), null, "#7");
assert.sameValue("abcdef".match(/(?<!a\wc)def/), null, "#8");
assert.sameValue("abcdef".match(/(?<!a[a-z][a-z])def/), null, "#9");
assert.sameValue("abcdef".match(/(?<!a[a-z]{2})def/), null, "#10");
assert.sameValue("abcdef".match(/(?<!a{1}b{1})cde/), null, "#11");
assert.sameValue("abcdef".match(/(?<!a{1}[a-z]{2})def/), null, "#12");
29 changes: 29 additions & 0 deletions test/built-ins/RegExp/lookBehind/nested-lookaround.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Nested lookaround
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.compareArray("abcdef".match(/(?<=ab(?=c)\wd)\w\w/), ["ef"], "#1");
assert.compareArray("abcdef".match(/(?<=a(?=([^a]{2})d)\w{3})\w\w/), ["ef", "bc"], "#2");
assert.compareArray("abcdef".match(/(?<=a(?=([bc]{2}(?<!a{2}))d)\w{3})\w\w/), ["ef", "bc"], "#3");
assert.compareArray("faaao".match(/^faaao?(?<=^f[oa]+(?=o))/), ["faaa"], "#4");

assert.sameValue("abcdef".match(/(?<=a(?=([bc]{2}(?<!a*))d)\w{3})\w\w/), null, "#5");
40 changes: 40 additions & 0 deletions test/built-ins/RegExp/lookBehind/simple-fixed-length.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-assertion
description: Simple fixed-length matches
info: |
The production Assertion :: (?<=Disjunction) evaluates as follows:
1. Evaluate Disjunction with -1 as its direction argument to obtain a Matcher m.
2. Return an internal Matcher closure that takes two arguments, a State x and a Continuation
c, and performs the following steps:
a. Let d be a Continuation that always returns its State argument as a successful MatchResult.
b. Call m(x, d) and let r be its result.
c. If r is failure, return failure.
d. Let y be r's State.
e. Let cap be y's captures List.
f. Let xe be x's endIndex.
g. Let z be the State (xe, cap).
h. Call c(z) and return its result.
features: [regexp-lookbehind]
includes: [compareArray.js]
---*/

assert.sameValue("b".match(/^.(?<=a)/), null, "#1");
assert.sameValue("boo".match(/^f\w\w(?<=\woo)/), null, "#2");
assert.sameValue("fao".match(/^f\w\w(?<=\woo)/), null, "#3");
assert.sameValue("foa".match(/^f\w\w(?<=\woo)/), null, "#4");

assert.compareArray("a".match(/^.(?<=a)/), ["a"], "#5");
assert.compareArray("foo1".match(/^f..(?<=.oo)/), ["foo"], "#6");
assert.compareArray("foo2".match(/^f\w\w(?<=\woo)/), ["foo"], "#7");
assert.compareArray("abcdef".match(/(?<=abc)\w\w\w/), ["def"], "#8");
assert.compareArray("abcdef".match(/(?<=a.c)\w\w\w/), ["def"], "#9");
assert.compareArray("abcdef".match(/(?<=a\wc)\w\w\w/), ["def"], "#10");
assert.compareArray("abcdef".match(/(?<=a[a-z])\w\w\w/), ["cde"], "#11");
assert.compareArray("abcdef".match(/(?<=a[a-z][a-z])\w\w\w/), ["def"], "#12");
assert.compareArray("abcdef".match(/(?<=a[a-z]{2})\w\w\w/), ["def"], "#13");
assert.compareArray("abcdef".match(/(?<=a{1})\w\w\w/), ["bcd"], "#14");
assert.compareArray("abcdef".match(/(?<=a{1}b{1})\w\w\w/), ["cde"], "#15");
assert.compareArray("abcdef".match(/(?<=a{1}[a-z]{2})\w\w\w/), ["def"], "#16");
Loading