Implement flag and source getters on RegExp.prototype.
R=littledan@chromium.org BUG=v8:3715, v8:4528 LOG=Y Committed: https://crrev.com/60e8877e161fe6175e19fafce2d6ed1c3999cdb1 Cr-Commit-Position: refs/heads/master@{#31753} Committed: https://crrev.com/b5c80a31ad266eb38a0cf2ff756be59c66d34aa5 Cr-Commit-Position: refs/heads/master@{#31773} Committed: https://crrev.com/85494e90bb63a3a9e19a1bf862cb6bfcb0162ee9 Cr-Commit-Position: refs/heads/master@{#31782} Review URL: https://codereview.chromium.org/1419823010 Cr-Commit-Position: refs/heads/master@{#31804}
This commit is contained in:
parent
5486eb6b3d
commit
152163c164
@ -4001,7 +4001,9 @@ class V8_EXPORT RegExp : public Object {
|
||||
kNone = 0,
|
||||
kGlobal = 1,
|
||||
kIgnoreCase = 2,
|
||||
kMultiline = 4
|
||||
kMultiline = 4,
|
||||
kSticky = 8,
|
||||
kUnicode = 16
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6147,6 +6147,8 @@ REGEXP_FLAG_ASSERT_EQ(kNone, NONE);
|
||||
REGEXP_FLAG_ASSERT_EQ(kGlobal, GLOBAL);
|
||||
REGEXP_FLAG_ASSERT_EQ(kIgnoreCase, IGNORE_CASE);
|
||||
REGEXP_FLAG_ASSERT_EQ(kMultiline, MULTILINE);
|
||||
REGEXP_FLAG_ASSERT_EQ(kSticky, STICKY);
|
||||
REGEXP_FLAG_ASSERT_EQ(kUnicode, UNICODE_ESCAPES);
|
||||
#undef REGEXP_FLAG_ASSERT_EQ
|
||||
|
||||
v8::RegExp::Flags v8::RegExp::GetFlags() const {
|
||||
|
@ -1228,31 +1228,16 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Map::EnsureDescriptorSlack(initial_map, 5);
|
||||
|
||||
{
|
||||
// ECMA-262, section 15.10.7.1.
|
||||
DataDescriptor field(factory->source_string(),
|
||||
// ES6 21.2.3.2.1
|
||||
DataDescriptor field(factory->regexp_source_symbol(),
|
||||
JSRegExp::kSourceFieldIndex, final,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
// ECMA-262, section 15.10.7.2.
|
||||
DataDescriptor field(factory->global_string(),
|
||||
JSRegExp::kGlobalFieldIndex, final,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
// ECMA-262, section 15.10.7.3.
|
||||
DataDescriptor field(factory->ignore_case_string(),
|
||||
JSRegExp::kIgnoreCaseFieldIndex, final,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
// ECMA-262, section 15.10.7.4.
|
||||
DataDescriptor field(factory->multiline_string(),
|
||||
JSRegExp::kMultilineFieldIndex, final,
|
||||
Representation::Tagged());
|
||||
DataDescriptor field(factory->regexp_flags_symbol(),
|
||||
JSRegExp::kFlagsFieldIndex, final,
|
||||
Representation::Smi());
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
@ -2055,8 +2040,6 @@ void Bootstrapper::ExportExperimentalFromRuntime(Isolate* isolate,
|
||||
isolate->factory()->ToBoolean(FLAG), NONE); \
|
||||
}
|
||||
|
||||
INITIALIZE_FLAG(FLAG_harmony_regexps)
|
||||
INITIALIZE_FLAG(FLAG_harmony_unicode_regexps)
|
||||
INITIALIZE_FLAG(FLAG_harmony_tostring)
|
||||
INITIALIZE_FLAG(FLAG_harmony_tolength)
|
||||
|
||||
|
@ -249,7 +249,6 @@ namespace internal {
|
||||
V(Generator_string, "Generator") \
|
||||
V(get_string, "get") \
|
||||
V(global_string, "global") \
|
||||
V(ignore_case_string, "ignoreCase") \
|
||||
V(illegal_access_string, "illegal access") \
|
||||
V(illegal_argument_string, "illegal argument") \
|
||||
V(index_string, "index") \
|
||||
@ -268,7 +267,6 @@ namespace internal {
|
||||
V(Map_string, "Map") \
|
||||
V(minus_infinity_string, "-Infinity") \
|
||||
V(minus_zero_string, "-0") \
|
||||
V(multiline_string, "multiline") \
|
||||
V(name_string, "name") \
|
||||
V(nan_string, "NaN") \
|
||||
V(next_string, "next") \
|
||||
@ -288,7 +286,6 @@ namespace internal {
|
||||
V(source_string, "source") \
|
||||
V(source_url_string, "source_url") \
|
||||
V(stack_string, "stack") \
|
||||
V(sticky_string, "sticky") \
|
||||
V(strict_compare_ic_string, "===") \
|
||||
V(string_string, "string") \
|
||||
V(String_string, "String") \
|
||||
@ -305,7 +302,6 @@ namespace internal {
|
||||
V(uint8x16_string, "uint8x16") \
|
||||
V(Uint8x16_string, "Uint8x16") \
|
||||
V(undefined_string, "undefined") \
|
||||
V(unicode_string, "unicode") \
|
||||
V(valueOf_string, "valueOf") \
|
||||
V(value_string, "value") \
|
||||
V(WeakMap_string, "WeakMap") \
|
||||
@ -349,6 +345,8 @@ namespace internal {
|
||||
V(promise_raw_symbol) \
|
||||
V(promise_status_symbol) \
|
||||
V(promise_value_symbol) \
|
||||
V(regexp_flags_symbol) \
|
||||
V(regexp_source_symbol) \
|
||||
V(sealed_symbol) \
|
||||
V(stack_trace_symbol) \
|
||||
V(string_iterator_iterated_string_symbol) \
|
||||
@ -357,7 +355,6 @@ namespace internal {
|
||||
|
||||
#define PUBLIC_SYMBOL_LIST(V) \
|
||||
V(has_instance_symbol, Symbol.hasInstance) \
|
||||
V(is_regexp_symbol, Symbol.isRegExp) \
|
||||
V(iterator_symbol, Symbol.iterator) \
|
||||
V(match_symbol, Symbol.match) \
|
||||
V(replace_symbol, Symbol.replace) \
|
||||
|
@ -11,6 +11,7 @@
|
||||
// -------------------------------------------------------------------
|
||||
// Imports
|
||||
|
||||
var GetRegExpFlagGetter = utils.ImportNow("GetRegExpFlagGetter");
|
||||
var GlobalRegExp = global.RegExp;
|
||||
var MakeTypeError;
|
||||
|
||||
@ -24,7 +25,8 @@ utils.Import(function(from) {
|
||||
// + https://bugs.ecmascript.org/show_bug.cgi?id=3423
|
||||
function RegExpGetFlags() {
|
||||
if (!IS_SPEC_OBJECT(this)) {
|
||||
throw MakeTypeError(kFlagsGetterNonObject, TO_STRING(this));
|
||||
throw MakeTypeError(
|
||||
kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this));
|
||||
}
|
||||
var result = '';
|
||||
if (this.global) result += 'g';
|
||||
@ -39,4 +41,11 @@ function RegExpGetFlags() {
|
||||
RegExpGetFlags, null, DONT_ENUM);
|
||||
%SetNativeFlag(RegExpGetFlags);
|
||||
|
||||
%DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "sticky",
|
||||
GetRegExpFlagGetter("RegExp.prototype.sticky", REGEXP_STICKY_MASK),
|
||||
DONT_ENUM);
|
||||
|
||||
%DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "unicode",
|
||||
GetRegExpFlagGetter("RegExp.prototype.unicode", REGEXP_UNICODE_MASK),
|
||||
DONT_ENUM);
|
||||
})
|
||||
|
@ -178,6 +178,20 @@ python macro CHAR_CODE(str) = ord(str[1]);
|
||||
define REGEXP_NUMBER_OF_CAPTURES = 0;
|
||||
define REGEXP_FIRST_CAPTURE = 3;
|
||||
|
||||
# Constants and macros for internal slot access.
|
||||
define REGEXP_GLOBAL_MASK = 1;
|
||||
define REGEXP_IGNORE_CASE_MASK = 2;
|
||||
define REGEXP_MULTILINE_MASK = 4;
|
||||
define REGEXP_STICKY_MASK = 8;
|
||||
define REGEXP_UNICODE_MASK = 16;
|
||||
|
||||
macro REGEXP_GLOBAL(regexp) = (regexp[regExpFlagsSymbol] & REGEXP_GLOBAL_MASK);
|
||||
macro REGEXP_IGNORE_CASE(regexp) = (regexp[regExpFlagsSymbol] & REGEXP_IGNORE_CASE_MASK);
|
||||
macro REGEXP_MULTILINE(regexp) = (regexp[regExpFlagsSymbol] & REGEXP_MULTILINE_MASK);
|
||||
macro REGEXP_STICKY(regexp) = (regexp[regExpFlagsSymbol] & REGEXP_STICKY_MASK);
|
||||
macro REGEXP_UNICODE(regexp) = (regexp[regExpFlagsSymbol] & REGEXP_UNICODE_MASK);
|
||||
macro REGEXP_SOURCE(regexp) = (regexp[regExpSourceSymbol]);
|
||||
|
||||
# We can't put macros in macros so we use constants here.
|
||||
# REGEXP_NUMBER_OF_CAPTURES
|
||||
macro NUMBER_OF_CAPTURES(array) = ((array)[0]);
|
||||
|
@ -175,6 +175,7 @@ function PostNatives(utils) {
|
||||
"FunctionSourceString",
|
||||
"GetIterator",
|
||||
"GetMethod",
|
||||
"GetRegExpFlagGetter",
|
||||
"InnerArrayEvery",
|
||||
"InnerArrayFilter",
|
||||
"InnerArrayForEach",
|
||||
|
103
src/js/regexp.js
103
src/js/regexp.js
@ -9,18 +9,16 @@
|
||||
// -------------------------------------------------------------------
|
||||
// Imports
|
||||
|
||||
var FLAG_harmony_regexps;
|
||||
var FLAG_harmony_tolength;
|
||||
var FLAG_harmony_unicode_regexps;
|
||||
var GlobalObject = global.Object;
|
||||
var GlobalRegExp = global.RegExp;
|
||||
var InternalPackedArray = utils.InternalPackedArray;
|
||||
var MakeTypeError;
|
||||
var regExpFlagsSymbol = utils.ImportNow("regexp_flags_symbol");
|
||||
var regExpSourceSymbol = utils.ImportNow("regexp_source_symbol");
|
||||
|
||||
utils.ImportFromExperimental(function(from) {
|
||||
FLAG_harmony_regexps = from.FLAG_harmony_regexps;
|
||||
FLAG_harmony_tolength = from.FLAG_harmony_tolength;
|
||||
FLAG_harmony_unicode_regexps = from.FLAG_harmony_unicode_regexps;
|
||||
});
|
||||
|
||||
utils.Import(function(from) {
|
||||
@ -51,14 +49,12 @@ function DoConstructRegExp(object, pattern, flags) {
|
||||
// RegExp : Called as constructor; see ECMA-262, section 15.10.4.
|
||||
if (IS_REGEXP(pattern)) {
|
||||
if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags);
|
||||
flags = (pattern.global ? 'g' : '')
|
||||
+ (pattern.ignoreCase ? 'i' : '')
|
||||
+ (pattern.multiline ? 'm' : '');
|
||||
if (FLAG_harmony_unicode_regexps)
|
||||
flags += (pattern.unicode ? 'u' : '');
|
||||
if (FLAG_harmony_regexps)
|
||||
flags += (pattern.sticky ? 'y' : '');
|
||||
pattern = pattern.source;
|
||||
flags = (REGEXP_GLOBAL(pattern) ? 'g' : '')
|
||||
+ (REGEXP_IGNORE_CASE(pattern) ? 'i' : '')
|
||||
+ (REGEXP_MULTILINE(pattern) ? 'm' : '')
|
||||
+ (REGEXP_UNICODE(pattern) ? 'u' : '')
|
||||
+ (REGEXP_STICKY(pattern) ? 'y' : '');
|
||||
pattern = REGEXP_SOURCE(pattern);
|
||||
}
|
||||
|
||||
pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern);
|
||||
@ -142,9 +138,7 @@ function RegExpExecNoTests(regexp, string, start) {
|
||||
var matchInfo = %_RegExpExec(regexp, string, start, RegExpLastMatchInfo);
|
||||
if (matchInfo !== null) {
|
||||
// ES6 21.2.5.2.2 step 18.
|
||||
if (FLAG_harmony_regexps && regexp.sticky) {
|
||||
regexp.lastIndex = matchInfo[CAPTURE1];
|
||||
}
|
||||
if (REGEXP_STICKY(regexp)) regexp.lastIndex = matchInfo[CAPTURE1];
|
||||
RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string);
|
||||
}
|
||||
regexp.lastIndex = 0;
|
||||
@ -165,7 +159,7 @@ function RegExpExecJS(string) {
|
||||
// algorithm, step 4) even if the value is discarded for non-global RegExps.
|
||||
var i = TO_LENGTH_OR_INTEGER(lastIndex);
|
||||
|
||||
var updateLastIndex = this.global || (FLAG_harmony_regexps && this.sticky);
|
||||
var updateLastIndex = REGEXP_GLOBAL(this) || REGEXP_STICKY(this);
|
||||
if (updateLastIndex) {
|
||||
if (i < 0 || i > string.length) {
|
||||
this.lastIndex = 0;
|
||||
@ -212,7 +206,7 @@ function RegExpTest(string) {
|
||||
// algorithm, step 4) even if the value is discarded for non-global RegExps.
|
||||
var i = TO_LENGTH_OR_INTEGER(lastIndex);
|
||||
|
||||
if (this.global || (FLAG_harmony_regexps && this.sticky)) {
|
||||
if (REGEXP_GLOBAL(this) || REGEXP_STICKY(this)) {
|
||||
if (i < 0 || i > string.length) {
|
||||
this.lastIndex = 0;
|
||||
return false;
|
||||
@ -231,10 +225,11 @@ function RegExpTest(string) {
|
||||
// checks whether this.source starts with '.*' and that the third char is
|
||||
// not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560
|
||||
var regexp = this;
|
||||
if (regexp.source.length >= 3 &&
|
||||
%_StringCharCodeAt(regexp.source, 0) == 46 && // '.'
|
||||
%_StringCharCodeAt(regexp.source, 1) == 42 && // '*'
|
||||
%_StringCharCodeAt(regexp.source, 2) != 63) { // '?'
|
||||
var source = REGEXP_SOURCE(regexp);
|
||||
if (regexp.length >= 3 &&
|
||||
%_StringCharCodeAt(regexp, 0) == 46 && // '.'
|
||||
%_StringCharCodeAt(regexp, 1) == 42 && // '*'
|
||||
%_StringCharCodeAt(regexp, 2) != 63) { // '?'
|
||||
regexp = TrimRegExp(regexp);
|
||||
}
|
||||
// matchIndices is either null or the RegExpLastMatchInfo array.
|
||||
@ -251,9 +246,10 @@ function TrimRegExp(regexp) {
|
||||
if (!%_ObjectEquals(regexp_key, regexp)) {
|
||||
regexp_key = regexp;
|
||||
regexp_val =
|
||||
new GlobalRegExp(%_SubString(regexp.source, 2, regexp.source.length),
|
||||
(regexp.ignoreCase ? regexp.multiline ? "im" : "i"
|
||||
: regexp.multiline ? "m" : ""));
|
||||
new GlobalRegExp(
|
||||
%_SubString(REGEXP_SOURCE(regexp), 2, REGEXP_SOURCE(regexp).length),
|
||||
(REGEXP_IGNORE_CASE(regexp) ? REGEXP_MULTILINE(regexp) ? "im" : "i"
|
||||
: REGEXP_MULTILINE(regexp) ? "m" : ""));
|
||||
}
|
||||
return regexp_val;
|
||||
}
|
||||
@ -264,12 +260,12 @@ function RegExpToString() {
|
||||
throw MakeTypeError(kIncompatibleMethodReceiver,
|
||||
'RegExp.prototype.toString', this);
|
||||
}
|
||||
var result = '/' + this.source + '/';
|
||||
if (this.global) result += 'g';
|
||||
if (this.ignoreCase) result += 'i';
|
||||
if (this.multiline) result += 'm';
|
||||
if (FLAG_harmony_unicode_regexps && this.unicode) result += 'u';
|
||||
if (FLAG_harmony_regexps && this.sticky) result += 'y';
|
||||
var result = '/' + REGEXP_SOURCE(this) + '/';
|
||||
if (REGEXP_GLOBAL(this)) result += 'g';
|
||||
if (REGEXP_IGNORE_CASE(this)) result += 'i';
|
||||
if (REGEXP_MULTILINE(this)) result += 'm';
|
||||
if (REGEXP_UNICODE(this)) result += 'u';
|
||||
if (REGEXP_STICKY(this)) result += 'y';
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -334,6 +330,40 @@ function RegExpMakeCaptureGetter(n) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// ES6 21.2.5.4, 21.2.5.5, 21.2.5.7, 21.2.5.12, 21.2.5.15.
|
||||
function GetRegExpFlagGetter(name, mask) {
|
||||
var getter = function() {
|
||||
if (!IS_SPEC_OBJECT(this)) {
|
||||
throw MakeTypeError(kRegExpNonObject, name, TO_STRING(this));
|
||||
}
|
||||
var flags = this[regExpFlagsSymbol];
|
||||
if (IS_UNDEFINED(flags)) {
|
||||
throw MakeTypeError(kRegExpNonRegExp, TO_STRING(this));
|
||||
}
|
||||
return !!(flags & mask);
|
||||
};
|
||||
%FunctionSetName(getter, name);
|
||||
%SetNativeFlag(getter);
|
||||
return getter;
|
||||
}
|
||||
|
||||
|
||||
// ES6 21.2.5.10.
|
||||
function RegExpGetSource() {
|
||||
if (!IS_SPEC_OBJECT(this)) {
|
||||
throw MakeTypeError(kRegExpNonObject, "RegExp.prototype.source",
|
||||
TO_STRING(this));
|
||||
}
|
||||
var source = this[regExpSourceSymbol];
|
||||
if (IS_UNDEFINED(source)) {
|
||||
throw MakeTypeError(kRegExpNonRegExp, TO_STRING(this));
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
%SetNativeFlag(RegExpGetSource);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
%FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
|
||||
@ -349,6 +379,18 @@ utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
|
||||
"compile", RegExpCompileJS
|
||||
]);
|
||||
|
||||
%DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "global",
|
||||
GetRegExpFlagGetter("RegExp.prototype.global", REGEXP_GLOBAL_MASK),
|
||||
DONT_ENUM);
|
||||
%DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "ignoreCase",
|
||||
GetRegExpFlagGetter("RegExp.prototype.ignoreCase", REGEXP_IGNORE_CASE_MASK),
|
||||
DONT_ENUM);
|
||||
%DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "multiline",
|
||||
GetRegExpFlagGetter("RegExp.prototype.multiline", REGEXP_MULTILINE_MASK),
|
||||
DONT_ENUM);
|
||||
%DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "source",
|
||||
RegExpGetSource, DONT_ENUM);
|
||||
|
||||
// The length of compile is 1 in SpiderMonkey.
|
||||
%FunctionSetLength(GlobalRegExp.prototype.compile, 1);
|
||||
|
||||
@ -422,6 +464,7 @@ for (var i = 1; i < 10; ++i) {
|
||||
// Exports
|
||||
|
||||
utils.Export(function(to) {
|
||||
to.GetRegExpFlagGetter = GetRegExpFlagGetter;
|
||||
to.RegExpExec = DoRegExpExec;
|
||||
to.RegExpExecNoTests = RegExpExecNoTests;
|
||||
to.RegExpLastMatchInfo = RegExpLastMatchInfo;
|
||||
|
@ -19,6 +19,7 @@ var MakeRangeError;
|
||||
var MakeTypeError;
|
||||
var RegExpExec;
|
||||
var RegExpExecNoTests;
|
||||
var regExpFlagsSymbol = utils.ImportNow("regexp_flags_symbol");
|
||||
var RegExpLastMatchInfo;
|
||||
|
||||
utils.Import(function(from) {
|
||||
@ -155,7 +156,7 @@ function StringMatchJS(regexp) {
|
||||
|
||||
var subject = TO_STRING(this);
|
||||
if (IS_REGEXP(regexp)) {
|
||||
if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
|
||||
if (!REGEXP_GLOBAL(regexp)) return RegExpExecNoTests(regexp, subject, 0);
|
||||
var result = %StringMatch(subject, regexp, RegExpLastMatchInfo);
|
||||
regexp.lastIndex = 0;
|
||||
return result;
|
||||
@ -225,7 +226,7 @@ function StringReplace(search, replace) {
|
||||
if (!IS_CALLABLE(replace)) {
|
||||
replace = TO_STRING(replace);
|
||||
|
||||
if (!search.global) {
|
||||
if (!REGEXP_GLOBAL(search)) {
|
||||
// Non-global regexp search, string replace.
|
||||
var match = RegExpExec(search, subject, 0);
|
||||
if (match == null) {
|
||||
@ -247,7 +248,7 @@ function StringReplace(search, replace) {
|
||||
subject, search, replace, RegExpLastMatchInfo);
|
||||
}
|
||||
|
||||
if (search.global) {
|
||||
if (REGEXP_GLOBAL(search)) {
|
||||
// Global regexp search, function replace.
|
||||
return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ var GlobalSymbol = global.Symbol;
|
||||
var hasInstanceSymbol = utils.ImportNow("has_instance_symbol");
|
||||
var isConcatSpreadableSymbol =
|
||||
utils.ImportNow("is_concat_spreadable_symbol");
|
||||
var isRegExpSymbol = utils.ImportNow("is_regexp_symbol");
|
||||
var iteratorSymbol = utils.ImportNow("iterator_symbol");
|
||||
var MakeTypeError;
|
||||
var ObjectGetOwnPropertyKeys;
|
||||
@ -94,7 +93,6 @@ utils.InstallConstants(GlobalSymbol, [
|
||||
// TODO(rossberg): expose when implemented.
|
||||
// "hasInstance", hasInstanceSymbol,
|
||||
// "isConcatSpreadable", isConcatSpreadableSymbol,
|
||||
// "isRegExp", isRegExpSymbol,
|
||||
"iterator", iteratorSymbol,
|
||||
// TODO(yangguo): expose when implemented.
|
||||
// "match", matchSymbol,
|
||||
|
@ -117,8 +117,6 @@ class CallSite {
|
||||
"Class extends value % is not a function or null") \
|
||||
T(FirstArgumentNotRegExp, \
|
||||
"First argument to % must not be a regular expression") \
|
||||
T(FlagsGetterNonObject, \
|
||||
"RegExp.prototype.flags getter called on non-object %") \
|
||||
T(FunctionBind, "Bind must be called on a function") \
|
||||
T(GeneratorRunning, "Generator is already running") \
|
||||
T(IllegalInvocation, "Illegal invocation") \
|
||||
@ -203,6 +201,8 @@ class CallSite {
|
||||
T(ReduceNoInitial, "Reduce of empty array with no initial value") \
|
||||
T(RegExpFlags, \
|
||||
"Cannot supply flags when constructing one RegExp from another") \
|
||||
T(RegExpNonObject, "% getter called on non-object %") \
|
||||
T(RegExpNonRegExp, "% is not an RegExp object") \
|
||||
T(ReinitializeIntl, "Trying to re-initialize % object.") \
|
||||
T(ResolvedOptionsCalledOnNonObject, \
|
||||
"resolvedOptions method called on a non-object or on a object that is " \
|
||||
|
@ -7781,11 +7781,9 @@ class JSRegExp: public JSObject {
|
||||
|
||||
// In-object fields.
|
||||
static const int kSourceFieldIndex = 0;
|
||||
static const int kGlobalFieldIndex = 1;
|
||||
static const int kIgnoreCaseFieldIndex = 2;
|
||||
static const int kMultilineFieldIndex = 3;
|
||||
static const int kLastIndexFieldIndex = 4;
|
||||
static const int kInObjectFieldCount = 5;
|
||||
static const int kFlagsFieldIndex = 1;
|
||||
static const int kLastIndexFieldIndex = 2;
|
||||
static const int kInObjectFieldCount = 3;
|
||||
|
||||
// The uninitialized value for a regexp code object.
|
||||
static const int kUninitializedValue = -1;
|
||||
|
@ -924,26 +924,14 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, escaped_source,
|
||||
EscapeRegExpSource(isolate, source));
|
||||
|
||||
Handle<Object> global = factory->ToBoolean(flags.is_global());
|
||||
Handle<Object> ignore_case = factory->ToBoolean(flags.is_ignore_case());
|
||||
Handle<Object> multiline = factory->ToBoolean(flags.is_multiline());
|
||||
Handle<Object> sticky = factory->ToBoolean(flags.is_sticky());
|
||||
Handle<Object> unicode = factory->ToBoolean(flags.is_unicode());
|
||||
|
||||
Map* map = regexp->map();
|
||||
Object* constructor = map->GetConstructor();
|
||||
if (!FLAG_harmony_regexps && !FLAG_harmony_unicode_regexps &&
|
||||
constructor->IsJSFunction() &&
|
||||
if (constructor->IsJSFunction() &&
|
||||
JSFunction::cast(constructor)->initial_map() == map) {
|
||||
// If we still have the original map, set in-object properties directly.
|
||||
regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *escaped_source);
|
||||
// Both true and false are immovable immortal objects so no need for write
|
||||
// barrier.
|
||||
regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, *global,
|
||||
SKIP_WRITE_BARRIER);
|
||||
regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, *ignore_case,
|
||||
SKIP_WRITE_BARRIER);
|
||||
regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, *multiline,
|
||||
regexp->InObjectPropertyAtPut(JSRegExp::kFlagsFieldIndex,
|
||||
Smi::FromInt(flags.value()),
|
||||
SKIP_WRITE_BARRIER);
|
||||
regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
|
||||
Smi::FromInt(0), SKIP_WRITE_BARRIER);
|
||||
@ -958,22 +946,13 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
|
||||
PropertyAttributes writable =
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
|
||||
Handle<Object> zero(Smi::FromInt(0), isolate);
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->source_string(),
|
||||
escaped_source, final).Check();
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->global_string(),
|
||||
global, final).Check();
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
regexp, factory->ignore_case_string(), ignore_case, final).Check();
|
||||
regexp, factory->regexp_source_symbol(), escaped_source, final)
|
||||
.Check();
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
regexp, factory->multiline_string(), multiline, final).Check();
|
||||
if (FLAG_harmony_regexps) {
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->sticky_string(),
|
||||
sticky, final).Check();
|
||||
}
|
||||
if (FLAG_harmony_unicode_regexps) {
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
regexp, factory->unicode_string(), unicode, final).Check();
|
||||
}
|
||||
regexp, factory->regexp_flags_symbol(),
|
||||
Handle<Smi>(Smi::FromInt(flags.value()), isolate), final)
|
||||
.Check();
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
regexp, factory->last_index_string(), zero, writable).Check();
|
||||
}
|
||||
|
49
test/mjsunit/es6/regexp-flags.js
Normal file
49
test/mjsunit/es6/regexp-flags.js
Normal file
@ -0,0 +1,49 @@
|
||||
// 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.
|
||||
|
||||
// Flags: --harmony-regexps --harmony-unicode-regexps
|
||||
|
||||
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 do not affect the internal flags.
|
||||
assertEquals(expected, string.replace(r3, "X"));
|
||||
assertEquals(4, get_count);
|
@ -25,19 +25,17 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --expose-debug-as debug --harmony-unicode-regexps
|
||||
// Flags: --expose-debug-as debug --harmony-regexps --harmony-unicode-regexps
|
||||
// Test the mirror object for regular expression values
|
||||
|
||||
var all_attributes = debug.PropertyAttribute.ReadOnly |
|
||||
debug.PropertyAttribute.DontEnum |
|
||||
debug.PropertyAttribute.DontDelete;
|
||||
var expected_attributes = {
|
||||
'source': all_attributes,
|
||||
'global': all_attributes,
|
||||
'ignoreCase': all_attributes,
|
||||
'multiline': all_attributes,
|
||||
'unicode' : all_attributes,
|
||||
'lastIndex': debug.PropertyAttribute.DontEnum | debug.PropertyAttribute.DontDelete
|
||||
var dont_enum = debug.PropertyAttribute.DontEnum;
|
||||
var dont_delete = debug.PropertyAttribute.DontDelete;
|
||||
var expected_prototype_attributes = {
|
||||
'source': dont_enum,
|
||||
'global': dont_enum,
|
||||
'ignoreCase': dont_enum,
|
||||
'multiline': dont_enum,
|
||||
'unicode' : dont_enum,
|
||||
};
|
||||
|
||||
function MirrorRefCache(json_refs) {
|
||||
@ -70,9 +68,12 @@ function testRegExpMirror(r) {
|
||||
assertTrue(mirror.isRegExp());
|
||||
assertEquals('regexp', mirror.type());
|
||||
assertFalse(mirror.isPrimitive());
|
||||
for (var p in expected_attributes) {
|
||||
assertEquals(expected_attributes[p],
|
||||
mirror.property(p).attributes(),
|
||||
assertEquals(dont_enum | dont_delete,
|
||||
mirror.property('lastIndex').attributes());
|
||||
var proto_mirror = mirror.protoObject();
|
||||
for (var p in expected_prototype_attributes) {
|
||||
assertEquals(expected_prototype_attributes[p],
|
||||
proto_mirror.property(p).attributes(),
|
||||
p + ' attributes');
|
||||
}
|
||||
|
||||
@ -83,24 +84,12 @@ function testRegExpMirror(r) {
|
||||
var fromJSON = eval('(' + json + ')');
|
||||
assertEquals('regexp', fromJSON.type);
|
||||
assertEquals('RegExp', fromJSON.className);
|
||||
for (var p in expected_attributes) {
|
||||
for (var i = 0; i < fromJSON.properties.length; i++) {
|
||||
if (fromJSON.properties[i].name == p) {
|
||||
assertEquals(expected_attributes[p],
|
||||
fromJSON.properties[i].attributes,
|
||||
'Unexpected value for ' + p + ' attributes');
|
||||
assertEquals(mirror.property(p).propertyType(),
|
||||
fromJSON.properties[i].propertyType,
|
||||
'Unexpected value for ' + p + ' propertyType');
|
||||
assertEquals(mirror.property(p).value().handle(),
|
||||
fromJSON.properties[i].ref,
|
||||
'Unexpected handle for ' + p);
|
||||
assertEquals(mirror.property(p).value().value(),
|
||||
refs.lookup(fromJSON.properties[i].ref).value,
|
||||
'Unexpected value for ' + p);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals('lastIndex', fromJSON.properties[0].name);
|
||||
assertEquals(dont_enum | dont_delete, fromJSON.properties[0].attributes);
|
||||
assertEquals(mirror.property('lastIndex').propertyType(),
|
||||
fromJSON.properties[0].propertyType);
|
||||
assertEquals(mirror.property('lastIndex').value().value(),
|
||||
refs.lookup(fromJSON.properties[0].ref).value);
|
||||
}
|
||||
|
||||
|
||||
|
@ -605,23 +605,29 @@ assertEquals(["ts", "li"], log);
|
||||
|
||||
// Check that properties of RegExp have the correct permissions.
|
||||
var re = /x/g;
|
||||
var desc = Object.getOwnPropertyDescriptor(re, "global");
|
||||
assertEquals(true, desc.value);
|
||||
assertEquals(false, desc.configurable);
|
||||
var desc = Object.getOwnPropertyDescriptor(re.__proto__, "global");
|
||||
assertInstanceof(desc.get, Function);
|
||||
assertEquals(true, desc.configurable);
|
||||
assertEquals(false, desc.enumerable);
|
||||
assertEquals(false, desc.writable);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(re.__proto__, "multiline");
|
||||
assertInstanceof(desc.get, Function);
|
||||
assertEquals(true, desc.configurable);
|
||||
assertEquals(false, desc.enumerable);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(re.__proto__, "ignoreCase");
|
||||
assertInstanceof(desc.get, Function);
|
||||
assertEquals(true, desc.configurable);
|
||||
assertEquals(false, desc.enumerable);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(re, "global");
|
||||
assertEquals(undefined, desc);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(re, "multiline");
|
||||
assertEquals(false, desc.value);
|
||||
assertEquals(false, desc.configurable);
|
||||
assertEquals(false, desc.enumerable);
|
||||
assertEquals(false, desc.writable);
|
||||
assertEquals(undefined, desc);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(re, "ignoreCase");
|
||||
assertEquals(false, desc.value);
|
||||
assertEquals(false, desc.configurable);
|
||||
assertEquals(false, desc.enumerable);
|
||||
assertEquals(false, desc.writable);
|
||||
assertEquals(undefined, desc);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(re, "lastIndex");
|
||||
assertEquals(0, desc.value);
|
||||
|
@ -3,8 +3,8 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
__proto__ = /foo/gi;
|
||||
assertEquals("foo", source);
|
||||
assertTrue(global);
|
||||
assertTrue(ignoreCase);
|
||||
assertFalse(multiline);
|
||||
assertThrows(function() { source });
|
||||
assertThrows(function() { global });
|
||||
assertThrows(function() { ignoreCase });
|
||||
assertThrows(function() { multiline });
|
||||
assertEquals(0, lastIndex);
|
||||
|
@ -144,24 +144,6 @@
|
||||
'built-ins/WeakMap/iterator-items-are-not-object-close-iterator': [FAIL],
|
||||
'built-ins/WeakSet/iterator-close-after-add-failure': [FAIL],
|
||||
|
||||
# https://code.google.com/p/v8/issues/detail?id=3715
|
||||
'built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-212': [FAIL],
|
||||
'built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-213': [FAIL],
|
||||
'built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-214': [FAIL],
|
||||
'built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-215': [FAIL],
|
||||
'built-ins/RegExp/prototype/global/15.10.7.2-1': [FAIL],
|
||||
'built-ins/RegExp/prototype/global/15.10.7.2-2': [FAIL],
|
||||
'built-ins/RegExp/prototype/global/S15.10.7.2_A9': [FAIL],
|
||||
'built-ins/RegExp/prototype/ignoreCase/15.10.7.3-1': [FAIL],
|
||||
'built-ins/RegExp/prototype/ignoreCase/15.10.7.3-2': [FAIL],
|
||||
'built-ins/RegExp/prototype/ignoreCase/S15.10.7.3_A9': [FAIL],
|
||||
'built-ins/RegExp/prototype/multiline/15.10.7.4-1': [FAIL],
|
||||
'built-ins/RegExp/prototype/multiline/15.10.7.4-2': [FAIL],
|
||||
'built-ins/RegExp/prototype/multiline/S15.10.7.4_A9': [FAIL],
|
||||
'built-ins/RegExp/prototype/source/15.10.7.1-1': [FAIL],
|
||||
'built-ins/RegExp/prototype/source/15.10.7.1-2': [FAIL],
|
||||
'built-ins/RegExp/prototype/source/S15.10.7.1_A9': [FAIL],
|
||||
|
||||
# https://code.google.com/p/v8/issues/detail?id=4243
|
||||
'built-ins/Promise/race/S25.4.4.3_A3.1_T2': [FAIL],
|
||||
'built-ins/Promise/reject/S25.4.4.4_A3.1_T1': [FAIL],
|
||||
@ -181,16 +163,6 @@
|
||||
'built-ins/RegExp/from-regexp-like-get-ctor-err': [FAIL],
|
||||
'built-ins/RegExp/call_with_regexp_not_same_constructor': [FAIL],
|
||||
|
||||
# https://code.google.com/p/v8/issues/detail?id=4528
|
||||
'built-ins/RegExp/prototype/source/S15.10.7.1_A8': [FAIL],
|
||||
'built-ins/RegExp/prototype/source/S15.10.7.1_A10': [FAIL],
|
||||
'built-ins/RegExp/prototype/global/S15.10.7.2_A8': [FAIL],
|
||||
'built-ins/RegExp/prototype/global/S15.10.7.2_A10': [FAIL],
|
||||
'built-ins/RegExp/prototype/ignoreCase/S15.10.7.3_A8': [FAIL],
|
||||
'built-ins/RegExp/prototype/ignoreCase/S15.10.7.3_A10': [FAIL],
|
||||
'built-ins/RegExp/prototype/multiline/S15.10.7.4_A8': [FAIL],
|
||||
'built-ins/RegExp/prototype/multiline/S15.10.7.4_A10': [FAIL],
|
||||
|
||||
# https://code.google.com/p/v8/issues/detail?id=4006
|
||||
'built-ins/String/prototype/S15.5.4_A1': [FAIL],
|
||||
'built-ins/String/prototype/S15.5.4_A2': [FAIL],
|
||||
@ -380,11 +352,7 @@
|
||||
'built-ins/RegExp/prototype/test/u-captured-value': [FAIL],
|
||||
'built-ins/RegExp/prototype/test/u-lastindex-adv': [FAIL],
|
||||
'built-ins/RegExp/prototype/test/u-lastindex-value': [FAIL],
|
||||
'built-ins/RegExp/prototype/unicode/length': [FAIL],
|
||||
'built-ins/RegExp/prototype/unicode/name': [FAIL],
|
||||
'built-ins/RegExp/prototype/unicode/prop-desc': [FAIL],
|
||||
'built-ins/RegExp/prototype/unicode/this-invald-obj': [FAIL],
|
||||
'built-ins/RegExp/prototype/unicode/this-non-obj': [FAIL],
|
||||
'built-ins/RegExp/prototype/unicode/this-regexp': [FAIL],
|
||||
'built-ins/RegExp/unicode_identity_escape': [FAIL],
|
||||
'language/literals/regexp/u-unicode-esc': [FAIL],
|
||||
@ -395,9 +363,6 @@
|
||||
# https://code.google.com/p/v8/issues/detail?id=4342
|
||||
'built-ins/RegExp/prototype/exec/get-sticky-coerce': [FAIL],
|
||||
'built-ins/RegExp/prototype/exec/get-sticky-err': [FAIL],
|
||||
'built-ins/RegExp/prototype/sticky/prop-desc': [FAIL],
|
||||
'built-ins/RegExp/prototype/sticky/this-invalid-obj': [FAIL],
|
||||
'built-ins/RegExp/prototype/sticky/this-non-obj': [FAIL],
|
||||
'built-ins/RegExp/prototype/test/get-sticky-coerce': [FAIL],
|
||||
'built-ins/RegExp/prototype/test/get-sticky-err': [FAIL],
|
||||
'built-ins/RegExp/valid-flags-y': [FAIL],
|
||||
@ -441,7 +406,6 @@
|
||||
|
||||
# https://code.google.com/p/v8/issues/detail?id=4346
|
||||
'built-ins/RegExp/prototype/flags/name': [FAIL],
|
||||
'built-ins/RegExp/prototype/flags/y-attr-err': [FAIL],
|
||||
'built-ins/RegExp/prototype/flags/u': [FAIL],
|
||||
|
||||
# https://code.google.com/p/v8/issues/detail?id=4347
|
||||
|
@ -28,7 +28,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
|
||||
|
||||
PASS RegExp('/').source is "\\/"
|
||||
PASS RegExp('').source is "(?:)"
|
||||
FAIL RegExp.prototype.source should be (?:) (of type string). Was undefined (of type undefined).
|
||||
FAIL RegExp.prototype.source should be (?:). Threw exception TypeError: Method RegExp.prototype.toString called on incompatible receiver [object Object]
|
||||
PASS RegExp('/').toString() is "/\\//"
|
||||
PASS RegExp('').toString() is "/(?:)/"
|
||||
FAIL RegExp.prototype.toString() should be /(?:)/. Threw exception TypeError: Method RegExp.prototype.toString called on incompatible receiver [object Object]
|
||||
@ -58,3 +58,4 @@ PASS successfullyParsed is true
|
||||
|
||||
TEST COMPLETE
|
||||
|
||||
|
||||
|
@ -348,8 +348,8 @@ def BuildFilterChain(macro_filename, message_template_file):
|
||||
|
||||
if macro_filename:
|
||||
(consts, macros) = ReadMacros(ReadFile(macro_filename))
|
||||
filter_chain.append(lambda l: ExpandConstants(l, consts))
|
||||
filter_chain.append(lambda l: ExpandMacros(l, macros))
|
||||
filter_chain.append(lambda l: ExpandConstants(l, consts))
|
||||
|
||||
if message_template_file:
|
||||
message_templates = ReadMessageTemplates(ReadFile(message_template_file))
|
||||
|
Loading…
Reference in New Issue
Block a user