| Index: src/regexp.js
|
| diff --git a/src/regexp.js b/src/regexp.js
|
| index 416f5865e217973554c2192c816b915db372c20a..140f7798a5cb1923d6a34b823542034d0abb3bb5 100644
|
| --- a/src/regexp.js
|
| +++ b/src/regexp.js
|
| @@ -2,12 +2,37 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -// This file relies on the fact that the following declaration has been made
|
| -// in runtime.js:
|
| -// var $Object = global.Object;
|
| -// var $Array = global.Array;
|
| +var $regexpExec;
|
| +var $regexpExecNoTests;
|
| +var $regexpLastMatchInfo;
|
| +var $regexpLastMatchInfoOverride;
|
|
|
| -var $RegExp = global.RegExp;
|
| +(function() {
|
| +
|
| +%CheckIsBootstrapping();
|
| +
|
| +var GlobalRegExp = global.RegExp;
|
| +var GlobalArray = global.Array;
|
| +
|
| +// Property of the builtins object for recording the result of the last
|
| +// regexp match. The property $regexpLastMatchInfo includes the matchIndices
|
| +// array of the last successful regexp match (an array of start/end index
|
| +// pairs for the match and all the captured substrings), the invariant is
|
| +// that there are at least two capture indeces. The array also contains
|
| +// the subject string for the last successful match.
|
| +$regexpLastMatchInfo = new InternalPackedArray(
|
| + 2, // REGEXP_NUMBER_OF_CAPTURES
|
| + "", // Last subject.
|
| + UNDEFINED, // Last input - settable with RegExpSetInput.
|
| + 0, // REGEXP_FIRST_CAPTURE + 0
|
| + 0 // REGEXP_FIRST_CAPTURE + 1
|
| +);
|
| +
|
| +// Override last match info with an array of actual substrings.
|
| +// Used internally by replace regexp with function.
|
| +// The array has the format of an "apply" argument for a replacement
|
| +// function.
|
| +$regexpLastMatchInfoOverride = null;
|
|
|
| // -------------------------------------------------------------------
|
|
|
| @@ -44,7 +69,7 @@ function RegExpConstructor(pattern, flags) {
|
| if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) {
|
| return pattern;
|
| }
|
| - return new $RegExp(pattern, flags);
|
| + return new GlobalRegExp(pattern, flags);
|
| }
|
| }
|
|
|
| @@ -60,7 +85,7 @@ function RegExpCompileJS(pattern, flags) {
|
| // RegExp.prototype.compile and in the constructor, where they are
|
| // the empty string. For compatibility with JSC, we match their
|
| // behavior.
|
| - if (this == $RegExp.prototype) {
|
| + if (this == GlobalRegExp.prototype) {
|
| // We don't allow recompiling RegExp.prototype.
|
| throw MakeTypeError('incompatible_method_receiver',
|
| ['RegExp.prototype.compile', this]);
|
| @@ -74,8 +99,8 @@ function RegExpCompileJS(pattern, flags) {
|
|
|
|
|
| function DoRegExpExec(regexp, string, index) {
|
| - var result = %_RegExpExec(regexp, string, index, lastMatchInfo);
|
| - if (result !== null) lastMatchInfoOverride = null;
|
| + var result = %_RegExpExec(regexp, string, index, $regexpLastMatchInfo);
|
| + if (result !== null) $regexpLastMatchInfoOverride = null;
|
| return result;
|
| }
|
|
|
| @@ -108,9 +133,9 @@ endmacro
|
|
|
| function RegExpExecNoTests(regexp, string, start) {
|
| // Must be called with RegExp, string and positive integer as arguments.
|
| - var matchInfo = %_RegExpExec(regexp, string, start, lastMatchInfo);
|
| + var matchInfo = %_RegExpExec(regexp, string, start, $regexpLastMatchInfo);
|
| if (matchInfo !== null) {
|
| - lastMatchInfoOverride = null;
|
| + $regexpLastMatchInfoOverride = null;
|
| RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string);
|
| }
|
| regexp.lastIndex = 0;
|
| @@ -141,8 +166,8 @@ function RegExpExec(string) {
|
| i = 0;
|
| }
|
|
|
| - // matchIndices is either null or the lastMatchInfo array.
|
| - var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
|
| + // matchIndices is either null or the $regexpLastMatchInfo array.
|
| + var matchIndices = %_RegExpExec(this, string, i, $regexpLastMatchInfo);
|
|
|
| if (IS_NULL(matchIndices)) {
|
| this.lastIndex = 0;
|
| @@ -150,9 +175,9 @@ function RegExpExec(string) {
|
| }
|
|
|
| // Successful match.
|
| - lastMatchInfoOverride = null;
|
| + $regexpLastMatchInfoOverride = null;
|
| if (updateLastIndex) {
|
| - this.lastIndex = lastMatchInfo[CAPTURE1];
|
| + this.lastIndex = $regexpLastMatchInfo[CAPTURE1];
|
| }
|
| RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
|
| }
|
| @@ -184,14 +209,14 @@ function RegExpTest(string) {
|
| this.lastIndex = 0;
|
| return false;
|
| }
|
| - // matchIndices is either null or the lastMatchInfo array.
|
| - var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
|
| + // matchIndices is either null or the $regexpLastMatchInfo array.
|
| + var matchIndices = %_RegExpExec(this, string, i, $regexpLastMatchInfo);
|
| if (IS_NULL(matchIndices)) {
|
| this.lastIndex = 0;
|
| return false;
|
| }
|
| - lastMatchInfoOverride = null;
|
| - this.lastIndex = lastMatchInfo[CAPTURE1];
|
| + $regexpLastMatchInfoOverride = null;
|
| + this.lastIndex = $regexpLastMatchInfo[CAPTURE1];
|
| return true;
|
| } else {
|
| // Non-global, non-sticky regexp.
|
| @@ -205,13 +230,13 @@ function RegExpTest(string) {
|
| %_StringCharCodeAt(regexp.source, 2) != 63) { // '?'
|
| regexp = TrimRegExp(regexp);
|
| }
|
| - // matchIndices is either null or the lastMatchInfo array.
|
| - var matchIndices = %_RegExpExec(regexp, string, 0, lastMatchInfo);
|
| + // matchIndices is either null or the $regexpLastMatchInfo array.
|
| + var matchIndices = %_RegExpExec(regexp, string, 0, $regexpLastMatchInfo);
|
| if (IS_NULL(matchIndices)) {
|
| this.lastIndex = 0;
|
| return false;
|
| }
|
| - lastMatchInfoOverride = null;
|
| + $regexpLastMatchInfoOverride = null;
|
| return true;
|
| }
|
| }
|
| @@ -220,9 +245,9 @@ function TrimRegExp(regexp) {
|
| if (!%_ObjectEquals(regexp_key, regexp)) {
|
| regexp_key = regexp;
|
| regexp_val =
|
| - new $RegExp(%_SubString(regexp.source, 2, regexp.source.length),
|
| - (regexp.ignoreCase ? regexp.multiline ? "im" : "i"
|
| - : regexp.multiline ? "m" : ""));
|
| + new GlobalRegExp(%_SubString(regexp.source, 2, regexp.source.length),
|
| + (regexp.ignoreCase ? regexp.multiline ? "im" : "i"
|
| + : regexp.multiline ? "m" : ""));
|
| }
|
| return regexp_val;
|
| }
|
| @@ -248,30 +273,30 @@ function RegExpToString() {
|
| // on the captures array of the last successful match and the subject string
|
| // of the last successful match.
|
| function RegExpGetLastMatch() {
|
| - if (lastMatchInfoOverride !== null) {
|
| - return OVERRIDE_MATCH(lastMatchInfoOverride);
|
| + if ($regexpLastMatchInfoOverride !== null) {
|
| + return OVERRIDE_MATCH($regexpLastMatchInfoOverride);
|
| }
|
| - var regExpSubject = LAST_SUBJECT(lastMatchInfo);
|
| + var regExpSubject = LAST_SUBJECT($regexpLastMatchInfo);
|
| return %_SubString(regExpSubject,
|
| - lastMatchInfo[CAPTURE0],
|
| - lastMatchInfo[CAPTURE1]);
|
| + $regexpLastMatchInfo[CAPTURE0],
|
| + $regexpLastMatchInfo[CAPTURE1]);
|
| }
|
|
|
|
|
| function RegExpGetLastParen() {
|
| - if (lastMatchInfoOverride) {
|
| - var override = lastMatchInfoOverride;
|
| + if ($regexpLastMatchInfoOverride) {
|
| + var override = $regexpLastMatchInfoOverride;
|
| if (override.length <= 3) return '';
|
| return override[override.length - 3];
|
| }
|
| - var length = NUMBER_OF_CAPTURES(lastMatchInfo);
|
| + var length = NUMBER_OF_CAPTURES($regexpLastMatchInfo);
|
| if (length <= 2) return ''; // There were no captures.
|
| // We match the SpiderMonkey behavior: return the substring defined by the
|
| // last pair (after the first pair) of elements of the capture array even if
|
| // it is empty.
|
| - var regExpSubject = LAST_SUBJECT(lastMatchInfo);
|
| - var start = lastMatchInfo[CAPTURE(length - 2)];
|
| - var end = lastMatchInfo[CAPTURE(length - 1)];
|
| + var regExpSubject = LAST_SUBJECT($regexpLastMatchInfo);
|
| + var start = $regexpLastMatchInfo[CAPTURE(length - 2)];
|
| + var end = $regexpLastMatchInfo[CAPTURE(length - 1)];
|
| if (start != -1 && end != -1) {
|
| return %_SubString(regExpSubject, start, end);
|
| }
|
| @@ -282,11 +307,11 @@ function RegExpGetLastParen() {
|
| function RegExpGetLeftContext() {
|
| var start_index;
|
| var subject;
|
| - if (!lastMatchInfoOverride) {
|
| - start_index = lastMatchInfo[CAPTURE0];
|
| - subject = LAST_SUBJECT(lastMatchInfo);
|
| + if (!$regexpLastMatchInfoOverride) {
|
| + start_index = $regexpLastMatchInfo[CAPTURE0];
|
| + subject = LAST_SUBJECT($regexpLastMatchInfo);
|
| } else {
|
| - var override = lastMatchInfoOverride;
|
| + var override = $regexpLastMatchInfoOverride;
|
| start_index = OVERRIDE_POS(override);
|
| subject = OVERRIDE_SUBJECT(override);
|
| }
|
| @@ -297,11 +322,11 @@ function RegExpGetLeftContext() {
|
| function RegExpGetRightContext() {
|
| var start_index;
|
| var subject;
|
| - if (!lastMatchInfoOverride) {
|
| - start_index = lastMatchInfo[CAPTURE1];
|
| - subject = LAST_SUBJECT(lastMatchInfo);
|
| + if (!$regexpLastMatchInfoOverride) {
|
| + start_index = $regexpLastMatchInfo[CAPTURE1];
|
| + subject = LAST_SUBJECT($regexpLastMatchInfo);
|
| } else {
|
| - var override = lastMatchInfoOverride;
|
| + var override = $regexpLastMatchInfoOverride;
|
| subject = OVERRIDE_SUBJECT(override);
|
| var match = OVERRIDE_MATCH(override);
|
| start_index = OVERRIDE_POS(override) + match.length;
|
| @@ -314,126 +339,106 @@ function RegExpGetRightContext() {
|
| // successful match, or ''. The function RegExpMakeCaptureGetter will be
|
| // called with indices from 1 to 9.
|
| function RegExpMakeCaptureGetter(n) {
|
| - return function() {
|
| - if (lastMatchInfoOverride) {
|
| - if (n < lastMatchInfoOverride.length - 2) {
|
| - return OVERRIDE_CAPTURE(lastMatchInfoOverride, n);
|
| + return function foo() {
|
| + if ($regexpLastMatchInfoOverride) {
|
| + if (n < $regexpLastMatchInfoOverride.length - 2) {
|
| + return OVERRIDE_CAPTURE($regexpLastMatchInfoOverride, n);
|
| }
|
| return '';
|
| }
|
| var index = n * 2;
|
| - if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return '';
|
| - var matchStart = lastMatchInfo[CAPTURE(index)];
|
| - var matchEnd = lastMatchInfo[CAPTURE(index + 1)];
|
| + if (index >= NUMBER_OF_CAPTURES($regexpLastMatchInfo)) return '';
|
| + var matchStart = $regexpLastMatchInfo[CAPTURE(index)];
|
| + var matchEnd = $regexpLastMatchInfo[CAPTURE(index + 1)];
|
| if (matchStart == -1 || matchEnd == -1) return '';
|
| - return %_SubString(LAST_SUBJECT(lastMatchInfo), matchStart, matchEnd);
|
| + return %_SubString(LAST_SUBJECT($regexpLastMatchInfo), matchStart, matchEnd);
|
| };
|
| }
|
|
|
| -
|
| -// Property of the builtins object for recording the result of the last
|
| -// regexp match. The property lastMatchInfo includes the matchIndices
|
| -// array of the last successful regexp match (an array of start/end index
|
| -// pairs for the match and all the captured substrings), the invariant is
|
| -// that there are at least two capture indeces. The array also contains
|
| -// the subject string for the last successful match.
|
| -var lastMatchInfo = new InternalPackedArray(
|
| - 2, // REGEXP_NUMBER_OF_CAPTURES
|
| - "", // Last subject.
|
| - UNDEFINED, // Last input - settable with RegExpSetInput.
|
| - 0, // REGEXP_FIRST_CAPTURE + 0
|
| - 0 // REGEXP_FIRST_CAPTURE + 1
|
| -);
|
| -
|
| -// Override last match info with an array of actual substrings.
|
| -// Used internally by replace regexp with function.
|
| -// The array has the format of an "apply" argument for a replacement
|
| -// function.
|
| -var lastMatchInfoOverride = null;
|
| -
|
| // -------------------------------------------------------------------
|
|
|
| -function SetUpRegExp() {
|
| - %CheckIsBootstrapping();
|
| - %FunctionSetInstanceClassName($RegExp, 'RegExp');
|
| - %AddNamedProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
|
| - %SetCode($RegExp, RegExpConstructor);
|
| -
|
| - InstallFunctions($RegExp.prototype, DONT_ENUM, $Array(
|
| - "exec", RegExpExec,
|
| - "test", RegExpTest,
|
| - "toString", RegExpToString,
|
| - "compile", RegExpCompileJS
|
| - ));
|
| -
|
| - // The length of compile is 1 in SpiderMonkey.
|
| - %FunctionSetLength($RegExp.prototype.compile, 1);
|
| -
|
| - // The properties `input` and `$_` are aliases for each other. When this
|
| - // value is set the value it is set to is coerced to a string.
|
| - // Getter and setter for the input.
|
| - var RegExpGetInput = function() {
|
| - var regExpInput = LAST_INPUT(lastMatchInfo);
|
| - return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
|
| - };
|
| - var RegExpSetInput = function(string) {
|
| - LAST_INPUT(lastMatchInfo) = ToString(string);
|
| - };
|
| -
|
| - %OptimizeObjectForAddingMultipleProperties($RegExp, 22);
|
| - %DefineAccessorPropertyUnchecked($RegExp, 'input', RegExpGetInput,
|
| - RegExpSetInput, DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, '$_', RegExpGetInput,
|
| - RegExpSetInput, DONT_ENUM | DONT_DELETE);
|
| -
|
| - // The properties multiline and $* are aliases for each other. When this
|
| - // value is set in SpiderMonkey, the value it is set to is coerced to a
|
| - // boolean. We mimic that behavior with a slight difference: in SpiderMonkey
|
| - // the value of the expression 'RegExp.multiline = null' (for instance) is the
|
| - // boolean false (i.e., the value after coercion), while in V8 it is the value
|
| - // null (i.e., the value before coercion).
|
| -
|
| - // Getter and setter for multiline.
|
| - var multiline = false;
|
| - var RegExpGetMultiline = function() { return multiline; };
|
| - var RegExpSetMultiline = function(flag) { multiline = flag ? true : false; };
|
| -
|
| - %DefineAccessorPropertyUnchecked($RegExp, 'multiline', RegExpGetMultiline,
|
| - RegExpSetMultiline, DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, '$*', RegExpGetMultiline,
|
| - RegExpSetMultiline,
|
| - DONT_ENUM | DONT_DELETE);
|
| -
|
| -
|
| - var NoOpSetter = function(ignored) {};
|
| -
|
| -
|
| - // Static properties set by a successful match.
|
| - %DefineAccessorPropertyUnchecked($RegExp, 'lastMatch', RegExpGetLastMatch,
|
| - NoOpSetter, DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, '$&', RegExpGetLastMatch,
|
| - NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, 'lastParen', RegExpGetLastParen,
|
| - NoOpSetter, DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, '$+', RegExpGetLastParen,
|
| - NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, 'leftContext',
|
| - RegExpGetLeftContext, NoOpSetter,
|
| +%FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
|
| +%AddNamedProperty(
|
| + GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
|
| +%SetCode(GlobalRegExp, RegExpConstructor);
|
| +
|
| +InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, GlobalArray(
|
| + "exec", RegExpExec,
|
| + "test", RegExpTest,
|
| + "toString", RegExpToString,
|
| + "compile", RegExpCompileJS
|
| +));
|
| +
|
| +// The length of compile is 1 in SpiderMonkey.
|
| +%FunctionSetLength(GlobalRegExp.prototype.compile, 1);
|
| +
|
| +// The properties `input` and `$_` are aliases for each other. When this
|
| +// value is set the value it is set to is coerced to a string.
|
| +// Getter and setter for the input.
|
| +var RegExpGetInput = function() {
|
| + var regExpInput = LAST_INPUT($regexpLastMatchInfo);
|
| + return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
|
| +};
|
| +var RegExpSetInput = function(string) {
|
| + LAST_INPUT($regexpLastMatchInfo) = ToString(string);
|
| +};
|
| +
|
| +%OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, 'input', RegExpGetInput,
|
| + RegExpSetInput, DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, '$_', RegExpGetInput,
|
| + RegExpSetInput, DONT_ENUM | DONT_DELETE);
|
| +
|
| +// The properties multiline and $* are aliases for each other. When this
|
| +// value is set in SpiderMonkey, the value it is set to is coerced to a
|
| +// boolean. We mimic that behavior with a slight difference: in SpiderMonkey
|
| +// the value of the expression 'RegExp.multiline = null' (for instance) is the
|
| +// boolean false (i.e., the value after coercion), while in V8 it is the value
|
| +// null (i.e., the value before coercion).
|
| +
|
| +// Getter and setter for multiline.
|
| +var multiline = false;
|
| +var RegExpGetMultiline = function() { return multiline; };
|
| +var RegExpSetMultiline = function(flag) { multiline = flag ? true : false; };
|
| +
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, 'multiline', RegExpGetMultiline,
|
| + RegExpSetMultiline, DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, '$*', RegExpGetMultiline,
|
| + RegExpSetMultiline,
|
| + DONT_ENUM | DONT_DELETE);
|
| +
|
| +
|
| +var NoOpSetter = function(ignored) {};
|
| +
|
| +
|
| +// Static properties set by a successful match.
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, 'lastMatch', RegExpGetLastMatch,
|
| + NoOpSetter, DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, '$&', RegExpGetLastMatch,
|
| + NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, 'lastParen', RegExpGetLastParen,
|
| + NoOpSetter, DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, '$+', RegExpGetLastParen,
|
| + NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, 'leftContext',
|
| + RegExpGetLeftContext, NoOpSetter,
|
| + DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, '$`', RegExpGetLeftContext,
|
| + NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, 'rightContext',
|
| + RegExpGetRightContext, NoOpSetter,
|
| + DONT_DELETE);
|
| +%DefineAccessorPropertyUnchecked(GlobalRegExp, "$'", RegExpGetRightContext,
|
| + NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| +
|
| +for (var i = 1; i < 10; ++i) {
|
| + %DefineAccessorPropertyUnchecked(GlobalRegExp, '$' + i,
|
| + RegExpMakeCaptureGetter(i), NoOpSetter,
|
| DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, '$`', RegExpGetLeftContext,
|
| - NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, 'rightContext',
|
| - RegExpGetRightContext, NoOpSetter,
|
| - DONT_DELETE);
|
| - %DefineAccessorPropertyUnchecked($RegExp, "$'", RegExpGetRightContext,
|
| - NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| -
|
| - for (var i = 1; i < 10; ++i) {
|
| - %DefineAccessorPropertyUnchecked($RegExp, '$' + i,
|
| - RegExpMakeCaptureGetter(i), NoOpSetter,
|
| - DONT_DELETE);
|
| - }
|
| - %ToFastProperties($RegExp);
|
| }
|
| +%ToFastProperties(GlobalRegExp);
|
| +
|
| +$regexpExecNoTests = RegExpExecNoTests;
|
| +$regexpExec = DoRegExpExec;
|
|
|
| -SetUpRegExp();
|
| +})();
|
|
|