OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 var matchInfo = DoRegExpExec(regexp, subject, 0); | 380 var matchInfo = DoRegExpExec(regexp, subject, 0); |
381 if (IS_NULL(matchInfo)) return subject; | 381 if (IS_NULL(matchInfo)) return subject; |
382 | 382 |
383 var result = new ReplaceResultBuilder(subject); | 383 var result = new ReplaceResultBuilder(subject); |
384 // There's at least one match. If the regexp is global, we have to loop | 384 // There's at least one match. If the regexp is global, we have to loop |
385 // over all matches. The loop is not in C++ code here like the one in | 385 // over all matches. The loop is not in C++ code here like the one in |
386 // RegExp.prototype.exec, because of the interleaved function application. | 386 // RegExp.prototype.exec, because of the interleaved function application. |
387 // Unfortunately, that means this code is nearly duplicated, here and in | 387 // Unfortunately, that means this code is nearly duplicated, here and in |
388 // jsregexp.cc. | 388 // jsregexp.cc. |
389 if (regexp.global) { | 389 if (regexp.global) { |
390 var numberOfCaptures = NUMBER_OF_CAPTURES(matchInfo) >> 1; | |
391 var previous = 0; | 390 var previous = 0; |
392 do { | 391 var startOfMatch; |
393 var startOfMatch = matchInfo[CAPTURE0]; | 392 if (NUMBER_OF_CAPTURES(matchInfo) == 2) { |
394 result.addSpecialSlice(previous, startOfMatch); | 393 // Both branches contain essentially the same loop except for the call |
395 previous = matchInfo[CAPTURE1]; | 394 // to the replace function. The branch is put outside of the loop for |
396 if (numberOfCaptures == 1) { | 395 // speed |
| 396 do { |
| 397 startOfMatch = matchInfo[CAPTURE0]; |
| 398 result.addSpecialSlice(previous, startOfMatch); |
| 399 previous = matchInfo[CAPTURE1]; |
397 var match = SubString(subject, startOfMatch, previous); | 400 var match = SubString(subject, startOfMatch, previous); |
398 // Don't call directly to avoid exposing the built-in global object. | 401 // Don't call directly to avoid exposing the built-in global object. |
399 result.add(replace.call(null, match, startOfMatch, subject)); | 402 result.add(replace.call(null, match, startOfMatch, subject)); |
400 } else { | 403 // Can't use matchInfo any more from here, since the function could |
| 404 // overwrite it. |
| 405 // Continue with the next match. |
| 406 // Increment previous if we matched an empty string, as per ECMA-262 |
| 407 // 15.5.4.10. |
| 408 if (previous == startOfMatch) { |
| 409 // Add the skipped character to the output, if any. |
| 410 if (previous < subject.length) { |
| 411 result.addSpecialSlice(previous, previous + 1); |
| 412 } |
| 413 previous++; |
| 414 // Per ECMA-262 15.10.6.2, if the previous index is greater than the |
| 415 // string length, there is no match |
| 416 if (previous > subject.length) { |
| 417 return result.generate(); |
| 418 } |
| 419 } |
| 420 matchInfo = DoRegExpExec(regexp, subject, previous); |
| 421 } while (!IS_NULL(matchInfo)); |
| 422 } else { |
| 423 do { |
| 424 startOfMatch = matchInfo[CAPTURE0]; |
| 425 result.addSpecialSlice(previous, startOfMatch); |
| 426 previous = matchInfo[CAPTURE1]; |
401 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); | 427 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); |
402 } | 428 // Can't use matchInfo any more from here, since the function could |
403 // Can't use matchInfo any more from here, since the function could | 429 // overwrite it. |
404 // overwrite it. | 430 // Continue with the next match. |
405 // Continue with the next match. | 431 // Increment previous if we matched an empty string, as per ECMA-262 |
406 // Increment previous if we matched an empty string, as per ECMA-262 | 432 // 15.5.4.10. |
407 // 15.5.4.10. | 433 if (previous == startOfMatch) { |
408 if (previous == startOfMatch) { | 434 // Add the skipped character to the output, if any. |
409 // Add the skipped character to the output, if any. | 435 if (previous < subject.length) { |
410 if (previous < subject.length) { | 436 result.addSpecialSlice(previous, previous + 1); |
411 result.addSpecialSlice(previous, previous + 1); | 437 } |
| 438 previous++; |
| 439 // Per ECMA-262 15.10.6.2, if the previous index is greater than the |
| 440 // string length, there is no match |
| 441 if (previous > subject.length) { |
| 442 return result.generate(); |
| 443 } |
412 } | 444 } |
413 previous++; | 445 matchInfo = DoRegExpExec(regexp, subject, previous); |
414 } | 446 } while (!IS_NULL(matchInfo)); |
| 447 } |
415 | 448 |
416 // Per ECMA-262 15.10.6.2, if the previous index is greater than the | 449 // Tack on the final right substring after the last match. |
417 // string length, there is no match | 450 result.addSpecialSlice(previous, subject.length); |
418 matchInfo = (previous > subject.length) | |
419 ? null | |
420 : DoRegExpExec(regexp, subject, previous); | |
421 } while (!IS_NULL(matchInfo)); | |
422 | 451 |
423 // Tack on the final right substring after the last match, if necessary. | |
424 if (previous < subject.length) { | |
425 result.addSpecialSlice(previous, subject.length); | |
426 } | |
427 } else { // Not a global regexp, no need to loop. | 452 } else { // Not a global regexp, no need to loop. |
428 result.addSpecialSlice(0, matchInfo[CAPTURE0]); | 453 result.addSpecialSlice(0, matchInfo[CAPTURE0]); |
429 var endOfMatch = matchInfo[CAPTURE1]; | 454 var endOfMatch = matchInfo[CAPTURE1]; |
430 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); | 455 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); |
431 // Can't use matchInfo any more from here, since the function could | 456 // Can't use matchInfo any more from here, since the function could |
432 // overwrite it. | 457 // overwrite it. |
433 result.addSpecialSlice(endOfMatch, subject.length); | 458 result.addSpecialSlice(endOfMatch, subject.length); |
434 } | 459 } |
435 | 460 |
436 return result.generate(); | 461 return result.generate(); |
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
910 "small", StringSmall, | 935 "small", StringSmall, |
911 "strike", StringStrike, | 936 "strike", StringStrike, |
912 "sub", StringSub, | 937 "sub", StringSub, |
913 "sup", StringSup, | 938 "sup", StringSup, |
914 "toJSON", StringToJSON | 939 "toJSON", StringToJSON |
915 )); | 940 )); |
916 } | 941 } |
917 | 942 |
918 | 943 |
919 SetupString(); | 944 SetupString(); |
OLD | NEW |