blob: c76b09d37706d9025614623f27d703a17aff0fbb [file] [log] [blame]
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Expect $Object = global.Object;
29// Expect $Array = global.Array;
30
31const $RegExp = global.RegExp;
32
33// A recursive descent parser for Patterns according to the grammar of
34// ECMA-262 15.10.1, with deviations noted below.
35function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
36 // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
37 if (IS_REGEXP(pattern)) {
38 if (!IS_UNDEFINED(flags)) {
39 throw MakeTypeError('regexp_flags', []);
40 }
41 flags = (pattern.global ? 'g' : '')
42 + (pattern.ignoreCase ? 'i' : '')
43 + (pattern.multiline ? 'm' : '');
44 pattern = pattern.source;
45 }
46
47 pattern = IS_UNDEFINED(pattern) ? '' : ToString(pattern);
48 flags = IS_UNDEFINED(flags) ? '' : ToString(flags);
49
50 var global = false;
51 var ignoreCase = false;
52 var multiline = false;
53
54 for (var i = 0; i < flags.length; i++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000055 var c = StringCharAt.call(flags, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056 switch (c) {
57 case 'g':
iposva@chromium.org245aa852009-02-10 00:49:54 +000058 // Allow duplicate flags to be consistent with JSC and others.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059 global = true;
60 break;
61 case 'i':
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062 ignoreCase = true;
63 break;
64 case 'm':
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065 multiline = true;
66 break;
67 default:
68 // Ignore flags that have no meaning to be consistent with
iposva@chromium.org245aa852009-02-10 00:49:54 +000069 // JSC.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070 break;
71 }
72 }
73
lrn@chromium.org25156de2010-04-06 13:10:27 +000074 if (!isConstructorCall) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000075 regExpCache.type = 'none';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076 }
lrn@chromium.org25156de2010-04-06 13:10:27 +000077 %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078
79 // Call internal function to compile the pattern.
80 %RegExpCompile(object, pattern, flags);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000081}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082
83
84function RegExpConstructor(pattern, flags) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000085 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000086 DoConstructRegExp(this, pattern, flags, true);
87 } else {
88 // RegExp : Called as function; see ECMA-262, section 15.10.3.1.
89 if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) {
90 return pattern;
91 }
92 return new $RegExp(pattern, flags);
93 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000094}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095
96
97// Deprecated RegExp.prototype.compile method. We behave like the constructor
98// were called again. In SpiderMonkey, this method returns the regexp object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000099// In JSC, it returns undefined. For compatibility with JSC, we match their
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100// behavior.
101function CompileRegExp(pattern, flags) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102 // Both JSC and SpiderMonkey treat a missing pattern argument as the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 // empty subject string, and an actual undefined value passed as the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000104 // pattern as the string 'undefined'. Note that JSC is inconsistent
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 // here, treating undefined values differently in
106 // RegExp.prototype.compile and in the constructor, where they are
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000107 // the empty string. For compatibility with JSC, we match their
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 // behavior.
109 if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
110 DoConstructRegExp(this, 'undefined', flags, false);
111 } else {
112 DoConstructRegExp(this, pattern, flags, false);
113 }
114}
115
116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117function DoRegExpExec(regexp, string, index) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000118 return %_RegExpExec(regexp, string, index, lastMatchInfo);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000119}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120
121
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000122function RegExpCache() {
123 this.type = 'none';
124 this.regExp = 0;
125 this.subject = 0;
126 this.replaceString = 0;
127 this.lastIndex = 0;
128 this.answer = 0;
ager@chromium.org357bf652010-04-12 11:30:10 +0000129 // answerSaved marks whether the contents of answer is valid for a cache
130 // hit in RegExpExec, StringMatch and StringSplit.
131 this.answerSaved = false;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000132}
133
134
135var regExpCache = new RegExpCache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000136
137
138function CloneRegexpAnswer(array) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000139 if (array == null) return null;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000140 var len = array.length;
141 var answer = new $Array(len);
142 for (var i = 0; i < len; i++) {
143 answer[i] = array[i];
144 }
145 answer.index = array.index;
146 answer.input = array.input;
147 return answer;
148}
149
150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151function RegExpExec(string) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000152 if (!IS_REGEXP(this)) {
153 throw MakeTypeError('incompatible_method_receiver',
154 ['RegExp.prototype.exec', this]);
155 }
156
157 var cache = regExpCache;
ager@chromium.org357bf652010-04-12 11:30:10 +0000158 var saveAnswer = false;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000159
160 if (%_ObjectEquals(cache.type, 'exec') &&
161 %_ObjectEquals(cache.lastIndex, this.lastIndex) &&
162 %_ObjectEquals(cache.regExp, this) &&
163 %_ObjectEquals(cache.subject, string)) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000164 if (cache.answerSaved) {
165 return CloneRegexpAnswer(cache.answer);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000166 } else {
ager@chromium.org357bf652010-04-12 11:30:10 +0000167 saveAnswer = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000168 }
169 }
170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 if (%_ArgumentsLength() == 0) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000172 var regExpInput = LAST_INPUT(lastMatchInfo);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000173 if (IS_UNDEFINED(regExpInput)) {
174 throw MakeError('no_input_to_regexp', [this]);
175 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000176 string = regExpInput;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000177 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000178 var s;
179 if (IS_STRING(string)) {
180 s = string;
181 } else {
182 s = ToString(string);
183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184 var lastIndex = this.lastIndex;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000185
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186 var i = this.global ? TO_INTEGER(lastIndex) : 0;
187
188 if (i < 0 || i > s.length) {
189 this.lastIndex = 0;
190 return null;
191 }
192
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000193 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000194 // matchIndices is either null or the lastMatchInfo array.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000195 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196
197 if (matchIndices == null) {
198 if (this.global) this.lastIndex = 0;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000199 cache.lastIndex = lastIndex;
200 cache.regExp = this;
201 cache.subject = s;
202 cache.answer = matchIndices; // Null.
ager@chromium.org357bf652010-04-12 11:30:10 +0000203 cache.answerSaved = true; // Safe since no cloning is needed.
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000204 cache.type = 'exec';
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000205 return matchIndices; // No match.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206 }
207
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000208 var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000209 var result;
210 if (numResults === 1) {
211 var matchStart = lastMatchInfo[CAPTURE(0)];
212 var matchEnd = lastMatchInfo[CAPTURE(1)];
213 result = [SubString(s, matchStart, matchEnd)];
214 } else {
215 result = new $Array(numResults);
216 for (var i = 0; i < numResults; i++) {
217 var matchStart = lastMatchInfo[CAPTURE(i << 1)];
218 var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
219 if (matchStart != -1 && matchEnd != -1) {
220 result[i] = SubString(s, matchStart, matchEnd);
221 } else {
222 // Make sure the element is present. Avoid reading the undefined
223 // property from the global object since this may change.
224 result[i] = void 0;
225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226 }
227 }
228
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000229 result.index = lastMatchInfo[CAPTURE0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 result.input = s;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000231 if (this.global) {
232 this.lastIndex = lastMatchInfo[CAPTURE1];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000233 } else {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000234 cache.regExp = this;
235 cache.subject = s;
236 cache.lastIndex = lastIndex;
ager@chromium.org357bf652010-04-12 11:30:10 +0000237 if (saveAnswer) cache.answer = CloneRegexpAnswer(result);
238 cache.answerSaved = saveAnswer;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000239 cache.type = 'exec';
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000240 }
ager@chromium.org357bf652010-04-12 11:30:10 +0000241 return result;
242
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000243}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244
245
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000246// Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000247// that test is defined in terms of String.prototype.exec. However, it probably
248// means the original value of String.prototype.exec, which is what everybody
249// else implements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250function RegExpTest(string) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000251 if (!IS_REGEXP(this)) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000252 throw MakeTypeError('incompatible_method_receiver',
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000253 ['RegExp.prototype.test', this]);
254 }
255 if (%_ArgumentsLength() == 0) {
256 var regExpInput = LAST_INPUT(lastMatchInfo);
257 if (IS_UNDEFINED(regExpInput)) {
258 throw MakeError('no_input_to_regexp', [this]);
259 }
260 string = regExpInput;
261 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000262 var s;
263 if (IS_STRING(string)) {
264 s = string;
265 } else {
266 s = ToString(string);
267 }
268
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000269 var lastIndex = this.lastIndex;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000270
271 var cache = regExpCache;
272
273 if (%_ObjectEquals(cache.type, 'test') &&
274 %_ObjectEquals(cache.regExp, this) &&
275 %_ObjectEquals(cache.subject, string) &&
276 %_ObjectEquals(cache.lastIndex, lastIndex)) {
277 return cache.answer;
278 }
279
280 var length = s.length;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000281 var i = this.global ? TO_INTEGER(lastIndex) : 0;
282
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000283 cache.type = 'test';
284 cache.regExp = this;
285 cache.subject = s;
286 cache.lastIndex = i;
287
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000288 if (i < 0 || i > s.length) {
289 this.lastIndex = 0;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000290 cache.answer = false;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000291 return false;
292 }
293
294 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
295 // matchIndices is either null or the lastMatchInfo array.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000296 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000297
298 if (matchIndices == null) {
299 if (this.global) this.lastIndex = 0;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000300 cache.answer = false;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000301 return false;
302 }
303
304 if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1];
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000305 cache.answer = true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000306 return true;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308
309
310function RegExpToString() {
311 // If this.source is an empty string, output /(?:)/.
312 // http://bugzilla.mozilla.org/show_bug.cgi?id=225550
313 // ecma_2/RegExp/properties-001.js.
314 var src = this.source ? this.source : '(?:)';
315 var result = '/' + src + '/';
316 if (this.global)
317 result += 'g';
318 if (this.ignoreCase)
319 result += 'i';
320 if (this.multiline)
321 result += 'm';
322 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000323}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
325
326// Getters for the static properties lastMatch, lastParen, leftContext, and
327// rightContext of the RegExp constructor. The properties are computed based
328// on the captures array of the last successful match and the subject string
329// of the last successful match.
330function RegExpGetLastMatch() {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000331 if (lastMatchInfoOverride) { return lastMatchInfoOverride[0]; }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000332 var regExpSubject = LAST_SUBJECT(lastMatchInfo);
333 return SubString(regExpSubject,
334 lastMatchInfo[CAPTURE0],
335 lastMatchInfo[CAPTURE1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336}
337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338
339function RegExpGetLastParen() {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000340 if (lastMatchInfoOverride) {
341 var override = lastMatchInfoOverride;
342 if (override.length <= 3) return '';
343 return override[override.length - 3];
344 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000345 var length = NUMBER_OF_CAPTURES(lastMatchInfo);
346 if (length <= 2) return ''; // There were no captures.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347 // We match the SpiderMonkey behavior: return the substring defined by the
348 // last pair (after the first pair) of elements of the capture array even if
349 // it is empty.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000350 var regExpSubject = LAST_SUBJECT(lastMatchInfo);
351 var start = lastMatchInfo[CAPTURE(length - 2)];
352 var end = lastMatchInfo[CAPTURE(length - 1)];
353 if (start != -1 && end != -1) {
354 return SubString(regExpSubject, start, end);
355 }
356 return "";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000357}
358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359
360function RegExpGetLeftContext() {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000361 var start_index;
362 var subject;
363 if (!lastMatchInfoOverride) {
364 start_index = lastMatchInfo[CAPTURE0];
365 subject = LAST_SUBJECT(lastMatchInfo);
366 } else {
367 var override = lastMatchInfoOverride;
368 start_index = override[override.length - 2];
369 subject = override[override.length - 1];
370 }
371 return SubString(subject, 0, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000372}
373
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374
375function RegExpGetRightContext() {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000376 var start_index;
377 var subject;
378 if (!lastMatchInfoOverride) {
379 start_index = lastMatchInfo[CAPTURE1];
380 subject = LAST_SUBJECT(lastMatchInfo);
381 } else {
382 var override = lastMatchInfoOverride;
383 subject = override[override.length - 1];
384 start_index = override[override.length - 2] + subject.length;
385 }
386 return SubString(subject, start_index, subject.length);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000387}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000388
389
390// The properties $1..$9 are the first nine capturing substrings of the last
391// successful match, or ''. The function RegExpMakeCaptureGetter will be
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000392// called with indices from 1 to 9.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000393function RegExpMakeCaptureGetter(n) {
394 return function() {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000395 if (lastMatchInfoOverride) {
396 if (n < lastMatchInfoOverride.length - 2) return lastMatchInfoOverride[n];
397 return '';
398 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 var index = n * 2;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000400 if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return '';
401 var matchStart = lastMatchInfo[CAPTURE(index)];
402 var matchEnd = lastMatchInfo[CAPTURE(index + 1)];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000403 if (matchStart == -1 || matchEnd == -1) return '';
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000404 return SubString(LAST_SUBJECT(lastMatchInfo), matchStart, matchEnd);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 };
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000406}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407
408
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000409// Property of the builtins object for recording the result of the last
410// regexp match. The property lastMatchInfo includes the matchIndices
411// array of the last successful regexp match (an array of start/end index
412// pairs for the match and all the captured substrings), the invariant is
413// that there are at least two capture indeces. The array also contains
414// the subject string for the last successful match.
415var lastMatchInfo = [
416 2, // REGEXP_NUMBER_OF_CAPTURES
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000417 "", // Last subject.
418 void 0, // Last input - settable with RegExpSetInput.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419 0, // REGEXP_FIRST_CAPTURE + 0
420 0, // REGEXP_FIRST_CAPTURE + 1
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000421];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000422
lrn@chromium.org25156de2010-04-06 13:10:27 +0000423// Override last match info with an array of actual substrings.
424// Used internally by replace regexp with function.
425// The array has the format of an "apply" argument for a replacement
426// function.
427var lastMatchInfoOverride = null;
428
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000429// -------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000431function SetupRegExp() {
432 %FunctionSetInstanceClassName($RegExp, 'RegExp');
433 %FunctionSetPrototype($RegExp, new $Object());
434 %SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
435 %SetCode($RegExp, RegExpConstructor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000437 InstallFunctions($RegExp.prototype, DONT_ENUM, $Array(
438 "exec", RegExpExec,
439 "test", RegExpTest,
440 "toString", RegExpToString,
441 "compile", CompileRegExp
442 ));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000444 // The length of compile is 1 in SpiderMonkey.
445 %FunctionSetLength($RegExp.prototype.compile, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000447 // The properties input, $input, and $_ are aliases for each other. When this
lrn@chromium.org25156de2010-04-06 13:10:27 +0000448 // value is set the value it is set to is coerced to a string.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000449 // Getter and setter for the input.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000450 function RegExpGetInput() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000451 var regExpInput = LAST_INPUT(lastMatchInfo);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000452 return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
453 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000454 function RegExpSetInput(string) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000455 regExpCache.type = 'none';
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000456 LAST_INPUT(lastMatchInfo) = ToString(string);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000457 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000459 %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
460 %DefineAccessor($RegExp, 'input', SETTER, RegExpSetInput, DONT_DELETE);
461 %DefineAccessor($RegExp, '$_', GETTER, RegExpGetInput, DONT_ENUM | DONT_DELETE);
462 %DefineAccessor($RegExp, '$_', SETTER, RegExpSetInput, DONT_ENUM | DONT_DELETE);
463 %DefineAccessor($RegExp, '$input', GETTER, RegExpGetInput, DONT_ENUM | DONT_DELETE);
464 %DefineAccessor($RegExp, '$input', SETTER, RegExpSetInput, DONT_ENUM | DONT_DELETE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000465
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000466 // The properties multiline and $* are aliases for each other. When this
467 // value is set in SpiderMonkey, the value it is set to is coerced to a
468 // boolean. We mimic that behavior with a slight difference: in SpiderMonkey
469 // the value of the expression 'RegExp.multiline = null' (for instance) is the
470 // boolean false (ie, the value after coercion), while in V8 it is the value
471 // null (ie, the value before coercion).
472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473 // Getter and setter for multiline.
474 var multiline = false;
475 function RegExpGetMultiline() { return multiline; };
476 function RegExpSetMultiline(flag) { multiline = flag ? true : false; };
477
478 %DefineAccessor($RegExp, 'multiline', GETTER, RegExpGetMultiline, DONT_DELETE);
479 %DefineAccessor($RegExp, 'multiline', SETTER, RegExpSetMultiline, DONT_DELETE);
480 %DefineAccessor($RegExp, '$*', GETTER, RegExpGetMultiline, DONT_ENUM | DONT_DELETE);
481 %DefineAccessor($RegExp, '$*', SETTER, RegExpSetMultiline, DONT_ENUM | DONT_DELETE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482
483
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000484 function NoOpSetter(ignored) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
486
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000487 // Static properties set by a successful match.
488 %DefineAccessor($RegExp, 'lastMatch', GETTER, RegExpGetLastMatch, DONT_DELETE);
489 %DefineAccessor($RegExp, 'lastMatch', SETTER, NoOpSetter, DONT_DELETE);
490 %DefineAccessor($RegExp, '$&', GETTER, RegExpGetLastMatch, DONT_ENUM | DONT_DELETE);
491 %DefineAccessor($RegExp, '$&', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
492 %DefineAccessor($RegExp, 'lastParen', GETTER, RegExpGetLastParen, DONT_DELETE);
493 %DefineAccessor($RegExp, 'lastParen', SETTER, NoOpSetter, DONT_DELETE);
494 %DefineAccessor($RegExp, '$+', GETTER, RegExpGetLastParen, DONT_ENUM | DONT_DELETE);
495 %DefineAccessor($RegExp, '$+', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
496 %DefineAccessor($RegExp, 'leftContext', GETTER, RegExpGetLeftContext, DONT_DELETE);
497 %DefineAccessor($RegExp, 'leftContext', SETTER, NoOpSetter, DONT_DELETE);
498 %DefineAccessor($RegExp, '$`', GETTER, RegExpGetLeftContext, DONT_ENUM | DONT_DELETE);
499 %DefineAccessor($RegExp, '$`', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
500 %DefineAccessor($RegExp, 'rightContext', GETTER, RegExpGetRightContext, DONT_DELETE);
501 %DefineAccessor($RegExp, 'rightContext', SETTER, NoOpSetter, DONT_DELETE);
502 %DefineAccessor($RegExp, "$'", GETTER, RegExpGetRightContext, DONT_ENUM | DONT_DELETE);
503 %DefineAccessor($RegExp, "$'", SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505 for (var i = 1; i < 10; ++i) {
506 %DefineAccessor($RegExp, '$' + i, GETTER, RegExpMakeCaptureGetter(i), DONT_DELETE);
507 %DefineAccessor($RegExp, '$' + i, SETTER, NoOpSetter, DONT_DELETE);
508 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000509}
510
511
512SetupRegExp();