Title: [273160] trunk
Revision
273160
Author
msab...@apple.com
Date
2021-02-19 12:50:48 -0800 (Fri, 19 Feb 2021)

Log Message

Minor fixes to RegExp match indices after r273086
https://bugs.webkit.org/show_bug.cgi?id=222157

Reviewed by Yusuke Suzuki.

JSTests:

Added a new test to verify that all flag RegExp flag combinations work round tripping
from flags to flag proerties and back.
Added standalone versions of the updated regexp-match-indices from the PR
https://github.com/tc39/test262/pull/2934 as JSTest/stress test.
Disabled the regexp-match-indices feature test in test262 until the pull request
with updated tests land and we update the WebKit version.
This is tracked in https://bugs.webkit.org/show_bug.cgi?id=222142.

* stress/regexp-all-flags.js: Added.
(flagsFromVariation):
(setPropertiesForVariation):
(missingPropertiesForVariation):
(test.let.flagsSet.get call):
(test):
* stress/test262-indices-array-element.js: Added.
(assertSameValue):
* stress/test262-indices-array-matched.js: Added.
(assertSameValue):
(assertCompareArray):
* stress/test262-indices-array-non-unicode-match.js: Added.
(assertSameValue):
(assertCompareArray):
(assertDeepEqual):
(verifyProperty):
* stress/test262-indices-array-properties.js: Added.
(verifyProperty):
* stress/test262-indices-array-unicode-match.js: Added.
(assertSameValue):
(assertCompareArray):
(assertDeepEqual):
(verifyProperty):
* stress/test262-indices-array-unicode-property-names.js: Added.
(assertCompareArray):
* stress/test262-indices-array-unmatched.js: Added.
(assertSameValue):
* stress/test262-indices-array.js: Added.
(assert):
(assertSameValue):
* stress/test262-indices-groups-object-undefined.js: Added.
(verifyProperty):
* stress/test262-indices-groups-object-unmatched.js: Added.
(assertSameValue):
(assertCompareArray):
* stress/test262-indices-groups-object.js: Added.
(assertSameValue):
(assertCompareArray):
(verifyProperty):
* stress/test262-indices-groups-properties.js: Added.
(assertCompareArray):
(verifyProperty):
* stress/test262-indices-property.js: Added.
(assertSameValue):
(verifyProperty):
* test262/config.yaml:

Source/_javascript_Core:

When hasIndices is true, but there aren't any named groups, the spec says that we should
create the indices.groups property is the value undefined.
Increased the size of FlagsString to 7 plus terminater to account for the new 'd' flags.

* runtime/RegExpMatchesArray.h:
(JSC::createRegExpMatchesArray):
* runtime/RegExpPrototype.cpp:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (273159 => 273160)


