diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex-err.js b/test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex-err.js
new file mode 100644
index 00000000000..dee21d54156
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex-err.js
@@ -0,0 +1,51 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Abrupt completion during coercion of "lastIndex" property of `this` value.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 11. Repeat, while done is false
+ a. Let result be ? RegExpExec(rx, S).
+ b. If result is null, set done to true.
+ c. Else,
+ i. Append result to the end of results.
+ ii. If global is false, set done to true.
+ iii. Else,
+ 1. Let matchStr be ? ToString(? Get(result, "0")).
+ 2. If matchStr is the empty String, then
+ a. Let thisIndex be ? ToLength(? Get(rx, "lastIndex")).
+features: [Symbol.replace]
+---*/
+
+var r = /./g;
+var execWasCalled = false;
+var coercibleIndex = {
+ valueOf: function() {
+ throw new Test262Error();
+ },
+};
+
+var result = {
+ length: 1,
+ 0: '',
+ index: 0,
+};
+
+r.exec = function() {
+ if (execWasCalled) {
+ return null;
+ }
+
+ r.lastIndex = coercibleIndex;
+ execWasCalled = true;
+ return result;
+};
+
+assert.throws(Test262Error, function() {
+ r[Symbol.replace]('', '');
+});
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex.js b/test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex.js
new file mode 100644
index 00000000000..f860ad18863
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex.js
@@ -0,0 +1,52 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Length coercion of "lastIndex" property of `this` value.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 11. Repeat, while done is false
+ a. Let result be ? RegExpExec(rx, S).
+ b. If result is null, set done to true.
+ c. Else,
+ i. Append result to the end of results.
+ ii. If global is false, set done to true.
+ iii. Else,
+ 1. Let matchStr be ? ToString(? Get(result, "0")).
+ 2. If matchStr is the empty String, then
+ a. Let thisIndex be ? ToLength(? Get(rx, "lastIndex")).
+ b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
+ c. Perform ? Set(rx, "lastIndex", nextIndex, true).
+features: [Symbol.replace]
+---*/
+
+var r = /./g;
+var execWasCalled = false;
+var coercibleIndex = {
+ valueOf: function() {
+ return Math.pow(2, 54);
+ },
+};
+
+var result = {
+ length: 1,
+ 0: '',
+ index: 0,
+};
+
+r.exec = function() {
+ if (execWasCalled) {
+ return null;
+ }
+
+ r.lastIndex = coercibleIndex;
+ execWasCalled = true;
+ return result;
+};
+
+assert.sameValue(r[Symbol.replace]('', ''), '');
+assert.sameValue(r.lastIndex, Math.pow(2, 53));
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/fn-coerce-replacement.js b/test/built-ins/RegExp/prototype/Symbol.replace/fn-coerce-replacement.js
index 5ecc7b47b17..5afd2f43140 100644
--- a/test/built-ins/RegExp/prototype/Symbol.replace/fn-coerce-replacement.js
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/fn-coerce-replacement.js
@@ -2,19 +2,19 @@
// This code is governed by the BSD license found in the LICENSE file.
/*---
-description: String coercion of the value returned by functional replaceValue
-es6id: 21.2.5.8
+esid: sec-regexp.prototype-@@replace
+description: >
+ String coercion of the value returned by functional replaceValue.
info: |
- 16. Repeat, for each result in results,
- [...]
- m. If functionalReplace is true, then
- i. Let replacerArgs be «matched».
- ii. Append in list order the elements of captures to the end of the
- List replacerArgs.
- iii. Append position and S as the last two elements of replacerArgs.
- iv. Let replValue be Call(replaceValue, undefined, replacerArgs).
- v. Let replacement be ToString(replValue).
- [...]
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ k. If functionalReplace is true, then
+ [...]
+ v. Let replValue be ? Call(replaceValue, undefined, replacerArgs).
+ vi. Let replacement be ? ToString(replValue).
features: [Symbol.replace]
---*/
@@ -22,7 +22,10 @@ var replacer = function() {
return {
toString: function() {
return 'toString value';
- }
+ },
+ valueOf: function() {
+ throw new Test262Error('This method should not be invoked.');
+ },
};
};
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result.js b/test/built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result.js
new file mode 100644
index 00000000000..6df1aede509
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result.js
@@ -0,0 +1,41 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Arguments of functional replaceValue (`exec` result is empty array).
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ e. Let position be ? ToInteger(? Get(result, "index")).
+ [...]
+ k. If functionalReplace is true, then
+ i. Let replacerArgs be « matched ».
+ ii. Append in list order the elements of captures to the end of the List replacerArgs.
+ iii. Append position and S to replacerArgs.
+ [...]
+ v. Let replValue be ? Call(replaceValue, undefined, replacerArgs).
+features: [Symbol.replace]
+---*/
+
+var args;
+var replacer = function() {
+ args = arguments;
+};
+
+var r = /./;
+r.exec = function() {
+ return [];
+};
+
+r[Symbol.replace]('foo', replacer);
+
+assert.notSameValue(args, undefined);
+assert.sameValue(args.length, 3);
+assert.sameValue(args[0], 'undefined');
+assert.sameValue(args[1], 0);
+assert.sameValue(args[2], 'foo');
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/poisoned-stdlib.js b/test/built-ins/RegExp/prototype/Symbol.replace/poisoned-stdlib.js
new file mode 100644
index 00000000000..09dcaf6aacc
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/poisoned-stdlib.js
@@ -0,0 +1,31 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Both functional and pattern replacement performs as expected with poisoned stdlib.
+features: [Symbol.replace, regexp-named-groups]
+---*/
+
+assert(delete Array.prototype.concat);
+assert(delete Array.prototype.push);
+assert(delete Function.prototype.apply);
+assert(delete String.prototype.charAt);
+assert(delete String.prototype.charCodeAt);
+assert(delete String.prototype.indexOf);
+assert(delete String.prototype.slice);
+assert(delete String.prototype.substring);
+
+var str = "1a2";
+
+assert.sameValue(/a/[Symbol.replace](str, "$`b"), "11b2");
+assert.sameValue(/a/[Symbol.replace](str, "b$'"), "1b22");
+assert.sameValue(/a/[Symbol.replace](str, "$3b$33"), "1$3b$332");
+assert.sameValue(/(a)/[Symbol.replace](str, "$1b"), "1ab2");
+assert.sameValue(/(?a)/[Symbol.replace](str, "$b"), "1ab2");
+
+var replacer = function() {
+ return "b";
+};
+
+assert.sameValue(/a/[Symbol.replace](str, replacer), "1b2");
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-capture.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-capture.js
index f2ef443bc94..dbff175308a 100644
--- a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-capture.js
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-capture.js
@@ -2,32 +2,38 @@
// This code is governed by the BSD license found in the LICENSE file.
/*---
-description: Type coercion of `1` property of result
-es6id: 21.2.5.8
+esid: sec-regexp.prototype-@@replace
+description: >
+ String coercion of "3" property of the value returned by RegExpExec.
info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 11. Repeat, while done is false
+ a. Let result be ? RegExpExec(rx, S).
[...]
- 13. Repeat, while done is false
- a. Let result be RegExpExec(rx, S).
- [...]
- 16. Repeat, for each result in results,
+ 14. For each result in results, do
+ [...]
+ i. Repeat, while n ≤ nCaptures
+ i. Let capN be ? Get(result, ! ToString(n)).
+ ii. If capN is not undefined, then
+ 1. Set capN to ? ToString(capN).
[...]
- l. Repeat while n ≤ nCaptures
- i. Let capN be Get(result, ToString(n)).
- ii. ReturnIfAbrupt(capN).
- iii. If capN is not undefined, then
- 1. Let capN be ToString(capN).
- [...]
features: [Symbol.replace]
---*/
var r = /./;
var coercibleValue = {
length: 4,
+ index: 0,
3: {
toString: function() {
return 'toString value';
- }
- }
+ },
+ valueOf: function() {
+ throw new Test262Error('This method should not be invoked.');
+ },
+ },
};
r.exec = function() {
return coercibleValue;
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-err.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-err.js
new file mode 100644
index 00000000000..d9221d2ac9b
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-err.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Abrupt completion during coercion of "groups"
+ property of the value returned by RegExpExec.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ j. Let namedCaptures be ? Get(result, "groups").
+ k. If functionalReplace is true, then
+ [...]
+ l. Else,
+ i. If namedCaptures is not undefined, then
+ 1. Set namedCaptures to ? ToObject(namedCaptures).
+features: [Symbol.replace, regexp-named-groups]
+---*/
+
+var r = /./;
+var coercibleValue = {
+ length: 1,
+ 0: '',
+ index: 0,
+ groups: null,
+};
+
+r.exec = function() {
+ return coercibleValue;
+};
+
+assert.throws(TypeError, function() {
+ r[Symbol.replace]('bar', '');
+});
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop-err.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop-err.js
new file mode 100644
index 00000000000..d6770b5fc4b
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop-err.js
@@ -0,0 +1,67 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Abrupt completion during coercion of value of "groups" object.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ j. Let namedCaptures be ? Get(result, "groups").
+ k. If functionalReplace is true, then
+ [...]
+ l. Else,
+ [...]
+ ii. Let replacement be ? GetSubstitution(matched, S, position, captures, namedCaptures, replaceValue).
+
+ Runtime Semantics: GetSubstitution ( matched, str, position, captures, namedCaptures, replacement )
+
+ [...]
+ 11. Let result be the String value derived from replacement by copying code unit elements
+ from replacement to result while performing replacements as specified in Table 54.
+ These $ replacements are done left-to-right, and, once such a replacement is performed,
+ the new replacement text is not subject to further replacements.
+ 12. Return result.
+
+ Table 54: Replacement Text Symbol Substitutions
+
+ $<
+
+ 1. If namedCaptures is undefined, the replacement text is the String "$<".
+ 2. Else,
+ a. Assert: Type(namedCaptures) is Object.
+ b. Scan until the next > U+003E (GREATER-THAN SIGN).
+ c. If none is found, the replacement text is the String "$<".
+ d. Else,
+ i. Let groupName be the enclosed substring.
+ ii. Let capture be ? Get(namedCaptures, groupName).
+ iii. If capture is undefined, replace the text through > with the empty String.
+ iv. Otherwise, replace the text through > with ? ToString(capture).
+features: [Symbol.replace, regexp-named-groups]
+---*/
+
+var r = /./;
+var coercibleValue = {
+ length: 1,
+ 0: '',
+ index: 0,
+ groups: {
+ foo: {
+ toString: function() {
+ throw new Test262Error();
+ },
+ },
+ },
+};
+
+r.exec = function() {
+ return coercibleValue;
+};
+
+assert.throws(Test262Error, function() {
+ r[Symbol.replace]('a', '$');
+});
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop.js
new file mode 100644
index 00000000000..5d324825cf1
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop.js
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ String coercion of "groups" object values returned by RegExpExec.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ j. Let namedCaptures be ? Get(result, "groups").
+ k. If functionalReplace is true, then
+ [...]
+ l. Else,
+ [...]
+ ii. Let replacement be ? GetSubstitution(matched, S, position, captures, namedCaptures, replaceValue).
+
+ Runtime Semantics: GetSubstitution ( matched, str, position, captures, namedCaptures, replacement )
+
+ [...]
+ 11. Let result be the String value derived from replacement by copying code unit elements
+ from replacement to result while performing replacements as specified in Table 54.
+ These $ replacements are done left-to-right, and, once such a replacement is performed,
+ the new replacement text is not subject to further replacements.
+ 12. Return result.
+
+ Table 54: Replacement Text Symbol Substitutions
+
+ $<
+
+ 1. If namedCaptures is undefined, the replacement text is the String "$<".
+ 2. Else,
+ a. Assert: Type(namedCaptures) is Object.
+ b. Scan until the next > U+003E (GREATER-THAN SIGN).
+ c. If none is found, the replacement text is the String "$<".
+ d. Else,
+ i. Let groupName be the enclosed substring.
+ ii. Let capture be ? Get(namedCaptures, groupName).
+ iii. If capture is undefined, replace the text through > with the empty String.
+ iv. Otherwise, replace the text through > with ? ToString(capture).
+features: [Symbol.replace, regexp-named-groups]
+---*/
+
+var r = /./;
+var coercibleValue = {
+ length: 1,
+ 0: 'a',
+ index: 0,
+ groups: {
+ foo: {
+ toString: function() {
+ return 'toString value';
+ },
+ valueOf: function() {
+ throw new Test262Error('This method should not be invoked.');
+ },
+ },
+ },
+};
+
+r.exec = function() {
+ return coercibleValue;
+};
+
+assert.sameValue(r[Symbol.replace]('ab', '[$]'), '[toString value]b');
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups.js
new file mode 100644
index 00000000000..83ea5c3f88d
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups.js
@@ -0,0 +1,36 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ String coercion of "groups" property of the value returned by RegExpExec.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ j. Let namedCaptures be ? Get(result, "groups").
+ k. If functionalReplace is true, then
+ [...]
+ l. Else,
+ i. If namedCaptures is not undefined, then
+ 1. Set namedCaptures to ? ToObject(namedCaptures).
+ ii. Let replacement be ? GetSubstitution(matched, S, position, captures, namedCaptures, replaceValue).
+features: [Symbol.replace, regexp-named-groups]
+---*/
+
+var r = /./;
+var coercibleValue = {
+ length: 1,
+ 0: 'b',
+ index: 1,
+ groups: '123',
+};
+
+r.exec = function() {
+ return coercibleValue;
+};
+
+assert.sameValue(r[Symbol.replace]('ab', '[$]'), 'a[3]');
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-index-undefined.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-index-undefined.js
new file mode 100644
index 00000000000..2e2359f8079
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-index-undefined.js
@@ -0,0 +1,41 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Integer coercion of "index" property of the value returned by RegExpExec.
+ (undefined value)
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ e. Let position be ? ToInteger(? Get(result, "index")).
+ [...]
+
+ ToInteger ( argument )
+
+ 1. Let number be ? ToNumber(argument).
+ 2. If number is NaN, return +0.
+features: [Symbol.toPrimitive, Symbol.replace]
+---*/
+
+var index = {};
+var toPrimitiveHint;
+index[Symbol.toPrimitive] = function(hint) {
+ toPrimitiveHint = hint;
+};
+
+var r = /./;
+r.exec = function() {
+ return {
+ length: 1,
+ 0: 'a',
+ index: index,
+ };
+};
+
+assert.sameValue(r[Symbol.replace]('ab', '$`'), 'b');
+assert.sameValue(toPrimitiveHint, 'number');
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-index.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-index.js
index fcec0644343..b9c75c12f80 100644
--- a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-index.js
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-index.js
@@ -2,32 +2,42 @@
// This code is governed by the BSD license found in the LICENSE file.
/*---
+esid: sec-regexp.prototype-@@replace
description: >
- Type coercion of `index` property of result
-es6id: 21.2.5.8
+ Integer coercion of "index" property of the value returned by RegExpExec.
info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ e. Let position be ? ToInteger(? Get(result, "index")).
[...]
- 13. Repeat, while done is false
- a. Let result be RegExpExec(rx, S).
- [...]
- 16. Repeat, for each result in results,
- [...]
- g. Let position be ToInteger(Get(result, "index")).
- [...]
+ k. If functionalReplace is true, then
+ i. Let replacerArgs be « matched ».
+ ii. Append in list order the elements of captures to the end of the List replacerArgs.
+ iii. Append position and S to replacerArgs.
+ [...]
+ v. Let replValue be ? Call(replaceValue, undefined, replacerArgs).
features: [Symbol.replace]
---*/
var r = /./;
-var counter = 0;
var coercibleIndex = {
+ length: 1,
+ 0: '',
index: {
valueOf: function() {
return 2.9;
- }
- }
+ },
+ },
};
r.exec = function() {
return coercibleIndex;
};
-assert.sameValue(r[Symbol.replace]('abcd', ''), 'ab');
+var replacer = function(_matched, position) {
+ return position;
+};
+
+assert.sameValue(r[Symbol.replace]('abcd', replacer), 'ab2cd');
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-length.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-length.js
index 1e9497f9bb9..77c1fbe7029 100644
--- a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-length.js
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-length.js
@@ -2,32 +2,31 @@
// This code is governed by the BSD license found in the LICENSE file.
/*---
+esid: sec-regexp.prototype-@@replace
description: >
- Type coercion of `length` property of result
-es6id: 21.2.5.8
+ Type coercion of "length" property of the value returned by RegExpExec.
info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ a. Let nCaptures be ? LengthOfArrayLike(result).
[...]
- 13. Repeat, while done is false
- a. Let result be RegExpExec(rx, S).
- [...]
- 16. Repeat, for each result in results,
- a. Let nCaptures be ToLength(Get(result, "length")).
- [...]
features: [Symbol.replace]
---*/
var r = /./;
-var counter = 0;
var coercibleIndex = {
length: {
valueOf: function() {
return 3.9;
- }
+ },
},
0: '',
1: 'foo',
2: 'bar',
- 3: 'baz'
+ 3: 'baz',
+ index: 0,
};
r.exec = function() {
return coercibleIndex;
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched-global.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched-global.js
new file mode 100644
index 00000000000..44b049c3074
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched-global.js
@@ -0,0 +1,53 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ String coercion of "0" property of the value returned by RegExpExec.
+ (global RegExp)
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 11. Repeat, while done is false
+ a. Let result be ? RegExpExec(rx, S).
+ b. If result is null, set done to true.
+ c. Else,
+ i. Append result to the end of results.
+ ii. If global is false, set done to true.
+ iii. Else,
+ 1. Let matchStr be ? ToString(? Get(result, "0")).
+ 2. If matchStr is the empty String, then
+ a. Let thisIndex be ? ToLength(? Get(rx, "lastIndex")).
+ b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
+ c. Perform ? Set(rx, "lastIndex", nextIndex, true).
+features: [Symbol.replace]
+---*/
+
+var r = /./g;
+var coercibleValueWasReturned = false;
+var coercibleValue = {
+ length: 1,
+ 0: {
+ toString: function() {
+ return '';
+ },
+ valueOf: function() {
+ throw new Test262Error('This method should not be invoked.');
+ },
+ },
+ index: 0,
+};
+
+r.exec = function() {
+ if (coercibleValueWasReturned) {
+ return null;
+ }
+
+ coercibleValueWasReturned = true;
+ return coercibleValue;
+};
+
+assert.sameValue(r[Symbol.replace]('', 'foo'), 'foo');
+assert.sameValue(r.lastIndex, 1);
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched.js
index 72cff4ce8ff..e7ad35af6d4 100644
--- a/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched.js
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched.js
@@ -2,27 +2,34 @@
// This code is governed by the BSD license found in the LICENSE file.
/*---
-description: Type coercion of `0` property of result
-es6id: 21.2.5.8
+esid: sec-regexp.prototype-@@replace
+description: >
+ String coercion of "0" property of the value returned by RegExpExec.
info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 11. Repeat, while done is false
+ a. Let result be ? RegExpExec(rx, S).
+ [...]
+ 14. For each result in results, do
[...]
- 13. Repeat, while done is false
- a. Let result be RegExpExec(rx, S).
- [...]
- 16. Repeat, for each result in results,
- [...]
- d. Let matched be ToString(Get(result, "0")).
- [...]
+ c. Let matched be ? ToString(? Get(result, "0")).
features: [Symbol.replace]
---*/
var r = /./;
var coercibleValue = {
+ length: 1,
0: {
toString: function() {
return 'toString value';
- }
- }
+ },
+ valueOf: function() {
+ throw new Test262Error('This method should not be invoked.');
+ },
+ },
+ index: 0,
};
r.exec = function() {
return coercibleValue;
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-err.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-err.js
new file mode 100644
index 00000000000..3e7947920fb
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-err.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Abrupt completion during lookup of "groups"
+ property of the value returned by RegExpExec.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ j. Let namedCaptures be ? Get(result, "groups").
+features: [Symbol.replace, regexp-named-groups]
+---*/
+
+var r = /./;
+var coercibleValue = {
+ length: 0,
+ index: 0,
+ get groups() {
+ throw new Test262Error();
+ },
+};
+
+r.exec = function() {
+ return coercibleValue;
+};
+
+assert.throws(Test262Error, function() {
+ r[Symbol.replace]('a', '$');
+});
diff --git a/test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-prop-err.js b/test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-prop-err.js
new file mode 100644
index 00000000000..9f4bbff2187
--- /dev/null
+++ b/test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-prop-err.js
@@ -0,0 +1,62 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-regexp.prototype-@@replace
+description: >
+ Abrupt completion during lookup of value of "groups" object.
+info: |
+ RegExp.prototype [ @@replace ] ( string, replaceValue )
+
+ [...]
+ 14. For each result in results, do
+ [...]
+ j. Let namedCaptures be ? Get(result, "groups").
+ k. If functionalReplace is true, then
+ [...]
+ l. Else,
+ [...]
+ ii. Let replacement be ? GetSubstitution(matched, S, position, captures, namedCaptures, replaceValue).
+
+ Runtime Semantics: GetSubstitution ( matched, str, position, captures, namedCaptures, replacement )
+
+ [...]
+ 11. Let result be the String value derived from replacement by copying code unit elements
+ from replacement to result while performing replacements as specified in Table 54.
+ These $ replacements are done left-to-right, and, once such a replacement is performed,
+ the new replacement text is not subject to further replacements.
+ 12. Return result.
+
+ Table 54: Replacement Text Symbol Substitutions
+
+ $<
+
+ 1. If namedCaptures is undefined, the replacement text is the String "$<".
+ 2. Else,
+ a. Assert: Type(namedCaptures) is Object.
+ b. Scan until the next > U+003E (GREATER-THAN SIGN).
+ c. If none is found, the replacement text is the String "$<".
+ d. Else,
+ i. Let groupName be the enclosed substring.
+ ii. Let capture be ? Get(namedCaptures, groupName).
+features: [Symbol.replace, regexp-named-groups]
+---*/
+
+var r = /./;
+var coercibleValue = {
+ length: 0,
+ index: 0,
+ groups: {
+ get foo() {
+ throw new Test262Error();
+ },
+ },
+};
+
+r.exec = function() {
+ return coercibleValue;
+};
+
+assert.throws(Test262Error, function() {
+ r[Symbol.replace]('a', '$');
+});
diff --git a/test/built-ins/RegExp/unicode_restricted_incomple_quantifier.js b/test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js
similarity index 100%
rename from test/built-ins/RegExp/unicode_restricted_incomple_quantifier.js
rename to test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js