eb10dc4c91
These map checks were implemented for TF code already. This CL makes sure that parts implemented in C++ follow the same logic, which is: An object is an unmodified regexp if: 1) it's a receiver, 2) its map is the initial regexp map, 3) its prototype is a receiver, 4) and its prototype's map is the initial prototype's initial map. We can now be smarter in @@replace and @@split since checking maps (unlike the previous check of RegExp.prototype.exec) is not observable, so we can perform fast-path checks at a time of our choosing. BUG=v8:5339,v8:5434,v8:5123 Review-Url: https://chromiumcodereview.appspot.com/2434983002 Cr-Commit-Position: refs/heads/master@{#40501}
124 lines
3.8 KiB
JavaScript
124 lines
3.8 KiB
JavaScript
// Copyright 2015 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.
|
|
|
|
var r1 = /abc/gi;
|
|
assertEquals("abc", r1.source);
|
|
assertTrue(r1.global);
|
|
assertTrue(r1.ignoreCase);
|
|
assertFalse(r1.multiline);
|
|
assertFalse(r1.sticky);
|
|
assertFalse(r1.unicode);
|
|
|
|
// Internal slot of prototype is not read.
|
|
var r2 = { __proto__: r1 };
|
|
assertThrows(function() { r2.source; }, TypeError);
|
|
assertThrows(function() { r2.global; }, TypeError);
|
|
assertThrows(function() { r2.ignoreCase; }, TypeError);
|
|
assertThrows(function() { r2.multiline; }, TypeError);
|
|
assertThrows(function() { r2.sticky; }, TypeError);
|
|
assertThrows(function() { r2.unicode; }, TypeError);
|
|
|
|
var r3 = /I/;
|
|
var string = "iIiIi";
|
|
var expected = "iXiIi";
|
|
assertFalse(r3.global);
|
|
assertFalse(r3.ignoreCase);
|
|
assertEquals("", r3.flags);
|
|
assertEquals(expected, string.replace(r3, "X"));
|
|
|
|
var get_count = 0;
|
|
Object.defineProperty(r3, "global", {
|
|
get: function() { get_count++; return true; }
|
|
});
|
|
Object.defineProperty(r3, "ignoreCase", {
|
|
get: function() { get_count++; return true; }
|
|
});
|
|
|
|
assertTrue(r3.global);
|
|
assertEquals(1, get_count);
|
|
assertTrue(r3.ignoreCase);
|
|
assertEquals(2, get_count);
|
|
// Overridden flag getters affects the flags getter.
|
|
assertEquals("gi", r3.flags);
|
|
assertEquals(4, get_count);
|
|
// Overridden flag getters affect string.replace
|
|
// TODO(adamk): Add more tests here once we've switched
|
|
// to use [[OriginalFlags]] in more cases.
|
|
// TODO(jgruber): This exact case actually causes an infinite loop in the spec
|
|
// (@@replace sees global = true while BuiltinExec sees global = false).
|
|
// Comment the test for now and remove / fix once this has been resolved on
|
|
// the spec side.
|
|
//assertEquals(expected, string.replace(r3, "X"));
|
|
//assertEquals(5, get_count);
|
|
|
|
|
|
function testName(name) {
|
|
// Test for ES2017 RegExp web compatibility semantics
|
|
// https://github.com/tc39/ecma262/pull/511
|
|
assertEquals(name === "source" ? "(?:)" : undefined,
|
|
RegExp.prototype[name]);
|
|
assertEquals(
|
|
"get " + name,
|
|
Object.getOwnPropertyDescriptor(RegExp.prototype, name).get.name);
|
|
}
|
|
|
|
testName("global");
|
|
testName("ignoreCase");
|
|
testName("multiline");
|
|
testName("source");
|
|
testName("sticky");
|
|
testName("unicode");
|
|
|
|
|
|
RegExp.prototype.flags = 'setter should be undefined';
|
|
|
|
assertEquals('', RegExp('').flags);
|
|
assertEquals('', /./.flags);
|
|
assertEquals('gimuy', RegExp('', 'yugmi').flags);
|
|
assertEquals('gimuy', /foo/yumig.flags);
|
|
|
|
var descriptor = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags');
|
|
assertTrue(descriptor.configurable);
|
|
assertFalse(descriptor.enumerable);
|
|
assertInstanceof(descriptor.get, Function);
|
|
assertEquals(undefined, descriptor.set);
|
|
|
|
function testGenericFlags(object) {
|
|
return descriptor.get.call(object);
|
|
}
|
|
|
|
assertEquals('', testGenericFlags({}));
|
|
assertEquals('i', testGenericFlags({ ignoreCase: true }));
|
|
assertEquals('uy', testGenericFlags({ global: 0, sticky: 1, unicode: 1 }));
|
|
assertEquals('m', testGenericFlags({ __proto__: { multiline: true } }));
|
|
assertThrows(function() { testGenericFlags(); }, TypeError);
|
|
assertThrows(function() { testGenericFlags(undefined); }, TypeError);
|
|
assertThrows(function() { testGenericFlags(null); }, TypeError);
|
|
assertThrows(function() { testGenericFlags(true); }, TypeError);
|
|
assertThrows(function() { testGenericFlags(false); }, TypeError);
|
|
assertThrows(function() { testGenericFlags(''); }, TypeError);
|
|
assertThrows(function() { testGenericFlags(42); }, TypeError);
|
|
|
|
var counter = 0;
|
|
var map = {};
|
|
var object = {
|
|
get global() {
|
|
map.g = counter++;
|
|
},
|
|
get ignoreCase() {
|
|
map.i = counter++;
|
|
},
|
|
get multiline() {
|
|
map.m = counter++;
|
|
},
|
|
get unicode() {
|
|
map.u = counter++;
|
|
},
|
|
get sticky() {
|
|
map.y = counter++;
|
|
}
|
|
};
|
|
testGenericFlags(object);
|
|
assertEquals({ g: 0, i: 1, m: 2, u: 3, y: 4 }, map);
|