--- trunk/JSTests/ChangeLog	2021-02-19 20:47:53 UTC (rev 273159)
+++ trunk/JSTests/ChangeLog	2021-02-19 20:50:48 UTC (rev 273160)
@@ -1,3 +1,65 @@
+2021-02-19  Michael Saboff  <msab...@apple.com>
+
+        Minor fixes to RegExp match indices after r273086
+        https://bugs.webkit.org/show_bug.cgi?id=222157
+
+        Reviewed by Yusuke Suzuki.
+
+        Added a new test to verify that all flag RegExp flag combinations work round tripping
+        from flags to flag proerties and back.
+        Added standalone versions of the updated regexp-match-indices from the PR
+        https://github.com/tc39/test262/pull/2934 as JSTest/stress test.
+        Disabled the regexp-match-indices feature test in test262 until the pull request
+        with updated tests land and we update the WebKit version.
+        This is tracked in https://bugs.webkit.org/show_bug.cgi?id=222142.
+
+        * stress/regexp-all-flags.js: Added.
+        (flagsFromVariation):
+        (setPropertiesForVariation):
+        (missingPropertiesForVariation):
+        (test.let.flagsSet.get call):
+        (test):
+        * stress/test262-indices-array-element.js: Added.
+        (assertSameValue):
+        * stress/test262-indices-array-matched.js: Added.
+        (assertSameValue):
+        (assertCompareArray):
+        * stress/test262-indices-array-non-unicode-match.js: Added.
+        (assertSameValue):
+        (assertCompareArray):
+        (assertDeepEqual):
+        (verifyProperty):
+        * stress/test262-indices-array-properties.js: Added.
+        (verifyProperty):
+        * stress/test262-indices-array-unicode-match.js: Added.
+        (assertSameValue):
+        (assertCompareArray):
+        (assertDeepEqual):
+        (verifyProperty):
+        * stress/test262-indices-array-unicode-property-names.js: Added.
+        (assertCompareArray):
+        * stress/test262-indices-array-unmatched.js: Added.
+        (assertSameValue):
+        * stress/test262-indices-array.js: Added.
+        (assert):
+        (assertSameValue):
+        * stress/test262-indices-groups-object-undefined.js: Added.
+        (verifyProperty):
+        * stress/test262-indices-groups-object-unmatched.js: Added.
+        (assertSameValue):
+        (assertCompareArray):
+        * stress/test262-indices-groups-object.js: Added.
+        (assertSameValue):
+        (assertCompareArray):
+        (verifyProperty):
+        * stress/test262-indices-groups-properties.js: Added.
+        (assertCompareArray):
+        (verifyProperty):
+        * stress/test262-indices-property.js: Added.
+        (assertSameValue):
+        (verifyProperty):
+        * test262/config.yaml:
+
 2021-02-19  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Do not use toObject for options in new Intl constructors

Added: trunk/JSTests/stress/regexp-all-flags.js (0 => 273160)


--- trunk/JSTests/stress/regexp-all-flags.js	                        (rev 0)
+++ trunk/JSTests/stress/regexp-all-flags.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,60 @@
+let allRegExpFlags = "dgimsuy";
+let allRegExpProperties = [ 'hasIndices', 'global', 'ignoreCase', 'multiline', 'dotAll', 'unicode', 'sticky'];
+const numFlags = allRegExpFlags.length;
+const numVariations = 2 ** numFlags;
+
+function flagsFromVariation(variation)
+{
+    let flags = "";
+
+    for (let i = 0; i < numFlags; i++)
+        if (variation & (2 ** i))
+            flags = flags + allRegExpFlags[i];
+
+    return flags;
+}
+
+function setPropertiesForVariation(variation, o)
+{
+    for (let i = 0; i < numFlags; i++)
+        if (variation & (2 ** i))
+            o[allRegExpProperties[i]] = true;
+
+    return o;
+}
+
+function missingPropertiesForVariation(variation, o)
+{
+    let missingProperties = [];
+
+    for (let i = 0; i < numFlags; i++)
+        if (variation & (2 ** i) && !o[allRegExpProperties[i]])
+            missingProperties.push(allRegExpProperties[i]);
+
+    return missingProperties;
+}
+
+var get = Object.getOwnPropertyDescriptor(RegExp.prototype, "flags").get
+
+function test()
+{
+    for (let variation = 0; variation < numVariations; ++variation) {
+        let flags = flagsFromVariation(variation);
+
+        let r = new RegExp("foo", flags);
+
+        let missingProperties = missingPropertiesForVariation(variation, r);
+        if (missingProperties.length)
+            throw "RegExp " + r.toString() + " missing properties: " + missingProperties;
+
+        r = setPropertiesForVariation(variation, {});
+
+        let flagsSet = get.call(r);
+
+        if (flagsSet != flags)
+            throw "RegExp with flags: \"" + flags + "\" should have properties: " + missingPropertiesForVariation(variation, {});
+    }
+}
+
+test();
+

