94890a0d46
Implements TC39 String.prototype.replaceAll as a torque builtin per the https://github.com/tc39/proposal-string-replaceall proposal. Note: matchAll changes were already added to V8 in https://chromium-review.googlesource.com/c/v8/v8/+/1846067 Bug: v8:9801 Change-Id: Ib8158eb39c854202d04710d6f9c33dcdd93fad93 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1877054 Commit-Queue: Joshua Litt <joshualitt@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#64785}
101 lines
2.6 KiB
JavaScript
101 lines
2.6 KiB
JavaScript
// Copyright 2019 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
// Flags: --harmony-string-replaceall
|
|
|
|
assertEquals('a-b-c-d', 'a+b+c+d'.replaceAll('+', '-'));
|
|
assertEquals('aaaa', 'abcd'.replaceAll(/./g, 'a'));
|
|
assertEquals('', ''.replaceAll('a', 'b'));
|
|
assertEquals('b', ''.replaceAll('', 'b'));
|
|
assertEquals('_x_x_x_', 'xxx'.replaceAll('', '_'));
|
|
assertEquals('yx', 'xxx'.replaceAll('xx', 'y'));
|
|
assertEquals('xxxx', 'xx'.replaceAll('xx', '$&$&'));
|
|
assertEquals('ii', '.+*$.+*$'.replaceAll('.+*$', 'i'));
|
|
|
|
{
|
|
// Non regexp search value with replace method.
|
|
const nonRegExpSearchValue = {
|
|
[Symbol.replace]: (string, replacer) => {
|
|
assertEquals(string, 'barbar');
|
|
assertEquals(replacer, 'moo');
|
|
return 'foo'
|
|
},
|
|
toString: () => {
|
|
// Verify toString is not called.
|
|
unreachable();
|
|
}
|
|
};
|
|
assertEquals('foo', 'barbar'.replaceAll(nonRegExpSearchValue, 'moo'));
|
|
}
|
|
|
|
{
|
|
// A custom regexp with non coercible flags.
|
|
class RegExpNonCoercibleFlags extends RegExp {
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
static get [Symbol.species]() {
|
|
return RegExp;
|
|
}
|
|
|
|
get flags() { return null; }
|
|
};
|
|
assertThrows(
|
|
() => { assertEquals(
|
|
'foo',
|
|
'barbar'.replaceAll(new RegExpNonCoercibleFlags, 'moo')); },
|
|
TypeError);
|
|
}
|
|
|
|
{
|
|
// Non regexp search value with replace property
|
|
const nonRegExpSearchValue = {
|
|
[Symbol.replace]: "doh",
|
|
toString: () => {
|
|
// Verify toString is not called.
|
|
unreachable();
|
|
}
|
|
};
|
|
assertThrows(
|
|
() => { 'barbar'.replaceAll(nonRegExpSearchValue, 'moo'); },
|
|
TypeError);
|
|
}
|
|
|
|
{
|
|
// Non callable, non string replace value.
|
|
const nonCallableNonStringReplace = {
|
|
toString: () => {
|
|
return 'boo';
|
|
},
|
|
};
|
|
assertEquals('booboo', 'moomoo'.replaceAll('moo', nonCallableNonStringReplace));
|
|
}
|
|
|
|
{
|
|
const positions = [];
|
|
assertEquals('bcb', 'aca'.replaceAll('a',
|
|
(searchString, position, string) => {
|
|
assertEquals('a', searchString);
|
|
assertEquals('aca', string);
|
|
positions.push(position);
|
|
return 'b';
|
|
}));
|
|
assertEquals(positions, [0,2]);
|
|
}
|
|
|
|
(function NonGlobalRegex() {
|
|
assertThrows(
|
|
() => { 'ab'.replaceAll(/./, '.'); },
|
|
TypeError);
|
|
assertThrows(
|
|
() => { 'ab'.replaceAll(/./y, '.'); },
|
|
TypeError);
|
|
})();
|
|
|
|
// Tests for stickiness gotcha.
|
|
assertEquals('o ppercase!', 'No Uppercase!'.replaceAll(/[A-Z]/g, ''));
|
|
assertEquals('o Uppercase?', 'No Uppercase?'.replaceAll(/[A-Z]/gy, ''));
|
|
assertEquals(' UPPERCASE!', 'NO UPPERCASE!'.replaceAll(/[A-Z]/gy, ''));
|