nodejs/deps/v8/test/mjsunit/es9/regexp-lookbehind.js
Michaël Zasso 5edec0e39a
deps: update V8 to 13.0.245.25
PR-URL: https://github.com/nodejs/node/pull/55014
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2025-01-31 12:45:51 +01:00

200 lines
8.2 KiB
JavaScript

// Copyright 2015 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.
function checkEquals(array, subject, regexp) {
// Do it once with the interpreter.
var result = subject.match(regexp);
assertEquals(array, result);
// Do it again with the machine code.
result = subject.match(regexp);
assertEquals(array, result);
}
function checkExec(array, regexp, subject) {
// Do it once with the interpreter.
var result = regexp.exec(subject);
assertEquals(array, result);
// Do it again with the machine code.
result = regexp.exec(subject);
assertEquals(array, result);
}
function checkNull(subject, regexp) {
// Do it once with the interpreter.
var result = subject.match(regexp);
assertNull(result);
// Do it again with the machine code.
result = subject.match(regexp);
assertNull(result);
}
// Simple fixed-length matches.
checkEquals(["a"], "a", /^.(?<=a)/);
checkNull("b", /^.(?<=a)/);
checkEquals(["foo"], "foo1", /^f..(?<=.oo)/);
checkEquals(["foo"], "foo2", /^f\w\w(?<=\woo)/);
checkNull("boo", /^f\w\w(?<=\woo)/);
checkNull("fao", /^f\w\w(?<=\woo)/);
checkNull("foa", /^f\w\w(?<=\woo)/);
checkEquals(["def"], "abcdef", /(?<=abc)\w\w\w/);
checkEquals(["def"], "abcdef", /(?<=a.c)\w\w\w/);
checkEquals(["def"], "abcdef", /(?<=a\wc)\w\w\w/);
checkEquals(["cde"], "abcdef", /(?<=a[a-z])\w\w\w/);
checkEquals(["def"], "abcdef", /(?<=a[a-z][a-z])\w\w\w/);
checkEquals(["def"], "abcdef", /(?<=a[a-z]{2})\w\w\w/);
checkEquals(["bcd"], "abcdef", /(?<=a{1})\w\w\w/);
checkEquals(["cde"], "abcdef", /(?<=a{1}b{1})\w\w\w/);
checkEquals(["def"], "abcdef", /(?<=a{1}[a-z]{2})\w\w\w/);
// Variable-length matches.
checkEquals(["def"], "abcdef", /(?<=[a|b|c]*)[^a|b|c]{3}/);
checkEquals(["def"], "abcdef", /(?<=\w*)[^a|b|c]{3}/);
// Start of line matches.
checkEquals(["def"], "abcdef", /(?<=^abc)def/);
checkEquals(["def"], "abcdef", /(?<=^[a-c]{3})def/);
checkEquals(["def"], "abcabcdef", /(?<=^[a-c]{6})def/);
checkEquals(["def"], "xyz\nabcdef", /(?<=^[a-c]{3})def/m);
checkEquals(["ab", "cd", "efg"], "ab\ncd\nefg", /(?<=^)\w+/gm);
checkEquals(["ab", "cd", "efg"], "ab\ncd\nefg", /\w+(?<=$)/gm);
checkEquals(["ab", "cd", "efg"], "ab\ncd\nefg", /(?<=^)\w+(?<=$)/gm);
checkNull("abcdef", /(?<=^[^a-c]{3})def/);
checkNull("foooo", /"^foooo(?<=^o+)$/);
checkNull("foooo", /"^foooo(?<=^o*)$/);
checkEquals(["foo"], "foo", /^foo(?<=^fo+)$/);
checkEquals(["foooo"], "foooo", /^foooo(?<=^fo*)/);
checkEquals(["foo", "f"], "foo", /^(f)oo(?<=^\1o+)$/);
checkEquals(["foo", "f"], "foo", /^(f)oo(?<=^\1o+)$/i);
checkEquals(["foo\u1234", "f"], "foo\u1234", /^(f)oo(?<=^\1o+).$/i);
checkEquals(["def"], "abcdefdef", /(?<=^\w+)def/);
checkEquals(["def", "def"], "abcdefdef", /(?<=^\w+)def/g);
// Word boundary matches.
checkEquals(["def"], "abc def", /(?<=\b)[d-f]{3}/);
checkEquals(["def"], "ab cdef", /(?<=\B)\w{3}/);
checkEquals(["def"], "ab cdef", /(?<=\B)(?<=c(?<=\w))\w{3}/);
checkNull("abcdef", /(?<=\b)[d-f]{3}/);
// Negative lookbehind.
checkEquals(["abc"], "abcdef", /(?<!abc)\w\w\w/);
checkEquals(["abc"], "abcdef", /(?<!a.c)\w\w\w/);
checkEquals(["abc"], "abcdef", /(?<!a\wc)\w\w\w/);
checkEquals(["abc"], "abcdef", /(?<!a[a-z])\w\w\w/);
checkEquals(["abc"], "abcdef", /(?<!a[a-z]{2})\w\w\w/);
checkNull("abcdef", /(?<!abc)def/);
checkNull("abcdef", /(?<!a.c)def/);
checkNull("abcdef", /(?<!a\wc)def/);
checkNull("abcdef", /(?<!a[a-z][a-z])def/);
checkNull("abcdef", /(?<!a[a-z]{2})def/);
checkNull("abcdef", /(?<!a{1}b{1})cde/);
checkNull("abcdef", /(?<!a{1}[a-z]{2})def/);
// Capturing matches.
checkEquals(["def", "c"], "abcdef", /(?<=(c))def/);
checkEquals(["def", "bc"], "abcdef", /(?<=(\w{2}))def/);
checkEquals(["def", "bc", "c"], "abcdef", /(?<=(\w(\w)))def/);
checkEquals(["def", "a"], "abcdef", /(?<=(\w){3})def/);
checkEquals(["d", "bc", undefined], "abcdef", /(?<=(bc)|(cd))./);
checkEquals(["c", "a", undefined],
"abcdef", /(?<=([ab]{1,2})\D|(abc))\w/);
checkEquals(["ab", "a", "b"], "abcdef", /\D(?<=([ab]+))(\w)/);
checkEquals(["c", "d"], "abcdef", /(?<=b|c)\w/g);
checkEquals(["cd", "ef"], "abcdef", /(?<=[b-e])\w{2}/g);
// Captures inside negative lookbehind. (They never capture.)
checkEquals(["de", undefined], "abcdef", /(?<!(^|[ab]))\w{2}/);
// Nested lookaround.
checkEquals(["ef"], "abcdef", /(?<=ab(?=c)\wd)\w\w/);
checkEquals(["ef", "bc"], "abcdef", /(?<=a(?=([^a]{2})d)\w{3})\w\w/);
checkEquals(["ef", "bc"],
"abcdef", /(?<=a(?=([bc]{2}(?<!a{2}))d)\w{3})\w\w/);
checkNull("abcdef", /(?<=a(?=([bc]{2}(?<!a*))d)\w{3})\w\w/);
checkEquals(["faaa"], "faaao", /^faaao?(?<=^f[oa]+(?=o))/);
// Back references.
checkEquals(["b", "b", "bb"], "abb", /(.)(?<=(\1\1))/);
checkEquals(["B", "B", "bB"], "abB", /(.)(?<=(\1\1))/i);
checkEquals(["aB", "aB", "a"], "aabAaBa", /((\w)\w)(?<=\1\2\1)/i);
checkEquals(["Ba", "Ba", "a"], "aabAaBa", /(\w(\w))(?<=\1\2\1)/i);
checkEquals(["b", "b", "B"], "abaBbAa", /(?=(\w))(?<=(\1))./i);
checkEquals(["foo", "'", "foo"], " 'foo' ", /(?<=(.))(\w+)(?=\1)/);
checkEquals(["foo", "\"", "foo"], " \"foo\" ", /(?<=(.))(\w+)(?=\1)/);
checkNull(" .foo\" ", /(?<=(.))(\w+)(?=\1)/);
checkNull("ab", /(.)(?<=\1\1\1)/);
checkNull("abb", /(.)(?<=\1\1\1)/);
checkEquals(["b", "b"], "abbb", /(.)(?<=\1\1\1)/);
checkNull("ab", /(..)(?<=\1\1\1)/);
checkNull("abb", /(..)(?<=\1\1\1)/);
checkNull("aabb", /(..)(?<=\1\1\1)/);
checkNull("abab", /(..)(?<=\1\1\1)/);
checkNull("fabxbab", /(..)(?<=\1\1\1)/);
checkNull("faxabab", /(..)(?<=\1\1\1)/);
checkEquals(["ab", "ab"], "fababab", /(..)(?<=\1\1\1)/);
// Back references to captures inside the lookbehind.
checkEquals(["d", "C"], "abcCd", /(?<=\1(\w))d/i);
checkEquals(["d", "x"], "abxxd", /(?<=\1([abx]))d/);
checkEquals(["c", "ab"], "ababc", /(?<=\1(\w+))c/);
checkEquals(["c", "b"], "ababbc", /(?<=\1(\w+))c/);
checkNull("ababdc", /(?<=\1(\w+))c/);
checkEquals(["c", "abab"], "ababc", /(?<=(\w+)\1)c/);
// Alternations are tried left to right,
// and we do not backtrack into a lookbehind.
checkEquals(["xabcd", "cd", ""], "xabcd", /.*(?<=(..|...|....))(.*)/);
checkEquals(["xabcd", "bcd", ""], "xabcd", /.*(?<=(xx|...|....))(.*)/);
checkEquals(["xxabcd", "bcd", ""], "xxabcd", /.*(?<=(xx|...))(.*)/);
checkEquals(["xxabcd", "xx", "abcd"], "xxabcd", /.*(?<=(xx|xxx))(.*)/);
// We do not backtrack into a lookbehind.
// The lookbehind captures "abc" so that \1 does not match. We do not backtrack
// to capture only "bc" in the lookbehind.
checkNull("abcdbc", /(?<=([abc]+)).\1/);
// Greedy loop.
checkEquals(["c", "bbbbbb"], "abbbbbbc", /(?<=(b+))c/);
checkEquals(["c", "b1234"], "ab1234c", /(?<=(b\d+))c/);
checkEquals(["c", "b12b23b34"], "ab12b23b34c", /(?<=((?:b\d{2})+))c/);
// Sticky
var re1 = /(?<=^(\w+))def/g;
assertEquals(["def", "abc"], re1.exec("abcdefdef"));
assertEquals(["def", "abcdef"], re1.exec("abcdefdef"));
var re2 = /\Bdef/g;
assertEquals(["def"], re2.exec("abcdefdef"));
assertEquals(["def"], re2.exec("abcdefdef"));
// Misc
checkNull("abcdef", /(?<=$abc)def/);
checkEquals(["foo"], "foo", /^foo(?<=foo)$/);
checkEquals(["foo"], "foo", /^f.o(?<=foo)$/);
checkNull("fno", /^f.o(?<=foo)$/);
checkNull("foo", /^foo(?<!foo)$/);
checkNull("foo", /^f.o(?<!foo)$/);
assertEquals(["fno"], "fno".match(/^f.o(?<!foo)$/));
assertEquals(["foooo"], "foooo".match(/^foooo(?<=fo+)$/));
assertEquals(["foooo"], "foooo".match(/^foooo(?<=fo*)$/));
checkExec(["abc", "abc"], /(abc\1)/, "abc");
checkExec(["abc", "abc"], /(abc\1)/, "abc\u1234");
checkExec(["abc", "abc"], /(abc\1)/i, "abc");
checkExec(["abc", "abc"], /(abc\1)/i, "abc\u1234");
var oob_subject = "abcdefghijklmnabcdefghijklmn".substr(14);
checkNull(oob_subject, /(?=(abcdefghijklmn))(?<=\1)a/i);
checkNull(oob_subject, /(?=(abcdefghijklmn))(?<=\1)a/);
checkNull("abcdefgabcdefg".substr(1), /(?=(abcdefg))(?<=\1)/);
// Mutual recursive capture/back references
checkExec(["cacb", "a", ""], /(?<=a(.\2)b(\1)).{4}/, "aabcacbc");
checkExec(["b", "ac", "ac"], /(?<=a(\2)b(..\1))b/, "aacbacb");
checkExec(["x", "aa"], /(?<=(?:\1b)(aa))./, "aabaax");
checkExec(["x", "aa"], /(?<=(?:\1|b)(aa))./, "aaaax");
// Restricted syntax in Annex B 1.4.
assertThrows("/(?<=.)*/u", SyntaxError);
assertThrows("/(?<=.){1,2}/u", SyntaxError);
assertThrows("/(?<=.)*/", SyntaxError);
assertThrows("/(?<=.)?/", SyntaxError);
assertThrows("/(?<=.)+/", SyntaxError);