Added: trunk/JSTests/stress/test262-indices-array-element.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array-element.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array-element.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,33 @@
+// 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]] ยป).
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+let input = "abcd";
+let match = /b(c)/d.exec(input);
+let indices = match.indices;
+
+// `indices[0]` is an array
+assertSameValue(Object.getPrototypeOf(indices[0]), Array.prototype);
+assertSameValue(indices[0].length, 2);
+assertSameValue(typeof indices[0][0], "number");
+assertSameValue(typeof indices[0][1], "number");
+
+// `indices[1]` is an array
+assertSameValue(Object.getPrototypeOf(indices[1]), Array.prototype);
+assertSameValue(indices[1].length, 2);
+assertSameValue(typeof indices[1][0], "number");
+assertSameValue(typeof indices[1][1], "number");

Added: trunk/JSTests/stress/test262-indices-array-matched.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array-matched.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array-matched.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,60 @@
+// 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, hasIndices )
+    4. Let _n_ be the number of elements in _indices_.
+    ...
+    8. Set _A_ to ! ArrayCreate(_n_).
+    ...
+    13. 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_).
+        ...
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+function assertCompareArray(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i)
+        if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+}
+
+let input = "abcd";
+let match = /b(c)/d.exec(input);
+let indices = match.indices;
+
+// `indices` has the same length as match
+assertSameValue(indices.length, match.length);
+
+// The first element of `indices` contains the start/end indices of the match
+assertCompareArray(indices[0], [1, 3]);
+assertSameValue(input.slice(indices[0][0], indices[0][1]), match[0]);
+
+// The second element of `indices` contains the start/end indices of the first capture
+assertCompareArray(indices[1], [2, 3]);
+assertSameValue(input.slice(indices[1][0], indices[1][1]), match[1]);

