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

Side by Side Diff: src/string.js

Issue 12177015: Refactor implementation for String.prototype.replace. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 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
« no previous file with comments | « src/runtime.cc ('k') | 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 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 222
223 223
224 // ECMA-262, section 15.5.4.11 224 // ECMA-262, section 15.5.4.11
225 function StringReplace(search, replace) { 225 function StringReplace(search, replace) {
226 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 226 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
227 throw MakeTypeError("called_on_null_or_undefined", 227 throw MakeTypeError("called_on_null_or_undefined",
228 ["String.prototype.replace"]); 228 ["String.prototype.replace"]);
229 } 229 }
230 var subject = TO_STRING_INLINE(this); 230 var subject = TO_STRING_INLINE(this);
231 231
232 // Delegate to one of the regular expression variants if necessary. 232 // Decision tree for dispatch
233 // .. regexp search
234 // .... string replace
235 // ...... non-global search
236 // ........ empty string replace
237 // ........ non-empty string replace (with $-expansion)
238 // ...... global search
239 // ........ no need to circumvent last match info override
240 // ........ need to circument last match info override
241 // .... function replace
242 // ...... global search
243 // ...... non-global search
244 // .. string search
245 // .... special case that replaces with one single character
246 // ...... function replace
247 // ...... string replace (with $-expansion)
248
233 if (IS_REGEXP(search)) { 249 if (IS_REGEXP(search)) {
234 // Emulate RegExp.prototype.exec's side effect in step 5, even though 250 // Emulate RegExp.prototype.exec's side effect in step 5, even if
235 // value is discarded. 251 // value is discarded.
236 ToInteger(search.lastIndex); 252 ToInteger(search.lastIndex);
237 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); 253 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
238 if (IS_SPEC_FUNCTION(replace)) { 254
239 if (search.global) { 255 if (!IS_SPEC_FUNCTION(replace)) {
240 return StringReplaceGlobalRegExpWithFunction(subject, search, replace); 256 if (!search.global) {
241 } else { 257 // Non-global regexp search, string replace.
242 return StringReplaceNonGlobalRegExpWithFunction(subject, 258 var match = DoRegExpExec(search, subject, 0);
243 search, 259 if (match == null) {
244 replace); 260 search.lastIndex = 0
245 }
246 } else {
247 if (lastMatchInfoOverride == null) {
248 var answer = %StringReplaceRegExpWithString(subject,
249 search,
250 TO_STRING_INLINE(replace),
251 lastMatchInfo);
252 if (IS_UNDEFINED(answer)) { // No match. Return subject string.
253 search.lastIndex = 0;
254 return subject; 261 return subject;
255 } 262 }
256 if (search.global) search.lastIndex = 0; 263 if (replace.length == 0) {
257 return answer; 264 return SubString(subject, 0, match[CAPTURE0]) +
265 SubString(subject, match[CAPTURE1], subject.length)
266 }
267 return ExpandReplacement(TO_STRING_INLINE(replace),
268 subject,
269 lastMatchInfo,
270 SubString(subject, 0, match[CAPTURE0])) +
271 SubString(subject, match[CAPTURE1], subject.length);
ulan 2013/02/05 09:30:58 I would reformat by putting the first argument of
Yang 2013/02/05 10:47:32 Not entirely sure what you mean here.
272 }
273
274 // Global regexp search, string replace.
275 search.lastIndex = 0;
276 if (lastMatchInfoOverride == null) {
277 return %StringReplaceGlobalRegExpWithString(
278 subject, search, replace, lastMatchInfo);
258 } else { 279 } else {
259 // We use this hack to detect whether StringReplaceRegExpWithString 280 // We use this hack to detect whether StringReplaceRegExpWithString
260 // found at least one hit. In that case we need to remove any 281 // found at least one hit. In that case we need to remove any
261 // override. 282 // override.
262 var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX]; 283 var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX];
263 lastMatchInfo[LAST_SUBJECT_INDEX] = 0; 284 lastMatchInfo[LAST_SUBJECT_INDEX] = 0;
264 var answer = %StringReplaceRegExpWithString(subject, 285 var answer = %StringReplaceGlobalRegExpWithString(
265 search, 286 subject, search, replace, lastMatchInfo);
266 TO_STRING_INLINE(replace),
267 lastMatchInfo);
268 if (IS_UNDEFINED(answer)) { // No match. Return subject string.
269 search.lastIndex = 0;
270 lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
271 return subject;
272 }
273 if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) { 287 if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
274 lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject; 288 lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
275 } else { 289 } else {
276 lastMatchInfoOverride = null; 290 lastMatchInfoOverride = null;
277 } 291 }
278 if (search.global) search.lastIndex = 0;
279 return answer; 292 return answer;
280 } 293 }
281 } 294 }
295
296 if (search.global) {
297 // Global regexp search, function replace.
298 return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
299 }
300 // Non-global regexp search, function replace.
301 return StringReplaceNonGlobalRegExpWithFunction(subject, search, replace);
282 } 302 }
283 303
284 // Convert the search argument to a string and search for it.
285 search = TO_STRING_INLINE(search);
ulan 2013/02/05 09:30:58 Looks like it was remove accidentally.
286 if (search.length == 1 && 304 if (search.length == 1 &&
287 subject.length > 0xFF && 305 subject.length > 0xFF &&
288 IS_STRING(replace) && 306 IS_STRING(replace) &&
289 %StringIndexOf(replace, '$', 0) < 0) { 307 %StringIndexOf(replace, '$', 0) < 0) {
290 // Searching by traversing a cons string tree and replace with cons of 308 // Searching by traversing a cons string tree and replace with cons of
291 // slices works only when the replaced string is a single character, being 309 // slices works only when the replaced string is a single character, being
292 // replaced by a simple string and only pays off for long strings. 310 // replaced by a simple string and only pays off for long strings.
293 return %StringReplaceOneCharWithString(subject, search, replace); 311 return %StringReplaceOneCharWithString(subject, search, replace);
294 } 312 }
295 var start = %StringIndexOf(subject, search, 0); 313 var start = %StringIndexOf(subject, search, 0);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 result += '$'; 353 result += '$';
336 } else if (peek == 38) { // $& - match 354 } else if (peek == 38) { // $& - match
337 ++position; 355 ++position;
338 result += SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]); 356 result += SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]);
339 } else if (peek == 96) { // $` - prefix 357 } else if (peek == 96) { // $` - prefix
340 ++position; 358 ++position;
341 result += SubString(subject, 0, matchInfo[CAPTURE0]); 359 result += SubString(subject, 0, matchInfo[CAPTURE0]);
342 } else if (peek == 39) { // $' - suffix 360 } else if (peek == 39) { // $' - suffix
343 ++position; 361 ++position;
344 result += SubString(subject, matchInfo[CAPTURE1], subject.length); 362 result += SubString(subject, matchInfo[CAPTURE1], subject.length);
363 } else if (peek >= 48 && peek <= 57) { // between '0' and '9'
364 // Convert to digit by subtracting '0'.
365 var scaled_index;
366 var advance;
367 if (peek == 48) { // $0...
368 if (position + 1 == string.length || // ends with '$0', invalid.
369 %_StringCharCodeAt(string, position + 1) != 49) { // not '$01'
ulan 2013/02/05 09:30:58 As discussed offline, we should check $02, ... $nn
370 scaled_index = 1 << 18;
371 } else {
372 scaled_index = 2; // 1 * 2
373 advance = 2;
374 }
375 } else if (peek == 49 &&
376 position + 1 < string.length &&
377 %_StringCharCodeAt(string, position + 1) == 48) { // $10
378 scaled_index = 20; // 10 * 2
379 advance = 2;
380 } else {
381 scaled_index = (peek - 48) << 1; // index * 2
382 advance = 1;
383 }
384
385 if (NUMBER_OF_CAPTURES(matchInfo) > scaled_index) {
386 var start = matchInfo[CAPTURE(scaled_index)];
387 if (start >= 0) {
388 result +=
389 SubString(subject, start, matchInfo[CAPTURE(scaled_index + 1)]);
390 }
391 position += advance;
392 } else {
393 result += '$';
394 }
345 } else { 395 } else {
346 result += '$'; 396 result += '$';
347 } 397 }
348 } else { 398 } else {
349 result += '$'; 399 result += '$';
350 } 400 }
351 401
352 // Go the the next $ in the string. 402 // Go the the next $ in the string.
353 next = %StringIndexOf(string, '$', position); 403 next = %StringIndexOf(string, '$', position);
354 404
(...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after
1015 "fixed", StringFixed, 1065 "fixed", StringFixed,
1016 "italics", StringItalics, 1066 "italics", StringItalics,
1017 "small", StringSmall, 1067 "small", StringSmall,
1018 "strike", StringStrike, 1068 "strike", StringStrike,
1019 "sub", StringSub, 1069 "sub", StringSub,
1020 "sup", StringSup 1070 "sup", StringSup
1021 )); 1071 ));
1022 } 1072 }
1023 1073
1024 SetUpString(); 1074 SetUpString();
OLDNEW
« no previous file with comments | « src/runtime.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698