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

Side by Side Diff: src/string.js

Issue 1994019: Simplified replace JS a little. (Closed)
Patch Set: Address review comments. Forward to head. Created 10 years, 7 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 | « no previous file | no next file » | 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 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 234
235 // ECMA-262, section 15.5.4.11 235 // ECMA-262, section 15.5.4.11
236 function StringReplace(search, replace) { 236 function StringReplace(search, replace) {
237 var subject = TO_STRING_INLINE(this); 237 var subject = TO_STRING_INLINE(this);
238 238
239 // Delegate to one of the regular expression variants if necessary. 239 // Delegate to one of the regular expression variants if necessary.
240 if (IS_REGEXP(search)) { 240 if (IS_REGEXP(search)) {
241 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); 241 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
242 if (IS_FUNCTION(replace)) { 242 if (IS_FUNCTION(replace)) {
243 regExpCache.type = 'none'; 243 regExpCache.type = 'none';
244 return StringReplaceRegExpWithFunction(subject, search, replace); 244 if (search.global) {
245 return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
246 } else {
247 return StringReplaceNonGlobalRegExpWithFunction(subject,
248 search,
249 replace);
250 }
245 } else { 251 } else {
246 return StringReplaceRegExp(subject, search, replace); 252 return StringReplaceRegExp(subject, search, replace);
247 } 253 }
248 } 254 }
249 255
250 // Convert the search argument to a string and search for it. 256 // Convert the search argument to a string and search for it.
251 search = TO_STRING_INLINE(search); 257 search = TO_STRING_INLINE(search);
252 var start = %StringIndexOf(subject, search, 0); 258 var start = %StringIndexOf(subject, search, 0);
253 if (start < 0) return subject; 259 if (start < 0) return subject;
254 var end = start + search.length; 260 var end = start + search.length;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 } 395 }
390 }; 396 };
391 397
392 398
393 // Compute the string of a given regular expression capture. 399 // Compute the string of a given regular expression capture.
394 function CaptureString(string, lastCaptureInfo, index) { 400 function CaptureString(string, lastCaptureInfo, index) {
395 // Scale the index. 401 // Scale the index.
396 var scaled = index << 1; 402 var scaled = index << 1;
397 // Compute start and end. 403 // Compute start and end.
398 var start = lastCaptureInfo[CAPTURE(scaled)]; 404 var start = lastCaptureInfo[CAPTURE(scaled)];
405 // If start isn't valid, return undefined.
406 if (start < 0) return;
399 var end = lastCaptureInfo[CAPTURE(scaled + 1)]; 407 var end = lastCaptureInfo[CAPTURE(scaled + 1)];
400 // If either start or end is missing return undefined.
401 if (start < 0 || end < 0) return;
402 return SubString(string, start, end); 408 return SubString(string, start, end);
403 }; 409 };
404 410
405 411
406 // Add the string of a given regular expression capture to the 412 // Add the string of a given regular expression capture to the
407 // ReplaceResultBuilder 413 // ReplaceResultBuilder
408 function addCaptureString(builder, matchInfo, index) { 414 function addCaptureString(builder, matchInfo, index) {
409 // Scale the index. 415 // Scale the index.
410 var scaled = index << 1; 416 var scaled = index << 1;
411 // Compute start and end. 417 // Compute start and end.
412 var start = matchInfo[CAPTURE(scaled)]; 418 var start = matchInfo[CAPTURE(scaled)];
419 if (start < 0) return;
413 var end = matchInfo[CAPTURE(scaled + 1)]; 420 var end = matchInfo[CAPTURE(scaled + 1)];
414 // If either start or end is missing return.
415 if (start < 0 || end <= start) return;
416 builder.addSpecialSlice(start, end); 421 builder.addSpecialSlice(start, end);
417 }; 422 };
418 423
419 // TODO(lrn): This array will survive indefinitely if replace is never 424 // TODO(lrn): This array will survive indefinitely if replace is never
420 // called again. However, it will be empty, since the contents are cleared 425 // called again. However, it will be empty, since the contents are cleared
421 // in the finally block. 426 // in the finally block.
422 var reusableReplaceArray = $Array(16); 427 var reusableReplaceArray = $Array(16);
423 428
424 // Helper function for replacing regular expressions with the result of a 429 // Helper function for replacing regular expressions with the result of a
425 // function application in String.prototype.replace. 430 // function application in String.prototype.replace.
426 function StringReplaceRegExpWithFunction(subject, regexp, replace) { 431 function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
427 if (regexp.global) { 432 var resultArray = reusableReplaceArray;
428 var resultArray = reusableReplaceArray; 433 if (resultArray) {
429 if (resultArray) { 434 reusableReplaceArray = null;
430 reusableReplaceArray = null; 435 } else {
431 } else { 436 // Inside a nested replace (replace called from the replacement function
432 // Inside a nested replace (replace called from the replacement function 437 // of another replace) or we have failed to set the reusable array
433 // of another replace) or we have failed to set the reusable array 438 // back due to an exception in a replacement function. Create a new
434 // back due to an exception in a replacement function. Create a new 439 // array to use in the future, or until the original is written back.
435 // array to use in the future, or until the original is written back. 440 resultArray = $Array(16);
436 resultArray = $Array(16); 441 }
442 var res = %RegExpExecMultiple(regexp,
443 subject,
444 lastMatchInfo,
445 resultArray);
446 regexp.lastIndex = 0;
447 if (IS_NULL(res)) {
448 // No matches at all.
449 reusableReplaceArray = resultArray;
450 return subject;
451 }
452 var len = res.length;
453 var i = 0;
454 if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
455 var match_start = 0;
456 var override = [null, 0, subject];
457 var receiver = %GetGlobalReceiver();
458 while (i < len) {
459 var elem = res[i];
460 if (%_IsSmi(elem)) {
461 if (elem > 0) {
462 match_start = (elem >> 11) + (elem & 0x7ff);
463 } else {
464 match_start = res[++i] - elem;
465 }
466 } else {
467 override[0] = elem;
468 override[1] = match_start;
469 lastMatchInfoOverride = override;
470 var func_result =
471 %_CallFunction(receiver, elem, match_start, subject, replace);
472 if (!IS_STRING(func_result)) {
473 func_result = NonStringToString(func_result);
474 }
475 res[i] = func_result;
476 match_start += elem.length;
477 }
478 i++;
437 } 479 }
438 480 } else {
439 var res = %RegExpExecMultiple(regexp, 481 while (i < len) {
440 subject, 482 var elem = res[i];
441 lastMatchInfo, 483 if (!%_IsSmi(elem)) {
442 resultArray); 484 // elem must be an Array.
443 regexp.lastIndex = 0; 485 // Use the apply argument as backing for global RegExp properties.
444 if (IS_NULL(res)) { 486 lastMatchInfoOverride = elem;
445 // No matches at all. 487 var func_result = replace.apply(null, elem);
446 return subject; 488 if (!IS_STRING(func_result)) {
489 func_result = NonStringToString(func_result);
490 }
491 res[i] = func_result;
492 }
493 i++;
447 } 494 }
448 var len = res.length;
449 var i = 0;
450 if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
451 var match_start = 0;
452 var override = [null, 0, subject];
453 while (i < len) {
454 var elem = res[i];
455 if (%_IsSmi(elem)) {
456 if (elem > 0) {
457 match_start = (elem >> 11) + (elem & 0x7ff);
458 } else {
459 match_start = res[++i] - elem;
460 }
461 } else {
462 override[0] = elem;
463 override[1] = match_start;
464 lastMatchInfoOverride = override;
465 var func_result = replace.call(null, elem, match_start, subject);
466 if (!IS_STRING(func_result)) {
467 func_result = NonStringToString(func_result);
468 }
469 res[i] = func_result;
470 match_start += elem.length;
471 }
472 i++;
473 }
474 } else {
475 while (i < len) {
476 var elem = res[i];
477 if (!%_IsSmi(elem)) {
478 // elem must be an Array.
479 // Use the apply argument as backing for global RegExp properties.
480 lastMatchInfoOverride = elem;
481 var func_result = replace.apply(null, elem);
482 if (!IS_STRING(func_result)) {
483 func_result = NonStringToString(func_result);
484 }
485 res[i] = func_result;
486 }
487 i++;
488 }
489 }
490 var resultBuilder = new ReplaceResultBuilder(subject, res);
491 var result = resultBuilder.generate();
492 resultArray.length = 0;
493 reusableReplaceArray = resultArray;
494 return result;
495 } else { // Not a global regexp, no need to loop.
496 var matchInfo = DoRegExpExec(regexp, subject, 0);
497 if (IS_NULL(matchInfo)) return subject;
498
499 var result = new ReplaceResultBuilder(subject);
500 result.addSpecialSlice(0, matchInfo[CAPTURE0]);
501 var endOfMatch = matchInfo[CAPTURE1];
502 result.add(ApplyReplacementFunction(replace, matchInfo, subject));
503 // Can't use matchInfo any more from here, since the function could
504 // overwrite it.
505 result.addSpecialSlice(endOfMatch, subject.length);
506 return result.generate();
507 } 495 }
496 var resultBuilder = new ReplaceResultBuilder(subject, res);
497 var result = resultBuilder.generate();
498 resultArray.length = 0;
499 reusableReplaceArray = resultArray;
500 return result;
508 } 501 }
509 502
510 503
511 // Helper function to apply a string replacement function once. 504 function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
512 function ApplyReplacementFunction(replace, matchInfo, subject) { 505 var matchInfo = DoRegExpExec(regexp, subject, 0);
506 if (IS_NULL(matchInfo)) return subject;
507 var result = new ReplaceResultBuilder(subject);
508 var index = matchInfo[CAPTURE0];
509 result.addSpecialSlice(0, index);
510 var endOfMatch = matchInfo[CAPTURE1];
513 // Compute the parameter list consisting of the match, captures, index, 511 // Compute the parameter list consisting of the match, captures, index,
514 // and subject for the replace function invocation. 512 // and subject for the replace function invocation.
515 var index = matchInfo[CAPTURE0];
516 // The number of captures plus one for the match. 513 // The number of captures plus one for the match.
517 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; 514 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
515 var replacement;
518 if (m == 1) { 516 if (m == 1) {
519 var s = CaptureString(subject, matchInfo, 0); 517 // No captures, only the match, which is always valid.
518 var s = SubString(subject, index, endOfMatch);
520 // Don't call directly to avoid exposing the built-in global object. 519 // Don't call directly to avoid exposing the built-in global object.
521 return replace.call(null, s, index, subject); 520 replacement =
521 %_CallFunction(%GetGlobalReceiver(), s, index, subject, replace);
522 } else {
523 var parameters = $Array(m + 2);
524 for (var j = 0; j < m; j++) {
525 parameters[j] = CaptureString(subject, matchInfo, j);
526 }
527 parameters[j] = index;
528 parameters[j + 1] = subject;
529
530 replacement = replace.apply(null, parameters);
522 } 531 }
523 var parameters = $Array(m + 2); 532
524 for (var j = 0; j < m; j++) { 533 result.add(replacement); // The add method converts to string if necessary.
525 parameters[j] = CaptureString(subject, matchInfo, j); 534 // Can't use matchInfo any more from here, since the function could
526 } 535 // overwrite it.
527 parameters[j] = index; 536 result.addSpecialSlice(endOfMatch, subject.length);
528 parameters[j + 1] = subject; 537 return result.generate();
529 return replace.apply(null, parameters);
530 } 538 }
531 539
540
532 // ECMA-262 section 15.5.4.12 541 // ECMA-262 section 15.5.4.12
533 function StringSearch(re) { 542 function StringSearch(re) {
534 var regexp; 543 var regexp;
535 if (IS_STRING(re)) { 544 if (IS_STRING(re)) {
536 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re); 545 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re);
537 } else if (IS_REGEXP(re)) { 546 } else if (IS_REGEXP(re)) {
538 regexp = re; 547 regexp = re;
539 } else { 548 } else {
540 regexp = new $RegExp(re); 549 regexp = new $RegExp(re);
541 } 550 }
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after
1003 "small", StringSmall, 1012 "small", StringSmall,
1004 "strike", StringStrike, 1013 "strike", StringStrike,
1005 "sub", StringSub, 1014 "sub", StringSub,
1006 "sup", StringSup, 1015 "sup", StringSup,
1007 "toJSON", StringToJSON 1016 "toJSON", StringToJSON
1008 )); 1017 ));
1009 } 1018 }
1010 1019
1011 1020
1012 SetupString(); 1021 SetupString();
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698