Added: trunk/JSTests/stress/test262-indices-array-non-unicode-match.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array-non-unicode-match.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array-non-unicode-match.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,129 @@
+// 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")).
+    ...
+    8. If _flags_ contains `"d"`, let _hasIndices_ be *true*, else let _hasIndices_ be *false*.
+    ...
+    26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }.
+    27. Let _indices_ be a new empty List.
+    29. Add _match_ as the last element of _indices_.
+    ...
+    35. 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_.
+        ...
+    36. If _hasIndices_ is *true*, then
+      a. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_).
+      b. Perform ! CreateDataProperty(_A_, `"indices"`, _indicesArray_).
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+function assertCompareArray(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i)
+        if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+}
+
+function assertDeepEqual(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i) {
+        if (a[i] instanceof Array)
+            assertDeepEqual(a[i], b[i]);
+        else if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+    }
+}
+
+function verifyProperty(obj, prop, expect)
+{
+    let desc = Object.getOwnPropertyDescriptor(obj, prop);
+
+    for (const [key, value] of Object.entries(expect))
+        if (desc[key] != value)
+            throw "obj." + prop + " " + key + ": is not " + value;
+}
+
+assertDeepEqual([[1, 2], [1, 2]], "bab".match(/(a)/d).indices);
+assertDeepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./d).indices);
+assertDeepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/d).indices);
+assertDeepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/d).indices);
+assertDeepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/d).indices);
+assertDeepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/d).indices);
+assertDeepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/d).indices);
+
+let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/d.exec("abccba").indices.groups;
+assertCompareArray([0, 1], groups.a);
+assertCompareArray([1, 2], groups.b);
+assertCompareArray([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:
+assertSameValue("๐".length, 2, 'The length of "๐" is 2');
+assertSameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2');
+assertSameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2');
+assertSameValue("๐".match(/./)[0].length, 1, 'The length of a single code unit match against "๐" is 1 (without /u flag)');
+assertSameValue("\u{1d401}".match(/./)[0].length, 1, 'The length of a single code unit match against "\\u{1d401}" is 1 (without /u flag)');
+assertSameValue("\uD835\uDC01".match(/./)[0].length, 1, 'The length of a single code unit match against "\\ud835\\udc01" is 1 (without /u flag)');
+
+assertCompareArray([0, 1], "๐".match(/./d).indices[0], 'Indices for non-unicode match against "๐" (without /u flag)');
+assertCompareArray([0, 1], "\u{1d401}".match(/./d).indices[0], 'Indices for non-unicode match against "\\u{1d401}" (without /u flag)');
+assertCompareArray([0, 1], "\uD835\uDC01".match(/./d).indices[0], 'Indices for non-unicode match against "\\ud835\\udc01" (without /u flag)');
+assertCompareArray([0, 1], "๐".match(/(?<a>.)/d).indices.groups.a, 'Indices for non-unicode match against "๐" in groups.a (without /u flag)');
+assertCompareArray([0, 1], "\u{1d401}".match(/(?<a>.)/d).indices.groups.a, 'Indices for non-unicode match against "\\u{1d401}" in groups.a (without /u flag)');
+assertCompareArray([0, 1], "\uD835\uDC01".match(/(?<a>.)/d).indices.groups.a, 'Indices for non-unicode match against "\\ud835\\udc01" in groups.a (without /u flag)');

Added: trunk/JSTests/stress/test262-indices-array-properties.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array-properties.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array-properties.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,38 @@
+// 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, hasGroups )
+    13. 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)/d.exec(input);
+let indices = match.indices;
+
+function verifyProperty(obj, prop, expect)
+{
+    let desc = Object.getOwnPropertyDescriptor(obj, prop);
+
+    for (const [key, value] of Object.entries(expect))
+        if (desc[key] != value)
+            throw "obj." + prop + " " + key + ": is not " + value;
+}
+
+verifyProperty(indices, '0', {
+  enumerable: true,
+  configurable: true,
+  writable: true
+});
+
+verifyProperty(indices, '1', {
+  enumerable: true,
+  configurable: true,
+  writable: true
+});

Added: trunk/JSTests/stress/test262-indices-array-unicode-match.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array-unicode-match.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array-unicode-match.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,137 @@
+// 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_).
+    ...
+    26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }.
+    27. Let _indices_ be a new empty List.
+    ...
+    29. Add _match_ as the last element of _indices_.
+    ...
+    35. 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_.
+        ...
+    36. If _hasIndices_ is *true*, then
+      a. Let _indicesArray_ be MakeIndicesArray(_S_, _indices_, _groupNames_, _hasGroups_).
+      b. Perform ! CreateDataProperty(_A_, `"indices"`, _indicesArray_).
+
+  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_.
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+function assertCompareArray(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i)
+        if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+}
+
+function assertDeepEqual(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i) {
+        if (a[i] instanceof Array)
+            assertDeepEqual(a[i], b[i]);
+        else if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+    }
+}
+
+function verifyProperty(obj, prop, expect)
+{
+    let desc = Object.getOwnPropertyDescriptor(obj, prop);
+
+    for (const [key, value] of Object.entries(expect))
+        if (desc[key] != value)
+            throw "obj." + prop + " " + key + ": is not " + value;
+}
+
+assertDeepEqual([[1, 2], [1, 2]], "bab".match(/(a)/du).indices);
+assertDeepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./du).indices);
+assertDeepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/du).indices);
+assertDeepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/du).indices);
+assertDeepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/du).indices);
+assertDeepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/du).indices);
+assertDeepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/du).indices);
+
+let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/du.exec("abccba").indices.groups;
+assertCompareArray([0, 1], groups.a);
+assertCompareArray([1, 2], groups.b);
+assertCompareArray([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:
+assertSameValue("๐".length, 2, 'The length of "๐" is 2');
+assertSameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2');
+assertSameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2');
+assertSameValue(2, "๐".match(/./u)[0].length, 'The length of a single code point match against "๐" is 2 (with /du flag)');
+assertSameValue(2, "\u{1d401}".match(/./u)[0].length, 'The length of a single code point match against "\\u{1d401}" is 2 (with /du flag)');
+assertSameValue(2, "\uD835\uDC01".match(/./u)[0].length, 'The length of a single code point match against "\\ud835\\udc01" is 2 (with /du flag)');
+
+assertCompareArray([0, 2], "๐".match(/./du).indices[0], 'Indices for unicode match against "๐" (with /du flag)');
+assertCompareArray([0, 2], "\u{1d401}".match(/./du).indices[0], 'Indices for unicode match against \\u{1d401} (with /du flag)');
+assertCompareArray([0, 2], "\uD835\uDC01".match(/./du).indices[0], 'Indices for unicode match against \\ud835\\udc01 (with /du flag)');
+assertCompareArray([0, 2], "๐".match(/(?<a>.)/du).indices.groups.a, 'Indices for unicode match against ๐ in groups.a (with /du flag)');
+assertCompareArray([0, 2], "\u{1d401}".match(/(?<a>.)/du).indices.groups.a, 'Indices for unicode match against \\u{1d401} in groups.a (with /du flag)');
+assertCompareArray([0, 2], "\uD835\uDC01".match(/(?<a>.)/du).indices.groups.a, 'Indices for unicode match against \\ud835\\udc01 in groups.a (with /du flag)');

Added: trunk/JSTests/stress/test262-indices-array-unicode-property-names.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array-unicode-property-names.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array-unicode-property-names.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,36 @@
+// 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]
+---*/
+
+function assertCompareArray(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i)
+        if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+}
+
+assertCompareArray([1, 2], /(?<ฯ€>a)/du.exec("bab").indices.groups.ฯ€);
+assertCompareArray([1, 2], /(?<\u{03C0}>a)/du.exec("bab").indices.groups.ฯ€);
+assertCompareArray([1, 2], /(?<ฯ€>a)/du.exec("bab").indices.groups.\u03C0);
+assertCompareArray([1, 2], /(?<\u{03C0}>a)/du.exec("bab").indices.groups.\u03C0);
+assertCompareArray([1, 2], /(?<$>a)/du.exec("bab").indices.groups.$);
+assertCompareArray([1, 2], /(?<_>a)/du.exec("bab").indices.groups._);
+assertCompareArray([1, 2], /(?<$๐’ค>a)/du.exec("bab").indices.groups.$๐’ค);
+assertCompareArray([1, 2], /(?<_\u200C>a)/du.exec("bab").indices.groups._\u200C);
+assertCompareArray([1, 2], /(?<_\u200D>a)/du.exec("bab").indices.groups._\u200D);
+assertCompareArray([1, 2], /(?<เฒ _เฒ >a)/du.exec("bab").indices.groups.เฒ _เฒ );

Added: trunk/JSTests/stress/test262-indices-array-unmatched.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array-unmatched.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array-unmatched.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,38 @@
+// 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_).
+        ...
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+let input = "abd";
+let match = /b(c)?/d.exec(input);
+let indices = match.indices;
+
+// `indices` has the same length as match
+assertSameValue(indices.length, match.length);
+
+// The second element of `indices` should be undefined.
+assertSameValue(indices[1], undefined);

Added: trunk/JSTests/stress/test262-indices-array.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-array.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-array.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,30 @@
+// 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, hasGroups )
+    6. Set _A_ to ! ArrayCreate(_n_).
+---*/
+
+function assert(a)
+{
+    if (!a)
+        throw "Values not true";
+}
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+let match = /a/d.exec("a");
+let indices = match.indices;
+
+// `indices` is an array
+assertSameValue(Object.getPrototypeOf(indices), Array.prototype);
+assert(Array.isArray(indices));

Added: trunk/JSTests/stress/test262-indices-groups-object-undefined.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-groups-object-undefined.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-groups-object-undefined.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,34 @@
+// 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, hasGroups )
+    10. If _hasGroups_ is *true*, then
+      a. Let _groups_ be ! ObjectCreate(*null*).
+    11. Else,
+      a. Let _groups_ be *undefined*.
+    12. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_).
+---*/
+
+function verifyProperty(obj, prop, expect)
+{
+    let desc = Object.getOwnPropertyDescriptor(obj, prop);
+
+    for (const [key, value] of Object.entries(expect))
+        if (desc[key] != value)
+            throw "obj." + prop + " " + key + ": is not " + value;
+}
+
+const re = /./d;
+const indices = re.exec("a").indices;
+verifyProperty(indices, 'groups', {
+  writable: true,
+  enumerable: true,
+  configurable: true,
+  value: undefined
+});

