| Index: src/regexp-delay.js
|
| ===================================================================
|
| --- src/regexp-delay.js (revision 1426)
|
| +++ src/regexp-delay.js (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2006-2009 the V8 project authors. All rights reserved.
|
| +// Copyright 2006-2008 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:
|
| @@ -52,7 +52,7 @@
|
| var multiline = false;
|
|
|
| for (var i = 0; i < flags.length; i++) {
|
| - var c = StringCharAt.call(flags, i);
|
| + var c = flags.charAt(i);
|
| switch (c) {
|
| case 'g':
|
| // Allow duplicate flags to be consistent with JSC and others.
|
| @@ -117,15 +117,15 @@
|
|
|
| // 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
|
| +// In KJS, it returns undefined. For compatibility with KJS, we match their
|
| // behavior.
|
| function CompileRegExp(pattern, flags) {
|
| - // Both JSC and SpiderMonkey treat a missing pattern argument as the
|
| + // Both KJS 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
|
| + // patter as the string 'undefined'. Note that KJS 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
|
| + // the empty string. For compatibility with KJS, we match their
|
| // behavior.
|
| if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
|
| DoConstructRegExp(this, 'undefined', flags, false);
|
| @@ -135,20 +135,32 @@
|
| }
|
|
|
|
|
| +// DoRegExpExec and DoRegExpExecGlobal are wrappers around the runtime
|
| +// %RegExp and %RegExpGlobal functions that ensure that the static
|
| +// properties of the RegExp constructor are set.
|
| function DoRegExpExec(regexp, string, index) {
|
| - return %RegExpExec(regexp, string, index, lastMatchInfo);
|
| + var matchIndices = %RegExpExec(regexp, string, index);
|
| + if (!IS_NULL(matchIndices)) {
|
| + regExpCaptures = matchIndices;
|
| + regExpSubject = regExpInput = string;
|
| + }
|
| + return matchIndices;
|
| }
|
|
|
|
|
| function DoRegExpExecGlobal(regexp, string) {
|
| - // Returns an array of arrays of substring indices.
|
| - return %RegExpExecGlobal(regexp, string, lastMatchInfo);
|
| + // Here, matchIndices is an array of arrays of substring indices.
|
| + var matchIndices = %RegExpExecGlobal(regexp, string);
|
| + if (matchIndices.length != 0) {
|
| + regExpCaptures = matchIndices[matchIndices.length - 1];
|
| + regExpSubject = regExpInput = string;
|
| + }
|
| + return matchIndices;
|
| }
|
|
|
|
|
| function RegExpExec(string) {
|
| if (%_ArgumentsLength() == 0) {
|
| - var regExpInput = LAST_INPUT(lastMatchInfo);
|
| if (IS_UNDEFINED(regExpInput)) {
|
| throw MakeError('no_input_to_regexp', [this]);
|
| }
|
| @@ -165,21 +177,23 @@
|
| }
|
|
|
| %_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);
|
| + // matchIndices is an array of integers with length of captures*2,
|
| + // each pair of integers specified the start and the end of index
|
| + // in the string.
|
| + var matchIndices = DoRegExpExec(this, s, i);
|
|
|
| if (matchIndices == null) {
|
| if (this.global) this.lastIndex = 0;
|
| return matchIndices; // no match
|
| }
|
|
|
| - var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
|
| + var numResults = matchIndices.length >> 1;
|
| var result = new $Array(numResults);
|
| for (var i = 0; i < numResults; i++) {
|
| - var matchStart = lastMatchInfo[CAPTURE(i << 1)];
|
| - var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
|
| + var matchStart = matchIndices[2*i];
|
| + var matchEnd = matchIndices[2*i + 1];
|
| if (matchStart != -1 && matchEnd != -1) {
|
| - result[i] = SubString(s, matchStart, matchEnd);
|
| + result[i] = s.slice(matchStart, matchEnd);
|
| } else {
|
| // Make sure the element is present. Avoid reading the undefined
|
| // property from the global object since this may change.
|
| @@ -188,46 +202,16 @@
|
| }
|
|
|
| if (this.global)
|
| - this.lastIndex = lastMatchInfo[CAPTURE1];
|
| - result.index = lastMatchInfo[CAPTURE0];
|
| + this.lastIndex = matchIndices[1];
|
| + result.index = matchIndices[0];
|
| result.input = s;
|
| return 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 even if the method is
|
| -// called on a non-RegExp object. However, it probably means the original
|
| -// value of String.prototype.exec, which is what everybody else implements.
|
| function RegExpTest(string) {
|
| - if (%_ArgumentsLength() == 0) {
|
| - var regExpInput = LAST_INPUT(lastMatchInfo);
|
| - if (IS_UNDEFINED(regExpInput)) {
|
| - throw MakeError('no_input_to_regexp', [this]);
|
| - }
|
| - string = regExpInput;
|
| - }
|
| - var s = ToString(string);
|
| - var length = s.length;
|
| - var lastIndex = this.lastIndex;
|
| - var i = this.global ? TO_INTEGER(lastIndex) : 0;
|
| -
|
| - if (i < 0 || i > s.length) {
|
| - this.lastIndex = 0;
|
| - 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;
|
| - return false;
|
| - }
|
| -
|
| - if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1];
|
| - return true;
|
| + var result = (%_ArgumentsLength() == 0) ? this.exec() : this.exec(string);
|
| + return result != null;
|
| }
|
|
|
|
|
| @@ -252,69 +236,56 @@
|
| // 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]);
|
| + return regExpSubject.slice(regExpCaptures[0], regExpCaptures[1]);
|
| }
|
|
|
|
|
| function RegExpGetLastParen() {
|
| - var length = NUMBER_OF_CAPTURES(lastMatchInfo);
|
| - if (length <= 2) return ''; // There were no captures.
|
| + var length = regExpCaptures.length;
|
| + 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);
|
| - return SubString(regExpSubject,
|
| - lastMatchInfo[CAPTURE(length - 2)],
|
| - lastMatchInfo[CAPTURE(length - 1)]);
|
| + return regExpSubject.slice(regExpCaptures[length - 2],
|
| + regExpCaptures[length - 1]);
|
| }
|
|
|
|
|
| function RegExpGetLeftContext() {
|
| - return SubString(LAST_SUBJECT(lastMatchInfo),
|
| - 0,
|
| - lastMatchInfo[CAPTURE0]);
|
| + return regExpSubject.slice(0, regExpCaptures[0]);
|
| }
|
|
|
|
|
| function RegExpGetRightContext() {
|
| - var subject = LAST_SUBJECT(lastMatchInfo);
|
| - return SubString(subject,
|
| - lastMatchInfo[CAPTURE1],
|
| - subject.length);
|
| + return regExpSubject.slice(regExpCaptures[1], regExpSubject.length);
|
| }
|
|
|
|
|
| // The properties $1..$9 are the first nine capturing substrings of the last
|
| // successful match, or ''. The function RegExpMakeCaptureGetter will be
|
| -// called with indeces from 1 to 9.
|
| +// called with an index greater than or equal to 1 but it actually works for
|
| +// any non-negative index.
|
| 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 (index >= regExpCaptures.length) return '';
|
| + var matchStart = regExpCaptures[index];
|
| + var matchEnd = regExpCaptures[index + 1];
|
| if (matchStart == -1 || matchEnd == -1) return '';
|
| - return SubString(LAST_SUBJECT(lastMatchInfo), matchStart, matchEnd);
|
| + return regExpSubject.slice(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
|
| - 0, // REGEXP_FIRST_CAPTURE + 0
|
| - 0, // REGEXP_FIRST_CAPTURE + 1
|
| - "", // Last subject.
|
| - void 0, // Last input - settable with RegExpSetInput.
|
| -];
|
| +// Properties of the builtins object for recording the result of the last
|
| +// regexp match. The property regExpCaptures is 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 is at
|
| +// least two elements. The property regExpSubject is the subject string for
|
| +// the last successful match.
|
| +var regExpCaptures = [0, 0];
|
| +var regExpSubject = '';
|
| +var regExpInput;
|
|
|
| // -------------------------------------------------------------------
|
|
|
| @@ -332,23 +303,19 @@
|
| ));
|
|
|
| // The spec says nothing about the length of exec and test, but
|
| - // SpiderMonkey and JSC have length equal to 0.
|
| + // SpiderMonkey and KJS have length equal to 0.
|
| %FunctionSetLength($RegExp.prototype.exec, 0);
|
| %FunctionSetLength($RegExp.prototype.test, 0);
|
| // 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.
|
| + // 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) {
|
| - lastMatchInfo[lastMatchInfo[REGEXP_NUMBER_OF_CAPTURES] + 2] =
|
| - ToString(string);
|
| - };
|
| + function RegExpSetInput(string) { regExpInput = ToString(string); }
|
|
|
| %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
|
| %DefineAccessor($RegExp, 'input', SETTER, RegExpSetInput, DONT_DELETE);
|
|
|