mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 03:35:33 +00:00
Backed out changeset 537d40121b6d (bug 887016)
This commit is contained in:
parent
0be2d6fd80
commit
ab25ebfb49
@ -644,7 +644,6 @@ const JSFunctionSpec js::regexp_methods[] = {
|
|||||||
JS_FN("compile", regexp_compile, 2,0),
|
JS_FN("compile", regexp_compile, 2,0),
|
||||||
JS_SELF_HOSTED_FN("exec", "RegExp_prototype_Exec", 1,0),
|
JS_SELF_HOSTED_FN("exec", "RegExp_prototype_Exec", 1,0),
|
||||||
JS_SELF_HOSTED_FN("test", "RegExpTest" , 1,0),
|
JS_SELF_HOSTED_FN("test", "RegExpTest" , 1,0),
|
||||||
JS_SELF_HOSTED_SYM_FN(match, "RegExpMatch", 1,0),
|
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,97 +56,6 @@ function RegExpToString()
|
|||||||
}
|
}
|
||||||
_SetCanonicalName(RegExpToString, "toString");
|
_SetCanonicalName(RegExpToString, "toString");
|
||||||
|
|
||||||
// ES 2016 draft Mar 25, 2016 21.2.5.2.3.
|
|
||||||
function AdvanceStringIndex(S, index) {
|
|
||||||
// Step 1.
|
|
||||||
assert(typeof S === "string", "Expected string as 1st argument");
|
|
||||||
|
|
||||||
// Step 2.
|
|
||||||
assert(index >= 0 && index <= MAX_NUMERIC_INDEX, "Expected integer as 2nd argument");
|
|
||||||
|
|
||||||
// Step 3 (skipped).
|
|
||||||
|
|
||||||
// Step 4 (skipped).
|
|
||||||
|
|
||||||
// Step 5.
|
|
||||||
var length = S.length;
|
|
||||||
|
|
||||||
// Step 6.
|
|
||||||
if (index + 1 >= length)
|
|
||||||
return index + 1;
|
|
||||||
|
|
||||||
// Step 7.
|
|
||||||
var first = callFunction(std_String_charCodeAt, S, index);
|
|
||||||
|
|
||||||
// Step 8.
|
|
||||||
if (first < 0xD800 || first > 0xDBFF)
|
|
||||||
return index + 1;
|
|
||||||
|
|
||||||
// Step 9.
|
|
||||||
var second = callFunction(std_String_charCodeAt, S, index + 1);
|
|
||||||
|
|
||||||
// Step 10.
|
|
||||||
if (second < 0xDC00 || second > 0xDFFF)
|
|
||||||
return index + 1;
|
|
||||||
|
|
||||||
// Step 11.
|
|
||||||
return index + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ES 2016 draft Mar 25, 2016 21.2.5.6.
|
|
||||||
function RegExpMatch(string) {
|
|
||||||
// Step 1.
|
|
||||||
var rx = this;
|
|
||||||
|
|
||||||
// Step 2.
|
|
||||||
if (!IsObject(rx))
|
|
||||||
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, rx === null ? "null" : typeof rx);
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
var S = ToString(string);
|
|
||||||
|
|
||||||
// Steps 4-5.
|
|
||||||
if (!rx.global)
|
|
||||||
return RegExpExec(rx, S, false);
|
|
||||||
|
|
||||||
// Step 6.a.
|
|
||||||
var fullUnicode = !!rx.unicode;
|
|
||||||
|
|
||||||
// Step 6.b.
|
|
||||||
rx.lastIndex = 0;
|
|
||||||
|
|
||||||
// Step 6.c.
|
|
||||||
var A = [];
|
|
||||||
|
|
||||||
// Step 6.d.
|
|
||||||
var n = 0;
|
|
||||||
|
|
||||||
// Step 6.e.
|
|
||||||
while (true) {
|
|
||||||
// Step 6.e.i.
|
|
||||||
var result = RegExpExec(rx, S, false);
|
|
||||||
|
|
||||||
// Step 6.e.ii.
|
|
||||||
if (result === null)
|
|
||||||
return (n === 0) ? null : A;
|
|
||||||
|
|
||||||
// Step 6.e.iii.1.
|
|
||||||
var matchStr = ToString(result[0]);
|
|
||||||
|
|
||||||
// Step 6.e.iii.2.
|
|
||||||
_DefineDataProperty(A, n, matchStr);
|
|
||||||
|
|
||||||
// Step 6.e.iii.4.
|
|
||||||
if (matchStr === "") {
|
|
||||||
var lastIndex = ToLength(rx.lastIndex);
|
|
||||||
rx.lastIndex = fullUnicode ? AdvanceStringIndex(S, lastIndex) : lastIndex + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 6.e.iii.5.
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ES6 21.2.5.2.
|
// ES6 21.2.5.2.
|
||||||
// NOTE: This is not RegExpExec (21.2.5.2.1).
|
// NOTE: This is not RegExpExec (21.2.5.2.1).
|
||||||
function RegExp_prototype_Exec(string) {
|
function RegExp_prototype_Exec(string) {
|
||||||
|
@ -4,73 +4,6 @@
|
|||||||
|
|
||||||
/*global intl_Collator: false, */
|
/*global intl_Collator: false, */
|
||||||
|
|
||||||
function StringProtoHasNoMatch() {
|
|
||||||
var ObjectProto = GetBuiltinPrototype("Object");
|
|
||||||
var StringProto = GetBuiltinPrototype("String");
|
|
||||||
if (!ObjectHasPrototype(StringProto, ObjectProto))
|
|
||||||
return false;
|
|
||||||
return !(std_match in StringProto);
|
|
||||||
}
|
|
||||||
|
|
||||||
function IsStringMatchOptimizable() {
|
|
||||||
var RegExpProto = GetBuiltinPrototype("RegExp");
|
|
||||||
// If RegExpPrototypeOptimizable succeeds, `exec` and `@@match` are
|
|
||||||
// guaranteed to be data properties.
|
|
||||||
return RegExpPrototypeOptimizable(RegExpProto) &&
|
|
||||||
RegExpProto.exec === RegExp_prototype_Exec &&
|
|
||||||
RegExpProto[std_match] === RegExpMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ES 2016 draft Mar 25, 2016 21.1.3.11.
|
|
||||||
function String_match(regexp) {
|
|
||||||
// Step 1.
|
|
||||||
RequireObjectCoercible(this);
|
|
||||||
|
|
||||||
// Step 2.
|
|
||||||
var isPatternString = (typeof regexp === "string");
|
|
||||||
if (!(isPatternString && StringProtoHasNoMatch()) && regexp !== undefined && regexp !== null) {
|
|
||||||
// Step 2.a.
|
|
||||||
var matcher = GetMethod(regexp, std_match);
|
|
||||||
|
|
||||||
// Step 2.b.
|
|
||||||
if (matcher !== undefined)
|
|
||||||
return callContentFunction(matcher, regexp, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
var S = ToString(this);
|
|
||||||
|
|
||||||
// FIXME: Non-standard flags argument (bug 1108382).
|
|
||||||
var flags = undefined;
|
|
||||||
if (arguments.length > 1) {
|
|
||||||
if (IsMatchFlagsArgumentEnabled())
|
|
||||||
flags = arguments[1];
|
|
||||||
WarnOnceAboutFlagsArgument();
|
|
||||||
} else {
|
|
||||||
if (isPatternString && IsStringMatchOptimizable()) {
|
|
||||||
var flatResult = FlatStringMatch(S, regexp);
|
|
||||||
if (flatResult !== undefined)
|
|
||||||
return flatResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4.
|
|
||||||
var rx = RegExpCreate(regexp, flags);
|
|
||||||
|
|
||||||
// Step 5 (optimized case).
|
|
||||||
if (IsStringMatchOptimizable() && !flags)
|
|
||||||
return RegExpMatcher(rx, S, 0, false);
|
|
||||||
|
|
||||||
// Step 5.
|
|
||||||
return callContentFunction(GetMethod(rx, std_match), rx, S);
|
|
||||||
}
|
|
||||||
|
|
||||||
function String_generic_match(thisValue, regexp) {
|
|
||||||
if (thisValue === undefined)
|
|
||||||
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.match');
|
|
||||||
return callFunction(String_match, thisValue, regexp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ES6 Draft Oct 14, 2014 21.1.3.19 */
|
/* ES6 Draft Oct 14, 2014 21.1.3.19 */
|
||||||
function String_substring(start, end) {
|
function String_substring(start, end) {
|
||||||
// Steps 1-3.
|
// Steps 1-3.
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
setJitCompilerOption("ion.warmup.trigger", 4);
|
|
||||||
|
|
||||||
function testBasic() {
|
|
||||||
var f = function() {
|
|
||||||
var result = "abc".match("b");
|
|
||||||
assertEq(result.length, 1);
|
|
||||||
assertEq(result.index, 1);
|
|
||||||
assertEq(result[0], "b");
|
|
||||||
};
|
|
||||||
for (var i = 0; i < 40; i++) {
|
|
||||||
f();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
testBasic();
|
|
||||||
|
|
||||||
function testMod(apply, unapply) {
|
|
||||||
var f = function(applied) {
|
|
||||||
var result = "abc".match("b");
|
|
||||||
assertEq(result.length, 1);
|
|
||||||
if (applied) {
|
|
||||||
assertEq(result[0], "mod");
|
|
||||||
} else {
|
|
||||||
assertEq(result.index, 1);
|
|
||||||
assertEq(result[0], "b");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var applied = false;
|
|
||||||
for (var i = 0; i < 120; i++) {
|
|
||||||
f(applied);
|
|
||||||
if (i == 40) {
|
|
||||||
apply();
|
|
||||||
applied = true;
|
|
||||||
}
|
|
||||||
if (i == 80) {
|
|
||||||
unapply();
|
|
||||||
applied = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
testMod(() => {
|
|
||||||
String.prototype[Symbol.match] = () => ["mod"];
|
|
||||||
}, () => {
|
|
||||||
delete String.prototype[Symbol.match];
|
|
||||||
});
|
|
||||||
testMod(() => {
|
|
||||||
Object.prototype[Symbol.match] = () => ["mod"];
|
|
||||||
}, () => {
|
|
||||||
delete Object.prototype[Symbol.match];
|
|
||||||
});
|
|
||||||
|
|
||||||
testMod(() => {
|
|
||||||
Object.setPrototypeOf(String.prototype, {
|
|
||||||
[Symbol.match]: () => ["mod"]
|
|
||||||
});
|
|
||||||
}, () => {
|
|
||||||
Object.setPrototypeOf(String.prototype, Object.prototype);
|
|
||||||
});
|
|
||||||
|
|
||||||
var orig_exec = RegExp.prototype.exec;
|
|
||||||
testMod(() => {
|
|
||||||
RegExp.prototype.exec = () => ["mod"];
|
|
||||||
}, () => {
|
|
||||||
RegExp.prototype.exec = orig_exec;
|
|
||||||
});
|
|
||||||
|
|
||||||
var orig_match = RegExp.prototype[Symbol.match];
|
|
||||||
testMod(() => {
|
|
||||||
RegExp.prototype[Symbol.match] = () => ["mod"];
|
|
||||||
}, () => {
|
|
||||||
RegExp.prototype[Symbol.match] = orig_match;
|
|
||||||
});
|
|
||||||
|
|
||||||
var observed = false;
|
|
||||||
function testObserved(apply, unapply) {
|
|
||||||
var f = function(applied) {
|
|
||||||
observed = false;
|
|
||||||
var result = "abc".match("b."); // Use meta char to avoid flat match.
|
|
||||||
assertEq(result.length, 1);
|
|
||||||
assertEq(result.index, 1);
|
|
||||||
assertEq(result[0], "bc");
|
|
||||||
assertEq(observed, applied);
|
|
||||||
};
|
|
||||||
var applied = false;
|
|
||||||
for (var i = 0; i < 120; i++) {
|
|
||||||
f(applied);
|
|
||||||
if (i == 40) {
|
|
||||||
apply();
|
|
||||||
applied = true;
|
|
||||||
}
|
|
||||||
if (i == 80) {
|
|
||||||
unapply();
|
|
||||||
applied = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var orig_global = Object.getOwnPropertyDescriptor(RegExp.prototype, "global");
|
|
||||||
testObserved(() => {
|
|
||||||
Object.defineProperty(RegExp.prototype, "global", {
|
|
||||||
get: function() {
|
|
||||||
observed = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, () => {
|
|
||||||
Object.defineProperty(RegExp.prototype, "global", orig_global);
|
|
||||||
});
|
|
||||||
|
|
||||||
var orig_sticky = Object.getOwnPropertyDescriptor(RegExp.prototype, "sticky");
|
|
||||||
testObserved(() => {
|
|
||||||
Object.defineProperty(RegExp.prototype, "sticky", {
|
|
||||||
get: function() {
|
|
||||||
observed = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, () => {
|
|
||||||
Object.defineProperty(RegExp.prototype, "sticky", orig_sticky);
|
|
||||||
});
|
|
@ -2190,6 +2190,7 @@ MustCloneRegExpForCall(MCall* call, uint32_t useIndex)
|
|||||||
if (useIndex == MCall::IndexOfArgument(0) &&
|
if (useIndex == MCall::IndexOfArgument(0) &&
|
||||||
(target->native() == str_split ||
|
(target->native() == str_split ||
|
||||||
target->native() == str_replace ||
|
target->native() == str_replace ||
|
||||||
|
target->native() == str_match ||
|
||||||
target->native() == str_search))
|
target->native() == str_search))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -444,7 +444,6 @@ MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in
|
|||||||
MSG_DEF(JSMSG_BACK_REF_OUT_OF_RANGE, 0, JSEXN_SYNTAXERR, "back reference out of range in regular expression")
|
MSG_DEF(JSMSG_BACK_REF_OUT_OF_RANGE, 0, JSEXN_SYNTAXERR, "back reference out of range in regular expression")
|
||||||
MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class")
|
MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class")
|
||||||
MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
|
MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
|
||||||
MSG_DEF(JSMSG_EXEC_NOT_OBJORNULL, 0, JSEXN_TYPEERR, "RegExp exec method should return object or null")
|
|
||||||
MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression")
|
MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression")
|
||||||
MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group")
|
MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group")
|
||||||
MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression")
|
MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression")
|
||||||
|
347
js/src/jsstr.cpp
347
js/src/jsstr.cpp
@ -2260,6 +2260,32 @@ class MOZ_STACK_CLASS StringRegExpGuard
|
|||||||
|
|
||||||
} /* anonymous namespace */
|
} /* anonymous namespace */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DoMatchLocal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLinearString input,
|
||||||
|
RegExpShared& re)
|
||||||
|
{
|
||||||
|
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||||
|
bool sticky = re.sticky();
|
||||||
|
RegExpRunStatus status = re.execute(cx, input, 0, sticky, &matches, nullptr);
|
||||||
|
if (status == RegExpRunStatus_Error)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (status == RegExpRunStatus_Success_NotFound) {
|
||||||
|
args.rval().setNull();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res->updateFromMatchPairs(cx, input, matches))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RootedValue rval(cx);
|
||||||
|
if (!CreateRegExpMatchResult(cx, input, matches, &rval))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
args.rval().set(rval);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* ES6 21.2.5.2.3. */
|
/* ES6 21.2.5.2.3. */
|
||||||
static size_t
|
static size_t
|
||||||
AdvanceStringIndex(HandleLinearString input, size_t length, size_t index, bool unicode)
|
AdvanceStringIndex(HandleLinearString input, size_t length, size_t index, bool unicode)
|
||||||
@ -2295,6 +2321,199 @@ AdvanceStringIndex(HandleLinearString input, size_t length, size_t index, bool u
|
|||||||
return index + 2;
|
return index + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ES5 15.5.4.10 step 8. */
|
||||||
|
static bool
|
||||||
|
DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLinearString input,
|
||||||
|
StringRegExpGuard& g)
|
||||||
|
{
|
||||||
|
// Step 8a.
|
||||||
|
//
|
||||||
|
// This single zeroing of "lastIndex" covers all "lastIndex" changes in the
|
||||||
|
// rest of String.prototype.match, particularly in steps 8f(i) and
|
||||||
|
// 8f(iii)(2)(a). Here's why.
|
||||||
|
//
|
||||||
|
// The inputs to the calls to RegExp.prototype.exec are a RegExp object
|
||||||
|
// whose .global is true and a string. The only side effect of a call in
|
||||||
|
// these circumstances is that the RegExp's .lastIndex will be modified to
|
||||||
|
// the next starting index after the discovered match (or to 0 if there's
|
||||||
|
// no remaining match). Because .lastIndex is a non-configurable data
|
||||||
|
// property and no script-controllable code executes after step 8a, passing
|
||||||
|
// step 8a implies *every* .lastIndex set succeeds. String.prototype.match
|
||||||
|
// calls RegExp.prototype.exec repeatedly, and the last call doesn't match,
|
||||||
|
// so the final value of .lastIndex is 0: exactly the state after step 8a
|
||||||
|
// succeeds. No spec step lets script observe intermediate .lastIndex
|
||||||
|
// values.
|
||||||
|
//
|
||||||
|
// The arrays returned by RegExp.prototype.exec always have a string at
|
||||||
|
// index 0, for which [[Get]]s have no side effects.
|
||||||
|
//
|
||||||
|
// Filling in a new array using [[DefineOwnProperty]] is unobservable.
|
||||||
|
//
|
||||||
|
// This is a tricky point, because after this set, our implementation *can*
|
||||||
|
// fail. The key is that script can't distinguish these failure modes from
|
||||||
|
// one where, in spec terms, we fail immediately after step 8a. That *in
|
||||||
|
// reality* we might have done extra matching work, or created a partial
|
||||||
|
// results array to return, or hit an interrupt, is irrelevant. The
|
||||||
|
// script can't tell we did any of those things but didn't update
|
||||||
|
// .lastIndex. Thus we can optimize steps 8b onward however we want,
|
||||||
|
// including eliminating intermediate .lastIndex sets, as long as we don't
|
||||||
|
// add ways for script to observe the intermediate states.
|
||||||
|
//
|
||||||
|
// In short: it's okay to cheat (by setting .lastIndex to 0, once) because
|
||||||
|
// we can't get caught.
|
||||||
|
if (!g.zeroLastIndex(cx))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 8b.
|
||||||
|
AutoValueVector elements(cx);
|
||||||
|
|
||||||
|
size_t lastSuccessfulStart = 0;
|
||||||
|
|
||||||
|
// The loop variables from steps 8c-e aren't needed, as we use different
|
||||||
|
// techniques from the spec to implement step 8f's loop.
|
||||||
|
|
||||||
|
// Step 8f.
|
||||||
|
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||||
|
size_t charsLen = input->length();
|
||||||
|
RegExpShared& re = g.regExp();
|
||||||
|
bool unicode = re.unicode();
|
||||||
|
bool sticky = re.sticky();
|
||||||
|
for (size_t searchIndex = 0; searchIndex <= charsLen; ) {
|
||||||
|
if (!CheckForInterrupt(cx))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 8f(i-ii), minus "lastIndex" updates (see above).
|
||||||
|
RegExpRunStatus status = re.execute(cx, input, searchIndex, sticky, &matches, nullptr);
|
||||||
|
if (status == RegExpRunStatus_Error)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 8f(ii).
|
||||||
|
if (status == RegExpRunStatus_Success_NotFound)
|
||||||
|
break;
|
||||||
|
|
||||||
|
lastSuccessfulStart = searchIndex;
|
||||||
|
MatchPair& match = matches[0];
|
||||||
|
|
||||||
|
// Steps 8f(iii)(1-3).
|
||||||
|
searchIndex = match.isEmpty()
|
||||||
|
? AdvanceStringIndex(input, charsLen, match.limit, unicode)
|
||||||
|
: match.limit;
|
||||||
|
|
||||||
|
// Step 8f(iii)(4-5).
|
||||||
|
JSLinearString* str = NewDependentString(cx, input, match.start, match.length());
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
if (!elements.append(StringValue(str)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8g.
|
||||||
|
if (elements.empty()) {
|
||||||
|
args.rval().setNull();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last *successful* match updates the RegExpStatics. (Interestingly,
|
||||||
|
// this implies that String.prototype.match's semantics aren't those
|
||||||
|
// implied by the RegExp.prototype.exec calls in the ES5 algorithm.)
|
||||||
|
res->updateLazily(cx, input, &re, lastSuccessfulStart, sticky);
|
||||||
|
|
||||||
|
// Steps 8b, 8f(iii)(5-6), 8h.
|
||||||
|
JSObject* array = NewDenseCopiedArray(cx, elements.length(), elements.begin());
|
||||||
|
if (!array)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
args.rval().setObject(*array);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
BuildFlatMatchArray(JSContext* cx, HandleString textstr, const FlatMatch& fm, CallArgs* args)
|
||||||
|
{
|
||||||
|
if (fm.match() < 0) {
|
||||||
|
args->rval().setNull();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the templateObject that defines the shape and type of the output object */
|
||||||
|
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
|
||||||
|
if (!templateObject)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, 1, templateObject));
|
||||||
|
if (!arr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Store a Value for each pair. */
|
||||||
|
arr->setDenseInitializedLength(1);
|
||||||
|
arr->initDenseElement(0, StringValue(fm.pattern()));
|
||||||
|
|
||||||
|
/* Set the |index| property. (TemplateObject positions it in slot 0) */
|
||||||
|
arr->setSlot(0, Int32Value(fm.match()));
|
||||||
|
|
||||||
|
/* Set the |input| property. (TemplateObject positions it in slot 1) */
|
||||||
|
arr->setSlot(1, StringValue(textstr));
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
RootedValue test(cx);
|
||||||
|
RootedId id(cx, NameToId(cx->names().index));
|
||||||
|
if (!NativeGetProperty(cx, arr, id, &test))
|
||||||
|
return false;
|
||||||
|
MOZ_ASSERT(test == arr->getSlot(0));
|
||||||
|
id = NameToId(cx->names().input);
|
||||||
|
if (!NativeGetProperty(cx, arr, id, &test))
|
||||||
|
return false;
|
||||||
|
MOZ_ASSERT(test == arr->getSlot(1));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
args->rval().setObject(*arr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES5 15.5.4.10. */
|
||||||
|
bool
|
||||||
|
js::str_match(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
/* Steps 1-2. */
|
||||||
|
RootedString str(cx, ThisToStringForStringProto(cx, args));
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Steps 3-4, plus the trailing-argument "flags" extension. */
|
||||||
|
StringRegExpGuard g(cx);
|
||||||
|
if (!g.init(cx, args, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Fast path when the search pattern can be searched for as a string. */
|
||||||
|
if (const FlatMatch* fm = g.tryFlatMatch(cx, str, 1, args.length()))
|
||||||
|
return BuildFlatMatchArray(cx, str, *fm, &args);
|
||||||
|
|
||||||
|
/* Return if there was an error in tryFlatMatch. */
|
||||||
|
if (cx->isExceptionPending())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Create regular-expression internals as needed to perform the match. */
|
||||||
|
if (!g.normalizeRegExp(cx, false, 1, args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RegExpStatics* res = cx->global()->getRegExpStatics(cx);
|
||||||
|
if (!res)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RootedLinearString linearStr(cx, str->ensureLinear(cx));
|
||||||
|
if (!linearStr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Steps 5-6, 7. */
|
||||||
|
if (!g.regExp().global())
|
||||||
|
return DoMatchLocal(cx, args, res, linearStr, g.regExp());
|
||||||
|
|
||||||
|
/* Steps 6, 8. */
|
||||||
|
return DoMatchGlobal(cx, args, res, linearStr, g);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::str_search(JSContext* cx, unsigned argc, Value* vp)
|
js::str_search(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
@ -3992,7 +4211,7 @@ static const JSFunctionSpec string_methods[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Perl-ish methods (search is actually Python-esque). */
|
/* Perl-ish methods (search is actually Python-esque). */
|
||||||
JS_SELF_HOSTED_FN("match", "String_match", 1,0),
|
JS_FN("match", str_match, 1,JSFUN_GENERIC_NATIVE),
|
||||||
JS_FN("search", str_search, 1,JSFUN_GENERIC_NATIVE),
|
JS_FN("search", str_search, 1,JSFUN_GENERIC_NATIVE),
|
||||||
JS_INLINABLE_FN("replace", str_replace, 2,JSFUN_GENERIC_NATIVE, StringReplace),
|
JS_INLINABLE_FN("replace", str_replace, 2,JSFUN_GENERIC_NATIVE, StringReplace),
|
||||||
JS_INLINABLE_FN("split", str_split, 2,JSFUN_GENERIC_NATIVE, StringSplit),
|
JS_INLINABLE_FN("split", str_split, 2,JSFUN_GENERIC_NATIVE, StringSplit),
|
||||||
@ -4147,8 +4366,6 @@ static const JSFunctionSpec string_static_methods[] = {
|
|||||||
JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0),
|
JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0),
|
||||||
JS_SELF_HOSTED_FN("slice", "String_static_slice", 3,0),
|
JS_SELF_HOSTED_FN("slice", "String_static_slice", 3,0),
|
||||||
|
|
||||||
JS_SELF_HOSTED_FN("match", "String_generic_match", 2,0),
|
|
||||||
|
|
||||||
// This must be at the end because of bug 853075: functions listed after
|
// This must be at the end because of bug 853075: functions listed after
|
||||||
// self-hosted methods aren't available in self-hosted code.
|
// self-hosted methods aren't available in self-hosted code.
|
||||||
#if EXPOSE_INTL_API
|
#if EXPOSE_INTL_API
|
||||||
@ -5180,127 +5397,3 @@ js::PutEscapedString(char* buffer, size_t bufferSize, const Latin1Char* chars, s
|
|||||||
template size_t
|
template size_t
|
||||||
js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
|
js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
|
||||||
uint32_t quote);
|
uint32_t quote);
|
||||||
|
|
||||||
static bool
|
|
||||||
FlatStringMatchHelper(JSContext* cx, HandleString str, HandleString pattern, bool* isFlat, int32_t* match)
|
|
||||||
{
|
|
||||||
RootedLinearString linearPattern(cx, pattern->ensureLinear(cx));
|
|
||||||
if (!linearPattern)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static const size_t MAX_FLAT_PAT_LEN = 256;
|
|
||||||
if (linearPattern->length() > MAX_FLAT_PAT_LEN || StringHasRegExpMetaChars(linearPattern)) {
|
|
||||||
*isFlat = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
*isFlat = true;
|
|
||||||
if (str->isRope()) {
|
|
||||||
if (!RopeMatch(cx, &str->asRope(), linearPattern, match))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
*match = StringMatch(&str->asLinear(), linearPattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
BuildFlatMatchArray(JSContext* cx, HandleString str, HandleString pattern, int32_t match,
|
|
||||||
MutableHandleValue rval)
|
|
||||||
{
|
|
||||||
if (match < 0) {
|
|
||||||
rval.setNull();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the templateObject that defines the shape and type of the output object */
|
|
||||||
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
|
|
||||||
if (!templateObject)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, 1, templateObject));
|
|
||||||
if (!arr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Store a Value for each pair. */
|
|
||||||
arr->setDenseInitializedLength(1);
|
|
||||||
arr->initDenseElement(0, StringValue(pattern));
|
|
||||||
|
|
||||||
/* Set the |index| property. (TemplateObject positions it in slot 0) */
|
|
||||||
arr->setSlot(0, Int32Value(match));
|
|
||||||
|
|
||||||
/* Set the |input| property. (TemplateObject positions it in slot 1) */
|
|
||||||
arr->setSlot(1, StringValue(str));
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
RootedValue test(cx);
|
|
||||||
RootedId id(cx, NameToId(cx->names().index));
|
|
||||||
if (!NativeGetProperty(cx, arr, id, &test))
|
|
||||||
return false;
|
|
||||||
MOZ_ASSERT(test == arr->getSlot(0));
|
|
||||||
id = NameToId(cx->names().input);
|
|
||||||
if (!NativeGetProperty(cx, arr, id, &test))
|
|
||||||
return false;
|
|
||||||
MOZ_ASSERT(test == arr->getSlot(1));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
rval.setObject(*arr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
static bool
|
|
||||||
CallIsStringOptimizable(JSContext* cx, const char* name, bool* result)
|
|
||||||
{
|
|
||||||
JSAtom* atom = Atomize(cx, name, strlen(name));
|
|
||||||
if (!atom)
|
|
||||||
return false;
|
|
||||||
RootedPropertyName propName(cx, atom->asPropertyName());
|
|
||||||
|
|
||||||
RootedValue funcVal(cx);
|
|
||||||
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), propName, propName, 0, &funcVal))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
InvokeArgs args(cx);
|
|
||||||
if (!args.init(0))
|
|
||||||
return false;
|
|
||||||
args.setCallee(funcVal);
|
|
||||||
args.setThis(UndefinedValue());
|
|
||||||
if (!Invoke(cx, args))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*result = args.rval().toBoolean();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::FlatStringMatch(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
MOZ_ASSERT(args.length() == 2);
|
|
||||||
MOZ_ASSERT(args[0].isString());
|
|
||||||
MOZ_ASSERT(args[1].isString());
|
|
||||||
#ifdef DEBUG
|
|
||||||
bool isOptimizable = false;
|
|
||||||
if (!CallIsStringOptimizable(cx, "IsStringMatchOptimizable", &isOptimizable))
|
|
||||||
return false;
|
|
||||||
MOZ_ASSERT(isOptimizable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RootedString str(cx,args[0].toString());
|
|
||||||
RootedString pattern(cx, args[1].toString());
|
|
||||||
|
|
||||||
bool isFlat = false;
|
|
||||||
int32_t match = 0;
|
|
||||||
if (!FlatStringMatchHelper(cx, str, pattern, &isFlat, &match))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!isFlat) {
|
|
||||||
args.rval().setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BuildFlatMatchArray(cx, str, pattern, match, args.rval());
|
|
||||||
}
|
|
||||||
|
@ -430,6 +430,9 @@ FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
str_match(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
str_search(JSContext* cx, unsigned argc, Value* vp);
|
str_search(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
@ -450,9 +453,6 @@ str_replace_string_raw(JSContext* cx, HandleString string, HandleString pattern,
|
|||||||
extern bool
|
extern bool
|
||||||
StringConstructor(JSContext* cx, unsigned argc, Value* vp);
|
StringConstructor(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
extern bool
|
|
||||||
FlatStringMatch(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jsstr_h */
|
#endif /* jsstr_h */
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
var BUGNUMBER = 887016;
|
|
||||||
var summary = "RegExpExec should throw if exec property of non-RegExp is not callable";
|
|
||||||
|
|
||||||
print(BUGNUMBER + ": " + summary);
|
|
||||||
|
|
||||||
for (var exec of [null, 0, false, undefined, ""]) {
|
|
||||||
// RegExp with non-callable exec
|
|
||||||
var re = /a/;
|
|
||||||
re.exec = exec;
|
|
||||||
RegExp.prototype[Symbol.match].call(re, "foo");
|
|
||||||
|
|
||||||
// non-RegExp with non-callable exec
|
|
||||||
assertThrowsInstanceOf(() => RegExp.prototype[Symbol.match].call({ exec }, "foo"),
|
|
||||||
TypeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
@ -1,31 +0,0 @@
|
|||||||
var BUGNUMBER = 887016;
|
|
||||||
var summary = "RegExpExec should throw if returned value is not an object nor null.";
|
|
||||||
|
|
||||||
print(BUGNUMBER + ": " + summary);
|
|
||||||
|
|
||||||
for (var ret of [null, {}, [], /a/]) {
|
|
||||||
assertEq(RegExp.prototype[Symbol.match].call({
|
|
||||||
get global() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
exec(S) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}, "foo"), ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ret of [undefined, 1, true, false, Symbol.iterator]) {
|
|
||||||
assertThrowsInstanceOf(() => {
|
|
||||||
RegExp.prototype[Symbol.match].call({
|
|
||||||
get global() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
exec(S) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}, "foo");
|
|
||||||
}, TypeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
@ -25,24 +25,6 @@ re = new Proxy(/a/, {
|
|||||||
return that[name];
|
return that[name];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertEq(RegExp(re), re);
|
|
||||||
re = new Proxy(/a/, {
|
|
||||||
get(that, name) {
|
|
||||||
if (name == "constructor") {
|
|
||||||
return function() {};
|
|
||||||
}
|
|
||||||
return that[name];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertEq(RegExp(re) === re, false);
|
|
||||||
re = new Proxy(/a/, {
|
|
||||||
get(that, name) {
|
|
||||||
if (name == Symbol.match) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return that[name];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertEq(RegExp(re) === re, false);
|
assertEq(RegExp(re) === re, false);
|
||||||
|
|
||||||
re = new Proxy(g.eval(`/a/`), {
|
re = new Proxy(g.eval(`/a/`), {
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
var BUGNUMBER = 887016;
|
|
||||||
var summary = "RegExp.prototype[@@match] should check this value.";
|
|
||||||
|
|
||||||
print(BUGNUMBER + ": " + summary);
|
|
||||||
|
|
||||||
for (var v of [null, 1, true, undefined, "", Symbol.iterator]) {
|
|
||||||
assertThrowsInstanceOf(() => RegExp.prototype[Symbol.match].call(v),
|
|
||||||
TypeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
@ -1,147 +0,0 @@
|
|||||||
var BUGNUMBER = 887016;
|
|
||||||
var summary = "Trace RegExp.prototype[@@match] behavior.";
|
|
||||||
|
|
||||||
print(BUGNUMBER + ": " + summary);
|
|
||||||
|
|
||||||
var n;
|
|
||||||
var log;
|
|
||||||
var target;
|
|
||||||
var global;
|
|
||||||
var unicode;
|
|
||||||
var logProxy;
|
|
||||||
|
|
||||||
var execResult;
|
|
||||||
var lastIndexResult;
|
|
||||||
var lastIndexExpected;
|
|
||||||
|
|
||||||
function P(A) {
|
|
||||||
return new Proxy(A, {
|
|
||||||
get(that, name) {
|
|
||||||
if (logProxy)
|
|
||||||
log += "get:result[" + name + "],";
|
|
||||||
return that[name];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var myRegExp = {
|
|
||||||
get global() {
|
|
||||||
log += "get:global,";
|
|
||||||
return global;
|
|
||||||
},
|
|
||||||
get lastIndex() {
|
|
||||||
log += "get:lastIndex,";
|
|
||||||
return lastIndexResult[n];
|
|
||||||
},
|
|
||||||
set lastIndex(v) {
|
|
||||||
log += "set:lastIndex,";
|
|
||||||
assertEq(v, lastIndexExpected[n]);
|
|
||||||
},
|
|
||||||
get unicode() {
|
|
||||||
log += "get:unicode,";
|
|
||||||
return unicode;
|
|
||||||
},
|
|
||||||
get exec() {
|
|
||||||
log += "get:exec,";
|
|
||||||
return function(S) {
|
|
||||||
log += "call:exec,";
|
|
||||||
assertEq(S, target);
|
|
||||||
return execResult[n++];
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function reset() {
|
|
||||||
n = 0;
|
|
||||||
log = "";
|
|
||||||
target = "abcAbcABC";
|
|
||||||
global = true;
|
|
||||||
unicode = false;
|
|
||||||
logProxy = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trace global with non-empty match.
|
|
||||||
reset();
|
|
||||||
execResult = [ P(["abc"]), P(["ABC"]), null ];
|
|
||||||
lastIndexResult = [ , , , ];
|
|
||||||
lastIndexExpected = [ 0, , , ];
|
|
||||||
var ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
|
|
||||||
assertEq(JSON.stringify(ret), `["abc","ABC"]`);
|
|
||||||
assertEq(log,
|
|
||||||
"get:global," +
|
|
||||||
"get:unicode," +
|
|
||||||
"set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0]," +
|
|
||||||
"get:exec,call:exec,get:result[0]," +
|
|
||||||
"get:exec,call:exec,");
|
|
||||||
|
|
||||||
// Trace global with empty match.
|
|
||||||
reset();
|
|
||||||
execResult = [ P([""]), P([""]), null ];
|
|
||||||
lastIndexResult = [ , 4, 20, ];
|
|
||||||
lastIndexExpected = [ 0, 5, 21, ];
|
|
||||||
ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
|
|
||||||
assertEq(JSON.stringify(ret), `["",""]`);
|
|
||||||
assertEq(log,
|
|
||||||
"get:global," +
|
|
||||||
"get:unicode," +
|
|
||||||
"set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
|
|
||||||
"get:exec,call:exec,");
|
|
||||||
|
|
||||||
// Trace global and unicode with empty match.
|
|
||||||
// 1. not surrogate pair
|
|
||||||
// 2. lead surrogate pair
|
|
||||||
// 3. trail surrogate pair
|
|
||||||
// 4. lead surrogate pair without trail surrogate pair
|
|
||||||
// 5. index overflow
|
|
||||||
reset();
|
|
||||||
unicode = true;
|
|
||||||
// 0123 4 5678
|
|
||||||
target = "___\uD83D\uDC38___\uD83D";
|
|
||||||
execResult = [ P([""]), P([""]), P([""]), P([""]), P([""]), null ];
|
|
||||||
lastIndexResult = [ , 2, 3, 4, 8, 9, ];
|
|
||||||
lastIndexExpected = [ 0, 3, 5, 5, 9, 10, ];
|
|
||||||
ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
|
|
||||||
assertEq(JSON.stringify(ret), `["","","","",""]`);
|
|
||||||
assertEq(log,
|
|
||||||
"get:global," +
|
|
||||||
"get:unicode," +
|
|
||||||
"set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
|
|
||||||
"get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
|
|
||||||
"get:exec,call:exec,");
|
|
||||||
|
|
||||||
// Trace global with no match.
|
|
||||||
reset();
|
|
||||||
execResult = [ null ];
|
|
||||||
lastIndexResult = [ , ];
|
|
||||||
lastIndexExpected = [ 0, ];
|
|
||||||
ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
|
|
||||||
assertEq(ret, null);
|
|
||||||
assertEq(log,
|
|
||||||
"get:global," +
|
|
||||||
"get:unicode," +
|
|
||||||
"set:lastIndex," +
|
|
||||||
"get:exec,call:exec,");
|
|
||||||
|
|
||||||
// Trace non-global.
|
|
||||||
reset();
|
|
||||||
global = false;
|
|
||||||
execResult = [ P(["abc"]) ];
|
|
||||||
lastIndexResult = [];
|
|
||||||
lastIndexExpected = [];
|
|
||||||
ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
|
|
||||||
// ret is the Proxy on non-global case, disable logging.
|
|
||||||
logProxy = false;
|
|
||||||
assertEq(JSON.stringify(ret), `["abc"]`);
|
|
||||||
assertEq(log,
|
|
||||||
"get:global," +
|
|
||||||
"get:exec,call:exec,");
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
@ -1,36 +0,0 @@
|
|||||||
var BUGNUMBER = 887016;
|
|
||||||
var summary = "Implement RegExp.prototype[@@match].";
|
|
||||||
|
|
||||||
print(BUGNUMBER + ": " + summary);
|
|
||||||
|
|
||||||
assertEq(RegExp.prototype[Symbol.match].name, "[Symbol.match]");
|
|
||||||
assertEq(RegExp.prototype[Symbol.match].length, 1);
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, Symbol.match);
|
|
||||||
assertEq(desc.configurable, true);
|
|
||||||
assertEq(desc.enumerable, false);
|
|
||||||
assertEq(desc.writable, true);
|
|
||||||
|
|
||||||
var re = /a/;
|
|
||||||
var v = re[Symbol.match]("abcAbcABC");
|
|
||||||
assertEq(Array.isArray(v), true);
|
|
||||||
assertEq(v.length, 1);
|
|
||||||
assertEq(v[0], "a");
|
|
||||||
|
|
||||||
re = /d/;
|
|
||||||
v = re[Symbol.match]("abcAbcABC");
|
|
||||||
assertEq(v, null);
|
|
||||||
|
|
||||||
re = /a/ig;
|
|
||||||
v = re[Symbol.match]("abcAbcABC");
|
|
||||||
assertEq(Array.isArray(v), true);
|
|
||||||
assertEq(v.length, 3);
|
|
||||||
assertEq(v[0], "a");
|
|
||||||
assertEq(v[1], "A");
|
|
||||||
assertEq(v[2], "A");
|
|
||||||
|
|
||||||
re = /d/g;
|
|
||||||
v = re[Symbol.match]("abcAbcABC");
|
|
||||||
assertEq(v, null);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
@ -1,31 +0,0 @@
|
|||||||
var BUGNUMBER = 887016;
|
|
||||||
var summary = "Call RegExp.prototype[@@match] from String.prototype.match.";
|
|
||||||
|
|
||||||
print(BUGNUMBER + ": " + summary);
|
|
||||||
|
|
||||||
var called = 0;
|
|
||||||
var myRegExp = {
|
|
||||||
[Symbol.match](S) {
|
|
||||||
assertEq(S, "abcAbcABC");
|
|
||||||
called++;
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
assertEq("abcAbcABC".match(myRegExp), 42);
|
|
||||||
assertEq(called, 1);
|
|
||||||
|
|
||||||
var origMatch = RegExp.prototype[Symbol.match];
|
|
||||||
|
|
||||||
called = 0;
|
|
||||||
RegExp.prototype[Symbol.match] = function(S) {
|
|
||||||
assertEq(S, "abcAbcABC");
|
|
||||||
called++;
|
|
||||||
return 43;
|
|
||||||
};
|
|
||||||
assertEq("abcAbcABC".match("abc"), 43);
|
|
||||||
assertEq(called, 1);
|
|
||||||
|
|
||||||
RegExp.prototype[Symbol.match] = origMatch;
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(true, true);
|
|
@ -453,14 +453,6 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedValue std_match(cx);
|
|
||||||
std_match.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::match));
|
|
||||||
if (!JS_DefineProperty(cx, global, "std_match", std_match,
|
|
||||||
JSPROP_PERMANENT | JSPROP_READONLY))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedValue std_species(cx);
|
RootedValue std_species(cx);
|
||||||
std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
|
std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
|
||||||
if (!JS_DefineProperty(cx, global, "std_species", std_species,
|
if (!JS_DefineProperty(cx, global, "std_species", std_species,
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "jsfun.h"
|
#include "jsfun.h"
|
||||||
#include "jshashutil.h"
|
#include "jshashutil.h"
|
||||||
#include "jsstr.h"
|
|
||||||
#include "jsweakmap.h"
|
#include "jsweakmap.h"
|
||||||
#include "jswrapper.h"
|
#include "jswrapper.h"
|
||||||
#include "selfhosted.out.h"
|
#include "selfhosted.out.h"
|
||||||
@ -2075,32 +2074,6 @@ intrinsic_captureCurrentStack(JSContext* cx, unsigned argc, Value* vp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
IsMatchFlagsArgumentEnabled(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
MOZ_ASSERT(args.length() == 0);
|
|
||||||
|
|
||||||
args.rval().setBoolean(cx->runtime()->options().matchFlagArgument());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
WarnOnceAboutFlagsArgument(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
if (!cx->compartment()->warnedAboutFlagsArgument) {
|
|
||||||
if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
|
|
||||||
cx->runtime()->options().matchFlagArgument()
|
|
||||||
? JSMSG_DEPRECATED_FLAGS_ARG
|
|
||||||
: JSMSG_OBSOLETE_FLAGS_ARG))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cx->compartment()->warnedAboutFlagsArgument = true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The self-hosting global isn't initialized with the normal set of builtins.
|
// The self-hosting global isn't initialized with the normal set of builtins.
|
||||||
// Instead, individual C++-implemented functions that're required by
|
// Instead, individual C++-implemented functions that're required by
|
||||||
// self-hosted code are defined as global functions. Accessing these
|
// self-hosted code are defined as global functions. Accessing these
|
||||||
@ -2158,6 +2131,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||||||
JS_INLINABLE_FN("std_String_charCodeAt", str_charCodeAt, 1,0, StringCharCodeAt),
|
JS_INLINABLE_FN("std_String_charCodeAt", str_charCodeAt, 1,0, StringCharCodeAt),
|
||||||
JS_FN("std_String_indexOf", str_indexOf, 1,0),
|
JS_FN("std_String_indexOf", str_indexOf, 1,0),
|
||||||
JS_FN("std_String_lastIndexOf", str_lastIndexOf, 1,0),
|
JS_FN("std_String_lastIndexOf", str_lastIndexOf, 1,0),
|
||||||
|
JS_FN("std_String_match", str_match, 1,0),
|
||||||
JS_INLINABLE_FN("std_String_replace", str_replace, 2,0, StringReplace),
|
JS_INLINABLE_FN("std_String_replace", str_replace, 2,0, StringReplace),
|
||||||
JS_INLINABLE_FN("std_String_split", str_split, 2,0, StringSplit),
|
JS_INLINABLE_FN("std_String_split", str_split, 2,0, StringSplit),
|
||||||
JS_FN("std_String_startsWith", str_startsWith, 1,0),
|
JS_FN("std_String_startsWith", str_startsWith, 1,0),
|
||||||
@ -2420,16 +2394,11 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||||||
JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,0,
|
JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,0,
|
||||||
RegExpInstanceOptimizable),
|
RegExpInstanceOptimizable),
|
||||||
|
|
||||||
JS_FN("FlatStringMatch", FlatStringMatch, 2,0),
|
|
||||||
|
|
||||||
// See builtin/RegExp.h for descriptions of the regexp_* functions.
|
// See builtin/RegExp.h for descriptions of the regexp_* functions.
|
||||||
JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
|
JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
|
||||||
JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
|
JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
|
||||||
JS_FN("regexp_construct", regexp_construct_self_hosting, 2,0),
|
JS_FN("regexp_construct", regexp_construct_self_hosting, 2,0),
|
||||||
|
|
||||||
JS_FN("IsMatchFlagsArgumentEnabled", IsMatchFlagsArgumentEnabled, 0,0),
|
|
||||||
JS_FN("WarnOnceAboutFlagsArgument", WarnOnceAboutFlagsArgument, 0,0),
|
|
||||||
|
|
||||||
JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
|
JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
|
||||||
JS_FN("CallModuleMethodIfWrapped",
|
JS_FN("CallModuleMethodIfWrapped",
|
||||||
CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
|
CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
|
||||||
|
@ -227,7 +227,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||||||
|
|
||||||
gPrototypeProperties['RegExp'] =
|
gPrototypeProperties['RegExp'] =
|
||||||
["constructor", "toSource", "toString", "compile", "exec", "test",
|
["constructor", "toSource", "toString", "compile", "exec", "test",
|
||||||
Symbol.match,
|
|
||||||
"flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode",
|
"flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode",
|
||||||
"lastIndex"];
|
"lastIndex"];
|
||||||
gConstructorProperties['RegExp'] =
|
gConstructorProperties['RegExp'] =
|
||||||
|
Loading…
Reference in New Issue
Block a user