Added: trunk/JSTests/stress/test262-indices-groups-object-unmatched.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-groups-object-unmatched.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-groups-object-unmatched.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,41 @@
+// 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, hasGroups )
+    11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
+      e. If _i_ > 0 and _groupNames_[_i_ - 1] is not *undefined*, then
+        i. Perform ! CreateDataProperty(_groups_, _groupNames_[_i_ - 1], _matchIndicesArray_).
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+function assertCompareArray(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i)
+        if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+}
+
+const re = /(?<a>a).|(?<x>x)/d;
+const result = re.exec("ab").indices;
+assertCompareArray([0, 1], result.groups.a);
+assertSameValue(undefined, result.groups.x);

Added: trunk/JSTests/stress/test262-indices-groups-object.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-groups-object.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-groups-object.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,70 @@
+// 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, hasIndices )
+    10. If _hasIndices_ is *true*, then
+      a. Let _groups_ be ! ObjectCreate(*null*).
+    11. Else,
+      a. Let _groups_ be *undefined*.
+    12. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_).
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+function assertCompareArray(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i)
+        if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+}
+
+function verifyProperty(obj, prop, expect)
+{
+    let desc = Object.getOwnPropertyDescriptor(obj, prop);
+
+    for (const [key, value] of Object.entries(expect))
+        if (desc[key] != value)
+            throw "obj." + prop + " " + key + ": is not " + value;
+}
+
+// `groups` is created with Define, not Set.
+let counter = 0;
+Object.defineProperty(Array.prototype, "groups", {
+  set() { counter++; }
+});
+
+let indices = /(?<x>.)/d.exec("a").indices;
+assertSameValue(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__>.)/d.exec("a").indices;
+assertCompareArray([0, 1], groups.__proto__);
+assertSameValue(null, Object.getPrototypeOf(groups));

