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

Side by Side Diff: src/js/regexp.js

Issue 1596483005: Add ES2015 RegExp full subclassing semantics behind a flag (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Update bytecode test expectations Created 4 years, 9 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
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 (function(global, utils) { 5 (function(global, utils) {
6 6
7 'use strict'; 7 'use strict';
8 8
9 %CheckIsBootstrapping(); 9 %CheckIsBootstrapping();
10 10
11 // ------------------------------------------------------------------- 11 // -------------------------------------------------------------------
12 // Imports 12 // Imports
13 13
14 var AddIndexedProperty;
14 var ExpandReplacement; 15 var ExpandReplacement;
16 var GlobalArray = global.Array;
15 var GlobalObject = global.Object; 17 var GlobalObject = global.Object;
16 var GlobalRegExp = global.RegExp; 18 var GlobalRegExp = global.RegExp;
17 var GlobalRegExpPrototype; 19 var GlobalRegExpPrototype;
18 var InternalArray = utils.InternalArray; 20 var InternalArray = utils.InternalArray;
19 var InternalPackedArray = utils.InternalPackedArray; 21 var InternalPackedArray = utils.InternalPackedArray;
20 var MakeTypeError; 22 var MakeTypeError;
23 var MathMax = global.Math.max;
24 var MathMin = global.Math.min;
21 var matchSymbol = utils.ImportNow("match_symbol"); 25 var matchSymbol = utils.ImportNow("match_symbol");
22 var replaceSymbol = utils.ImportNow("replace_symbol"); 26 var replaceSymbol = utils.ImportNow("replace_symbol");
23 var searchSymbol = utils.ImportNow("search_symbol"); 27 var searchSymbol = utils.ImportNow("search_symbol");
24 var splitSymbol = utils.ImportNow("split_symbol"); 28 var splitSymbol = utils.ImportNow("split_symbol");
29 var SpeciesConstructor;
25 30
26 utils.Import(function(from) { 31 utils.Import(function(from) {
32 AddIndexedProperty = from.AddIndexedProperty;
27 ExpandReplacement = from.ExpandReplacement; 33 ExpandReplacement = from.ExpandReplacement;
28 MakeTypeError = from.MakeTypeError; 34 MakeTypeError = from.MakeTypeError;
35 SpeciesConstructor = from.SpeciesConstructor;
29 }); 36 });
30 37
31 // ------------------------------------------------------------------- 38 // -------------------------------------------------------------------
32 39
33 // Property of the builtins object for recording the result of the last 40 // Property of the builtins object for recording the result of the last
34 // regexp match. The property RegExpLastMatchInfo includes the matchIndices 41 // regexp match. The property RegExpLastMatchInfo includes the matchIndices
35 // array of the last successful regexp match (an array of start/end index 42 // array of the last successful regexp match (an array of start/end index
36 // pairs for the match and all the captured substrings), the invariant is 43 // pairs for the match and all the captured substrings), the invariant is
37 // that there are at least two capture indeces. The array also contains 44 // that there are at least two capture indeces. The array also contains
38 // the subject string for the last successful match. 45 // the subject string for the last successful match.
39 var RegExpLastMatchInfo = new InternalPackedArray( 46 var RegExpLastMatchInfo = new InternalPackedArray(
40 2, // REGEXP_NUMBER_OF_CAPTURES 47 2, // REGEXP_NUMBER_OF_CAPTURES
41 "", // Last subject. 48 "", // Last subject.
42 UNDEFINED, // Last input - settable with RegExpSetInput. 49 UNDEFINED, // Last input - settable with RegExpSetInput.
43 0, // REGEXP_FIRST_CAPTURE + 0 50 0, // REGEXP_FIRST_CAPTURE + 0
44 0 // REGEXP_FIRST_CAPTURE + 1 51 0 // REGEXP_FIRST_CAPTURE + 1
45 ); 52 );
46 53
47 // ------------------------------------------------------------------- 54 // -------------------------------------------------------------------
48 55
56 // ES6 7.2.8
49 function IsRegExp(o) { 57 function IsRegExp(o) {
50 if (!IS_RECEIVER(o)) return false; 58 if (!IS_RECEIVER(o)) return false;
51 var is_regexp = o[matchSymbol]; 59 var is_regexp = o[matchSymbol];
52 if (!IS_UNDEFINED(is_regexp)) return TO_BOOLEAN(is_regexp); 60 if (!IS_UNDEFINED(is_regexp)) return TO_BOOLEAN(is_regexp);
53 return IS_REGEXP(o); 61 return IS_REGEXP(o);
54 } 62 }
55 63
56 64
57 // ES6 section 21.2.3.2.2 65 // ES6 section 21.2.3.2.2
58 function RegExpInitialize(object, pattern, flags) { 66 function RegExpInitialize(object, pattern, flags) {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 if (matchInfo !== null) { 166 if (matchInfo !== null) {
159 // ES6 21.2.5.2.2 step 18. 167 // ES6 21.2.5.2.2 step 18.
160 if (REGEXP_STICKY(regexp)) regexp.lastIndex = matchInfo[CAPTURE1]; 168 if (REGEXP_STICKY(regexp)) regexp.lastIndex = matchInfo[CAPTURE1];
161 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string); 169 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string);
162 } 170 }
163 regexp.lastIndex = 0; 171 regexp.lastIndex = 0;
164 return null; 172 return null;
165 } 173 }
166 174
167 175
176 function RegExpSubclassExecJS(string) {
177 if (!IS_REGEXP(this)) {
178 throw MakeTypeError(kIncompatibleMethodReceiver,
179 'RegExp.prototype.exec', this);
180 }
181
182 string = TO_STRING(string);
183 var lastIndex = this.lastIndex;
184
185 // Conversion is required by the ES2015 specification (RegExpBuiltinExec
186 // algorithm, step 4) even if the value is discarded for non-global RegExps.
187 var i = TO_LENGTH(lastIndex);
188
189 var global = TO_BOOLEAN(this.global);
190 var sticky = TO_BOOLEAN(this.sticky);
191 var updateLastIndex = global || sticky;
192 if (updateLastIndex) {
193 if (i < 0 || i > string.length) {
194 this.lastIndex = 0;
195 return null;
196 }
197 } else {
198 i = 0;
199 }
200
201 // matchIndices is either null or the RegExpLastMatchInfo array.
202 // TODO(littledan): Whether a RegExp is sticky is compiled into the RegExp
203 // itself, but ES2015 allows monkey-patching this property to differ from
204 // the internal flags. If it differs, recompile a different RegExp?
205 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo);
206
207 if (IS_NULL(matchIndices)) {
208 this.lastIndex = 0;
209 return null;
210 }
211
212 // Successful match.
213 if (updateLastIndex) {
214 this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
215 }
216 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
217 }
218 %FunctionRemovePrototype(RegExpSubclassExecJS);
Yang 2016/03/22 12:49:38 Like previously noted, let's always do this in Ove
Dan Ehrenberg 2016/03/22 18:26:31 See v8:4567 for the bug that this is working aroun
219
220
168 function RegExpExecJS(string) { 221 function RegExpExecJS(string) {
169 if (!IS_REGEXP(this)) { 222 if (!IS_REGEXP(this)) {
170 throw MakeTypeError(kIncompatibleMethodReceiver, 223 throw MakeTypeError(kIncompatibleMethodReceiver,
171 'RegExp.prototype.exec', this); 224 'RegExp.prototype.exec', this);
172 } 225 }
173 226
174 string = TO_STRING(string); 227 string = TO_STRING(string);
175 var lastIndex = this.lastIndex; 228 var lastIndex = this.lastIndex;
176 229
177 // Conversion is required by the ES2015 specification (RegExpBuiltinExec 230 // Conversion is required by the ES2015 specification (RegExpBuiltinExec
(...skipping 19 matching lines...) Expand all
197 } 250 }
198 251
199 // Successful match. 252 // Successful match.
200 if (updateLastIndex) { 253 if (updateLastIndex) {
201 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; 254 this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
202 } 255 }
203 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); 256 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
204 } 257 }
205 258
206 259
260 function RegExpSubclassExec(regexp, string) {
261 var exec = regexp.exec;
262 if (IS_CALLABLE(exec)) {
263 var result = %_Call(exec, regexp, string);
264 if (!IS_OBJECT(result) && !IS_NULL(result)) {
265 throw MakeTypeError(kInvalidRegExpExecResult);
266 }
267 return result;
268 }
269 return %_Call(RegExpExecJS, regexp, string);
270 }
271
272
207 // One-element cache for the simplified test regexp. 273 // One-element cache for the simplified test regexp.
208 var regexp_key; 274 var regexp_key;
209 var regexp_val; 275 var regexp_val;
210 276
211 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be 277 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
212 // that test is defined in terms of String.prototype.exec. However, it probably 278 // that test is defined in terms of String.prototype.exec. However, it probably
213 // means the original value of String.prototype.exec, which is what everybody 279 // means the original value of String.prototype.exec, which is what everybody
214 // else implements. 280 // else implements.
215 function RegExpTest(string) { 281 function RegExpTest(string) {
216 if (!IS_REGEXP(this)) { 282 if (!IS_REGEXP(this)) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 // matchIndices is either null or the RegExpLastMatchInfo array. 320 // matchIndices is either null or the RegExpLastMatchInfo array.
255 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo); 321 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo);
256 if (IS_NULL(matchIndices)) { 322 if (IS_NULL(matchIndices)) {
257 this.lastIndex = 0; 323 this.lastIndex = 0;
258 return false; 324 return false;
259 } 325 }
260 return true; 326 return true;
261 } 327 }
262 } 328 }
263 329
330 function RegExpSubclassTest(string) {
331 if (!IS_OBJECT(this)) {
332 throw MakeTypeError(kIncompatibleMethodReceiver,
333 'RegExp.prototype.test', this);
334 }
335 string = TO_STRING(string);
336 var match = RegExpSubclassExec(this, string);
337 return !IS_NULL(match);
338 }
339 %FunctionRemovePrototype(RegExpSubclassTest);
340
264 function TrimRegExp(regexp) { 341 function TrimRegExp(regexp) {
265 if (regexp_key !== regexp) { 342 if (regexp_key !== regexp) {
266 regexp_key = regexp; 343 regexp_key = regexp;
267 regexp_val = 344 regexp_val =
268 new GlobalRegExp( 345 new GlobalRegExp(
269 %_SubString(REGEXP_SOURCE(regexp), 2, REGEXP_SOURCE(regexp).length), 346 %_SubString(REGEXP_SOURCE(regexp), 2, REGEXP_SOURCE(regexp).length),
270 (REGEXP_IGNORE_CASE(regexp) ? REGEXP_MULTILINE(regexp) ? "im" : "i" 347 (REGEXP_IGNORE_CASE(regexp) ? REGEXP_MULTILINE(regexp) ? "im" : "i"
271 : REGEXP_MULTILINE(regexp) ? "m" : "")); 348 : REGEXP_MULTILINE(regexp) ? "m" : ""));
272 } 349 }
273 return regexp_val; 350 return regexp_val;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 452
376 startIndex = currentIndex = endIndex; 453 startIndex = currentIndex = endIndex;
377 } 454 }
378 455
379 var array_result = []; 456 var array_result = [];
380 %MoveArrayContents(result, array_result); 457 %MoveArrayContents(result, array_result);
381 return array_result; 458 return array_result;
382 } 459 }
383 460
384 461
462 function RegExpSubclassSplit(string, limit) {
463 if (!IS_RECEIVER(this)) {
464 throw MakeTypeError(kIncompatibleMethodReceiver,
465 "RegExp.prototype.@@split", this);
466 }
467 string = TO_STRING(string);
468 var constructor = SpeciesConstructor(this, GlobalRegExp);
469 var flags = TO_STRING(this.flags);
470 var unicode = %StringIndexOf(flags, 'u', 0) >= 0;
471 var sticky = %StringIndexOf(flags, 'y', 0) >= 0;
472 var new_flags = sticky ? flags : flags + "y";
473 var splitter = new constructor(this, new_flags);
474 var array = new GlobalArray();
475 var array_index = 0;
476 var lim = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit);
477 var size = string.length;
478 var prev_string_index = 0;
479 if (lim === 0) return array;
480 var result;
481 if (size === 0) {
482 result = RegExpSubclassExec(splitter, string);
483 if (IS_NULL(result)) AddIndexedProperty(array, 0, string);
484 return array;
485 }
486 var string_index = prev_string_index;
487 while (string_index < size) {
488 splitter.lastIndex = string_index;
489 result = RegExpSubclassExec(splitter, string);
490 if (IS_NULL(result)) {
491 string_index += GetUnicodeAdvancedIncrement(string, string_index,
492 unicode);
493 } else {
494 var end = MathMin(splitter.lastIndex, size);
495 if (end === prev_string_index) {
496 string_index += GetUnicodeAdvancedIncrement(string, string_index,
497 unicode);
498 } else {
499 AddIndexedProperty(
500 array, array_index,
501 %_SubString(string, prev_string_index, string_index));
502 array_index++;
503 if (array_index === lim) return array;
504 prev_string_index = end;
505 var number_of_captures = MathMax(TO_LENGTH(result.length), 0);
506 for (var i = 1; i < number_of_captures; i++) {
507 AddIndexedProperty(array, array_index, result[i]);
508 array_index++;
509 if (array_index === lim) return array;
510 }
511 string_index = prev_string_index;
512 }
513 }
514 }
515 AddIndexedProperty(array, array_index,
516 %_SubString(string, prev_string_index, size));
517 return array;
518 }
519 %FunctionRemovePrototype(RegExpSubclassSplit);
520
521
385 // ES6 21.2.5.6. 522 // ES6 21.2.5.6.
386 function RegExpMatch(string) { 523 function RegExpMatch(string) {
387 // TODO(yangguo): allow non-regexp receivers.
388 if (!IS_REGEXP(this)) { 524 if (!IS_REGEXP(this)) {
389 throw MakeTypeError(kIncompatibleMethodReceiver, 525 throw MakeTypeError(kIncompatibleMethodReceiver,
390 "RegExp.prototype.@@match", this); 526 "RegExp.prototype.@@match", this);
391 } 527 }
392 var subject = TO_STRING(string); 528 var subject = TO_STRING(string);
393 529
394 if (!REGEXP_GLOBAL(this)) return RegExpExecNoTests(this, subject, 0); 530 if (!REGEXP_GLOBAL(this)) return RegExpExecNoTests(this, subject, 0);
395 this.lastIndex = 0; 531 this.lastIndex = 0;
396 var result = %StringMatch(subject, this, RegExpLastMatchInfo); 532 var result = %StringMatch(subject, this, RegExpLastMatchInfo);
397 return result; 533 return result;
398 } 534 }
399 535
400 536
537 function RegExpSubclassMatch(string) {
538 if (!IS_OBJECT(this)) {
539 throw MakeTypeError(kIncompatibleMethodReceiver,
540 "RegExp.prototype.@@match", this);
541 }
542 string = TO_STRING(string);
543 var global = this.global;
544 if (!global) return RegExpSubclassExec(this, string);
545 var unicode = this.unicode;
546 this.lastIndex = 0;
547 var array = [];
548 var n = 0;
549 var result;
550 while (true) {
551 result = RegExpSubclassExec(this, string);
552 if (IS_NULL(result)) {
553 if (n === 0) return null;
554 return array;
555 }
556 var matchStr = TO_STRING(result[0]);
557 %AddElement(array, n, matchStr);
558 if (matchStr === "") AdvanceStringIndex(this, string, unicode);
559 n++;
560 }
561 }
562 %FunctionRemovePrototype(RegExpSubclassMatch);
563
564
401 // ES6 21.2.5.8. 565 // ES6 21.2.5.8.
402 566
403 // TODO(lrn): This array will survive indefinitely if replace is never 567 // TODO(lrn): This array will survive indefinitely if replace is never
404 // called again. However, it will be empty, since the contents are cleared 568 // called again. However, it will be empty, since the contents are cleared
405 // in the finally block. 569 // in the finally block.
406 var reusableReplaceArray = new InternalArray(4); 570 var reusableReplaceArray = new InternalArray(4);
407 571
408 // Helper function for replacing regular expressions with the result of a 572 // Helper function for replacing regular expressions with the result of a
409 // function application in String.prototype.replace. 573 // function application in String.prototype.replace.
410 function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { 574 function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 } 682 }
519 683
520 result += replacement; // The add method converts to string if necessary. 684 result += replacement; // The add method converts to string if necessary.
521 // Can't use matchInfo any more from here, since the function could 685 // Can't use matchInfo any more from here, since the function could
522 // overwrite it. 686 // overwrite it.
523 return result + %_SubString(subject, endOfMatch, subject.length); 687 return result + %_SubString(subject, endOfMatch, subject.length);
524 } 688 }
525 689
526 690
527 function RegExpReplace(string, replace) { 691 function RegExpReplace(string, replace) {
528 // TODO(littledan): allow non-regexp receivers.
529 if (!IS_REGEXP(this)) { 692 if (!IS_REGEXP(this)) {
530 throw MakeTypeError(kIncompatibleMethodReceiver, 693 throw MakeTypeError(kIncompatibleMethodReceiver,
531 "RegExp.prototype.@@replace", this); 694 "RegExp.prototype.@@replace", this);
532 } 695 }
533 var subject = TO_STRING(string); 696 var subject = TO_STRING(string);
534 var search = this; 697 var search = this;
535 698
536 if (!IS_CALLABLE(replace)) { 699 if (!IS_CALLABLE(replace)) {
537 replace = TO_STRING(replace); 700 replace = TO_STRING(replace);
538 701
(...skipping 21 matching lines...) Expand all
560 723
561 if (REGEXP_GLOBAL(search)) { 724 if (REGEXP_GLOBAL(search)) {
562 // Global regexp search, function replace. 725 // Global regexp search, function replace.
563 return StringReplaceGlobalRegExpWithFunction(subject, search, replace); 726 return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
564 } 727 }
565 // Non-global regexp search, function replace. 728 // Non-global regexp search, function replace.
566 return StringReplaceNonGlobalRegExpWithFunction(subject, search, replace); 729 return StringReplaceNonGlobalRegExpWithFunction(subject, search, replace);
567 } 730 }
568 731
569 732
733 // Expand the $-expressions in the string and return a new string with
734 // the result.
735 function GetCaptures(matched, string, position, captures, replacement) {
736 var match_length = matched.length;
737 var string_length = string.length;
738 var captures_length = captures.length;
739 var tail_pos = position + match_length;
740 var result = "";
741 var pos, expansion, peek, next, scaled_index, advance, new_scaled_index;
742
743 var next = %StringIndexOf(replacement, '$', 0);
744 if (next < 0) {
745 result += replacement;
746 return result;
747 }
748
749 if (next > 0) result += %_SubString(replacement, 0, next);
750
751 while (true) {
752 expansion = '$';
753 pos = next + 1;
754 if (pos < replacement.length) {
755 peek = %_StringCharCodeAt(replacement, pos);
756 if (peek == 36) { // $$
757 ++pos;
758 result += '$';
759 } else if (peek == 38) { // $& - match
760 ++pos;
761 result += matched;
762 } else if (peek == 96) { // $` - prefix
763 ++pos;
764 result += %_SubString(string, 0, position);
765 } else if (peek == 39) { // $' - suffix
766 ++pos;
767 result += %_SubString(string, tail_pos, string_length);
768 } else if (peek >= 48 && peek <= 57) {
769 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
770 scaled_index = (peek - 48);
771 advance = 1;
772 if (pos + 1 < replacement.length) {
773 next = %_StringCharCodeAt(replacement, pos + 1);
774 if (next >= 48 && next <= 57) {
775 new_scaled_index = scaled_index * 10 + ((next - 48));
776 if (new_scaled_index < captures_length) {
777 scaled_index = new_scaled_index;
778 advance = 2;
779 }
780 }
781 }
782 if (scaled_index != 0 && scaled_index < captures_length) {
783 var capture = captures[scaled_index];
784 if (!IS_UNDEFINED(capture)) result += capture;
785 pos += advance;
786 } else {
787 result += '$';
788 }
789 } else {
790 result += '$';
791 }
792 } else {
793 result += '$';
794 }
795
796 // Go the the next $ in the replacement.
797 next = %StringIndexOf(replacement, '$', pos);
798
799 // Return if there are no more $ characters in the replacement. If we
800 // haven't reached the end, we need to append the suffix.
801 if (next < 0) {
802 if (pos < replacement.length) {
803 result += %_SubString(replacement, pos, replacement.length);
804 }
805 return result;
806 }
807
808 // Append substring between the previous and the next $ character.
809 if (next > pos) {
810 result += %_SubString(replacement, pos, next);
811 }
812 }
813 return result;
814 }
815
816
817 function GetUnicodeAdvancedIncrement(string, index, unicode) {
818 var increment = 1;
819 if (unicode) {
820 var first = %_StringCharCodeAt(string, index);
821 if (first >= 0xD800 && first <= 0xDBFF && string.length > index + 1) {
822 var second = %_StringCharCodeAt(string, index + 1);
823 if (second >= 0xDC00 && second <= 0xDFFF) {
824 increment = 2;
825 }
826 }
827 }
828 return increment;
829 }
830
831
832 function AdvanceStringIndex(regexp, string, unicode) {
833 var last_index = regexp.lastIndex;
834 regexp.lastIndex = last_index +
835 GetUnicodeAdvancedIncrement(string, last_index, unicode);
836 }
837
838
839 function RegExpSubclassReplace(string, replace) {
840 if (!IS_OBJECT(this)) {
841 throw MakeTypeError(kIncompatibleMethodReceiver,
842 "RegExp.prototype.@@replace", this);
843 }
844 string = TO_STRING(string);
845 var length = string.length;
846 var functional_replace = IS_CALLABLE(replace);
847 if (!functional_replace) replace = TO_STRING(replace);
848 var global = this.global;
849 if (global) {
850 var unicode = this.unicode;
851 this.lastIndex = 0;
852 }
853 var results = new InternalArray();
854 var result, replacement;
855 while (true) {
856 result = RegExpSubclassExec(this, string);
857 if (IS_NULL(result)) {
858 break;
859 } else {
860 results.push(result);
861 if (!global) break;
862 var match_str = TO_STRING(result[0]);
863 if (match_str === "") AdvanceStringIndex(this, string, unicode);
864 }
865 }
866 var accumulated_result = "";
867 var next_source_position = 0;
868 for (var i = 0; i < results.length; i++) {
869 result = results[i];
870 var captures_length = MathMax(TO_LENGTH(result.length), 0);
871 var matched = TO_STRING(result[0]);
872 var matched_length = matched.length;
873 var position = MathMax(MathMin(TO_INTEGER(result.index), length), 0);
874 var captures = new InternalArray();
875 for (var n = 0; n < captures_length; n++) {
876 var capture = result[n];
877 if (!IS_UNDEFINED(capture)) capture = TO_STRING(capture);
878 captures[n] = capture;
879 }
880 if (functional_replace) {
881 var parameters = new InternalArray(captures_length + 2);
882 for (var j = 0; j < captures_length; j++) {
883 parameters[j] = captures[j];
884 }
885 parameters[j] = position;
886 parameters[j + 1] = string;
887 replacement = %reflect_apply(replace, UNDEFINED, parameters, 0,
888 parameters.length);
889 } else {
890 replacement = GetCaptures(matched, string, position, captures, replace);
891 }
892 if (position >= next_source_position) {
893 accumulated_result +=
894 %_SubString(string, next_source_position, position) + replacement;
895 next_source_position = position + matched_length;
896 }
897 }
898 if (next_source_position >= length) return accumulated_result;
899 return accumulated_result + %_SubString(string, next_source_position, length);
900 }
901 %FunctionRemovePrototype(RegExpSubclassReplace);
902
903
570 // ES6 21.2.5.9. 904 // ES6 21.2.5.9.
571 function RegExpSearch(string) { 905 function RegExpSearch(string) {
572 // TODO(yangguo): allow non-regexp receivers.
573 if (!IS_REGEXP(this)) { 906 if (!IS_REGEXP(this)) {
574 throw MakeTypeError(kIncompatibleMethodReceiver, 907 throw MakeTypeError(kIncompatibleMethodReceiver,
575 "RegExp.prototype.@@search", this); 908 "RegExp.prototype.@@search", this);
576 } 909 }
577 var match = DoRegExpExec(this, TO_STRING(string), 0); 910 var match = DoRegExpExec(this, TO_STRING(string), 0);
578 if (match) return match[CAPTURE0]; 911 if (match) return match[CAPTURE0];
579 return -1; 912 return -1;
580 } 913 }
581 914
582 915
916 function RegExpSubclassSearch(string) {
917 if (!IS_OBJECT(this)) {
918 throw MakeTypeError(kIncompatibleMethodReceiver,
919 "RegExp.prototype.@@search", this);
920 }
921 string = TO_STRING(string);
922 var previousLastIndex = this.lastIndex;
923 this.lastIndex = 0;
924 var result = RegExpSubclassExec(this, string);
925 this.lastIndex = previousLastIndex;
926 if (IS_NULL(result)) return -1;
927 return result.index;
928 }
929 %FunctionRemovePrototype(RegExpSubclassSearch);
930
931
583 // Getters for the static properties lastMatch, lastParen, leftContext, and 932 // Getters for the static properties lastMatch, lastParen, leftContext, and
584 // rightContext of the RegExp constructor. The properties are computed based 933 // rightContext of the RegExp constructor. The properties are computed based
585 // on the captures array of the last successful match and the subject string 934 // on the captures array of the last successful match and the subject string
586 // of the last successful match. 935 // of the last successful match.
587 function RegExpGetLastMatch() { 936 function RegExpGetLastMatch() {
588 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); 937 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo);
589 return %_SubString(regExpSubject, 938 return %_SubString(regExpSubject,
590 RegExpLastMatchInfo[CAPTURE0], 939 RegExpLastMatchInfo[CAPTURE0],
591 RegExpLastMatchInfo[CAPTURE1]); 940 RegExpLastMatchInfo[CAPTURE1]);
592 } 941 }
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
697 %IncrementUseCounter(kRegExpPrototypeSourceGetter); 1046 %IncrementUseCounter(kRegExpPrototypeSourceGetter);
698 return UNDEFINED; 1047 return UNDEFINED;
699 } 1048 }
700 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source"); 1049 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source");
701 } 1050 }
702 return REGEXP_SOURCE(this); 1051 return REGEXP_SOURCE(this);
703 } 1052 }
704 %FunctionSetName(RegExpGetSource, "RegExp.prototype.source"); 1053 %FunctionSetName(RegExpGetSource, "RegExp.prototype.source");
705 %SetNativeFlag(RegExpGetSource); 1054 %SetNativeFlag(RegExpGetSource);
706 1055
1056
Yang 2016/03/22 12:49:38 stray edit?
Dan Ehrenberg 2016/03/22 18:26:31 Reverted
707 // ------------------------------------------------------------------- 1057 // -------------------------------------------------------------------
708 1058
709 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp'); 1059 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
710 GlobalRegExpPrototype = new GlobalObject(); 1060 GlobalRegExpPrototype = new GlobalObject();
711 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype); 1061 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype);
712 %AddNamedProperty( 1062 %AddNamedProperty(
713 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM); 1063 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
714 %SetCode(GlobalRegExp, RegExpConstructor); 1064 %SetCode(GlobalRegExp, RegExpConstructor);
715 1065
716 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ 1066 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
774 } 1124 }
775 %ToFastProperties(GlobalRegExp); 1125 %ToFastProperties(GlobalRegExp);
776 1126
777 // ------------------------------------------------------------------- 1127 // -------------------------------------------------------------------
778 // Exports 1128 // Exports
779 1129
780 utils.Export(function(to) { 1130 utils.Export(function(to) {
781 to.RegExpExec = DoRegExpExec; 1131 to.RegExpExec = DoRegExpExec;
782 to.RegExpExecNoTests = RegExpExecNoTests; 1132 to.RegExpExecNoTests = RegExpExecNoTests;
783 to.RegExpLastMatchInfo = RegExpLastMatchInfo; 1133 to.RegExpLastMatchInfo = RegExpLastMatchInfo;
1134 to.RegExpSubclassExecJS = RegExpSubclassExecJS;
1135 to.RegExpSubclassMatch = RegExpSubclassMatch;
1136 to.RegExpSubclassReplace = RegExpSubclassReplace;
1137 to.RegExpSubclassSearch = RegExpSubclassSearch;
1138 to.RegExpSubclassSplit = RegExpSubclassSplit;
1139 to.RegExpSubclassTest = RegExpSubclassTest;
784 to.RegExpTest = RegExpTest; 1140 to.RegExpTest = RegExpTest;
785 to.IsRegExp = IsRegExp; 1141 to.IsRegExp = IsRegExp;
786 }); 1142 });
787 1143
788 }) 1144 })
OLDNEW
« src/js/prologue.js ('K') | « src/js/prologue.js ('k') | src/messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698