OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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(); |
OLD | NEW |