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

Side by Side Diff: src/string.js

Issue 28184: Avoids allocating a JSArray of capture information on each non-global... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 10 months 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 if (!regexp.global) return regexp.exec(subject); 158 if (!regexp.global) return regexp.exec(subject);
159 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); 159 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
160 var matches = DoRegExpExecGlobal(regexp, subject); 160 var matches = DoRegExpExecGlobal(regexp, subject);
161 161
162 // If the regexp did not match, return null. 162 // If the regexp did not match, return null.
163 if (matches.length == 0) return null; 163 if (matches.length == 0) return null;
164 164
165 // Build the result array. 165 // Build the result array.
166 var result = new $Array(match_string); 166 var result = new $Array(match_string);
167 for (var i = 0; i < matches.length; ++i) { 167 for (var i = 0; i < matches.length; ++i) {
168 var match = matches[i]; 168 var matchInfo = matches[i];
169 var match_string = subject.slice(match[0], match[1]); 169 var match_string = subject.slice(matchInfo[CAPTURE0],
170 matchInfo[CAPTURE1]);
170 result[i] = match_string; 171 result[i] = match_string;
171 } 172 }
172 173
173 return result; 174 return result;
174 } 175 }
175 176
176 177
177 // SubString is an internal function that returns the sub string of 'string'. 178 // SubString is an internal function that returns the sub string of 'string'.
178 // If resulting string is of length 1, we use the one character cache 179 // If resulting string is of length 1, we use the one character cache
179 // otherwise we call the runtime system. 180 // otherwise we call the runtime system.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 var end = start + search.length; 212 var end = start + search.length;
212 213
213 var builder = new ReplaceResultBuilder(subject); 214 var builder = new ReplaceResultBuilder(subject);
214 // prefix 215 // prefix
215 builder.addSpecialSlice(0, start); 216 builder.addSpecialSlice(0, start);
216 217
217 // Compute the string to replace with. 218 // Compute the string to replace with.
218 if (IS_FUNCTION(replace)) { 219 if (IS_FUNCTION(replace)) {
219 builder.add(replace.call(null, search, start, subject)); 220 builder.add(replace.call(null, search, start, subject));
220 } else { 221 } else {
221 ExpandReplacement(ToString(replace), subject, [ start, end ], builder); 222 reusableMatchInfo[CAPTURE0] = start;
223 reusableMatchInfo[CAPTURE1] = end;
224 ExpandReplacement(ToString(replace), subject, reusableMatchInfo, builder);
222 } 225 }
223 226
224 // suffix 227 // suffix
225 builder.addSpecialSlice(end, subject.length); 228 builder.addSpecialSlice(end, subject.length);
226 229
227 return builder.generate(); 230 return builder.generate();
228 } 231 }
229 232
230 233
234 // This has the same size as the lastMatchInfo array, and can be used for
235 // functions that expect that structure to be returned. It is used when the
236 // needle is a string rather than a regexp. In this case we can't update
237 // lastMatchArray without erroneously affecting the properties on the global
238 // RegExp object.
239 var reusableMatchInfo = [2, -1, -1, "", ""];
240 var reusableMatchArray = [ void 0 ];
241
242
231 // Helper function for regular expressions in String.prototype.replace. 243 // Helper function for regular expressions in String.prototype.replace.
232 function StringReplaceRegExp(subject, regexp, replace) { 244 function StringReplaceRegExp(subject, regexp, replace) {
233 // Compute an array of matches; each match is really a list of 245 // Compute an array of matches; each match is really a list of
234 // captures - pairs of (start, end) indexes into the subject string. 246 // captures - pairs of (start, end) indexes into the subject string.
235 var matches; 247 var matches;
236 if (regexp.global) { 248 if (regexp.global) {
237 matches = DoRegExpExecGlobal(regexp, subject); 249 matches = DoRegExpExecGlobal(regexp, subject);
238 if (matches.length == 0) return subject; 250 if (matches.length == 0) return subject;
239 } else { 251 } else {
240 var captures = DoRegExpExec(regexp, subject, 0); 252 var lastMatchInfo = DoRegExpExec(regexp, subject, 0);
241 if (IS_NULL(captures)) return subject; 253 if (IS_NULL(lastMatchInfo)) return subject;
242 matches = [ captures ]; 254 reusableMatchArray[0] = lastMatchInfo;
255 matches = reusableMatchArray;
243 } 256 }
244 257
245 // Determine the number of matches. 258 // Determine the number of matches.
246 var length = matches.length; 259 var length = matches.length;
247 260
248 // Build the resulting string of subject slices and replacements. 261 // Build the resulting string of subject slices and replacements.
249 var result = new ReplaceResultBuilder(subject); 262 var result = new ReplaceResultBuilder(subject);
250 var previous = 0; 263 var previous = 0;
251 // The caller of StringReplaceRegExp must ensure that replace is not a 264 // The caller of StringReplaceRegExp must ensure that replace is not a
252 // function. 265 // function.
253 replace = ToString(replace); 266 replace = ToString(replace);
254 if (%StringIndexOf(replace, "$", 0) < 0) { 267 if (%StringIndexOf(replace, "$", 0) < 0) {
255 for (var i = 0; i < length; i++) { 268 for (var i = 0; i < length; i++) {
256 var captures = matches[i]; 269 var matchInfo = matches[i];
257 result.addSpecialSlice(previous, captures[0]); 270 result.addSpecialSlice(previous, matchInfo[CAPTURE0]);
258 result.add(replace); 271 result.add(replace);
259 previous = captures[1]; // continue after match 272 previous = matchInfo[CAPTURE1]; // continue after match
260 } 273 }
261 } else { 274 } else {
262 for (var i = 0; i < length; i++) { 275 for (var i = 0; i < length; i++) {
263 var captures = matches[i]; 276 var matchInfo = matches[i];
264 result.addSpecialSlice(previous, captures[0]); 277 result.addSpecialSlice(previous, matchInfo[CAPTURE0]);
265 ExpandReplacement(replace, subject, captures, result); 278 ExpandReplacement(replace, subject, matchInfo, result);
266 previous = captures[1]; // continue after match 279 previous = matchInfo[CAPTURE1]; // continue after match
267 } 280 }
268 } 281 }
269 result.addSpecialSlice(previous, subject.length); 282 result.addSpecialSlice(previous, subject.length);
270 return result.generate(); 283 return result.generate();
271 }; 284 };
272 285
273 286
274 // Expand the $-expressions in the string and return a new string with 287 // Expand the $-expressions in the string and return a new string with
275 // the result. 288 // the result.
276 function ExpandReplacement(string, subject, captures, builder) { 289 function ExpandReplacement(string, subject, matchInfo, builder) {
277 var next = %StringIndexOf(string, '$', 0); 290 var next = %StringIndexOf(string, '$', 0);
278 if (next < 0) { 291 if (next < 0) {
279 builder.add(string); 292 builder.add(string);
280 return; 293 return;
281 } 294 }
282 295
283 // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. 296 // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
284 var m = captures.length >> 1; // includes the match 297 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
285 298
286 if (next > 0) builder.add(SubString(string, 0, next)); 299 if (next > 0) builder.add(SubString(string, 0, next));
287 var length = string.length; 300 var length = string.length;
288 301
302
289 while (true) { 303 while (true) {
290 var expansion = '$'; 304 var expansion = '$';
291 var position = next + 1; 305 var position = next + 1;
292 if (position < length) { 306 if (position < length) {
293 var peek = %_FastCharCodeAt(string, position); 307 var peek = %_FastCharCodeAt(string, position);
294 if (!%_IsSmi(peek)) { 308 if (!%_IsSmi(peek)) {
295 peek = %StringCharCodeAt(string, position); 309 peek = %StringCharCodeAt(string, position);
296 } 310 }
297 if (peek == 36) { // $$ 311 if (peek == 36) { // $$
298 ++position; 312 ++position;
299 builder.add('$'); 313 builder.add('$');
300 } else if (peek == 38) { // $& - match 314 } else if (peek == 38) { // $& - match
301 ++position; 315 ++position;
302 builder.addSpecialSlice(captures[0], captures[1]); 316 builder.addSpecialSlice(matchInfo[CAPTURE0],
317 matchInfo[CAPTURE1]);
303 } else if (peek == 96) { // $` - prefix 318 } else if (peek == 96) { // $` - prefix
304 ++position; 319 ++position;
305 builder.addSpecialSlice(0, captures[0]); 320 builder.addSpecialSlice(0, matchInfo[CAPTURE0]);
306 } else if (peek == 39) { // $' - suffix 321 } else if (peek == 39) { // $' - suffix
307 ++position; 322 ++position;
308 builder.addSpecialSlice(captures[1], subject.length); 323 builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length);
309 } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9 324 } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
310 ++position; 325 ++position;
311 var n = peek - 48; 326 var n = peek - 48;
312 if (position < length) { 327 if (position < length) {
313 peek = %_FastCharCodeAt(string, position); 328 peek = %_FastCharCodeAt(string, position);
314 if (!%_IsSmi(peek)) { 329 if (!%_IsSmi(peek)) {
315 peek = %StringCharCodeAt(string, position); 330 peek = %StringCharCodeAt(string, position);
316 } 331 }
317 // $nn, 01 <= nn <= 99 332 // $nn, 01 <= nn <= 99
318 if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) { 333 if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) {
319 var nn = n * 10 + (peek - 48); 334 var nn = n * 10 + (peek - 48);
320 if (nn < m) { 335 if (nn < m) {
321 // If the two digit capture reference is within range of 336 // If the two digit capture reference is within range of
322 // the captures, we use it instead of the single digit 337 // the captures, we use it instead of the single digit
323 // one. Otherwise, we fall back to using the single 338 // one. Otherwise, we fall back to using the single
324 // digit reference. This matches the behavior of 339 // digit reference. This matches the behavior of
325 // SpiderMonkey. 340 // SpiderMonkey.
326 ++position; 341 ++position;
327 n = nn; 342 n = nn;
328 } 343 }
329 } 344 }
330 } 345 }
331 if (0 < n && n < m) { 346 if (0 < n && n < m) {
332 addCaptureString(builder, captures, n); 347 addCaptureString(builder, matchInfo, n);
333 } else { 348 } else {
334 // Because of the captures range check in the parsing of two 349 // Because of the captures range check in the parsing of two
335 // digit capture references, we can only enter here when a 350 // digit capture references, we can only enter here when a
336 // single digit capture reference is outside the range of 351 // single digit capture reference is outside the range of
337 // captures. 352 // captures.
338 builder.add('$'); 353 builder.add('$');
339 --position; 354 --position;
340 } 355 }
341 } 356 }
342 } else { 357 } else {
(...skipping 11 matching lines...) Expand all
354 } 369 }
355 return; 370 return;
356 } 371 }
357 372
358 // Append substring between the previous and the next $ character. 373 // Append substring between the previous and the next $ character.
359 builder.add(SubString(string, position, next)); 374 builder.add(SubString(string, position, next));
360 } 375 }
361 }; 376 };
362 377
363 378
364 // Compute the string of a given PCRE capture. 379 // Compute the string of a given regular expression capture.
365 function CaptureString(string, captures, index) { 380 function CaptureString(string, lastCaptureInfo, index) {
366 // Scale the index. 381 // Scale the index.
367 var scaled = index << 1; 382 var scaled = index << 1;
368 // Compute start and end. 383 // Compute start and end.
369 var start = captures[scaled]; 384 var start = lastCaptureInfo[CAPTURE(scaled)];
370 var end = captures[scaled + 1]; 385 var end = lastCaptureInfo[CAPTURE(scaled + 1)];
371 // If either start or end is missing return undefined. 386 // If either start or end is missing return undefined.
372 if (start < 0 || end < 0) return; 387 if (start < 0 || end < 0) return;
373 return SubString(string, start, end); 388 return SubString(string, start, end);
374 }; 389 };
375 390
376 391
377 // Add the string of a given PCRE capture to the ReplaceResultBuilder 392 // Add the string of a given regular expression capture to the
378 function addCaptureString(builder, captures, index) { 393 // ReplaceResultBuilder
394 function addCaptureString(builder, matchInfo, index) {
379 // Scale the index. 395 // Scale the index.
380 var scaled = index << 1; 396 var scaled = index << 1;
381 // Compute start and end. 397 // Compute start and end.
382 var start = captures[scaled]; 398 var start = matchInfo[CAPTURE(scaled)];
383 var end = captures[scaled + 1]; 399 var end = matchInfo[CAPTURE(scaled + 1)];
384 // If either start or end is missing return. 400 // If either start or end is missing return.
385 if (start < 0 || end <= start) return; 401 if (start < 0 || end <= start) return;
386 builder.addSpecialSlice(start, end); 402 builder.addSpecialSlice(start, end);
387 }; 403 };
388 404
389 405
390 // Helper function for replacing regular expressions with the result of a 406 // Helper function for replacing regular expressions with the result of a
391 // function application in String.prototype.replace. The function application 407 // function application in String.prototype.replace. The function application
392 // must be interleaved with the regexp matching (contrary to ECMA-262 408 // must be interleaved with the regexp matching (contrary to ECMA-262
393 // 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses 409 // 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses
394 // the static properties of the RegExp constructor. Example: 410 // the static properties of the RegExp constructor. Example:
395 // 'abcd'.replace(/(.)/g, function() { return RegExp.$1; } 411 // 'abcd'.replace(/(.)/g, function() { return RegExp.$1; }
396 // should be 'abcd' and not 'dddd' (or anything else). 412 // should be 'abcd' and not 'dddd' (or anything else).
397 function StringReplaceRegExpWithFunction(subject, regexp, replace) { 413 function StringReplaceRegExpWithFunction(subject, regexp, replace) {
398 var result = new ReplaceResultBuilder(subject); 414 var result = new ReplaceResultBuilder(subject);
399 // Captures is an array of pairs of (start, end) indices for the match and 415 var lastMatchInfo = DoRegExpExec(regexp, subject, 0);
400 // any captured substrings. 416 if (IS_NULL(lastMatchInfo)) return subject;
401 var captures = DoRegExpExec(regexp, subject, 0);
402 if (IS_NULL(captures)) return subject;
403 417
404 // There's at least one match. If the regexp is global, we have to loop 418 // There's at least one match. If the regexp is global, we have to loop
405 // over all matches. The loop is not in C++ code here like the one in 419 // over all matches. The loop is not in C++ code here like the one in
406 // RegExp.prototype.exec, because of the interleaved function application. 420 // RegExp.prototype.exec, because of the interleaved function application.
407 // Unfortunately, that means this code is nearly duplicated, here and in 421 // Unfortunately, that means this code is nearly duplicated, here and in
408 // jsregexp.cc. 422 // jsregexp.cc.
409 if (regexp.global) { 423 if (regexp.global) {
410 var previous = 0; 424 var previous = 0;
411 do { 425 do {
412 result.addSpecialSlice(previous, captures[0]); 426 result.addSpecialSlice(previous, lastMatchInfo[CAPTURE0]);
413 result.add(ApplyReplacementFunction(replace, captures, subject)); 427 var startOfMatch = lastMatchInfo[CAPTURE0];
428 previous = lastMatchInfo[CAPTURE1];
429 result.add(ApplyReplacementFunction(replace, lastMatchInfo, subject));
430 // Can't use lastMatchInfo any more from here, since the function could
431 // overwrite it.
414 // Continue with the next match. 432 // Continue with the next match.
415 previous = captures[1];
416 // Increment previous if we matched an empty string, as per ECMA-262 433 // Increment previous if we matched an empty string, as per ECMA-262
417 // 15.5.4.10. 434 // 15.5.4.10.
418 if (previous == captures[0]) { 435 if (previous == startOfMatch) {
419 // Add the skipped character to the output, if any. 436 // Add the skipped character to the output, if any.
420 if (previous < subject.length) { 437 if (previous < subject.length) {
421 result.addSpecialSlice(previous, previous + 1); 438 result.addSpecialSlice(previous, previous + 1);
422 } 439 }
423 previous++; 440 previous++;
424 } 441 }
425 442
426 // Per ECMA-262 15.10.6.2, if the previous index is greater than the 443 // Per ECMA-262 15.10.6.2, if the previous index is greater than the
427 // string length, there is no match 444 // string length, there is no match
428 captures = (previous > subject.length) 445 lastMatchInfo = (previous > subject.length)
429 ? null 446 ? null
430 : DoRegExpExec(regexp, subject, previous); 447 : DoRegExpExec(regexp, subject, previous);
431 } while (!IS_NULL(captures)); 448 } while (!IS_NULL(lastMatchInfo));
432 449
433 // Tack on the final right substring after the last match, if necessary. 450 // Tack on the final right substring after the last match, if necessary.
434 if (previous < subject.length) { 451 if (previous < subject.length) {
435 result.addSpecialSlice(previous, subject.length); 452 result.addSpecialSlice(previous, subject.length);
436 } 453 }
437 } else { // Not a global regexp, no need to loop. 454 } else { // Not a global regexp, no need to loop.
438 result.addSpecialSlice(0, captures[0]); 455 result.addSpecialSlice(0, lastMatchInfo[CAPTURE0]);
439 result.add(ApplyReplacementFunction(replace, captures, subject)); 456 var endOfMatch = lastMatchInfo[CAPTURE1];
440 result.addSpecialSlice(captures[1], subject.length); 457 result.add(ApplyReplacementFunction(replace, lastMatchInfo, subject));
458 // Can't use lastMatchInfo any more from here, since the function could
459 // overwrite it.
460 result.addSpecialSlice(endOfMatch, subject.length);
441 } 461 }
442 462
443 return result.generate(); 463 return result.generate();
444 } 464 }
445 465
446 466
447 // Helper function to apply a string replacement function once. 467 // Helper function to apply a string replacement function once.
448 function ApplyReplacementFunction(replace, captures, subject) { 468 function ApplyReplacementFunction(replace, lastMatchInfo, subject) {
449 // Compute the parameter list consisting of the match, captures, index, 469 // Compute the parameter list consisting of the match, captures, index,
450 // and subject for the replace function invocation. 470 // and subject for the replace function invocation.
451 var index = captures[0]; 471 var index = lastMatchInfo[CAPTURE0];
452 // The number of captures plus one for the match. 472 // The number of captures plus one for the match.
453 var m = captures.length >> 1; 473 var m = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
454 if (m == 1) { 474 if (m == 1) {
455 var s = CaptureString(subject, captures, 0); 475 var s = CaptureString(subject, lastMatchInfo, 0);
456 // Don't call directly to avoid exposing the built-in global object. 476 // Don't call directly to avoid exposing the built-in global object.
457 return ToString(replace.call(null, s, index, subject)); 477 return ToString(replace.call(null, s, index, subject));
458 } 478 }
459 var parameters = $Array(m + 2); 479 var parameters = $Array(m + 2);
460 for (var j = 0; j < m; j++) { 480 for (var j = 0; j < m; j++) {
461 parameters[j] = CaptureString(subject, captures, j); 481 parameters[j] = CaptureString(subject, lastMatchInfo, j);
462 } 482 }
463 parameters[j] = index; 483 parameters[j] = index;
464 parameters[j + 1] = subject; 484 parameters[j + 1] = subject;
465 return ToString(replace.apply(null, parameters)); 485 return ToString(replace.apply(null, parameters));
466 } 486 }
467 487
468 488
469 // ECMA-262 section 15.5.4.12 489 // ECMA-262 section 15.5.4.12
470 function StringSearch(re) { 490 function StringSearch(re) {
471 var regexp = new ORIGINAL_REGEXP(re); 491 var regexp = new ORIGINAL_REGEXP(re);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 return result; 572 return result;
553 } 573 }
554 574
555 while (true) { 575 while (true) {
556 576
557 if (startIndex === length) { 577 if (startIndex === length) {
558 result[result.length] = subject.slice(currentIndex, length); 578 result[result.length] = subject.slice(currentIndex, length);
559 return result; 579 return result;
560 } 580 }
561 581
562 var match = splitMatch(sep, subject, currentIndex, startIndex); 582 var lastMatchInfo = splitMatch(sep, subject, currentIndex, startIndex);
563 583
564 if (IS_NULL(match)) { 584 if (IS_NULL(lastMatchInfo)) {
565 result[result.length] = subject.slice(currentIndex, length); 585 result[result.length] = subject.slice(currentIndex, length);
566 return result; 586 return result;
567 } 587 }
568 588
569 var endIndex = match[0]; 589 var endIndex = lastMatchInfo[CAPTURE1];
570 590
571 // We ignore a zero-length match at the currentIndex. 591 // We ignore a zero-length match at the currentIndex.
572 if (startIndex === endIndex && endIndex === currentIndex) { 592 if (startIndex === endIndex && endIndex === currentIndex) {
573 startIndex++; 593 startIndex++;
574 continue; 594 continue;
575 } 595 }
576 596
577 result[result.length] = match[1]; 597 result[result.length] =
598 SubString(subject, currentIndex, lastMatchInfo[CAPTURE0]);
578 if (result.length === lim) return result; 599 if (result.length === lim) return result;
579 600
580 for (var i = 2; i < match.length; i++) { 601 for (var i = 2; i < NUMBER_OF_CAPTURES(lastMatchInfo); i += 2) {
581 result[result.length] = match[i]; 602 var start = lastMatchInfo[CAPTURE(i)];
603 var end = lastMatchInfo[CAPTURE(i + 1)];
604 if (start != -1 && end != -1) {
605 result[result.length] = SubString(subject,
606 lastMatchInfo[CAPTURE(i)],
607 lastMatchInfo[CAPTURE(i + 1)]);
608 } else {
609 result[result.length] = void 0;
610 }
582 if (result.length === lim) return result; 611 if (result.length === lim) return result;
583 } 612 }
584 613
585 startIndex = currentIndex = endIndex; 614 startIndex = currentIndex = endIndex;
586 } 615 }
587 } 616 }
588 617
589 618
590 // ECMA-262 section 15.5.4.14 619 // ECMA-262 section 15.5.4.14
591 // Helper function used by split. 620 // Helper function used by split. This version returns the lastMatchInfo
621 // instead of allocating a new array with basically the same information.
592 function splitMatch(separator, subject, current_index, start_index) { 622 function splitMatch(separator, subject, current_index, start_index) {
593 if (IS_REGEXP(separator)) { 623 if (IS_REGEXP(separator)) {
594 var ovector = DoRegExpExec(separator, subject, start_index); 624 var lastMatchInfo = DoRegExpExec(separator, subject, start_index);
595 if (ovector == null) return null; 625 if (lastMatchInfo == null) return null;
596 var nof_results = ovector.length >> 1;
597 var result = new $Array(nof_results + 1);
598 // Section 15.5.4.14 paragraph two says that we do not allow zero length 626 // Section 15.5.4.14 paragraph two says that we do not allow zero length
599 // matches at the end of the string. 627 // matches at the end of the string.
600 if (ovector[0] === subject.length) return null; 628 if (lastMatchInfo[CAPTURE0] === subject.length) return null;
601 result[0] = ovector[1]; 629 return lastMatchInfo;
602 result[1] = subject.slice(current_index, ovector[0]);
603 for (var i = 1; i < nof_results; i++) {
604 var matching_start = ovector[2*i];
605 var matching_end = ovector[2*i + 1];
606 if (matching_start != -1 && matching_end != -1) {
607 result[i + 1] = subject.slice(matching_start, matching_end);
608 }
609 }
610 return result;
611 } 630 }
612 631
613 var separatorIndex = subject.indexOf(separator, start_index); 632 var separatorIndex = subject.indexOf(separator, start_index);
614 if (separatorIndex === -1) return null; 633 if (separatorIndex === -1) return null;
615 634
616 return [ separatorIndex + separator.length, subject.slice(current_index, separ atorIndex) ]; 635 reusableMatchInfo[CAPTURE0] = separatorIndex;
636 reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length;
637 return reusableMatchInfo;
617 }; 638 };
618 639
619 640
620 // ECMA-262 section 15.5.4.15 641 // ECMA-262 section 15.5.4.15
621 function StringSubstring(start, end) { 642 function StringSubstring(start, end) {
622 var s = ToString(this); 643 var s = ToString(this);
623 var s_len = s.length; 644 var s_len = s.length;
624 var start_i = TO_INTEGER(start); 645 var start_i = TO_INTEGER(start);
625 var end_i = s_len; 646 var end_i = s_len;
626 if (!IS_UNDEFINED(end)) 647 if (!IS_UNDEFINED(end))
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
883 "italics", StringItalics, 904 "italics", StringItalics,
884 "small", StringSmall, 905 "small", StringSmall,
885 "strike", StringStrike, 906 "strike", StringStrike,
886 "sub", StringSub, 907 "sub", StringSub,
887 "sup", StringSup 908 "sup", StringSup
888 )); 909 ));
889 } 910 }
890 911
891 912
892 SetupString(); 913 SetupString();
OLDNEW
« src/runtime.cc ('K') | « src/runtime.cc ('k') | test/mjsunit/regexp-string-methods.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698