Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1018)

Side by Side Diff: src/js/regexp.js

Issue 1418703003: RegExp: remove last match info override. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/js/string.js » ('j') | src/runtime/runtime-regexp.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 var $regexpLastMatchInfoOverride;
6
7 (function(global, utils) { 5 (function(global, utils) {
8 6
9 %CheckIsBootstrapping(); 7 %CheckIsBootstrapping();
10 8
11 // ------------------------------------------------------------------- 9 // -------------------------------------------------------------------
12 // Imports 10 // Imports
13 11
14 var FLAG_harmony_regexps; 12 var FLAG_harmony_regexps;
15 var FLAG_harmony_tolength; 13 var FLAG_harmony_tolength;
16 var FLAG_harmony_unicode_regexps; 14 var FLAG_harmony_unicode_regexps;
(...skipping 20 matching lines...) Expand all
37 // that there are at least two capture indeces. The array also contains 35 // that there are at least two capture indeces. The array also contains
38 // the subject string for the last successful match. 36 // the subject string for the last successful match.
39 var RegExpLastMatchInfo = new InternalPackedArray( 37 var RegExpLastMatchInfo = new InternalPackedArray(
40 2, // REGEXP_NUMBER_OF_CAPTURES 38 2, // REGEXP_NUMBER_OF_CAPTURES
41 "", // Last subject. 39 "", // Last subject.
42 UNDEFINED, // Last input - settable with RegExpSetInput. 40 UNDEFINED, // Last input - settable with RegExpSetInput.
43 0, // REGEXP_FIRST_CAPTURE + 0 41 0, // REGEXP_FIRST_CAPTURE + 0
44 0 // REGEXP_FIRST_CAPTURE + 1 42 0 // REGEXP_FIRST_CAPTURE + 1
45 ); 43 );
46 44
47 // Override last match info with an array of actual substrings.
48 // Used internally by replace regexp with function.
49 // The array has the format of an "apply" argument for a replacement
50 // function.
51 $regexpLastMatchInfoOverride = null;
52
53 // ------------------------------------------------------------------- 45 // -------------------------------------------------------------------
54 46
55 // A recursive descent parser for Patterns according to the grammar of 47 // A recursive descent parser for Patterns according to the grammar of
56 // ECMA-262 15.10.1, with deviations noted below. 48 // ECMA-262 15.10.1, with deviations noted below.
57 function DoConstructRegExp(object, pattern, flags) { 49 function DoConstructRegExp(object, pattern, flags) {
58 // RegExp : Called as constructor; see ECMA-262, section 15.10.4. 50 // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
59 if (IS_REGEXP(pattern)) { 51 if (IS_REGEXP(pattern)) {
60 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags); 52 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags);
61 flags = (pattern.global ? 'g' : '') 53 flags = (pattern.global ? 'g' : '')
62 + (pattern.ignoreCase ? 'i' : '') 54 + (pattern.ignoreCase ? 'i' : '')
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) { 99 if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
108 DoConstructRegExp(this, 'undefined', flags); 100 DoConstructRegExp(this, 'undefined', flags);
109 } else { 101 } else {
110 DoConstructRegExp(this, pattern, flags); 102 DoConstructRegExp(this, pattern, flags);
111 } 103 }
112 } 104 }
113 105
114 106
115 function DoRegExpExec(regexp, string, index) { 107 function DoRegExpExec(regexp, string, index) {
116 var result = %_RegExpExec(regexp, string, index, RegExpLastMatchInfo); 108 var result = %_RegExpExec(regexp, string, index, RegExpLastMatchInfo);
117 if (result !== null) $regexpLastMatchInfoOverride = null;
118 return result; 109 return result;
119 } 110 }
120 111
121 112
122 // This is kind of performance sensitive, so we want to avoid unnecessary 113 // This is kind of performance sensitive, so we want to avoid unnecessary
123 // type checks on inputs. But we also don't want to inline it several times 114 // type checks on inputs. But we also don't want to inline it several times
124 // manually, so we use a macro :-) 115 // manually, so we use a macro :-)
125 macro RETURN_NEW_RESULT_FROM_MATCH_INFO(MATCHINFO, STRING) 116 macro RETURN_NEW_RESULT_FROM_MATCH_INFO(MATCHINFO, STRING)
126 var numResults = NUMBER_OF_CAPTURES(MATCHINFO) >> 1; 117 var numResults = NUMBER_OF_CAPTURES(MATCHINFO) >> 1;
127 var start = MATCHINFO[CAPTURE0]; 118 var start = MATCHINFO[CAPTURE0];
(...skipping 14 matching lines...) Expand all
142 j++; 133 j++;
143 } 134 }
144 return result; 135 return result;
145 endmacro 136 endmacro
146 137
147 138
148 function RegExpExecNoTests(regexp, string, start) { 139 function RegExpExecNoTests(regexp, string, start) {
149 // Must be called with RegExp, string and positive integer as arguments. 140 // Must be called with RegExp, string and positive integer as arguments.
150 var matchInfo = %_RegExpExec(regexp, string, start, RegExpLastMatchInfo); 141 var matchInfo = %_RegExpExec(regexp, string, start, RegExpLastMatchInfo);
151 if (matchInfo !== null) { 142 if (matchInfo !== null) {
152 $regexpLastMatchInfoOverride = null;
153 // ES6 21.2.5.2.2 step 18. 143 // ES6 21.2.5.2.2 step 18.
154 if (FLAG_harmony_regexps && regexp.sticky) { 144 if (FLAG_harmony_regexps && regexp.sticky) {
155 regexp.lastIndex = matchInfo[CAPTURE1]; 145 regexp.lastIndex = matchInfo[CAPTURE1];
156 } 146 }
157 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string); 147 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string);
158 } 148 }
159 regexp.lastIndex = 0; 149 regexp.lastIndex = 0;
160 return null; 150 return null;
161 } 151 }
162 152
(...skipping 23 matching lines...) Expand all
186 176
187 // matchIndices is either null or the RegExpLastMatchInfo array. 177 // matchIndices is either null or the RegExpLastMatchInfo array.
188 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); 178 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo);
189 179
190 if (IS_NULL(matchIndices)) { 180 if (IS_NULL(matchIndices)) {
191 this.lastIndex = 0; 181 this.lastIndex = 0;
192 return null; 182 return null;
193 } 183 }
194 184
195 // Successful match. 185 // Successful match.
196 $regexpLastMatchInfoOverride = null;
197 if (updateLastIndex) { 186 if (updateLastIndex) {
198 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; 187 this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
199 } 188 }
200 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); 189 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
201 } 190 }
202 191
203 192
204 // One-element cache for the simplified test regexp. 193 // One-element cache for the simplified test regexp.
205 var regexp_key; 194 var regexp_key;
206 var regexp_val; 195 var regexp_val;
(...skipping 19 matching lines...) Expand all
226 if (i < 0 || i > string.length) { 215 if (i < 0 || i > string.length) {
227 this.lastIndex = 0; 216 this.lastIndex = 0;
228 return false; 217 return false;
229 } 218 }
230 // matchIndices is either null or the RegExpLastMatchInfo array. 219 // matchIndices is either null or the RegExpLastMatchInfo array.
231 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); 220 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo);
232 if (IS_NULL(matchIndices)) { 221 if (IS_NULL(matchIndices)) {
233 this.lastIndex = 0; 222 this.lastIndex = 0;
234 return false; 223 return false;
235 } 224 }
236 $regexpLastMatchInfoOverride = null;
237 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; 225 this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
238 return true; 226 return true;
239 } else { 227 } else {
240 // Non-global, non-sticky regexp. 228 // Non-global, non-sticky regexp.
241 // Remove irrelevant preceeding '.*' in a test regexp. The expression 229 // Remove irrelevant preceeding '.*' in a test regexp. The expression
242 // checks whether this.source starts with '.*' and that the third char is 230 // checks whether this.source starts with '.*' and that the third char is
243 // not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560 231 // not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560
244 var regexp = this; 232 var regexp = this;
245 if (regexp.source.length >= 3 && 233 if (regexp.source.length >= 3 &&
246 %_StringCharCodeAt(regexp.source, 0) == 46 && // '.' 234 %_StringCharCodeAt(regexp.source, 0) == 46 && // '.'
247 %_StringCharCodeAt(regexp.source, 1) == 42 && // '*' 235 %_StringCharCodeAt(regexp.source, 1) == 42 && // '*'
248 %_StringCharCodeAt(regexp.source, 2) != 63) { // '?' 236 %_StringCharCodeAt(regexp.source, 2) != 63) { // '?'
249 regexp = TrimRegExp(regexp); 237 regexp = TrimRegExp(regexp);
250 } 238 }
251 // matchIndices is either null or the RegExpLastMatchInfo array. 239 // matchIndices is either null or the RegExpLastMatchInfo array.
252 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo); 240 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo);
253 if (IS_NULL(matchIndices)) { 241 if (IS_NULL(matchIndices)) {
254 this.lastIndex = 0; 242 this.lastIndex = 0;
255 return false; 243 return false;
256 } 244 }
257 $regexpLastMatchInfoOverride = null;
258 return true; 245 return true;
259 } 246 }
260 } 247 }
261 248
262 function TrimRegExp(regexp) { 249 function TrimRegExp(regexp) {
263 if (!%_ObjectEquals(regexp_key, regexp)) { 250 if (!%_ObjectEquals(regexp_key, regexp)) {
264 regexp_key = regexp; 251 regexp_key = regexp;
265 regexp_val = 252 regexp_val =
266 new GlobalRegExp(%_SubString(regexp.source, 2, regexp.source.length), 253 new GlobalRegExp(%_SubString(regexp.source, 2, regexp.source.length),
267 (regexp.ignoreCase ? regexp.multiline ? "im" : "i" 254 (regexp.ignoreCase ? regexp.multiline ? "im" : "i"
(...skipping 16 matching lines...) Expand all
284 if (FLAG_harmony_regexps && this.sticky) result += 'y'; 271 if (FLAG_harmony_regexps && this.sticky) result += 'y';
285 return result; 272 return result;
286 } 273 }
287 274
288 275
289 // Getters for the static properties lastMatch, lastParen, leftContext, and 276 // Getters for the static properties lastMatch, lastParen, leftContext, and
290 // rightContext of the RegExp constructor. The properties are computed based 277 // rightContext of the RegExp constructor. The properties are computed based
291 // on the captures array of the last successful match and the subject string 278 // on the captures array of the last successful match and the subject string
292 // of the last successful match. 279 // of the last successful match.
293 function RegExpGetLastMatch() { 280 function RegExpGetLastMatch() {
294 if ($regexpLastMatchInfoOverride !== null) {
295 return OVERRIDE_MATCH($regexpLastMatchInfoOverride);
296 }
297 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); 281 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo);
298 return %_SubString(regExpSubject, 282 return %_SubString(regExpSubject,
299 RegExpLastMatchInfo[CAPTURE0], 283 RegExpLastMatchInfo[CAPTURE0],
300 RegExpLastMatchInfo[CAPTURE1]); 284 RegExpLastMatchInfo[CAPTURE1]);
301 } 285 }
302 286
303 287
304 function RegExpGetLastParen() { 288 function RegExpGetLastParen() {
305 if ($regexpLastMatchInfoOverride) {
306 var override = $regexpLastMatchInfoOverride;
307 if (override.length <= 3) return '';
308 return override[override.length - 3];
309 }
310 var length = NUMBER_OF_CAPTURES(RegExpLastMatchInfo); 289 var length = NUMBER_OF_CAPTURES(RegExpLastMatchInfo);
311 if (length <= 2) return ''; // There were no captures. 290 if (length <= 2) return ''; // There were no captures.
312 // We match the SpiderMonkey behavior: return the substring defined by the 291 // We match the SpiderMonkey behavior: return the substring defined by the
313 // last pair (after the first pair) of elements of the capture array even if 292 // last pair (after the first pair) of elements of the capture array even if
314 // it is empty. 293 // it is empty.
315 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); 294 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo);
316 var start = RegExpLastMatchInfo[CAPTURE(length - 2)]; 295 var start = RegExpLastMatchInfo[CAPTURE(length - 2)];
317 var end = RegExpLastMatchInfo[CAPTURE(length - 1)]; 296 var end = RegExpLastMatchInfo[CAPTURE(length - 1)];
318 if (start != -1 && end != -1) { 297 if (start != -1 && end != -1) {
319 return %_SubString(regExpSubject, start, end); 298 return %_SubString(regExpSubject, start, end);
320 } 299 }
321 return ""; 300 return "";
322 } 301 }
323 302
324 303
325 function RegExpGetLeftContext() { 304 function RegExpGetLeftContext() {
326 var start_index; 305 var start_index;
327 var subject; 306 var subject;
328 if (!$regexpLastMatchInfoOverride) { 307 start_index = RegExpLastMatchInfo[CAPTURE0];
329 start_index = RegExpLastMatchInfo[CAPTURE0]; 308 subject = LAST_SUBJECT(RegExpLastMatchInfo);
330 subject = LAST_SUBJECT(RegExpLastMatchInfo);
331 } else {
332 var override = $regexpLastMatchInfoOverride;
333 start_index = OVERRIDE_POS(override);
334 subject = OVERRIDE_SUBJECT(override);
335 }
336 return %_SubString(subject, 0, start_index); 309 return %_SubString(subject, 0, start_index);
337 } 310 }
338 311
339 312
340 function RegExpGetRightContext() { 313 function RegExpGetRightContext() {
341 var start_index; 314 var start_index;
342 var subject; 315 var subject;
343 if (!$regexpLastMatchInfoOverride) { 316 start_index = RegExpLastMatchInfo[CAPTURE1];
344 start_index = RegExpLastMatchInfo[CAPTURE1]; 317 subject = LAST_SUBJECT(RegExpLastMatchInfo);
345 subject = LAST_SUBJECT(RegExpLastMatchInfo);
346 } else {
347 var override = $regexpLastMatchInfoOverride;
348 subject = OVERRIDE_SUBJECT(override);
349 var match = OVERRIDE_MATCH(override);
350 start_index = OVERRIDE_POS(override) + match.length;
351 }
352 return %_SubString(subject, start_index, subject.length); 318 return %_SubString(subject, start_index, subject.length);
353 } 319 }
354 320
355 321
356 // The properties $1..$9 are the first nine capturing substrings of the last 322 // The properties $1..$9 are the first nine capturing substrings of the last
357 // successful match, or ''. The function RegExpMakeCaptureGetter will be 323 // successful match, or ''. The function RegExpMakeCaptureGetter will be
358 // called with indices from 1 to 9. 324 // called with indices from 1 to 9.
359 function RegExpMakeCaptureGetter(n) { 325 function RegExpMakeCaptureGetter(n) {
360 return function foo() { 326 return function foo() {
361 if ($regexpLastMatchInfoOverride) {
362 if (n < $regexpLastMatchInfoOverride.length - 2) {
363 return OVERRIDE_CAPTURE($regexpLastMatchInfoOverride, n);
364 }
365 return '';
366 }
367 var index = n * 2; 327 var index = n * 2;
368 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return ''; 328 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return '';
369 var matchStart = RegExpLastMatchInfo[CAPTURE(index)]; 329 var matchStart = RegExpLastMatchInfo[CAPTURE(index)];
370 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)]; 330 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)];
371 if (matchStart == -1 || matchEnd == -1) return ''; 331 if (matchStart == -1 || matchEnd == -1) return '';
372 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd); 332 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd);
373 }; 333 };
374 } 334 }
375 335
376 // ------------------------------------------------------------------- 336 // -------------------------------------------------------------------
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 // Exports 420 // Exports
461 421
462 utils.Export(function(to) { 422 utils.Export(function(to) {
463 to.RegExpExec = DoRegExpExec; 423 to.RegExpExec = DoRegExpExec;
464 to.RegExpExecNoTests = RegExpExecNoTests; 424 to.RegExpExecNoTests = RegExpExecNoTests;
465 to.RegExpLastMatchInfo = RegExpLastMatchInfo; 425 to.RegExpLastMatchInfo = RegExpLastMatchInfo;
466 to.RegExpTest = RegExpTest; 426 to.RegExpTest = RegExpTest;
467 }); 427 });
468 428
469 }) 429 })
OLDNEW
« no previous file with comments | « no previous file | src/js/string.js » ('j') | src/runtime/runtime-regexp.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698