Added: trunk/JSTests/stress/test262-indices-groups-properties.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-groups-properties.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-groups-properties.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,59 @@
+// 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, hasIndices )
+    13. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
+      e. If _i_ > 0 and _groupNames_[_i_ - 1] is not *undefined*, then
+        i. Perform ! CreateDataProperty(_groups_, _groupNames_[_i_ - 1], _matchIndicesArray_).
+---*/
+
+function assertCompareArray(a, b)
+{
+    if (!a instanceof Array)
+        throw "a not array";
+
+    if (!b instanceof Array)
+        throw "b not array";
+
+    if (a.length !== b.length)
+        throw "Arrays differ in length";
+
+    for (let i = 0; i < a.length; ++i)
+        if (a[i] !== b[i])
+            throw "Array element " + i + " differ";
+}
+
+function verifyProperty(obj, prop, expect)
+{
+    let desc = Object.getOwnPropertyDescriptor(obj, prop);
+
+    for (const [key, value] of Object.entries(expect))
+        if (desc[key] != value)
+            throw "obj." + prop + " " + key + ": is not " + value;
+}
+
+// Properties created on result.groups in textual order.
+let groupNames = Object.getOwnPropertyNames(/(?<fst>.)|(?<snd>.)/du.exec("abcd").indices.groups);
+assertCompareArray(groupNames, ["fst", "snd"]);
+
+// // Properties are created with Define, not Set
+// let counter = 0;
+// Object.defineProperty(Object.prototype, 'x', {set() { counter++; }});
+
+let indices = /(?<x>.)/d.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
+});

Added: trunk/JSTests/stress/test262-indices-property.js (0 => 273160)


