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

Side by Side Diff: src/string.js

Issue 1574003: Reapply svn r4269 plus fixes for issues 665 and 667. (Closed)
Patch Set: Created 10 years, 8 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
« no previous file with comments | « src/runtime.cc ('k') | src/version.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 387 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 // Scale the index. 398 // Scale the index.
399 var scaled = index << 1; 399 var scaled = index << 1;
400 // Compute start and end. 400 // Compute start and end.
401 var start = matchInfo[CAPTURE(scaled)]; 401 var start = matchInfo[CAPTURE(scaled)];
402 var end = matchInfo[CAPTURE(scaled + 1)]; 402 var end = matchInfo[CAPTURE(scaled + 1)];
403 // If either start or end is missing return. 403 // If either start or end is missing return.
404 if (start < 0 || end <= start) return; 404 if (start < 0 || end <= start) return;
405 builder.addSpecialSlice(start, end); 405 builder.addSpecialSlice(start, end);
406 }; 406 };
407 407
408 // TODO(lrn): This array will survive indefinitely if replace is never
409 // called again. However, it will be empty, since the contents are cleared
410 // in the finally block.
411 var reusableReplaceArray = $Array(16);
408 412
409 // Helper function for replacing regular expressions with the result of a 413 // Helper function for replacing regular expressions with the result of a
410 // function application in String.prototype.replace. The function application 414 // function application in String.prototype.replace.
411 // must be interleaved with the regexp matching (contrary to ECMA-262
412 // 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses
413 // the static properties of the RegExp constructor. Example:
414 // 'abcd'.replace(/(.)/g, function() { return RegExp.$1; }
415 // should be 'abcd' and not 'dddd' (or anything else).
416 function StringReplaceRegExpWithFunction(subject, regexp, replace) { 415 function StringReplaceRegExpWithFunction(subject, regexp, replace) {
417 var matchInfo = DoRegExpExec(regexp, subject, 0);
418 if (IS_NULL(matchInfo)) return subject;
419
420 var result = new ReplaceResultBuilder(subject);
421 // There's at least one match. If the regexp is global, we have to loop
422 // over all matches. The loop is not in C++ code here like the one in
423 // RegExp.prototype.exec, because of the interleaved function application.
424 // Unfortunately, that means this code is nearly duplicated, here and in
425 // jsregexp.cc.
426 if (regexp.global) { 416 if (regexp.global) {
427 var previous = 0; 417 var resultArray = reusableReplaceArray;
428 var startOfMatch; 418 if (resultArray) {
429 if (NUMBER_OF_CAPTURES(matchInfo) == 2) { 419 reusableReplaceArray = null;
430 // Both branches contain essentially the same loop except for the call 420 } else {
431 // to the replace function. The branch is put outside of the loop for 421 // Inside a nested replace (replace called from the replacement function
432 // speed 422 // of another replace) or we have failed to set the reusable array
433 do { 423 // back due to an exception in a replacement function. Create a new
434 startOfMatch = matchInfo[CAPTURE0]; 424 // array to use in the future, or until the original is written back.
435 result.addSpecialSlice(previous, startOfMatch); 425 resultArray = $Array(16);
436 previous = matchInfo[CAPTURE1]; 426 }
437 var match = SubString(subject, startOfMatch, previous); 427 try {
438 // Don't call directly to avoid exposing the built-in global object. 428 // Must handle exceptions thrown by the replace functions correctly,
439 result.add(replace.call(null, match, startOfMatch, subject)); 429 // including unregistering global regexps.
440 // Can't use matchInfo any more from here, since the function could 430 var res = %RegExpExecMultiple(regexp,
441 // overwrite it. 431 subject,
442 // Continue with the next match. 432 lastMatchInfo,
443 // Increment previous if we matched an empty string, as per ECMA-262 433 resultArray);
444 // 15.5.4.10. 434 regexp.lastIndex = 0;
445 if (previous == startOfMatch) { 435 if (IS_NULL(res)) {
446 // Add the skipped character to the output, if any. 436 // No matches at all.
447 if (previous < subject.length) { 437 return subject;
448 result.addSpecialSlice(previous, previous + 1); 438 }
439 var len = res.length;
440 var i = 0;
441 if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
442 var match_start = 0;
443 while (i < len) {
444 var elem = res[i];
445 if (%_IsSmi(elem)) {
446 if (elem > 0) {
447 match_start = (elem >> 11) + (elem & 0x7ff);
448 } else {
449 match_start = res[++i] - elem;
450 }
451 } else {
452 var func_result = replace.call(null, elem, match_start, subject);
453 if (!IS_STRING(func_result)) {
454 func_result = NonStringToString(func_result);
455 }
456 res[i] = func_result;
457 match_start += elem.length;
449 } 458 }
450 previous++; 459 i++;
451 // Per ECMA-262 15.10.6.2, if the previous index is greater than the 460 }
452 // string length, there is no match 461 } else {
453 if (previous > subject.length) { 462 while (i < len) {
454 return result.generate(); 463 var elem = res[i];
464 if (!%_IsSmi(elem)) {
465 // elem must be an Array.
466 // Use the apply argument as backing for global RegExp properties.
467 lastMatchInfoOverride = elem;
468 var func_result = replace.apply(null, elem);
469 if (!IS_STRING(func_result)) {
470 func_result = NonStringToString(func_result);
471 }
472 res[i] = func_result;
455 } 473 }
474 i++;
456 } 475 }
457 matchInfo = DoRegExpExec(regexp, subject, previous); 476 }
458 } while (!IS_NULL(matchInfo)); 477 var result = new ReplaceResultBuilder(subject, res);
459 } else { 478 return result.generate();
460 do { 479 } finally {
461 startOfMatch = matchInfo[CAPTURE0]; 480 lastMatchInfoOverride = null;
462 result.addSpecialSlice(previous, startOfMatch); 481 resultArray.length = 0;
463 previous = matchInfo[CAPTURE1]; 482 reusableReplaceArray = resultArray;
464 result.add(ApplyReplacementFunction(replace, matchInfo, subject));
465 // Can't use matchInfo any more from here, since the function could
466 // overwrite it.
467 // Continue with the next match.
468 // Increment previous if we matched an empty string, as per ECMA-262
469 // 15.5.4.10.
470 if (previous == startOfMatch) {
471 // Add the skipped character to the output, if any.
472 if (previous < subject.length) {
473 result.addSpecialSlice(previous, previous + 1);
474 }
475 previous++;
476 // Per ECMA-262 15.10.6.2, if the previous index is greater than the
477 // string length, there is no match
478 if (previous > subject.length) {
479 return result.generate();
480 }
481 }
482 matchInfo = DoRegExpExec(regexp, subject, previous);
483 } while (!IS_NULL(matchInfo));
484 } 483 }
485
486 // Tack on the final right substring after the last match.
487 result.addSpecialSlice(previous, subject.length);
488
489 } else { // Not a global regexp, no need to loop. 484 } else { // Not a global regexp, no need to loop.
485 var matchInfo = DoRegExpExec(regexp, subject, 0);
486 if (IS_NULL(matchInfo)) return subject;
487
488 var result = new ReplaceResultBuilder(subject);
490 result.addSpecialSlice(0, matchInfo[CAPTURE0]); 489 result.addSpecialSlice(0, matchInfo[CAPTURE0]);
491 var endOfMatch = matchInfo[CAPTURE1]; 490 var endOfMatch = matchInfo[CAPTURE1];
492 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); 491 result.add(ApplyReplacementFunction(replace, matchInfo, subject));
493 // Can't use matchInfo any more from here, since the function could 492 // Can't use matchInfo any more from here, since the function could
494 // overwrite it. 493 // overwrite it.
495 result.addSpecialSlice(endOfMatch, subject.length); 494 result.addSpecialSlice(endOfMatch, subject.length);
495 return result.generate();
496 } 496 }
497
498 return result.generate();
499 } 497 }
500 498
501 499
502 // Helper function to apply a string replacement function once. 500 // Helper function to apply a string replacement function once.
503 function ApplyReplacementFunction(replace, matchInfo, subject) { 501 function ApplyReplacementFunction(replace, matchInfo, subject) {
504 // Compute the parameter list consisting of the match, captures, index, 502 // Compute the parameter list consisting of the match, captures, index,
505 // and subject for the replace function invocation. 503 // and subject for the replace function invocation.
506 var index = matchInfo[CAPTURE0]; 504 var index = matchInfo[CAPTURE0];
507 // The number of captures plus one for the match. 505 // The number of captures plus one for the match.
508 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; 506 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 } 885 }
888 886
889 887
890 function StringSup() { 888 function StringSup() {
891 return "<sup>" + this + "</sup>"; 889 return "<sup>" + this + "</sup>";
892 } 890 }
893 891
894 892
895 // ReplaceResultBuilder support. 893 // ReplaceResultBuilder support.
896 function ReplaceResultBuilder(str) { 894 function ReplaceResultBuilder(str) {
897 this.__proto__ = void 0; 895 if (%_ArgumentsLength() > 1) {
898 this.elements = new $Array(); 896 this.elements = %_Arguments(1);
897 } else {
898 this.elements = new $Array();
899 }
899 this.special_string = str; 900 this.special_string = str;
900 } 901 }
901 902
902 903
903 ReplaceResultBuilder.prototype.add = function(str) { 904 ReplaceResultBuilder.prototype.add = function(str) {
904 str = TO_STRING_INLINE(str); 905 str = TO_STRING_INLINE(str);
905 if (str.length > 0) { 906 if (str.length > 0) {
906 var elements = this.elements; 907 var elements = this.elements;
907 elements[elements.length] = str; 908 elements[elements.length] = str;
908 } 909 }
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
984 "small", StringSmall, 985 "small", StringSmall,
985 "strike", StringStrike, 986 "strike", StringStrike,
986 "sub", StringSub, 987 "sub", StringSub,
987 "sup", StringSup, 988 "sup", StringSup,
988 "toJSON", StringToJSON 989 "toJSON", StringToJSON
989 )); 990 ));
990 } 991 }
991 992
992 993
993 SetupString(); 994 SetupString();
OLDNEW
« no previous file with comments | « src/runtime.cc ('k') | src/version.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698