| Index: src/regexp-delay.js
|
| ===================================================================
|
| --- src/regexp-delay.js (revision 4215)
|
| +++ src/regexp-delay.js (working copy)
|
| @@ -1,497 +0,0 @@
|
| -// Copyright 2006-2009 the V8 project authors. All rights reserved.
|
| -// Redistribution and use in source and binary forms, with or without
|
| -// modification, are permitted provided that the following conditions are
|
| -// met:
|
| -//
|
| -// * Redistributions of source code must retain the above copyright
|
| -// notice, this list of conditions and the following disclaimer.
|
| -// * Redistributions in binary form must reproduce the above
|
| -// copyright notice, this list of conditions and the following
|
| -// disclaimer in the documentation and/or other materials provided
|
| -// with the distribution.
|
| -// * Neither the name of Google Inc. nor the names of its
|
| -// contributors may be used to endorse or promote products derived
|
| -// from this software without specific prior written permission.
|
| -//
|
| -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| -
|
| -// Expect $Object = global.Object;
|
| -// Expect $Array = global.Array;
|
| -
|
| -const $RegExp = global.RegExp;
|
| -
|
| -// A recursive descent parser for Patterns according to the grammar of
|
| -// ECMA-262 15.10.1, with deviations noted below.
|
| -function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
|
| - // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
|
| - if (IS_REGEXP(pattern)) {
|
| - if (!IS_UNDEFINED(flags)) {
|
| - throw MakeTypeError('regexp_flags', []);
|
| - }
|
| - flags = (pattern.global ? 'g' : '')
|
| - + (pattern.ignoreCase ? 'i' : '')
|
| - + (pattern.multiline ? 'm' : '');
|
| - pattern = pattern.source;
|
| - }
|
| -
|
| - pattern = IS_UNDEFINED(pattern) ? '' : ToString(pattern);
|
| - flags = IS_UNDEFINED(flags) ? '' : ToString(flags);
|
| -
|
| - var global = false;
|
| - var ignoreCase = false;
|
| - var multiline = false;
|
| -
|
| - for (var i = 0; i < flags.length; i++) {
|
| - var c = StringCharAt.call(flags, i);
|
| - switch (c) {
|
| - case 'g':
|
| - // Allow duplicate flags to be consistent with JSC and others.
|
| - global = true;
|
| - break;
|
| - case 'i':
|
| - ignoreCase = true;
|
| - break;
|
| - case 'm':
|
| - multiline = true;
|
| - break;
|
| - default:
|
| - // Ignore flags that have no meaning to be consistent with
|
| - // JSC.
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (isConstructorCall) {
|
| - // ECMA-262, section 15.10.7.1.
|
| - %SetProperty(object, 'source', pattern,
|
| - DONT_DELETE | READ_ONLY | DONT_ENUM);
|
| -
|
| - // ECMA-262, section 15.10.7.2.
|
| - %SetProperty(object, 'global', global, DONT_DELETE | READ_ONLY | DONT_ENUM);
|
| -
|
| - // ECMA-262, section 15.10.7.3.
|
| - %SetProperty(object, 'ignoreCase', ignoreCase,
|
| - DONT_DELETE | READ_ONLY | DONT_ENUM);
|
| -
|
| - // ECMA-262, section 15.10.7.4.
|
| - %SetProperty(object, 'multiline', multiline,
|
| - DONT_DELETE | READ_ONLY | DONT_ENUM);
|
| -
|
| - // ECMA-262, section 15.10.7.5.
|
| - %SetProperty(object, 'lastIndex', 0, DONT_DELETE | DONT_ENUM);
|
| - } else { // RegExp is being recompiled via RegExp.prototype.compile.
|
| - %IgnoreAttributesAndSetProperty(object, 'source', pattern);
|
| - %IgnoreAttributesAndSetProperty(object, 'global', global);
|
| - %IgnoreAttributesAndSetProperty(object, 'ignoreCase', ignoreCase);
|
| - %IgnoreAttributesAndSetProperty(object, 'multiline', multiline);
|
| - %IgnoreAttributesAndSetProperty(object, 'lastIndex', 0);
|
| - regExpCache.type = 'none';
|
| - }
|
| -
|
| - // Call internal function to compile the pattern.
|
| - %RegExpCompile(object, pattern, flags);
|
| -}
|
| -
|
| -
|
| -function RegExpConstructor(pattern, flags) {
|
| - if (%_IsConstructCall()) {
|
| - DoConstructRegExp(this, pattern, flags, true);
|
| - } else {
|
| - // RegExp : Called as function; see ECMA-262, section 15.10.3.1.
|
| - if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) {
|
| - return pattern;
|
| - }
|
| - return new $RegExp(pattern, flags);
|
| - }
|
| -}
|
| -
|
| -
|
| -// Deprecated RegExp.prototype.compile method. We behave like the constructor
|
| -// were called again. In SpiderMonkey, this method returns the regexp object.
|
| -// In JSC, it returns undefined. For compatibility with JSC, we match their
|
| -// behavior.
|
| -function CompileRegExp(pattern, flags) {
|
| - // Both JSC and SpiderMonkey treat a missing pattern argument as the
|
| - // empty subject string, and an actual undefined value passed as the
|
| - // pattern as the string 'undefined'. Note that JSC is inconsistent
|
| - // here, treating undefined values differently in
|
| - // RegExp.prototype.compile and in the constructor, where they are
|
| - // the empty string. For compatibility with JSC, we match their
|
| - // behavior.
|
| - if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
|
| - DoConstructRegExp(this, 'undefined', flags, false);
|
| - } else {
|
| - DoConstructRegExp(this, pattern, flags, false);
|
| - }
|
| -}
|
| -
|
| -
|
| -function DoRegExpExec(regexp, string, index) {
|
| - return %_RegExpExec(regexp, string, index, lastMatchInfo);
|
| -}
|
| -
|
| -
|
| -function RegExpCache() {
|
| - this.type = 'none';
|
| - this.regExp = 0;
|
| - this.subject = 0;
|
| - this.replaceString = 0;
|
| - this.lastIndex = 0;
|
| - this.answer = 0;
|
| -}
|
| -
|
| -
|
| -var regExpCache = new RegExpCache();
|
| -
|
| -
|
| -function CloneRegexpAnswer(array) {
|
| - var len = array.length;
|
| - var answer = new $Array(len);
|
| - for (var i = 0; i < len; i++) {
|
| - answer[i] = array[i];
|
| - }
|
| - answer.index = array.index;
|
| - answer.input = array.input;
|
| - return answer;
|
| -}
|
| -
|
| -
|
| -function RegExpExec(string) {
|
| - if (!IS_REGEXP(this)) {
|
| - throw MakeTypeError('incompatible_method_receiver',
|
| - ['RegExp.prototype.exec', this]);
|
| - }
|
| -
|
| - var cache = regExpCache;
|
| -
|
| - if (%_ObjectEquals(cache.type, 'exec') &&
|
| - %_ObjectEquals(cache.lastIndex, this.lastIndex) &&
|
| - %_ObjectEquals(cache.regExp, this) &&
|
| - %_ObjectEquals(cache.subject, string)) {
|
| - var last = cache.answer;
|
| - if (last == null) {
|
| - return last;
|
| - } else {
|
| - return CloneRegexpAnswer(last);
|
| - }
|
| - }
|
| -
|
| - if (%_ArgumentsLength() == 0) {
|
| - var regExpInput = LAST_INPUT(lastMatchInfo);
|
| - if (IS_UNDEFINED(regExpInput)) {
|
| - throw MakeError('no_input_to_regexp', [this]);
|
| - }
|
| - string = regExpInput;
|
| - }
|
| - var s;
|
| - if (IS_STRING(string)) {
|
| - s = string;
|
| - } else {
|
| - s = ToString(string);
|
| - }
|
| - var lastIndex = this.lastIndex;
|
| -
|
| - var i = this.global ? TO_INTEGER(lastIndex) : 0;
|
| -
|
| - if (i < 0 || i > s.length) {
|
| - this.lastIndex = 0;
|
| - return null;
|
| - }
|
| -
|
| - %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
|
| - // matchIndices is either null or the lastMatchInfo array.
|
| - var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
|
| -
|
| - if (matchIndices == null) {
|
| - if (this.global) this.lastIndex = 0;
|
| - cache.lastIndex = lastIndex;
|
| - cache.regExp = this;
|
| - cache.subject = s;
|
| - cache.answer = matchIndices; // Null.
|
| - cache.type = 'exec';
|
| - return matchIndices; // No match.
|
| - }
|
| -
|
| - var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
|
| - var result;
|
| - if (numResults === 1) {
|
| - var matchStart = lastMatchInfo[CAPTURE(0)];
|
| - var matchEnd = lastMatchInfo[CAPTURE(1)];
|
| - result = [SubString(s, matchStart, matchEnd)];
|
| - } else {
|
| - result = new $Array(numResults);
|
| - for (var i = 0; i < numResults; i++) {
|
| - var matchStart = lastMatchInfo[CAPTURE(i << 1)];
|
| - var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
|
| - if (matchStart != -1 && matchEnd != -1) {
|
| - result[i] = SubString(s, matchStart, matchEnd);
|
| - } else {
|
| - // Make sure the element is present. Avoid reading the undefined
|
| - // property from the global object since this may change.
|
| - result[i] = void 0;
|
| - }
|
| - }
|
| - }
|
| -
|
| - result.index = lastMatchInfo[CAPTURE0];
|
| - result.input = s;
|
| - if (this.global) {
|
| - this.lastIndex = lastMatchInfo[CAPTURE1];
|
| - return result;
|
| - } else {
|
| - cache.regExp = this;
|
| - cache.subject = s;
|
| - cache.lastIndex = lastIndex;
|
| - cache.answer = result;
|
| - cache.type = 'exec';
|
| - return CloneRegexpAnswer(result);
|
| - }
|
| -}
|
| -
|
| -
|
| -// Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
|
| -// that test is defined in terms of String.prototype.exec. However, it probably
|
| -// means the original value of String.prototype.exec, which is what everybody
|
| -// else implements.
|
| -function RegExpTest(string) {
|
| - if (!IS_REGEXP(this)) {
|
| - throw MakeTypeError('incompatible_method_receiver',
|
| - ['RegExp.prototype.test', this]);
|
| - }
|
| - if (%_ArgumentsLength() == 0) {
|
| - var regExpInput = LAST_INPUT(lastMatchInfo);
|
| - if (IS_UNDEFINED(regExpInput)) {
|
| - throw MakeError('no_input_to_regexp', [this]);
|
| - }
|
| - string = regExpInput;
|
| - }
|
| - var s;
|
| - if (IS_STRING(string)) {
|
| - s = string;
|
| - } else {
|
| - s = ToString(string);
|
| - }
|
| -
|
| - var lastIndex = this.lastIndex;
|
| -
|
| - var cache = regExpCache;
|
| -
|
| - if (%_ObjectEquals(cache.type, 'test') &&
|
| - %_ObjectEquals(cache.regExp, this) &&
|
| - %_ObjectEquals(cache.subject, string) &&
|
| - %_ObjectEquals(cache.lastIndex, lastIndex)) {
|
| - return cache.answer;
|
| - }
|
| -
|
| - var length = s.length;
|
| - var i = this.global ? TO_INTEGER(lastIndex) : 0;
|
| -
|
| - cache.type = 'test';
|
| - cache.regExp = this;
|
| - cache.subject = s;
|
| - cache.lastIndex = i;
|
| -
|
| - if (i < 0 || i > s.length) {
|
| - this.lastIndex = 0;
|
| - cache.answer = false;
|
| - return false;
|
| - }
|
| -
|
| - %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
|
| - // matchIndices is either null or the lastMatchInfo array.
|
| - var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
|
| -
|
| - if (matchIndices == null) {
|
| - if (this.global) this.lastIndex = 0;
|
| - cache.answer = false;
|
| - return false;
|
| - }
|
| -
|
| - if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1];
|
| - cache.answer = true;
|
| - return true;
|
| -}
|
| -
|
| -
|
| -function RegExpToString() {
|
| - // If this.source is an empty string, output /(?:)/.
|
| - // http://bugzilla.mozilla.org/show_bug.cgi?id=225550
|
| - // ecma_2/RegExp/properties-001.js.
|
| - var src = this.source ? this.source : '(?:)';
|
| - var result = '/' + src + '/';
|
| - if (this.global)
|
| - result += 'g';
|
| - if (this.ignoreCase)
|
| - result += 'i';
|
| - if (this.multiline)
|
| - result += 'm';
|
| - return result;
|
| -}
|
| -
|
| -
|
| -// Getters for the static properties lastMatch, lastParen, leftContext, and
|
| -// rightContext of the RegExp constructor. The properties are computed based
|
| -// on the captures array of the last successful match and the subject string
|
| -// of the last successful match.
|
| -function RegExpGetLastMatch() {
|
| - var regExpSubject = LAST_SUBJECT(lastMatchInfo);
|
| - return SubString(regExpSubject,
|
| - lastMatchInfo[CAPTURE0],
|
| - lastMatchInfo[CAPTURE1]);
|
| -}
|
| -
|
| -
|
| -function RegExpGetLastParen() {
|
| - var length = NUMBER_OF_CAPTURES(lastMatchInfo);
|
| - 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)];
|
| - if (start != -1 && end != -1) {
|
| - return SubString(regExpSubject, start, end);
|
| - }
|
| - return "";
|
| -}
|
| -
|
| -
|
| -function RegExpGetLeftContext() {
|
| - return SubString(LAST_SUBJECT(lastMatchInfo),
|
| - 0,
|
| - lastMatchInfo[CAPTURE0]);
|
| -}
|
| -
|
| -
|
| -function RegExpGetRightContext() {
|
| - var subject = LAST_SUBJECT(lastMatchInfo);
|
| - return SubString(subject,
|
| - lastMatchInfo[CAPTURE1],
|
| - subject.length);
|
| -}
|
| -
|
| -
|
| -// The properties $1..$9 are the first nine capturing substrings of the last
|
| -// successful match, or ''. The function RegExpMakeCaptureGetter will be
|
| -// called with indices from 1 to 9.
|
| -function RegExpMakeCaptureGetter(n) {
|
| - return function() {
|
| - var index = n * 2;
|
| - if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return '';
|
| - var matchStart = lastMatchInfo[CAPTURE(index)];
|
| - var matchEnd = lastMatchInfo[CAPTURE(index + 1)];
|
| - if (matchStart == -1 || matchEnd == -1) return '';
|
| - return SubString(LAST_SUBJECT(lastMatchInfo), 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 = [
|
| - 2, // REGEXP_NUMBER_OF_CAPTURES
|
| - "", // Last subject.
|
| - void 0, // Last input - settable with RegExpSetInput.
|
| - 0, // REGEXP_FIRST_CAPTURE + 0
|
| - 0, // REGEXP_FIRST_CAPTURE + 1
|
| -];
|
| -
|
| -// -------------------------------------------------------------------
|
| -
|
| -function SetupRegExp() {
|
| - %FunctionSetInstanceClassName($RegExp, 'RegExp');
|
| - %FunctionSetPrototype($RegExp, new $Object());
|
| - %SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
|
| - %SetCode($RegExp, RegExpConstructor);
|
| -
|
| - InstallFunctions($RegExp.prototype, DONT_ENUM, $Array(
|
| - "exec", RegExpExec,
|
| - "test", RegExpTest,
|
| - "toString", RegExpToString,
|
| - "compile", CompileRegExp
|
| - ));
|
| -
|
| - // The length of compile is 1 in SpiderMonkey.
|
| - %FunctionSetLength($RegExp.prototype.compile, 1);
|
| -
|
| - // The properties input, $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.
|
| - function RegExpGetInput() {
|
| - var regExpInput = LAST_INPUT(lastMatchInfo);
|
| - return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
|
| - }
|
| - function RegExpSetInput(string) {
|
| - regExpCache.type = 'none';
|
| - LAST_INPUT(lastMatchInfo) = ToString(string);
|
| - };
|
| -
|
| - %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'input', SETTER, RegExpSetInput, DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$_', GETTER, RegExpGetInput, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$_', SETTER, RegExpSetInput, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$input', GETTER, RegExpGetInput, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$input', SETTER, 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 (ie, the value after coercion), while in V8 it is the value
|
| - // null (ie, the value before coercion).
|
| -
|
| - // Getter and setter for multiline.
|
| - var multiline = false;
|
| - function RegExpGetMultiline() { return multiline; };
|
| - function RegExpSetMultiline(flag) { multiline = flag ? true : false; };
|
| -
|
| - %DefineAccessor($RegExp, 'multiline', GETTER, RegExpGetMultiline, DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'multiline', SETTER, RegExpSetMultiline, DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$*', GETTER, RegExpGetMultiline, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$*', SETTER, RegExpSetMultiline, DONT_ENUM | DONT_DELETE);
|
| -
|
| -
|
| - function NoOpSetter(ignored) {}
|
| -
|
| -
|
| - // Static properties set by a successful match.
|
| - %DefineAccessor($RegExp, 'lastMatch', GETTER, RegExpGetLastMatch, DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'lastMatch', SETTER, NoOpSetter, DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$&', GETTER, RegExpGetLastMatch, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$&', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'lastParen', GETTER, RegExpGetLastParen, DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'lastParen', SETTER, NoOpSetter, DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$+', GETTER, RegExpGetLastParen, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$+', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'leftContext', GETTER, RegExpGetLeftContext, DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'leftContext', SETTER, NoOpSetter, DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$`', GETTER, RegExpGetLeftContext, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$`', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'rightContext', GETTER, RegExpGetRightContext, DONT_DELETE);
|
| - %DefineAccessor($RegExp, 'rightContext', SETTER, NoOpSetter, DONT_DELETE);
|
| - %DefineAccessor($RegExp, "$'", GETTER, RegExpGetRightContext, DONT_ENUM | DONT_DELETE);
|
| - %DefineAccessor($RegExp, "$'", SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
|
| -
|
| - for (var i = 1; i < 10; ++i) {
|
| - %DefineAccessor($RegExp, '$' + i, GETTER, RegExpMakeCaptureGetter(i), DONT_DELETE);
|
| - %DefineAccessor($RegExp, '$' + i, SETTER, NoOpSetter, DONT_DELETE);
|
| - }
|
| -}
|
| -
|
| -
|
| -SetupRegExp();
|
|
|