--- trunk/JSTests/stress/test262-indices-property.js	                        (rev 0)
+++ trunk/JSTests/stress/test262-indices-property.js	2021-02-19 20:50:48 UTC (rev 273160)
@@ -0,0 +1,47 @@
+// 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 )
+    8. If _flags_ contains `"d"`, let _hasIndices_ be *true*, else let _hasIndices_ be *false*.
+    ...
+    36. If _hasIndices_ is *true*, then
+      a. Let _indicesArray_ be MakeIndicesArray(_S_, _indices_, _groupNames_, _hasGroups_).
+      b. Perform ! CreateDataProperty(_A_, `"indices"`, _indicesArray_).
+---*/
+
+function assertSameValue(a, b)
+{
+    if (a !== b)
+        throw "Values not same";
+}
+
+function verifyProperty(obj, prop, expect)
+{
+    let desc = Object.getOwnPropertyDescriptor(obj, prop);
+
+    for (const [key, value] of Object.entries(expect))
+        if (desc[key] != value)
+            throw "obj." + prop + " " + key + ": is not " + value;
+}
+
+// `indices` is created with Define, not Set.
+let counter = 0;
+Object.defineProperty(Array.prototype, "indices", {
+  set() { counter++; }
+});
+
+let match = /a/d.exec("a");
+assertSameValue(counter, 0);
+
+// `indices` is a non-writable, non-enumerable, and configurable data-property.
+verifyProperty(match, 'indices', {
+  writable: true,
+  enumerable: true,
+  configurable: true
+});

Modified: trunk/JSTests/test262/config.yaml (273159 => 273160)


--- trunk/JSTests/test262/config.yaml	2021-02-19 20:47:53 UTC (rev 273159)
+++ trunk/JSTests/test262/config.yaml	2021-02-19 20:50:48 UTC (rev 273160)
@@ -23,7 +23,10 @@
 
     - cleanupSome
     - host-gc-required
-    # https://bugs.webkit.org/show_bug.cgi?id=202475
+
+    # FIXME: https://bugs.webkit.org/show_bug.cgi?id=222142
+    - regexp-match-indices
+
     - top-level-await
   paths:
   files:

Modified: trunk/Source/_javascript_Core/ChangeLog (273159 => 273160)


--- trunk/Source/_javascript_Core/ChangeLog	2021-02-19 20:47:53 UTC (rev 273159)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-02-19 20:50:48 UTC (rev 273160)
@@ -1,3 +1,18 @@
+2021-02-19  Michael Saboff  <msab...@apple.com>
+
+        Minor fixes to RegExp match indices after r273086
+        https://bugs.webkit.org/show_bug.cgi?id=222157
+
+        Reviewed by Yusuke Suzuki.
+
+        When hasIndices is true, but there aren't any named groups, the spec says that we should
+        create the indices.groups property is the value undefined.
+        Increased the size of FlagsString to 7 plus terminater to account for the new 'd' flags.
+
+        * runtime/RegExpMatchesArray.h:
+        (JSC::createRegExpMatchesArray):
+        * runtime/RegExpPrototype.cpp:
+
 2021-02-19  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Do not use toObject for options in new Intl constructors

Modified: trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h (273159 => 273160)


--- trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h	2021-02-19 20:47:53 UTC (rev 273159)
+++ trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h	2021-02-19 20:50:48 UTC (rev 273160)
@@ -106,7 +106,7 @@
 
             Structure* indicesStructure = globalObject->regExpMatchesIndicesArrayStructure();
 
-            indicesArray->putDirect(vm, RegExpMatchesIndicesGroupsPropertyOffset, indicesGroups);
+            indicesArray->putDirect(vm, RegExpMatchesIndicesGroupsPropertyOffset, indicesGroups ? indicesGroups : jsUndefined());
 
             ASSERT(!indicesArray->butterfly()->indexingHeader()->preCapacity(indicesStructure));
             auto indicesCapacity = indicesStructure->outOfLineCapacity();

Modified: trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp (273159 => 273160)


--- trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2021-02-19 20:47:53 UTC (rev 273159)
+++ trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2021-02-19 20:50:48 UTC (rev 273160)
@@ -162,7 +162,7 @@
     return JSValue::encode(thisRegExp);
 }
 
-typedef std::array<char, 6 + 1> FlagsString; // 6 different flags and a null character terminator.
+typedef std::array<char, 7 + 1> FlagsString; // 6 different flags and a null character terminator.
 
 static inline FlagsString flagsString(JSGlobalObject* globalObject, JSObject* regexp)
 {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to