summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/built-ins/RegExp/match-indices
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/test262/built-ins/RegExp/match-indices')
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-element.js30
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-matched.js41
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-non-unicode-match.js78
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-properties.js32
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-match.js87
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-property-names.js23
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unmatched.js35
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-array.js21
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-undefined.js29
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-unmatched.js23
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object.js42
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-properties.js38
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/indices-property.js32
-rw-r--r--js/src/tests/test262/built-ins/RegExp/match-indices/shell.js329
15 files changed, 840 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/browser.js b/js/src/tests/test262/built-ins/RegExp/match-indices/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/browser.js
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-element.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-element.js
new file mode 100644
index 0000000000..5b87efcc70
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-element.js
@@ -0,0 +1,30 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: A matching element of indices is an Array with exactly two number properties.
+esid: sec-getmatchindicesarray
+features: [regexp-match-indices]
+info: |
+ GetMatchIndicesArray ( S, match )
+ 5. Return CreateArrayFromList(ยซ _match_.[[StartIndex]], _match_.[[EndIndex]] ยป).
+---*/
+
+let input = "abcd";
+let match = /b(c)/.exec(input);
+let indices = match.indices;
+
+// `indices[0]` is an array
+assert.sameValue(Object.getPrototypeOf(indices[0]), Array.prototype);
+assert.sameValue(indices[0].length, 2);
+assert.sameValue(typeof indices[0][0], "number");
+assert.sameValue(typeof indices[0][1], "number");
+
+// `indices[1]` is an array
+assert.sameValue(Object.getPrototypeOf(indices[1]), Array.prototype);
+assert.sameValue(indices[1].length, 2);
+assert.sameValue(typeof indices[1][0], "number");
+assert.sameValue(typeof indices[1][1], "number");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-matched.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-matched.js
new file mode 100644
index 0000000000..cef6ead42d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-matched.js
@@ -0,0 +1,41 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The properties of the "indices" array correspond to the start/end indices of the same values in the match.
+includes: [compareArray.js]
+esid: sec-makeindicesarray
+features: [regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 4. Let _n_ be the number of elements in _indices_.
+ ...
+ 6. Set _A_ to ! ArrayCreate(_n_).
+ ...
+ 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
+ a. Let _matchIndices_ be _indices_[_i_].
+ b. If _matchIndices_ is not *undefined*, then
+ i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_).
+ c. Else,
+ i. Let _matchIndicesArray_ be *undefined*.
+ d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_).
+ ...
+---*/
+
+let input = "abcd";
+let match = /b(c)/.exec(input);
+let indices = match.indices;
+
+// `indices` has the same length as match
+assert.sameValue(indices.length, match.length);
+
+// The first element of `indices` contains the start/end indices of the match
+assert.compareArray(indices[0], [1, 3]);
+assert.sameValue(input.slice(indices[0][0], indices[0][1]), match[0]);
+
+// The second element of `indices` contains the start/end indices of the first capture
+assert.compareArray(indices[1], [2, 3]);
+assert.sameValue(input.slice(indices[1][0], indices[1][1]), match[1]);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-non-unicode-match.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-non-unicode-match.js
new file mode 100644
index 0000000000..4884ecee78
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-non-unicode-match.js
@@ -0,0 +1,78 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Basic matching cases with non-unicode matches.
+includes: [compareArray.js, propertyHelper.js, deepEqual.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-match-indices]
+info: |
+ Runtime Semantics: RegExpBuiltinExec ( R, S )
+ ...
+ 4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")).
+ ...
+ 25. Let _indices_ be a new empty List.
+ 26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }.
+ 27. Add _match_ as the last element of _indices_.
+ ...
+ 33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do
+ ...
+ f. Else,
+ i. Let _captureStart_ be _captureI_'s _startIndex_.
+ ii. Let _captureEnd_ be _captureI_'s _endIndex_.
+ ...
+ iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }.
+ v. Append _capture_ to _indices_.
+ ...
+ 34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_).
+---*/
+
+assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/).indices);
+assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./).indices);
+assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/).indices);
+assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/).indices);
+assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/).indices);
+assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/).indices);
+assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/).indices);
+
+let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/.exec("abccba").indices.groups;
+assert.compareArray([0, 1], groups.a);
+assert.compareArray([1, 2], groups.b);
+assert.compareArray([2, 3], groups.c);
+verifyProperty(groups, "a", {
+ enumerable: true,
+ writable: true,
+ configurable: true
+});
+verifyProperty(groups, "b", {
+ enumerable: true,
+ writable: true,
+ configurable: true
+});
+verifyProperty(groups, "c", {
+ enumerable: true,
+ writable: true,
+ configurable: true
+});
+
+// "๐" is U+1d401 MATHEMATICAL BOLD CAPITAL B
+// - Also representable as the code point "\u{1d401}"
+// - Also representable as the surrogate pair "\uD835\uDC01"
+
+// Verify assumptions:
+assert.sameValue("๐".length, 2, 'The length of "๐" is 2');
+assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2');
+assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2');
+assert.sameValue("๐".match(/./)[0].length, 1, 'The length of a single code unit match against "๐" is 1 (without /u flag)');
+assert.sameValue("\u{1d401}".match(/./)[0].length, 1, 'The length of a single code unit match against "\\u{1d401}" is 1 (without /u flag)');
+assert.sameValue("\uD835\uDC01".match(/./)[0].length, 1, 'The length of a single code unit match against "\\ud835\\udc01" is 1 (without /u flag)');
+
+assert.compareArray([0, 1], "๐".match(/./).indices[0], 'Indices for non-unicode match against "๐" (without /u flag)');
+assert.compareArray([0, 1], "\u{1d401}".match(/./).indices[0], 'Indices for non-unicode match against "\\u{1d401}" (without /u flag)');
+assert.compareArray([0, 1], "\uD835\uDC01".match(/./).indices[0], 'Indices for non-unicode match against "\\ud835\\udc01" (without /u flag)');
+assert.compareArray([0, 1], "๐".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "๐" in groups.a (without /u flag)');
+assert.compareArray([0, 1], "\u{1d401}".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "\\u{1d401}" in groups.a (without /u flag)');
+assert.compareArray([0, 1], "\uD835\uDC01".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "\\ud835\\udc01" in groups.a (without /u flag)');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-properties.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-properties.js
new file mode 100644
index 0000000000..e1cc453c34
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-properties.js
@@ -0,0 +1,32 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The properties of the "indices" array are created with CreateDataProperty.
+includes: [propertyHelper.js]
+esid: sec-makeindicesarray
+features: [regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
+ d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_).
+---*/
+
+let input = "abcd";
+let match = /b(c)/.exec(input);
+let indices = match.indices;
+
+verifyProperty(indices, '0', {
+ enumerable: true,
+ configurable: true,
+ writable: true
+});
+
+verifyProperty(indices, '1', {
+ enumerable: true,
+ configurable: true,
+ writable: true
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-match.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-match.js
new file mode 100644
index 0000000000..c8460bc580
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-match.js
@@ -0,0 +1,87 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Basic matching cases with non-unicode matches.
+includes: [compareArray.js, propertyHelper.js, deepEqual.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-match-indices]
+info: |
+ Runtime Semantics: RegExpBuiltinExec ( R, S )
+ ...
+ 4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")).
+ ...
+ 16. If _fullUnicode_ is *true*, set _e_ to ! GetStringIndex(_S_, _Input_, _e_).
+ ...
+ 25. Let _indices_ be a new empty List.
+ 26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }.
+ 27. Add _match_ as the last element of _indices_.
+ ...
+ 33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do
+ ...
+ f. Else,
+ i. Let _captureStart_ be _captureI_'s _startIndex_.
+ ii. Let _captureEnd_ be _captureI_'s _endIndex_.
+ iii. If _fullUnicode_ is *true*, then
+ 1. Set _captureStart_ to ! GetStringIndex(_S_, _Input_, _captureStart_).
+ 1. Set _captureEnd_ to ! GetStringIndex(_S_, _Input_, _captureEnd_).
+ iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }.
+ v. Append _capture_ to _indices_.
+ ...
+ 34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_).
+
+ GetStringIndex ( S, Input, e )
+ ...
+ 4. Let _eUTF_ be the smallest index into _S_ that corresponds to the character at element _e_ of _Input_. If _e_ is greater than or equal to the number of elements in _Input_, then _eUTF_ is the number of code units in _S_.
+ 5. Return _eUTF_.
+---*/
+
+assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/u).indices);
+assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./u).indices);
+assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/u).indices);
+assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/u).indices);
+assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/u).indices);
+assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/u).indices);
+assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/u).indices);
+
+let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/u.exec("abccba").indices.groups;
+assert.compareArray([0, 1], groups.a);
+assert.compareArray([1, 2], groups.b);
+assert.compareArray([2, 3], groups.c);
+verifyProperty(groups, "a", {
+ enumerable: true,
+ writable: true,
+ configurable: true
+});
+verifyProperty(groups, "b", {
+ enumerable: true,
+ writable: true,
+ configurable: true
+});
+verifyProperty(groups, "c", {
+ enumerable: true,
+ writable: true,
+ configurable: true
+});
+
+// "๐" is U+1d401 MATHEMATICAL BOLD CAPITAL B
+// - Also representable as the code point "\u{1d401}"
+// - Also representable as the surrogate pair "\uD835\uDC01"
+
+// Verify assumptions:
+assert.sameValue("๐".length, 2, 'The length of "๐" is 2');
+assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2');
+assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2');
+assert.sameValue(2, "๐".match(/./u)[0].length, 'The length of a single code point match against "๐" is 2 (with /u flag)');
+assert.sameValue(2, "\u{1d401}".match(/./u)[0].length, 'The length of a single code point match against "\\u{1d401}" is 2 (with /u flag)');
+assert.sameValue(2, "\uD835\uDC01".match(/./u)[0].length, 'The length of a single code point match against "\\ud835\\udc01" is 2 (with /u flag)');
+
+assert.compareArray([0, 2], "๐".match(/./u).indices[0], 'Indices for unicode match against "๐" (with /u flag)');
+assert.compareArray([0, 2], "\u{1d401}".match(/./u).indices[0], 'Indices for unicode match against \\u{1d401} (with /u flag)');
+assert.compareArray([0, 2], "\uD835\uDC01".match(/./u).indices[0], 'Indices for unicode match against \\ud835\\udc01 (with /u flag)');
+assert.compareArray([0, 2], "๐".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against ๐ in groups.a (with /u flag)');
+assert.compareArray([0, 2], "\u{1d401}".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against \\u{1d401} in groups.a (with /u flag)');
+assert.compareArray([0, 2], "\uD835\uDC01".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against \\ud835\\udc01 in groups.a (with /u flag)');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-property-names.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-property-names.js
new file mode 100644
index 0000000000..8bdfb693e2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unicode-property-names.js
@@ -0,0 +1,23 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Basic matching cases with non-unicode matches.
+includes: [compareArray.js]
+esid: sec-makeindicesarray
+features: [regexp-match-indices]
+---*/
+
+assert.compareArray([1, 2], /(?<ฯ€>a)/u.exec("bab").indices.groups.ฯ€);
+assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.ฯ€);
+assert.compareArray([1, 2], /(?<ฯ€>a)/u.exec("bab").indices.groups.\u03C0);
+assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.\u03C0);
+assert.compareArray([1, 2], /(?<$>a)/u.exec("bab").indices.groups.$);
+assert.compareArray([1, 2], /(?<_>a)/u.exec("bab").indices.groups._);
+assert.compareArray([1, 2], /(?<$๐’ค>a)/u.exec("bab").indices.groups.$๐’ค);
+assert.compareArray([1, 2], /(?<_\u200C>a)/u.exec("bab").indices.groups._\u200C);
+assert.compareArray([1, 2], /(?<_\u200D>a)/u.exec("bab").indices.groups._\u200D);
+assert.compareArray([1, 2], /(?<เฒ _เฒ >a)/u.exec("bab").indices.groups.เฒ _เฒ );
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unmatched.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unmatched.js
new file mode 100644
index 0000000000..236c167f5b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array-unmatched.js
@@ -0,0 +1,35 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: An unmatched capture in a match corresponds to an unmatched capture in "indices"
+esid: sec-makeindicesarray
+features: [regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 4. Let _n_ be the number of elements in _indices_.
+ ...
+ 6. Set _A_ to ! ArrayCreate(_n_).
+ ...
+ 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
+ a. Let _matchIndices_ be _indices_[_i_].
+ b. If _matchIndices_ is not *undefined*, then
+ i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_).
+ c. Else,
+ i. Let _matchIndicesArray_ be *undefined*.
+ d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_).
+ ...
+---*/
+
+let input = "abd";
+let match = /b(c)?/.exec(input);
+let indices = match.indices;
+
+// `indices` has the same length as match
+assert.sameValue(indices.length, match.length);
+
+// The second element of `indices` should be undefined.
+assert.sameValue(indices[1], undefined);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array.js
new file mode 100644
index 0000000000..3c7794e77e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-array.js
@@ -0,0 +1,21 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The "indices" property is an Array.
+esid: sec-makeindicesarray
+features: [regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 6. Set _A_ to ! ArrayCreate(_n_).
+---*/
+
+let match = /a/.exec("a");
+let indices = match.indices;
+
+// `indices` is an array
+assert.sameValue(Object.getPrototypeOf(indices), Array.prototype);
+assert(Array.isArray(indices));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-undefined.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-undefined.js
new file mode 100644
index 0000000000..8db544ef3b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-undefined.js
@@ -0,0 +1,29 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The groups object of indices is created unconditionally.
+includes: [propertyHelper.js]
+esid: sec-makeindicesarray
+features: [regexp-named-groups, regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 8. If _groupNames_ is not *undefined*, then
+ a. Let _groups_ be ! ObjectCreate(*null*).
+ 9. Else,
+ a. Let _groups_ be *undefined*.
+ 10. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_).
+---*/
+
+
+const re = /./;
+const indices = re.exec("a").indices;
+verifyProperty(indices, 'groups', {
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ value: undefined
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-unmatched.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-unmatched.js
new file mode 100644
index 0000000000..ee7c18e893
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object-unmatched.js
@@ -0,0 +1,23 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Test the groups object of indices with matched and unmatched named captures.
+includes: [compareArray.js]
+esid: sec-makeindicesarray
+features: [regexp-named-groups, regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
+ e. If _groupNames_ is not *undfined* and _groupNames_[_i_] is not *undefined*, then
+ i. Perform ! CreateDataProperty(_groups_, _groupNames_[_i_], _matchIndicesArray_).
+---*/
+
+
+const re = /(?<a>a).|(?<x>x)/;
+const result = re.exec("ab").indices;
+assert.compareArray([0, 1], result.groups.a);
+assert.sameValue(undefined, result.groups.x);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object.js
new file mode 100644
index 0000000000..32eb320def
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-object.js
@@ -0,0 +1,42 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The groups object of indices is created with CreateDataProperty
+includes: [propertyHelper.js, compareArray.js]
+esid: sec-makeindicesarray
+features: [regexp-named-groups, regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 8. If _groupNames_ is not *undefined*, then
+ a. Let _groups_ be ! ObjectCreate(*null*).
+ 9. Else,
+ a. Let _groups_ be *undefined*.
+ 10. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_).
+---*/
+
+// `groups` is created with Define, not Set.
+let counter = 0;
+Object.defineProperty(Array.prototype, "groups", {
+ set() { counter++; }
+});
+
+let indices = /(?<x>.)/.exec("a").indices;
+assert.sameValue(counter, 0);
+
+// `groups` is writable, enumerable and configurable
+// (from CreateDataProperty).
+verifyProperty(indices, '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").indices;
+assert.compareArray([0, 1], groups.__proto__);
+assert.sameValue(null, Object.getPrototypeOf(groups));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-properties.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-properties.js
new file mode 100644
index 0000000000..723a726602
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-groups-properties.js
@@ -0,0 +1,38 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Properties of the groups object of indices are created with CreateDataProperty
+includes: [compareArray.js, propertyHelper.js]
+esid: sec-makeindicesarray
+features: [regexp-named-groups, regexp-match-indices]
+info: |
+ MakeIndicesArray ( S, indices, groupNames )
+ 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
+ e. If _groupNames_ is not *undfined* and _groupNames_[_i_] is not *undefined*, then
+ i. Perform ! CreateDataProperty(_groups_, _groupNames_[_i_], _matchIndicesArray_).
+---*/
+
+
+// Properties created on result.groups in textual order.
+let groupNames = Object.getOwnPropertyNames(/(?<fst>.)|(?<snd>.)/u.exec("abcd").indices.groups);
+assert.compareArray(groupNames, ["fst", "snd"]);
+
+// // Properties are created with Define, not Set
+// let counter = 0;
+// Object.defineProperty(Object.prototype, 'x', {set() { counter++; }});
+
+let indices = /(?<x>.)/.exec('a').indices;
+let groups = indices.groups;
+// assert.sameValue(counter, 0);
+
+// Properties are writable, enumerable and configurable
+// (from CreateDataProperty)
+verifyProperty(groups, 'x', {
+ writable: true,
+ enumerable: true,
+ configurable: true
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/indices-property.js b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-property.js
new file mode 100644
index 0000000000..3c9f4b444b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/indices-property.js
@@ -0,0 +1,32 @@
+// |reftest| skip -- regexp-match-indices is not supported
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The "indices" property is created with DefinePropertyOrThrow
+includes: [propertyHelper.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-match-indices]
+info: |
+ Runtime Semantics: RegExpBuiltinExec ( R, S )
+ 34. Let _indicesArray_ be MakeIndicesArray(_S_, _indices_, _groupNames_).
+ 35. Perform ! DefinePropertyOrThrow(_A_, `"indices"`, PropertyDescriptor { [[Value]]: _indicesArray_, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }).
+---*/
+
+// `indices` is created with Define, not Set.
+let counter = 0;
+Object.defineProperty(Array.prototype, "indices", {
+ set() { counter++; }
+});
+
+let match = /a/.exec("a");
+assert.sameValue(counter, 0);
+
+// `indices` is a non-writable, non-enumerable, and configurable data-property.
+verifyProperty(match, 'indices', {
+ writable: true,
+ enumerable: true,
+ configurable: true
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/RegExp/match-indices/shell.js b/js/src/tests/test262/built-ins/RegExp/match-indices/shell.js
new file mode 100644
index 0000000000..276ee734ff
--- /dev/null
+++ b/js/src/tests/test262/built-ins/RegExp/match-indices/shell.js
@@ -0,0 +1,329 @@
+// GENERATED, DO NOT EDIT
+// file: deepEqual.js
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: >
+ Compare two values structurally
+defines: [assert.deepEqual]
+---*/
+
+assert.deepEqual = function(actual, expected, message) {
+ var format = assert.deepEqual.format;
+ assert(
+ assert.deepEqual._compare(actual, expected),
+ `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}`
+ );
+};
+
+assert.deepEqual.format = function(value, seen) {
+ switch (typeof value) {
+ case 'string':
+ return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`;
+ case 'number':
+ case 'boolean':
+ case 'symbol':
+ case 'bigint':
+ return value.toString();
+ case 'undefined':
+ return 'undefined';
+ case 'function':
+ return `[Function${value.name ? `: ${value.name}` : ''}]`;
+ case 'object':
+ if (value === null) return 'null';
+ if (value instanceof Date) return `Date "${value.toISOString()}"`;
+ if (value instanceof RegExp) return value.toString();
+ if (!seen) {
+ seen = {
+ counter: 0,
+ map: new Map()
+ };
+ }
+
+ let usage = seen.map.get(value);
+ if (usage) {
+ usage.used = true;
+ return `[Ref: #${usage.id}]`;
+ }
+
+ usage = { id: ++seen.counter, used: false };
+ seen.map.set(value, usage);
+
+ if (typeof Set !== "undefined" && value instanceof Set) {
+ return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (typeof Map !== "undefined" && value instanceof Map) {
+ return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (Array.isArray ? Array.isArray(value) : value instanceof Array) {
+ return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object';
+ if (tag === 'Object' && Object.getPrototypeOf(value) === null) {
+ tag = '[Object: null prototype]';
+ }
+ return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`;
+ default:
+ return typeof value;
+ }
+};
+
+assert.deepEqual._compare = (function () {
+ var EQUAL = 1;
+ var NOT_EQUAL = -1;
+ var UNKNOWN = 0;
+
+ function deepEqual(a, b) {
+ return compareEquality(a, b) === EQUAL;
+ }
+
+ function compareEquality(a, b, cache) {
+ return compareIf(a, b, isOptional, compareOptionality)
+ || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality)
+ || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache)
+ || NOT_EQUAL;
+ }
+
+ function compareIf(a, b, test, compare, cache) {
+ return !test(a)
+ ? !test(b) ? UNKNOWN : NOT_EQUAL
+ : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache);
+ }
+
+ function tryCompareStrictEquality(a, b) {
+ return a === b ? EQUAL : UNKNOWN;
+ }
+
+ function tryCompareTypeOfEquality(a, b) {
+ return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function tryCompareToStringTagEquality(a, b) {
+ var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined;
+ var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined;
+ return aTag !== bTag ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function isOptional(value) {
+ return value === undefined
+ || value === null;
+ }
+
+ function compareOptionality(a, b) {
+ return tryCompareStrictEquality(a, b)
+ || NOT_EQUAL;
+ }
+
+ function isPrimitiveEquatable(value) {
+ switch (typeof value) {
+ case 'string':
+ case 'number':
+ case 'bigint':
+ case 'boolean':
+ case 'symbol':
+ return true;
+ default:
+ return isBoxed(value);
+ }
+ }
+
+ function comparePrimitiveEquality(a, b) {
+ if (isBoxed(a)) a = a.valueOf();
+ if (isBoxed(b)) b = b.valueOf();
+ return tryCompareStrictEquality(a, b)
+ || tryCompareTypeOfEquality(a, b)
+ || compareIf(a, b, isNaNEquatable, compareNaNEquality)
+ || NOT_EQUAL;
+ }
+
+ function isNaNEquatable(value) {
+ return typeof value === 'number';
+ }
+
+ function compareNaNEquality(a, b) {
+ return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL;
+ }
+
+ function isObjectEquatable(value) {
+ return typeof value === 'object';
+ }
+
+ function compareObjectEquality(a, b, cache) {
+ if (!cache) cache = new Map();
+ return getCache(cache, a, b)
+ || setCache(cache, a, b, EQUAL) // consider equal for now
+ || cacheComparison(a, b, tryCompareStrictEquality, cache)
+ || cacheComparison(a, b, tryCompareToStringTagEquality, cache)
+ || compareIf(a, b, isValueOfEquatable, compareValueOfEquality)
+ || compareIf(a, b, isToStringEquatable, compareToStringEquality)
+ || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache)
+ || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache)
+ || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || cacheComparison(a, b, fail, cache);
+ }
+
+ function isBoxed(value) {
+ return value instanceof String
+ || value instanceof Number
+ || value instanceof Boolean
+ || typeof Symbol === 'function' && value instanceof Symbol
+ || typeof BigInt === 'function' && value instanceof BigInt;
+ }
+
+ function isValueOfEquatable(value) {
+ return value instanceof Date;
+ }
+
+ function compareValueOfEquality(a, b) {
+ return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isToStringEquatable(value) {
+ return value instanceof RegExp;
+ }
+
+ function compareToStringEquality(a, b) {
+ return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isArrayLikeEquatable(value) {
+ return (Array.isArray ? Array.isArray(value) : value instanceof Array)
+ || (typeof Uint8Array === 'function' && value instanceof Uint8Array)
+ || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray)
+ || (typeof Uint16Array === 'function' && value instanceof Uint16Array)
+ || (typeof Uint32Array === 'function' && value instanceof Uint32Array)
+ || (typeof Int8Array === 'function' && value instanceof Int8Array)
+ || (typeof Int16Array === 'function' && value instanceof Int16Array)
+ || (typeof Int32Array === 'function' && value instanceof Int32Array)
+ || (typeof Float32Array === 'function' && value instanceof Float32Array)
+ || (typeof Float64Array === 'function' && value instanceof Float64Array)
+ || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array)
+ || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array);
+ }
+
+ function compareArrayLikeEquality(a, b, cache) {
+ if (a.length !== b.length) return NOT_EQUAL;
+ for (var i = 0; i < a.length; i++) {
+ if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+ return EQUAL;
+ }
+
+ function isStructurallyEquatable(value) {
+ return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference
+ || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference
+ || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference
+ || typeof Map === 'function' && value instanceof Map // comparable via @@iterator
+ || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator
+ }
+
+ function compareStructuralEquality(a, b, cache) {
+ var aKeys = [];
+ for (var key in a) aKeys.push(key);
+
+ var bKeys = [];
+ for (var key in b) bKeys.push(key);
+
+ if (aKeys.length !== bKeys.length) {
+ return NOT_EQUAL;
+ }
+
+ aKeys.sort();
+ bKeys.sort();
+
+ for (var i = 0; i < aKeys.length; i++) {
+ var aKey = aKeys[i];
+ var bKey = bKeys[i];
+ if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+
+ return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || EQUAL;
+ }
+
+ function isIterableEquatable(value) {
+ return typeof Symbol === 'function'
+ && typeof value[Symbol.iterator] === 'function';
+ }
+
+ function compareIteratorEquality(a, b, cache) {
+ if (typeof Map === 'function' && a instanceof Map && b instanceof Map ||
+ typeof Set === 'function' && a instanceof Set && b instanceof Set) {
+ if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size
+ }
+
+ var ar, br;
+ while (true) {
+ ar = a.next();
+ br = b.next();
+ if (ar.done) {
+ if (br.done) return EQUAL;
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ if (br.done) {
+ if (a.return) a.return();
+ return NOT_EQUAL;
+ }
+ if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) {
+ if (a.return) a.return();
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ }
+ }
+
+ function compareIterableEquality(a, b, cache) {
+ return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache);
+ }
+
+ function cacheComparison(a, b, compare, cache) {
+ var result = compare(a, b, cache);
+ if (cache && (result === EQUAL || result === NOT_EQUAL)) {
+ setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result));
+ }
+ return result;
+ }
+
+ function fail() {
+ return NOT_EQUAL;
+ }
+
+ function setCache(cache, left, right, result) {
+ var otherCache;
+
+ otherCache = cache.get(left);
+ if (!otherCache) cache.set(left, otherCache = new Map());
+ otherCache.set(right, result);
+
+ otherCache = cache.get(right);
+ if (!otherCache) cache.set(right, otherCache = new Map());
+ otherCache.set(left, result);
+ }
+
+ function getCache(cache, left, right) {
+ var otherCache;
+ var result;
+
+ otherCache = cache.get(left);
+ result = otherCache && otherCache.get(right);
+ if (result) return result;
+
+ otherCache = cache.get(right);
+ result = otherCache && otherCache.get(left);
+ if (result) return result;
+
+ return UNKNOWN;
+ }
+
+ return deepEqual;
+})();