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