| Index: src/js/regexp.js
|
| diff --git a/src/js/regexp.js b/src/js/regexp.js
|
| index e51a6d227a8d40ef2308cfeb1eed557c44656f4f..ecf3289b61ca3392cdfe59946fb4d78bab869ac9 100644
|
| --- a/src/js/regexp.js
|
| +++ b/src/js/regexp.js
|
| @@ -17,7 +17,6 @@
|
| var InternalPackedArray = utils.InternalPackedArray;
|
| var MaxSimple;
|
| var MinSimple;
|
| -var lastMatchInfoSymbol = utils.ImportNow("regexp_last_match_info_symbol");
|
| var matchSymbol = utils.ImportNow("match_symbol");
|
| var replaceSymbol = utils.ImportNow("replace_symbol");
|
| var searchSymbol = utils.ImportNow("search_symbol");
|
| @@ -924,7 +923,179 @@
|
| %FunctionRemovePrototype(RegExpSubclassSearch);
|
|
|
|
|
| +// 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(RegExpLastMatchInfo);
|
| + return %_SubString(regExpSubject,
|
| + RegExpLastMatchInfo[CAPTURE0],
|
| + RegExpLastMatchInfo[CAPTURE1]);
|
| +}
|
| +
|
| +
|
| +function RegExpGetLastParen() {
|
| + 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(RegExpLastMatchInfo);
|
| + var start = RegExpLastMatchInfo[CAPTURE(length - 2)];
|
| + var end = RegExpLastMatchInfo[CAPTURE(length - 1)];
|
| + if (start != -1 && end != -1) {
|
| + return %_SubString(regExpSubject, start, end);
|
| + }
|
| + return "";
|
| +}
|
| +
|
| +
|
| +function RegExpGetLeftContext() {
|
| + var start_index;
|
| + var subject;
|
| + start_index = RegExpLastMatchInfo[CAPTURE0];
|
| + subject = LAST_SUBJECT(RegExpLastMatchInfo);
|
| + return %_SubString(subject, 0, start_index);
|
| +}
|
| +
|
| +
|
| +function RegExpGetRightContext() {
|
| + var start_index;
|
| + var subject;
|
| + start_index = RegExpLastMatchInfo[CAPTURE1];
|
| + subject = LAST_SUBJECT(RegExpLastMatchInfo);
|
| + return %_SubString(subject, start_index, 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 foo() {
|
| + var index = n * 2;
|
| + 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(RegExpLastMatchInfo), matchStart, matchEnd);
|
| + };
|
| +}
|
| +
|
| +
|
| +// ES6 21.2.5.3.
|
| +function RegExpGetFlags() {
|
| + if (!IS_RECEIVER(this)) {
|
| + throw %make_type_error(
|
| + kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this));
|
| + }
|
| + var result = '';
|
| + if (this.global) result += 'g';
|
| + if (this.ignoreCase) result += 'i';
|
| + if (this.multiline) result += 'm';
|
| + if (this.unicode) result += 'u';
|
| + if (this.sticky) result += 'y';
|
| + return result;
|
| +}
|
| +
|
| +
|
| +// ES6 21.2.5.4.
|
| +function RegExpGetGlobal() {
|
| + if (!IS_REGEXP(this)) {
|
| + // TODO(littledan): Remove this RegExp compat workaround
|
| + if (this === GlobalRegExp.prototype) {
|
| + %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
|
| + return UNDEFINED;
|
| + }
|
| + throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.global");
|
| + }
|
| + return TO_BOOLEAN(REGEXP_GLOBAL(this));
|
| +}
|
| +%SetForceInlineFlag(RegExpGetGlobal);
|
| +
|
| +
|
| +// ES6 21.2.5.5.
|
| +function RegExpGetIgnoreCase() {
|
| + if (!IS_REGEXP(this)) {
|
| + // TODO(littledan): Remove this RegExp compat workaround
|
| + if (this === GlobalRegExp.prototype) {
|
| + %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
|
| + return UNDEFINED;
|
| + }
|
| + throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.ignoreCase");
|
| + }
|
| + return TO_BOOLEAN(REGEXP_IGNORE_CASE(this));
|
| +}
|
| +
|
| +
|
| +// ES6 21.2.5.7.
|
| +function RegExpGetMultiline() {
|
| + if (!IS_REGEXP(this)) {
|
| + // TODO(littledan): Remove this RegExp compat workaround
|
| + if (this === GlobalRegExp.prototype) {
|
| + %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
|
| + return UNDEFINED;
|
| + }
|
| + throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.multiline");
|
| + }
|
| + return TO_BOOLEAN(REGEXP_MULTILINE(this));
|
| +}
|
| +
|
| +
|
| +// ES6 21.2.5.10.
|
| +function RegExpGetSource() {
|
| + if (!IS_REGEXP(this)) {
|
| + // TODO(littledan): Remove this RegExp compat workaround
|
| + if (this === GlobalRegExp.prototype) {
|
| + %IncrementUseCounter(kRegExpPrototypeSourceGetter);
|
| + return "(?:)";
|
| + }
|
| + throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.source");
|
| + }
|
| + return REGEXP_SOURCE(this);
|
| +}
|
| +
|
| +
|
| +// ES6 21.2.5.12.
|
| +function RegExpGetSticky() {
|
| + if (!IS_REGEXP(this)) {
|
| + // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
|
| + // TODO(littledan): Remove this workaround or standardize it
|
| + if (this === GlobalRegExp.prototype) {
|
| + %IncrementUseCounter(kRegExpPrototypeStickyGetter);
|
| + return UNDEFINED;
|
| + }
|
| + throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.sticky");
|
| + }
|
| + return TO_BOOLEAN(REGEXP_STICKY(this));
|
| +}
|
| +%SetForceInlineFlag(RegExpGetSticky);
|
| +
|
| +
|
| +// ES6 21.2.5.15.
|
| +function RegExpGetUnicode() {
|
| + if (!IS_REGEXP(this)) {
|
| + // TODO(littledan): Remove this RegExp compat workaround
|
| + if (this === GlobalRegExp.prototype) {
|
| + %IncrementUseCounter(kRegExpPrototypeUnicodeGetter);
|
| + return UNDEFINED;
|
| + }
|
| + throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.unicode");
|
| + }
|
| + return TO_BOOLEAN(REGEXP_UNICODE(this));
|
| +}
|
| +%SetForceInlineFlag(RegExpGetUnicode);
|
| +
|
| +
|
| +function RegExpSpecies() {
|
| + return this;
|
| +}
|
| +
|
| +
|
| // -------------------------------------------------------------------
|
| +
|
| +utils.InstallGetter(GlobalRegExp, speciesSymbol, RegExpSpecies);
|
|
|
| utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
|
| "exec", RegExpSubclassExecJS,
|
| @@ -937,8 +1108,58 @@
|
| splitSymbol, RegExpSubclassSplit,
|
| ]);
|
|
|
| -// Temporary until all RegExpLastMatchInfo accesses are ported to C++.
|
| -SET_PRIVATE(GlobalRegExp, lastMatchInfoSymbol, RegExpLastMatchInfo);
|
| +utils.InstallGetter(GlobalRegExp.prototype, 'flags', RegExpGetFlags);
|
| +utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal);
|
| +utils.InstallGetter(GlobalRegExp.prototype, 'ignoreCase', RegExpGetIgnoreCase);
|
| +utils.InstallGetter(GlobalRegExp.prototype, 'multiline', RegExpGetMultiline);
|
| +utils.InstallGetter(GlobalRegExp.prototype, 'source', RegExpGetSource);
|
| +utils.InstallGetter(GlobalRegExp.prototype, 'sticky', RegExpGetSticky);
|
| +utils.InstallGetter(GlobalRegExp.prototype, 'unicode', RegExpGetUnicode);
|
| +
|
| +// 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) = TO_STRING(string);
|
| +};
|
| +
|
| +%OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22);
|
| +utils.InstallGetterSetter(GlobalRegExp, 'input', RegExpGetInput, RegExpSetInput,
|
| + DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, '$_', RegExpGetInput, RegExpSetInput,
|
| + DONT_ENUM | DONT_DELETE);
|
| +
|
| +
|
| +var NoOpSetter = function(ignored) {};
|
| +
|
| +
|
| +// Static properties set by a successful match.
|
| +utils.InstallGetterSetter(GlobalRegExp, 'lastMatch', RegExpGetLastMatch,
|
| + NoOpSetter, DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, '$&', RegExpGetLastMatch, NoOpSetter,
|
| + DONT_ENUM | DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, 'lastParen', RegExpGetLastParen,
|
| + NoOpSetter, DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, '$+', RegExpGetLastParen, NoOpSetter,
|
| + DONT_ENUM | DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, 'leftContext', RegExpGetLeftContext,
|
| + NoOpSetter, DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, '$`', RegExpGetLeftContext, NoOpSetter,
|
| + DONT_ENUM | DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, 'rightContext', RegExpGetRightContext,
|
| + NoOpSetter, DONT_DELETE);
|
| +utils.InstallGetterSetter(GlobalRegExp, "$'", RegExpGetRightContext, NoOpSetter,
|
| + DONT_ENUM | DONT_DELETE);
|
| +
|
| +for (var i = 1; i < 10; ++i) {
|
| + utils.InstallGetterSetter(GlobalRegExp, '$' + i, RegExpMakeCaptureGetter(i),
|
| + NoOpSetter, DONT_DELETE);
|
| +}
|
| +%ToFastProperties(GlobalRegExp);
|
|
|
| // -------------------------------------------------------------------
|
| // Internal
|
|
|