diff options
Diffstat (limited to 'js/src/tests/test262/built-ins/RegExp/named-groups')
38 files changed, 1396 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/browser.js b/js/src/tests/test262/built-ins/RegExp/named-groups/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/browser.js diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-exec.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-exec.js new file mode 100644 index 0000000000..9624cc6545 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-exec.js @@ -0,0 +1,38 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Matching behavior with duplicate named capture groups +esid: prod-GroupSpecifier +features: [regexp-duplicate-named-groups] +includes: [compareArray.js] +---*/ + +assert.compareArray(/(?<x>a)|(?<x>b)/.exec("bab"), ["b", undefined, "b"]); +assert.compareArray(/(?<x>b)|(?<x>a)/.exec("bab"), ["b", "b", undefined]); + +assert.compareArray(/(?:(?<x>a)|(?<x>b))\k<x>/.exec("aa"), ["aa", "a", undefined]); +assert.compareArray(/(?:(?<x>a)|(?<x>b))\k<x>/.exec("bb"), ["bb", undefined, "b"]); + +let matchResult = /(?:(?:(?<x>a)|(?<x>b))\k<x>){2}/.exec("aabb"); +assert.compareArray(matchResult, ["aabb", undefined, "b"]); +assert.sameValue(matchResult.groups.x, "b"); + +assert.sameValue(/(?:(?:(?<x>a)|(?<x>b))\k<x>){2}/.exec("abab"), null); + +assert.sameValue(/(?:(?<x>a)|(?<x>b))\k<x>/.exec("abab"), null); + +assert.sameValue(/(?:(?<x>a)|(?<x>b))\k<x>/.exec("cdef"), null); + +assert.compareArray(/^(?:(?<a>x)|(?<a>y)|z)\k<a>$/.exec("xx"), ["xx", "x", undefined]); +assert.compareArray(/^(?:(?<a>x)|(?<a>y)|z)\k<a>$/.exec("z"), ["z", undefined, undefined]); +assert.sameValue(/^(?:(?<a>x)|(?<a>y)|z)\k<a>$/.exec("zz"), null); +assert.compareArray(/(?<a>x)|(?:zy\k<a>)/.exec("zy"), ["zy", undefined]); + +assert.compareArray(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/.exec("xz"), ["xz", undefined, undefined]); +assert.compareArray(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/.exec("yz"), ["yz", undefined, undefined]); +assert.sameValue(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/.exec("xzx"), null); +assert.sameValue(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/.exec("yzy"), null); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-group-property-enumeration-order.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-group-property-enumeration-order.js new file mode 100644 index 0000000000..33a21cbd2e --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-group-property-enumeration-order.js @@ -0,0 +1,27 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Kevin Gibbons. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Enumeration order of the groups object with duplicate named capture groups +esid: prod-GroupSpecifier +features: [regexp-duplicate-named-groups] +includes: [compareArray.js] +---*/ + + +let regexp = /(?<y>a)(?<x>a)|(?<x>b)(?<y>b)/; + +assert.compareArray( + Object.keys(regexp.exec("aa").groups), + ["y", "x"], + "property enumeration order of the groups object is based on source order, not match order" +); + +assert.compareArray( + Object.keys(regexp.exec("bb").groups), + ["y", "x"], + "property enumeration order of the groups object is based on source order, not match order" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-match-indices.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-match-indices.js new file mode 100644 index 0000000000..3135fd75a1 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-match-indices.js @@ -0,0 +1,18 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Kevin Gibbons. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: match indices with duplicate named capture groups +esid: sec-makematchindicesindexpairarray +features: [regexp-duplicate-named-groups, regexp-match-indices] +includes: [compareArray.js] +---*/ + +let indices = "..ab".match(/(?<x>a)|(?<x>b)/d).indices; +assert.compareArray(indices.groups.x, [2, 3]); + +indices = "..ba".match(/(?<x>a)|(?<x>b)/d).indices; +assert.compareArray(indices.groups.x, [2, 3]); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-match.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-match.js new file mode 100644 index 0000000000..dee2d62455 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-match.js @@ -0,0 +1,38 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Kevin Gibbons. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Matching behavior with duplicate named capture groups +esid: prod-GroupSpecifier +features: [regexp-duplicate-named-groups] +includes: [compareArray.js] +---*/ + +assert.compareArray("bab".match(/(?<x>a)|(?<x>b)/), ["b", undefined, "b"]); +assert.compareArray("bab".match(/(?<x>b)|(?<x>a)/), ["b", "b", undefined]); + +assert.compareArray("aa".match(/(?:(?<x>a)|(?<x>b))\k<x>/), ["aa", "a", undefined]); +assert.compareArray("bb".match(/(?:(?<x>a)|(?<x>b))\k<x>/), ["bb", undefined, "b"]); + +let matchResult = "aabb".match(/(?:(?:(?<x>a)|(?<x>b))\k<x>){2}/); +assert.compareArray(matchResult, ["aabb", undefined, "b"]); +assert.sameValue(matchResult.groups.x, "b"); + +assert.sameValue("abab".match(/(?:(?:(?<x>a)|(?<x>b))\k<x>){2}/), null); + +assert.sameValue("abab".match(/(?:(?<x>a)|(?<x>b))\k<x>/), null); + +assert.sameValue("cdef".match(/(?:(?<x>a)|(?<x>b))\k<x>/), null); + +assert.compareArray("xx".match(/^(?:(?<a>x)|(?<a>y)|z)\k<a>$/), ["xx", "x", undefined]); +assert.compareArray("z".match(/^(?:(?<a>x)|(?<a>y)|z)\k<a>$/), ["z", undefined, undefined]); +assert.sameValue("zz".match(/^(?:(?<a>x)|(?<a>y)|z)\k<a>$/), null); +assert.compareArray("zy".match(/(?<a>x)|(?:zy\k<a>)/), ["zy", undefined]); + +assert.compareArray("xz".match(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/), ["xz", undefined, undefined]); +assert.compareArray("yz".match(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/), ["yz", undefined, undefined]); +assert.sameValue("xzx".match(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/), null); +assert.sameValue("yzy".match(/^(?:(?<a>x)|(?<a>y)|z){2}\k<a>$/), null); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-matchall.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-matchall.js new file mode 100644 index 0000000000..fea434f83d --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-matchall.js @@ -0,0 +1,31 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: String.prototype.search behavior with duplicate named capture groups +esid: prod-GroupSpecifier +includes: [compareArray.js,compareIterator.js] +features: [regexp-duplicate-named-groups] +---*/ + +function matchesIterator(iterator, expected) { + assert.compareIterator(iterator, expected.map(e => { + return v => assert.compareArray(v, e); + })); +} + +matchesIterator("bab".matchAll(/(?<x>a)|(?<x>b)/g), + [ + ["b", undefined, "b"], + ["a", "a", undefined], + ["b", undefined, "b"], + ]); +matchesIterator("bab".matchAll(/(?<x>b)|(?<x>a)/g), + [ + ["b", "b", undefined], + ["a", undefined, "a"], + ["b", "b", undefined], + ]); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-replace.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-replace.js new file mode 100644 index 0000000000..76893704af --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-replace.js @@ -0,0 +1,20 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Kevin Gibbons. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: String.prototype.replace behavior with duplicate named capture groups +esid: prod-GroupSpecifier +features: [regexp-duplicate-named-groups] +---*/ + +assert.sameValue("ab".replace(/(?<x>a)|(?<x>b)/, "[$<x>]"), "[a]b"); +assert.sameValue("ba".replace(/(?<x>a)|(?<x>b)/, "[$<x>]"), "[b]a"); + +assert.sameValue("ab".replace(/(?<x>a)|(?<x>b)/, "[$<x>][$1][$2]"), "[a][a][]b"); +assert.sameValue("ba".replace(/(?<x>a)|(?<x>b)/, "[$<x>][$1][$2]"), "[b][][b]a"); + +assert.sameValue("ab".replace(/(?<x>a)|(?<x>b)/g, "[$<x>]"), "[a][b]"); +assert.sameValue("ba".replace(/(?<x>a)|(?<x>b)/g, "[$<x>]"), "[b][a]"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-replaceall.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-replaceall.js new file mode 100644 index 0000000000..1cd45805a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-replaceall.js @@ -0,0 +1,18 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: String.prototype.replaceAll behavior with duplicate named capture groups +esid: prod-GroupSpecifier +features: [regexp-duplicate-named-groups] +---*/ + +assert.sameValue("abxab".replaceAll(/(?<x>a)|(?<x>b)/g, "[$<x>]"), "[a][b]x[a][b]"); +assert.sameValue("baxba".replaceAll(/(?<x>a)|(?<x>b)/g, "[$<x>]"), "[b][a]x[b][a]"); + +assert.sameValue("abxab".replaceAll(/(?<x>a)|(?<x>b)/g, "[$<x>][$1][$2]"), "[a][a][][b][][b]x[a][a][][b][][b]"); +assert.sameValue("baxba".replaceAll(/(?<x>a)|(?<x>b)/g, "[$<x>][$1][$2]"), "[b][][b][a][a][]x[b][][b][a][a][]"); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-search.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-search.js new file mode 100644 index 0000000000..db6f8b7534 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-search.js @@ -0,0 +1,14 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: String.prototype.search behavior with duplicate named capture groups +esid: prod-GroupSpecifier +features: [regexp-duplicate-named-groups] +---*/ + +assert.sameValue("xab".search(/(?<x>a)|(?<x>b)/), 1); +assert.sameValue("xba".search(/(?<x>a)|(?<x>b)/), 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-split.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-split.js new file mode 100644 index 0000000000..ccd9c77993 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-split.js @@ -0,0 +1,15 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: String.prototype.search behavior with duplicate named capture groups +esid: prod-GroupSpecifier +includes: [compareArray.js] +features: [regexp-duplicate-named-groups] +---*/ + +assert.compareArray("xab".split(/(?<x>a)|(?<x>b)/), ["x", "a", undefined, "", undefined, "b", ""]); +assert.compareArray("xba".split(/(?<x>a)|(?<x>b)/), ["x", undefined, "b", "", "a", undefined, ""]); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-test.js b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-test.js new file mode 100644 index 0000000000..77a8dd4391 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/duplicate-names-test.js @@ -0,0 +1,23 @@ +// |reftest| skip -- regexp-duplicate-named-groups is not supported +// Copyright 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Matching behavior with duplicate named capture groups +esid: prod-GroupSpecifier +features: [regexp-duplicate-named-groups] +---*/ + +assert(/(?<x>a)|(?<x>b)/.test("bab")); +assert(/(?<x>b)|(?<x>a)/.test("bab")); + +assert(/(?:(?<x>a)|(?<x>b))\k<x>/.test("aa")); +assert(/(?:(?<x>a)|(?<x>b))\k<x>/.test("bb")); + +let matchResult = /(?:(?:(?<x>a)|(?<x>b))\k<x>){2}/.test("aabb"); +assert(matchResult); + +let notMatched = /(?:(?:(?<x>a)|(?<x>b))\k<x>){2}/.test("abab"); +assert.sameValue(notMatched, false); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/functional-replace-global.js b/js/src/tests/test262/built-ins/RegExp/named-groups/functional-replace-global.js new file mode 100644 index 0000000000..3285bf9cf0 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/functional-replace-global.js @@ -0,0 +1,58 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Function argument to String.prototype.replace gets groups as the last argument +esid: sec-regexp.prototype-@@replace +features: [regexp-named-groups] +info: | + RegExp.prototype [ @@replace ] ( string, replaceValue ) + 14. Repeat, for each result in results, + j. Let namedCaptures be ? Get(result, "groups"). + k. If functionalReplace is true, then + iv. If namedCaptures is not undefined, + 1. Append namedCaptures as the last element of replacerArgs. +---*/ + +let source = "(?<fst>.)(?<snd>.)"; +let alternateSource = "(?<fst>.)|(?<snd>.)"; + +for (let flags of ["g", "gu"]) { + let i = 0; + let re = new RegExp(source, flags); + let result = "abcd".replace(re, + (match, fst, snd, offset, str, groups) => { + if (i == 0) { + assert.sameValue("ab", match); + assert.sameValue("a", groups.fst); + assert.sameValue("b", groups.snd); + assert.sameValue("a", fst); + assert.sameValue("b", snd); + assert.sameValue(0, offset); + assert.sameValue("abcd", str); + } else if (i == 1) { + assert.sameValue("cd", match); + assert.sameValue("c", groups.fst); + assert.sameValue("d", groups.snd); + assert.sameValue("c", fst); + assert.sameValue("d", snd); + assert.sameValue(2, offset); + assert.sameValue("abcd", str); + } else { + assertUnreachable(); + } + i++; + return `${groups.snd}${groups.fst}`; + }); + assert.sameValue("badc", result); + assert.sameValue(i, 2); + + let re2 = new RegExp(alternateSource, flags); + assert.sameValue("undefinedundefinedundefinedundefined", + "abcd".replace(re2, + (match, fst, snd, offset, str, groups) => groups.snd)); +} + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/functional-replace-non-global.js b/js/src/tests/test262/built-ins/RegExp/named-groups/functional-replace-non-global.js new file mode 100644 index 0000000000..c2631d892d --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/functional-replace-non-global.js @@ -0,0 +1,45 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Function argument to String.prototype.replace gets groups as the last argument +esid: sec-regexp.prototype-@@replace +features: [regexp-named-groups] +info: | + RegExp.prototype [ @@replace ] ( string, replaceValue ) + 14. Repeat, for each result in results, + j. Let namedCaptures be ? Get(result, "groups"). + k. If functionalReplace is true, then + iv. If namedCaptures is not undefined, + 1. Append namedCaptures as the last element of replacerArgs. +---*/ + +let source = "(?<fst>.)(?<snd>.)"; +let alternateSource = "(?<fst>.)|(?<snd>.)"; + +for (let flags of ["", "u"]) { + let i = 0; + let re = new RegExp(source, flags); + let result = "abcd".replace(re, + (match, fst, snd, offset, str, groups) => { + assert.sameValue(i++, 0); + assert.sameValue("ab", match); + assert.sameValue("a", groups.fst); + assert.sameValue("b", groups.snd); + assert.sameValue("a", fst); + assert.sameValue("b", snd); + assert.sameValue(0, offset); + assert.sameValue("abcd", str); + return `${groups.snd}${groups.fst}`; + }); + assert.sameValue("bacd", result); + assert.sameValue(i, 1); + + let re2 = new RegExp(alternateSource, flags); + assert.sameValue("undefinedbcd", + "abcd".replace(re2, + (match, fst, snd, offset, str, groups) => groups.snd)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-subclass-sans.js b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-subclass-sans.js new file mode 100644 index 0000000000..a6674a6fb1 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-subclass-sans.js @@ -0,0 +1,38 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Test the groups object on RegExp subclass results that do not have their own. +esid: sec-regexpbuiltinexec +features: [regexp-named-groups] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + 24. If _R_ contains any |GroupName|, then + a. Let _groups_ be ObjectCreate(*null*). + 25. Else, + a. Let _groups_ be *undefined*. + 26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_). +---*/ + +class FakeRegExp extends RegExp { + exec(subject) { + const fakeResult = ["ab", "a"]; + fakeResult.index = 0; + // `groups` is not set, triggering prototype lookup. + return fakeResult; + } +}; + +const re = new FakeRegExp(); +const result = re.exec("ab"); +assert.sameValue(Object.getPrototypeOf(result), Array.prototype); +assert.sameValue(false, result.hasOwnProperty("groups")); + +Array.prototype.groups = { a: "b" }; +Object.getPrototypeOf(Array.prototype.groups).b = "c"; +assert.sameValue("b", "ab".replace(re, "$<a>")); +assert.sameValue("c", "ab".replace(re, "$<b>")); +Array.prototype.groups = undefined; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-subclass.js b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-subclass.js new file mode 100644 index 0000000000..a833d1f10f --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-subclass.js @@ -0,0 +1,36 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Test the groups object on RegExp subclass results that have their own. +esid: sec-regexpbuiltinexec +features: [regexp-named-groups] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + 24. If _R_ contains any |GroupName|, then + a. Let _groups_ be ObjectCreate(*null*). + 25. Else, + a. Let _groups_ be *undefined*. + 26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_). +---*/ + +class FakeRegExp extends RegExp { + exec(subject) { + const fakeResult = ["ab", "a"]; + fakeResult.index = 0; + fakeResult.groups = { a: "b" }; + Object.getPrototypeOf(fakeResult.groups).b = "c"; + return fakeResult; + } +}; + +const re = new FakeRegExp(); +const result = re.exec("ab"); +assert.sameValue(Object.getPrototypeOf(result), Array.prototype); +assert(result.hasOwnProperty("groups")); +assert.sameValue("b", result.groups.a); +assert.sameValue("b", "ab".replace(re, "$<a>")); +assert.sameValue("c", "ab".replace(re, "$<b>")); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-undefined.js b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-undefined.js new file mode 100644 index 0000000000..06f5e49454 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-undefined.js @@ -0,0 +1,35 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The groups object is created unconditionally. +includes: [propertyHelper.js] +esid: sec-regexpbuiltinexec +features: [regexp-named-groups] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + 24. If _R_ contains any |GroupName|, then + a. Let _groups_ be ObjectCreate(*null*). + 25. Else, + a. Let _groups_ be *undefined*. + 26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_). +---*/ + +const re = /./; +const result = re.exec("a"); +assert.sameValue(Object.getPrototypeOf(result), Array.prototype); +assert(result.hasOwnProperty("groups")); +assert.sameValue("a", result[0]); +assert.sameValue(0, result.index); +assert.sameValue(undefined, result.groups); +verifyProperty(result, "groups", { + writable: true, + enumerable: true, + configurable: true, +}); + +Array.prototype.groups = { a: "b" }; +assert.sameValue("$<a>", "a".replace(re, "$<a>")); +Array.prototype.groups = undefined; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-unmatched.js b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-unmatched.js new file mode 100644 index 0000000000..d43732eb06 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object-unmatched.js @@ -0,0 +1,37 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Test the groups object with matched and unmatched named captures. +esid: sec-regexpbuiltinexec +features: [regexp-named-groups] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + 24. If _R_ contains any |GroupName|, then + a. Let _groups_ be ObjectCreate(*null*). + 25. Else, + a. Let _groups_ be *undefined*. + 26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_). +---*/ + +const re = /(?<a>a).|(?<x>x)/; +const result = re.exec("ab"); +assert.sameValue(Object.getPrototypeOf(result), Array.prototype); +assert(result.hasOwnProperty("groups")); +assert.sameValue("ab", result[0]); +assert.sameValue("a", result[1]); +assert.sameValue(undefined, result[2]); +assert.sameValue(0, result.index); +assert.sameValue("a", result.groups.a); +assert.sameValue(undefined, result.groups.x); + +// `a` is a matched named capture, `b` is an unmatched named capture, and `z` +// is not a named capture. +Array.prototype.groups = { a: "b", x: "y", z: "z" }; +assert.sameValue("a", "ab".replace(re, "$<a>")); +assert.sameValue("", "ab".replace(re, "$<x>")); +assert.sameValue("", "ab".replace(re, "$<z>")); +Array.prototype.groups = undefined; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object.js b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object.js new file mode 100644 index 0000000000..bec4ae8d59 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-object.js @@ -0,0 +1,41 @@ +// Copyright 2017 Aleksey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Properties of the groups object are created with CreateDataProperty +includes: [propertyHelper.js] +esid: sec-regexpbuiltinexec +features: [regexp-named-groups] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + 24. If _R_ contains any |GroupName|, then + a. Let _groups_ be ObjectCreate(*null*). + 25. Else, + a. Let _groups_ be *undefined*. + 26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_). +---*/ + +// `groups` is created with Define, not Set. +let counter = 0; +Object.defineProperty(Array.prototype, "groups", { + set() { counter++; } +}); + +let match = /(?<x>.)/.exec("a"); +assert.sameValue(counter, 0); + +// `groups` is writable, enumerable and configurable +// (from CreateDataProperty). +verifyProperty(match, "groups", { + writable: true, + enumerable: true, + configurable: true, +}); + +// The `__proto__` property on the groups object is not special, +// and does not affect the [[Prototype]] of the resulting groups object. +let {groups} = /(?<__proto__>.)/.exec("a"); +assert.sameValue("a", groups.__proto__); +assert.sameValue(null, Object.getPrototypeOf(groups)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/groups-properties.js b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-properties.js new file mode 100644 index 0000000000..ce971cf0b5 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/groups-properties.js @@ -0,0 +1,34 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Properties of the groups object are created with CreateDataProperty +includes: [compareArray.js, propertyHelper.js] +esid: sec-regexpbuiltinexec +features: [regexp-named-groups] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + 25. For each integer i such that i > 0 and i β€ n + f. If the ith capture of R was defined with a GroupName, + i. Let s be the StringValue of the corresponding RegExpIdentifierName. + ii. Perform ! CreateDataProperty(groups, s, capturedValue). +---*/ + +// Properties created on result.groups in textual order. +assert.compareArray(["fst", "snd"], Object.getOwnPropertyNames( + /(?<fst>.)|(?<snd>.)/u.exec("abcd").groups)); + +// Properties are created with Define, not Set +let counter = 0; +Object.defineProperty(Object.prototype, 'x', {set() { counter++; }}); +let match = /(?<x>.)/.exec('a'); +let groups = match.groups; +assert.sameValue(counter, 0); + +// Properties are writable, enumerable and configurable +// (from CreateDataProperty) +verifyWritable(groups, "x"); +verifyEnumerable(groups, "x"); +verifyConfigurable(groups, "x"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/lookbehind.js b/js/src/tests/test262/built-ins/RegExp/named-groups/lookbehind.js new file mode 100644 index 0000000000..470ff342cd --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/lookbehind.js @@ -0,0 +1,47 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Named groups can be used in conjunction with lookbehind +esid: prod-GroupSpecifier +features: [regexp-named-groups, regexp-lookbehind] +includes: [compareArray.js] +---*/ + +// Unicode mode +assert.compareArray(["f", "c"], "abcdef".match(/(?<=(?<a>\w){3})f/u)); +assert.sameValue("c", "abcdef".match(/(?<=(?<a>\w){3})f/u).groups.a); +assert.sameValue("b", "abcdef".match(/(?<=(?<a>\w){4})f/u).groups.a); +assert.sameValue("a", "abcdef".match(/(?<=(?<a>\w)+)f/u).groups.a); +assert.sameValue(null, "abcdef".match(/(?<=(?<a>\w){6})f/u)); + +assert.compareArray(["f", ""], "abcdef".match(/((?<=\w{3}))f/u)); +assert.compareArray(["f", ""], "abcdef".match(/(?<a>(?<=\w{3}))f/u)); + +assert.compareArray(["f", undefined], "abcdef".match(/(?<!(?<a>\d){3})f/u)); +assert.sameValue(null, "abcdef".match(/(?<!(?<a>\D){3})f/u)); + +assert.compareArray(["f", undefined], "abcdef".match(/(?<!(?<a>\D){3})f|f/u)); +assert.compareArray(["f", undefined], "abcdef".match(/(?<a>(?<!\D{3}))f|f/u)); + +// Non-Unicode mode +assert.compareArray(["f", "c"], "abcdef".match(/(?<=(?<a>\w){3})f/)); +assert.sameValue("c", "abcdef".match(/(?<=(?<a>\w){3})f/).groups.a); +assert.sameValue("b", "abcdef".match(/(?<=(?<a>\w){4})f/).groups.a); +assert.sameValue("a", "abcdef".match(/(?<=(?<a>\w)+)f/).groups.a); +assert.sameValue(null, "abcdef".match(/(?<=(?<a>\w){6})f/)); + +assert.compareArray(["f", ""], "abcdef".match(/((?<=\w{3}))f/)); +assert.compareArray(["f", ""], "abcdef".match(/(?<a>(?<=\w{3}))f/)); + +assert.compareArray(["f", undefined], "abcdef".match(/(?<!(?<a>\d){3})f/)); +assert.sameValue(null, "abcdef".match(/(?<!(?<a>\D){3})f/)); + +assert.compareArray(["f", undefined], "abcdef".match(/(?<!(?<a>\D){3})f|f/)); +assert.compareArray(["f", undefined], "abcdef".match(/(?<a>(?<!\D{3}))f|f/)); + +// Even within a lookbehind, properties are created in left to right order +assert.compareArray(["fst", "snd"], Object.getOwnPropertyNames( + /(?<=(?<fst>.)|(?<snd>.))/u.exec("abcd").groups)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-match.js b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-match.js new file mode 100644 index 0000000000..bc68c12bf8 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-match.js @@ -0,0 +1,44 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Basic matching cases with non-Unicode groups +esid: prod-GroupSpecifier +features: [regexp-named-groups] +includes: [compareArray.js] +---*/ + +assert.compareArray(["a", "a"], "bab".match(/(?<a>a)/)); +assert.compareArray(["a", "a"], "bab".match(/(?<a42>a)/)); +assert.compareArray(["a", "a"], "bab".match(/(?<_>a)/)); +assert.compareArray(["a", "a"], "bab".match(/(?<$>a)/)); +assert.compareArray(["bab", "a"], "bab".match(/.(?<$>a)./)); +assert.compareArray(["bab", "a", "b"], "bab".match(/.(?<a>a)(.)/)); +assert.compareArray(["bab", "a", "b"], "bab".match(/.(?<a>a)(?<b>.)/)); +assert.compareArray(["bab", "ab"], "bab".match(/.(?<a>\w\w)/)); +assert.compareArray(["bab", "bab"], "bab".match(/(?<a>\w\w\w)/)); +assert.compareArray(["bab", "ba", "b"], "bab".match(/(?<a>\w\w)(?<b>\w)/)); + +let {a, b, c} = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/.exec("abccba").groups; +assert.sameValue(a, "a"); +assert.sameValue(b, "b"); +assert.sameValue(c, "c"); + +assert.compareArray("bab".match(/(a)/), "bab".match(/(?<a>a)/)); +assert.compareArray("bab".match(/(a)/), "bab".match(/(?<a42>a)/)); +assert.compareArray("bab".match(/(a)/), "bab".match(/(?<_>a)/)); +assert.compareArray("bab".match(/(a)/), "bab".match(/(?<$>a)/)); +assert.compareArray("bab".match(/.(a)./), "bab".match(/.(?<$>a)./)); +assert.compareArray("bab".match(/.(a)(.)/), "bab".match(/.(?<a>a)(.)/)); +assert.compareArray("bab".match(/.(a)(.)/), "bab".match(/.(?<a>a)(?<b>.)/)); +assert.compareArray("bab".match(/.(\w\w)/), "bab".match(/.(?<a>\w\w)/)); +assert.compareArray("bab".match(/(\w\w\w)/), "bab".match(/(?<a>\w\w\w)/)); +assert.compareArray("bab".match(/(\w\w)(\w)/), "bab".match(/(?<a>\w\w)(?<b>\w)/)); + +assert.compareArray(["bab", "b"], "bab".match(/(?<b>b).\1/)); +assert.compareArray(["baba", "b", "a"], "baba".match(/(.)(?<a>a)\1\2/)); +assert.compareArray(["baba", "b", "a", "b", "a"], "baba".match(/(.)(?<a>a)(?<b>\1)(\2)/)); +assert.compareArray(["<a", "<"], "<a".match(/(?<lt><)a/)); +assert.compareArray([">a", ">"], ">a".match(/(?<gt>>)a/)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names-invalid.js b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names-invalid.js new file mode 100644 index 0000000000..b2523652af --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names-invalid.js @@ -0,0 +1,57 @@ +// Copyright (C) 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +author: Michael Saboff +description: Invalid exotic named group names in non-Unicode RegExps +esid: prod-GroupSpecifier +features: [regexp-named-groups] +---*/ + +/* + Valid ID_Continue Unicode characters (Can't be first identifier character.) + + π \u{1d7da} \ud835 \udfda + + Invalid ID_Start / ID_Continue + + (fox face emoji) π¦ \u{1f98a} \ud83e \udd8a + (dog emoji) π \u{1f415} \ud83d \udc15 +*/ + +assert.throws(SyntaxError, function() { + return new RegExp("(?<π¦>fox)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\u{1f98a}>fox)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\ud83e\udd8a>fox)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<π>dog)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\u{1f415}>dog)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\ud83d \udc15>dog)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<πthe>the)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\u{1d7da}the>the)"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\ud835\udfdathe>the)"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js new file mode 100644 index 0000000000..eb568a1ee0 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js @@ -0,0 +1,96 @@ +// Copyright (C) 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +author: Michael Saboff +description: Exotic named group names in non-Unicode RegExps +esid: prod-GroupSpecifier +features: [regexp-named-groups] +---*/ + +/* + Valid ID_Start / ID_Continue Unicode characters + + π \u{1d453} \ud835 \udc53 + π \u{1d45c} \ud835 \udc5c + π₯ \u{id465} \ud835 \udc65 + + π \u{1d4d3} \ud835 \udcd3 + πΈ \u{1d4f8} \ud835 \udcf8 + π° \u{1d4f0} \ud835 \udcf0 + + π \u{1d4d1} \ud835 \udcd1 + π» \u{1d4fb} \ud835 \udcfb + πΈ \u{1d4f8} \ud835 \udcf8 + π \u{1d500} \ud835 \udd00 + π· \u{1d4f7} \ud835 \udcf7 + + π° \u{1d5b0} \ud835 \uddb0 + π‘ \u{1d5a1} \ud835 \udda1 + π₯ \u{1d5a5} \ud835 \udda5 + + (fox) ηΈ \u{72f8} \u72f8 + (dog) η \u{72d7} \u72d7 + + Valid ID_Continue Unicode characters (Can't be first identifier character.) + + π \u{1d7da} \ud835 \udfda +*/ + +var string = "The quick brown fox jumped over the lazy dog's back"; +var string2 = "It is a dog eat dog world."; + +let match = null; + +assert.sameValue(string.match(/(?<animal>fox|dog)/).groups.animal, "fox"); + +match = string.match(/(?<πππ₯>fox).*(?<ππΈπ°>dog)/); +assert.sameValue(match.groups.πππ₯, "fox"); +assert.sameValue(match.groups.ππΈπ°, "dog"); +assert.sameValue(match[1], "fox"); +assert.sameValue(match[2], "dog"); + +match = string.match(/(?<ηΈ>fox).*(?<η>dog)/); +assert.sameValue(match.groups.ηΈ, "fox"); +assert.sameValue(match.groups.η, "dog"); +assert.sameValue(match[1], "fox"); +assert.sameValue(match[2], "dog"); + +assert.sameValue(string.match(/(?<ππ»πΈππ·>brown)/).groups.ππ»πΈππ·, "brown"); +assert.sameValue(string.match(/(?<ππ»πΈππ·>brown)/).groups.\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}, "brown"); +assert.sameValue(string.match(/(?<\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}>brown)/).groups.ππ»πΈππ·, "brown"); +assert.sameValue(string.match(/(?<\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}>brown)/).groups.\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}, "brown"); +assert.sameValue(string.match(/(?<\ud835\udcd1\ud835\udcfb\ud835\udcf8\ud835\udd00\ud835\udcf7>brown)/).groups.ππ»πΈππ·, "brown"); +assert.sameValue(string.match(/(?<\ud835\udcd1\ud835\udcfb\ud835\udcf8\ud835\udd00\ud835\udcf7>brown)/).groups.\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}, "brown"); + +assert.sameValue(string.match(/(?<π°π‘π₯>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<π°π‘\u{1d5a5}>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<π°\u{1d5a1}π₯>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<π°\u{1d5a1}\u{1d5a5}>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}π‘π₯>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}π‘\u{1d5a5}>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}\u{1d5a1}π₯>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}\u{1d5a1}\u{1d5a5}>q\w*\W\w*\W\w*)/).groups.π°π‘π₯, "quick brown fox"); + +assert.sameValue(string.match(/(?<theπ>the)/).groups.theπ, "the"); +assert.sameValue(string.match(/(?<the\u{1d7da}>the)/).groups.theπ, "the"); +assert.sameValue(string.match(/(?<the\ud835\udfda>the)/).groups.theπ, "the"); + +match = string2.match(/(?<dog>dog)(.*?)(\k<dog>)/); +assert.sameValue(match.groups.dog, "dog"); +assert.sameValue(match[1], "dog"); +assert.sameValue(match[2], " eat "); +assert.sameValue(match[3], "dog"); + +match = string2.match(/(?<ππΈπ°>dog)(.*?)(\k<ππΈπ°>)/); +assert.sameValue(match.groups.ππΈπ°, "dog"); +assert.sameValue(match[1], "dog"); +assert.sameValue(match[2], " eat "); +assert.sameValue(match[3], "dog"); + +match = string2.match(/(?<η>dog)(.*?)(\k<η>)/); +assert.sameValue(match.groups.η, "dog"); +assert.sameValue(match[1], "dog"); +assert.sameValue(match[2], " eat "); +assert.sameValue(match[3], "dog"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names.js b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names.js new file mode 100644 index 0000000000..e9b3cabb4d --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-property-names.js @@ -0,0 +1,25 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Exotic named group names in non-Unicode RegExps +esid: prod-GroupSpecifier +features: [regexp-named-groups] +---*/ + +assert.sameValue("a", /(?<Ο>a)/.exec("bab").groups.Ο); +assert.sameValue("a", /(?<Ο>a)/.exec("bab").groups.\u03C0); +assert.sameValue("a", /(?<$>a)/.exec("bab").groups.$); +assert.sameValue("a", /(?<_>a)/.exec("bab").groups._); +assert.sameValue("a", /(?<_\u200C>a)/.exec("bab").groups._\u200C); +assert.sameValue("a", /(?<_\u200D>a)/.exec("bab").groups._\u200D); +assert.sameValue("a", /(?<ΰ² _ΰ² >a)/.exec("bab").groups.ΰ² _ΰ² ); + +// Unicode escapes in capture names. +assert(/(?<\u0041>.)/.test("a")); +assert(RegExp("(?<\u{0041}>.)").test("a"), "Non-surrogate"); + +// 4-char escapes must be the proper ID_Start/ID_Continue +assert(RegExp("(?<\\u0041>.)").test("a"), "Non-surrogate"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-references.js b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-references.js new file mode 100644 index 0000000000..3f8f8c4ab3 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/non-unicode-references.js @@ -0,0 +1,36 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Named backreferences in non-Unicode RegExps +esid: prod-GroupSpecifier +features: [regexp-named-groups] +includes: [compareArray.js] +---*/ + +// Named references. +assert.compareArray(["bab", "b"], "bab".match(/(?<b>.).\k<b>/)); +assert.sameValue(null, "baa".match(/(?<b>.).\k<b>/)); + +// Reference inside group. +assert.compareArray(["bab", "b"], "bab".match(/(?<a>\k<a>\w)../)); +assert.sameValue("b", "bab".match(/(?<a>\k<a>\w)../).groups.a); + +// Reference before group. +assert.compareArray(["bab", "b"], "bab".match(/\k<a>(?<a>b)\w\k<a>/)); +assert.sameValue("b", "bab".match(/\k<a>(?<a>b)\w\k<a>/).groups.a); +assert.compareArray(["bab", "b", "a"], "bab".match(/(?<b>b)\k<a>(?<a>a)\k<b>/)); +let {a, b} = "bab".match(/(?<b>b)\k<a>(?<a>a)\k<b>/).groups; +assert.sameValue(a, "a"); +assert.sameValue(b, "b"); + +assert.compareArray(["bab", "b"], "bab".match(/\k<a>(?<a>b)\w\k<a>/)); +assert.compareArray(["bab", "b", "a"], "bab".match(/(?<b>b)\k<a>(?<a>a)\k<b>/)); + +// Reference properties. +assert.sameValue("a", /(?<a>a)(?<b>b)\k<a>/.exec("aba").groups.a); +assert.sameValue("b", /(?<a>a)(?<b>b)\k<a>/.exec("aba").groups.b); +assert.sameValue(undefined, /(?<a>a)(?<b>b)\k<a>/.exec("aba").groups.c); +assert.sameValue(undefined, /(?<a>a)(?<b>b)\k<a>|(?<c>c)/.exec("aba").groups.c); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/shell.js b/js/src/tests/test262/built-ins/RegExp/named-groups/shell.js new file mode 100644 index 0000000000..c752bae293 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/shell.js @@ -0,0 +1,37 @@ +// GENERATED, DO NOT EDIT +// file: compareIterator.js +// Copyright (C) 2018 Peter Wong. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: Compare the values of an iterator with an array of expected values +defines: [assert.compareIterator] +---*/ + +// Example: +// +// function* numbers() { +// yield 1; +// yield 2; +// yield 3; +// } +// +// assert.compareIterator(numbers(), [ +// v => assert.sameValue(v, 1), +// v => assert.sameValue(v, 2), +// v => assert.sameValue(v, 3), +// ]); +// +assert.compareIterator = function(iter, validators, message) { + message = message || ''; + + var i, result; + for (i = 0; i < validators.length; i++) { + result = iter.next(); + assert(!result.done, 'Expected ' + i + ' values(s). Instead iterator only produced ' + (i - 1) + ' value(s). ' + message); + validators[i](result.value); + } + + result = iter.next(); + assert(result.done, 'Expected only ' + i + ' values(s). Instead iterator produced more. ' + message); + assert.sameValue(result.value, undefined, 'Expected value of `undefined` when iterator completes. ' + message); +} diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-escaped.js b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-escaped.js new file mode 100644 index 0000000000..8a4f4b96d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-escaped.js @@ -0,0 +1,26 @@ +// Copyright 2017 Aleksey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Do not replace $<> preceded with $ +esid: sec-getsubstitution +features: [regexp-named-groups] +info: | + Runtime Semantics: GetSubstitution( matched, str, position, captures, namedCaptures, replacement ) + + 12. These $ replacements are done left-to-right, and, once such a replacement is performed, + the new replacement text is not subject to further replacements. + + Table: Replacement Text Symbol Substitutions + + Unicode Characters: $$ + Replacement text: $ +---*/ + +let source = "(?<fst>.)"; +for (let flags of ["", "u"]) { + let re = new RegExp(source, flags); + assert.sameValue("$<fst>bc", "abc".replace(re, "$$<fst>")); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-get.js b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-get.js new file mode 100644 index 0000000000..a765c9d30a --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-get.js @@ -0,0 +1,31 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Named substitutions are found by getting the property from the groups object +esid: sec-getsubstitution +features: [regexp-named-groups] +info: | + Runtime Semantics: GetSubstitution( matched, str, position, captures, namedCaptures, replacement ) + + Table: Replacement Text Symbol Substitutions + + Unicode Characters: $< + Replacement text: + 2. Otherwise, + c. Let capture be ? Get(namedCaptures, groupName). + d. If capture is undefined, replace the text through > with the empty string. + e. Otherwise, replace the text through this following > with ? ToString(capture). +---*/ + +let source = "(?<fst>.)(?<snd>.)|(?<thd>x)"; +for (let flags of ["g", "gu"]) { + let re = new RegExp(source, flags); + assert.sameValue("badc", "abcd".replace(re, "$<snd>$<fst>")); +} +for (let flags of ["", "u"]) { + let re = new RegExp(source, flags); + assert.sameValue("bacd", "abcd".replace(re, "$<snd>$<fst>")); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-missing.js b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-missing.js new file mode 100644 index 0000000000..defb9e358c --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-missing.js @@ -0,0 +1,26 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: If the group doesn't exist, replace with the empty string +esid: sec-getsubstitution +features: [regexp-named-groups] +---*/ + +let source = "(?<fst>.)(?<snd>.)|(?<thd>x)"; +for (let flags of ["", "u"]) { + let re = new RegExp(source, flags); + assert.sameValue("cd", "abcd".replace(re, "$<42$1>")); + assert.sameValue("cd", "abcd".replace(re, "$<fth>")); + assert.sameValue("cd", "abcd".replace(re, "$<$1>")); + assert.sameValue("cd", "abcd".replace(re, "$<>")); +} +for (let flags of ["g", "gu"]) { + let re = new RegExp(source, flags); + assert.sameValue("", "abcd".replace(re, "$<42$1>")); + assert.sameValue("", "abcd".replace(re, "$<fth>")); + assert.sameValue("", "abcd".replace(re, "$<$1>")); + assert.sameValue("", "abcd".replace(re, "$<>")); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-nocaptures.js b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-nocaptures.js new file mode 100644 index 0000000000..bfd98fa38d --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-nocaptures.js @@ -0,0 +1,34 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: If there are no named captures, don't replace $<> +esid: sec-getsubstitution +features: [regexp-named-groups] +info: | + Runtime Semantics: GetSubstitution( matched, str, position, captures, namedCaptures, replacement ) + + Table: Replacement Text Symbol Substitutions + + Unicode Characters: $< + Replacement text: + 1. If namedCaptures is undefined, the replacement text is the literal string $<. +---*/ + +// @@replace with a string replacement argument (no named captures). + +let source = "(.)(.)|(x)"; +for (let flags of ["", "u"]) { + let re = new RegExp(source, flags); + assert.sameValue("$<snd>$<fst>cd", "abcd".replace(re, "$<snd>$<fst>")); + assert.sameValue("bacd", "abcd".replace(re, "$2$1")); + assert.sameValue("cd", "abcd".replace(re, "$3")); + assert.sameValue("$<sndcd", "abcd".replace(re, "$<snd")); + assert.sameValue("$<sndacd", "abcd".replace(re, "$<snd$1")); + assert.sameValue("$<42a>cd", "abcd".replace(re, "$<42$1>")); + assert.sameValue("$<fth>cd", "abcd".replace(re, "$<fth>")); + assert.sameValue("$<a>cd", "abcd".replace(re, "$<$1>")); +} + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-numbered.js b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-numbered.js new file mode 100644 index 0000000000..a9943dc7d2 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-numbered.js @@ -0,0 +1,31 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Named groups may be accessed in their replacement string by number +esid: sec-getsubstitution +features: [regexp-named-groups] +info: | + Runtime Semantics: GetSubstitution( matched, str, position, captures, namedCaptures, replacement ) + + Table: Replacement Text Symbol Substitutions + + Unicode Characters: $n + Replacement text: + The nth element of captures, where n is a single digit in the range 1 to 9. If + nβ€m and the nth element of captures is undefined, use the empty String instead. + If n>m, the result is implementation-defined. +---*/ + +let source = "(?<fst>.)(?<snd>.)|(?<thd>x)"; +for (let flags of ["g", "gu"]) { + let re = new RegExp(source, flags); + assert.sameValue("badc", "abcd".replace(re, "$2$1")); +} +for (let flags of ["", "u"]) { + let re = new RegExp(source, flags); + assert.sameValue("bacd", "abcd".replace(re, "$2$1")); +} + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-unclosed.js b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-unclosed.js new file mode 100644 index 0000000000..1c1e927dcc --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-unclosed.js @@ -0,0 +1,22 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + A missing > following $< means that the $< is taken literally + in a replacement string in the context of named capture substitution. +esid: sec-getsubstitution +features: [regexp-named-groups] +---*/ + +let source = "(?<fst>.)(?<snd>.)|(?<thd>x)"; +for (let flags of ["", "u"]) { + let re = new RegExp(source, flags); + assert.sameValue("$<sndcd", "abcd".replace(re, "$<snd")); +} +for (let flags of ["g", "gu"]) { + let re = new RegExp(source, flags); + assert.sameValue("$<snd$<snd", "abcd".replace(re, "$<snd")); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-undefined.js b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-undefined.js new file mode 100644 index 0000000000..5c4d0e06f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/string-replace-undefined.js @@ -0,0 +1,30 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: If a named group was not reached, it is replaced by the empty string +esid: sec-getsubstitution +features: [regexp-named-groups] +info: | + Runtime Semantics: GetSubstitution( matched, str, position, captures, namedCaptures, replacement ) + + Table: Replacement Text Symbol Substitutions + + Unicode Characters: $< + Replacement text: + 2. Otherwise, + c. Let capture be ? Get(namedCaptures, groupName). + d. If capture is undefined, replace the text through > with the empty string. +---*/ + +let source = "(?<fst>.)(?<snd>.)|(?<thd>x)"; +for (let flags of ["g", "gu"]) { + let re = new RegExp(source, flags); + assert.sameValue("", "abcd".replace(re, "$<thd>")); +} +for (let flags of ["", "u"]) { + let re = new RegExp(source, flags); + assert.sameValue("cd", "abcd".replace(re, "$<thd>")); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-match.js b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-match.js new file mode 100644 index 0000000000..0e87178091 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-match.js @@ -0,0 +1,48 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Basic matching cases with Unicode groups +esid: prod-GroupSpecifier +features: [regexp-named-groups] +includes: [compareArray.js] +---*/ + +assert.compareArray(["a", "a"], "bab".match(/(?<a>a)/u)); +assert.compareArray(["a", "a"], "bab".match(/(?<a42>a)/u)); +assert.compareArray(["a", "a"], "bab".match(/(?<_>a)/u)); +assert.compareArray(["a", "a"], "bab".match(/(?<$>a)/u)); +assert.compareArray(["bab", "a"], "bab".match(/.(?<$>a)./u)); +assert.compareArray(["bab", "a", "b"], "bab".match(/.(?<a>a)(.)/u)); +assert.compareArray(["bab", "a", "b"], "bab".match(/.(?<a>a)(?<b>.)/u)); +assert.compareArray(["bab", "ab"], "bab".match(/.(?<a>\w\w)/u)); +assert.compareArray(["bab", "bab"], "bab".match(/(?<a>\w\w\w)/u)); +assert.compareArray(["bab", "ba", "b"], "bab".match(/(?<a>\w\w)(?<b>\w)/u)); + +let {a, b, c} = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/u.exec("abccba").groups; +assert.sameValue(a, "a"); +assert.sameValue(b, "b"); +assert.sameValue(c, "c"); + +assert.compareArray("bab".match(/(a)/u), "bab".match(/(?<a>a)/u)); +assert.compareArray("bab".match(/(a)/u), "bab".match(/(?<a42>a)/u)); +assert.compareArray("bab".match(/(a)/u), "bab".match(/(?<_>a)/u)); +assert.compareArray("bab".match(/(a)/u), "bab".match(/(?<$>a)/u)); +assert.compareArray("bab".match(/.(a)./u), "bab".match(/.(?<$>a)./u)); +assert.compareArray("bab".match(/.(a)(.)/u), "bab".match(/.(?<a>a)(.)/u)); +assert.compareArray("bab".match(/.(a)(.)/u), "bab".match(/.(?<a>a)(?<b>.)/u)); +assert.compareArray("bab".match(/.(\w\w)/u), "bab".match(/.(?<a>\w\w)/u)); +assert.compareArray("bab".match(/(\w\w\w)/u), "bab".match(/(?<a>\w\w\w)/u)); +assert.compareArray("bab".match(/(\w\w)(\w)/u), "bab".match(/(?<a>\w\w)(?<b>\w)/u)); + +assert.compareArray(["bab", "b"], "bab".match(/(?<b>b).\1/u)); +assert.compareArray(["baba", "b", "a"], "baba".match(/(.)(?<a>a)\1\2/u)); +assert.compareArray(["baba", "b", "a", "b", "a"], "baba".match(/(.)(?<a>a)(?<b>\1)(\2)/u)); +assert.compareArray(["<a", "<"], "<a".match(/(?<lt><)a/u)); +assert.compareArray([">a", ">"], ">a".match(/(?<gt>>)a/u)); + +// Nested groups. +assert.compareArray(["bab", "bab", "ab", "b"], "bab".match(/(?<a>.(?<b>.(?<c>.)))/u)); +assert.compareArray({a: "bab", b: "ab", c: "b"}, "bab".match(/(?<a>.(?<b>.(?<c>.)))/u).groups); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names-invalid.js b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names-invalid.js new file mode 100644 index 0000000000..9b0ef33496 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names-invalid.js @@ -0,0 +1,57 @@ +// Copyright (C) 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +author: Michael Saboff +description: Invalid exotic named group names in Unicode RegExps +esid: prod-GroupSpecifier +features: [regexp-named-groups] +---*/ + +/* + Valid ID_Continue Unicode characters (Can't be first identifier character.) + + π \u{1d7da} \ud835 \udfda + + Invalid ID_Start / ID_Continue + + (fox face emoji) π¦ \u{1f98a} \ud83e \udd8a + (dog emoji) π \u{1f415} \ud83d \udc15 +*/ + +assert.throws(SyntaxError, function() { + return new RegExp("(?<π¦>fox)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\u{1f98a}>fox)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\ud83e\udd8a>fox)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<π>dog)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\u{1f415}>dog)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\ud83d \udc15>dog)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<πthe>the)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\u{1d7da}the>the)", "u"); +}); + +assert.throws(SyntaxError, function() { + return new RegExp("(?<\ud835\udfdathe>the)", "u"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names-valid.js b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names-valid.js new file mode 100644 index 0000000000..d26f3c626b --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names-valid.js @@ -0,0 +1,102 @@ +// Copyright (C) 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +author: Michael Saboff +description: Exotic named group names in Unicode RegExps +esid: prod-GroupSpecifier +features: [regexp-named-groups] +---*/ + +/* + Valid ID_Start / ID_Continue Unicode characters + + π \u{1d453} \ud835 \udc53 + π \u{1d45c} \ud835 \udc5c + π₯ \u{id465} \ud835 \udc65 + + π \u{1d4d3} \ud835 \udcd3 + πΈ \u{1d4f8} \ud835 \udcf8 + π° \u{1d4f0} \ud835 \udcf0 + + π \u{1d4d1} \ud835 \udcd1 + π» \u{1d4fb} \ud835 \udcfb + πΈ \u{1d4f8} \ud835 \udcf8 + π \u{1d500} \ud835 \udd00 + π· \u{1d4f7} \ud835 \udcf7 + + π° \u{1d5b0} \ud835 \uddb0 + π‘ \u{1d5a1} \ud835 \udda1 + π₯ \u{1d5a5} \ud835 \udda5 + + (fox) ηΈ \u{72f8} \u72f8 + (dog) η \u{72d7} \u72d7 + + Valid ID_Continue Unicode characters (Can't be first identifier character.) + + π \u{1d7da} \ud835 \udfda + + Invalid ID_Start / ID_Continue + + (fox face emoji) π¦ \u{1f98a} \ud83e \udd8a + (dog emoji) π \u{1f415} \ud83d \udc15 +*/ + +var string = "The quick brown fox jumped over the lazy dog's back"; +var string2 = "It is a dog eat dog world."; + +let match = null; + +assert.sameValue(string.match(/(?<animal>fox|dog)/u).groups.animal, "fox"); +assert.sameValue(string.match(/(?<the2>the)/u).groups.the2, "the"); + +match = string.match(/(?<πππ₯>fox).*(?<ππΈπ°>dog)/u); +assert.sameValue(match.groups.πππ₯, "fox"); +assert.sameValue(match.groups.ππΈπ°, "dog"); +assert.sameValue(match[1], "fox"); +assert.sameValue(match[2], "dog"); + +match = string.match(/(?<ηΈ>fox).*(?<η>dog)/u); +assert.sameValue(match.groups.ηΈ, "fox"); +assert.sameValue(match.groups.η, "dog"); +assert.sameValue(match[1], "fox"); +assert.sameValue(match[2], "dog"); + +assert.sameValue(string.match(/(?<ππ»πΈππ·>brown)/u).groups.ππ»πΈππ·, "brown"); +assert.sameValue(string.match(/(?<ππ»πΈππ·>brown)/u).groups.\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}, "brown"); +assert.sameValue(string.match(/(?<\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}>brown)/u).groups.ππ»πΈππ·, "brown"); +assert.sameValue(string.match(/(?<\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}>brown)/u).groups.\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}, "brown"); +assert.sameValue(string.match(/(?<\ud835\udcd1\ud835\udcfb\ud835\udcf8\ud835\udd00\ud835\udcf7>brown)/u).groups.ππ»πΈππ·, "brown"); +assert.sameValue(string.match(/(?<\ud835\udcd1\ud835\udcfb\ud835\udcf8\ud835\udd00\ud835\udcf7>brown)/u).groups.\u{1d4d1}\u{1d4fb}\u{1d4f8}\u{1d500}\u{1d4f7}, "brown"); + +assert.sameValue(string.match(/(?<π°π‘π₯>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<π°π‘\u{1d5a5}>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<π°\u{1d5a1}π₯>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<π°\u{1d5a1}\u{1d5a5}>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}π‘π₯>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}π‘\u{1d5a5}>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}\u{1d5a1}π₯>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); +assert.sameValue(string.match(/(?<\u{1d5b0}\u{1d5a1}\u{1d5a5}>q\w*\W\w*\W\w*)/u).groups.π°π‘π₯, "quick brown fox"); + +assert.sameValue(string.match(/(?<theπ>the)/u).groups.theπ, "the"); +assert.sameValue(string.match(/(?<the\u{1d7da}>the)/u).groups.theπ, "the"); +assert.sameValue(string.match(/(?<the\ud835\udfda>the)/u).groups.theπ, "the"); + +match = string2.match(/(?<dog>dog)(.*?)(\k<dog>)/u); +assert.sameValue(match.groups.dog, "dog"); +assert.sameValue(match[1], "dog"); +assert.sameValue(match[2], " eat "); +assert.sameValue(match[3], "dog"); + +match = string2.match(/(?<ππΈπ°>dog)(.*?)(\k<ππΈπ°>)/u); +assert.sameValue(match.groups.ππΈπ°, "dog"); +assert.sameValue(match[1], "dog"); +assert.sameValue(match[2], " eat "); +assert.sameValue(match[3], "dog"); + +match = string2.match(/(?<η>dog)(.*?)(\k<η>)/u); +assert.sameValue(match.groups.η, "dog"); +assert.sameValue(match[1], "dog"); +assert.sameValue(match[2], " eat "); +assert.sameValue(match[3], "dog"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names.js b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names.js new file mode 100644 index 0000000000..bb321dd6ff --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-property-names.js @@ -0,0 +1,32 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Exotic named group names in Unicode RegExps +esid: prod-GroupSpecifier +features: [regexp-named-groups] +---*/ + +assert.sameValue("a", /(?<Ο>a)/u.exec("bab").groups.Ο); +assert.sameValue("a", /(?<\u{03C0}>a)/u.exec("bab").groups.Ο); +assert.sameValue("a", /(?<Ο>a)/u.exec("bab").groups.\u03C0); +assert.sameValue("a", /(?<\u{03C0}>a)/u.exec("bab").groups.\u03C0); +assert.sameValue("a", /(?<$>a)/u.exec("bab").groups.$); +assert.sameValue("a", /(?<_>a)/u.exec("bab").groups._); +assert.sameValue("a", /(?<$π€>a)/u.exec("bab").groups.$π€); +assert.sameValue("a", /(?<_\u200C>a)/u.exec("bab").groups._\u200C); +assert.sameValue("a", /(?<_\u200D>a)/u.exec("bab").groups._\u200D); +assert.sameValue("a", /(?<ΰ² _ΰ² >a)/u.exec("bab").groups.ΰ² _ΰ² ); + +// Unicode escapes in capture names. +assert(/(?<a\uD801\uDCA4>.)/u.test("a"), "\\u Lead \\u Trail"); +assert(/(?<\u0041>.)/u.test("a"), "\\u NonSurrogate"); +assert(/(?<\u{0041}>.)/u.test("a"), "\\u{ Non-surrogate }"); +assert(/(?<a\u{104A4}>.)/u.test("a"), "\\u{ Surrogate, ID_Continue }"); +assert(RegExp("(?<\u{0041}>.)", "u").test("a"), "Non-surrogate"); +assert(RegExp("(?<a\u{104A4}>.)", "u").test("a"), "Surrogate,ID_Continue"); +assert((/(?<\u{0041}>.)/u).test("a"), "Non-surrogate"); +assert(/(?<a\u{104A4}>.)/u.test("a"), "Surrogate, ID_Continue"); +assert(RegExp("(?<\\u0041>.)", "u").test("a"), "Non-surrogate"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-references.js b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-references.js new file mode 100644 index 0000000000..30d70ad112 --- /dev/null +++ b/js/src/tests/test262/built-ins/RegExp/named-groups/unicode-references.js @@ -0,0 +1,49 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Named backreferences in Unicode RegExps +esid: sec-atomescape +info: | + The production AtomEscape :: [+N] k GroupName evaluates as follows: + + 1. Search the enclosing RegExp for an instance of a GroupSpecifier for an + RegExpIdentifierName which has a StringValue equal to the StringValue + of the RegExpIdentifierName contained in GroupName. + 2. Assert: A unique such GroupSpecifier is found. + 3. Let parenIndex be the number of left capturing parentheses in the entire + regular expression that occur to the left of the located GroupSpecifier. + This is the total number of times the Atom::(GroupSpecifierDisjunction) + production is expanded prior to that production's Term plus the total + number of Atom :: (GroupSpecifierDisjunction) productions enclosing this Term. + 4. Call BackreferenceMatcher(parenIndex) and return its Matcher result. +features: [regexp-named-groups] +includes: [compareArray.js] +---*/ + +// Named references. +assert.compareArray(["bab", "b"], "bab".match(/(?<b>.).\k<b>/u)); +assert.sameValue(null, "baa".match(/(?<b>.).\k<b>/u)); + +// Reference inside group. +assert.compareArray(["bab", "b"], "bab".match(/(?<a>\k<a>\w)../u)); +assert.sameValue("b", "bab".match(/(?<a>\k<a>\w)../u).groups.a); + +// Reference before group. +assert.compareArray(["bab", "b"], "bab".match(/\k<a>(?<a>b)\w\k<a>/u)); +assert.sameValue("b", "bab".match(/\k<a>(?<a>b)\w\k<a>/u).groups.a); +assert.compareArray(["bab", "b", "a"], "bab".match(/(?<b>b)\k<a>(?<a>a)\k<b>/u)); +let {a, b} = "bab".match(/(?<b>b)\k<a>(?<a>a)\k<b>/u).groups; +assert.sameValue(a, "a"); +assert.sameValue(b, "b"); + +assert.compareArray(["bab", "b"], "bab".match(/\k<a>(?<a>b)\w\k<a>/)); +assert.compareArray(["bab", "b", "a"], "bab".match(/(?<b>b)\k<a>(?<a>a)\k<b>/)); + +// Reference properties. +assert.sameValue("a", /(?<a>a)(?<b>b)\k<a>/u.exec("aba").groups.a); +assert.sameValue("b", /(?<a>a)(?<b>b)\k<a>/u.exec("aba").groups.b); +assert.sameValue(undefined, /(?<a>a)(?<b>b)\k<a>/u.exec("aba").groups.c); +assert.sameValue(undefined, /(?<a>a)(?<b>b)\k<a>|(?<c>c)/u.exec("aba").groups.c); + +reportCompare(0, 0); |