OLD | NEW |
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 %CheckIsBootstrapping(); | 7 %CheckIsBootstrapping(); |
8 | 8 |
9 // ------------------------------------------------------------------- | 9 // ------------------------------------------------------------------- |
10 // Imports | 10 // Imports |
11 | 11 |
12 var FLAG_harmony_tolength; | 12 var FLAG_harmony_tolength; |
13 var GlobalObject = global.Object; | 13 var GlobalObject = global.Object; |
14 var GlobalRegExp = global.RegExp; | 14 var GlobalRegExp = global.RegExp; |
15 var InternalArray = utils.InternalArray; | 15 var InternalArray = utils.InternalArray; |
16 var InternalPackedArray = utils.InternalPackedArray; | 16 var InternalPackedArray = utils.InternalPackedArray; |
17 var MakeTypeError; | 17 var MakeTypeError; |
18 var splitSymbol = utils.ImportNow("split_symbol"); | 18 var splitSymbol = utils.ImportNow("split_symbol"); |
| 19 var matchSymbol = utils.ImportNow("match_symbol");; |
19 | 20 |
20 utils.ImportFromExperimental(function(from) { | 21 utils.ImportFromExperimental(function(from) { |
21 FLAG_harmony_tolength = from.FLAG_harmony_tolength; | 22 FLAG_harmony_tolength = from.FLAG_harmony_tolength; |
22 }); | 23 }); |
23 | 24 |
24 utils.Import(function(from) { | 25 utils.Import(function(from) { |
25 MakeTypeError = from.MakeTypeError; | 26 MakeTypeError = from.MakeTypeError; |
26 }); | 27 }); |
27 | 28 |
28 // ------------------------------------------------------------------- | 29 // ------------------------------------------------------------------- |
29 | 30 |
30 // Property of the builtins object for recording the result of the last | 31 // Property of the builtins object for recording the result of the last |
31 // regexp match. The property RegExpLastMatchInfo includes the matchIndices | 32 // regexp match. The property RegExpLastMatchInfo includes the matchIndices |
32 // array of the last successful regexp match (an array of start/end index | 33 // array of the last successful regexp match (an array of start/end index |
33 // pairs for the match and all the captured substrings), the invariant is | 34 // pairs for the match and all the captured substrings), the invariant is |
34 // that there are at least two capture indeces. The array also contains | 35 // that there are at least two capture indeces. The array also contains |
35 // the subject string for the last successful match. | 36 // the subject string for the last successful match. |
36 var RegExpLastMatchInfo = new InternalPackedArray( | 37 var RegExpLastMatchInfo = new InternalPackedArray( |
37 2, // REGEXP_NUMBER_OF_CAPTURES | 38 2, // REGEXP_NUMBER_OF_CAPTURES |
38 "", // Last subject. | 39 "", // Last subject. |
39 UNDEFINED, // Last input - settable with RegExpSetInput. | 40 UNDEFINED, // Last input - settable with RegExpSetInput. |
40 0, // REGEXP_FIRST_CAPTURE + 0 | 41 0, // REGEXP_FIRST_CAPTURE + 0 |
41 0 // REGEXP_FIRST_CAPTURE + 1 | 42 0 // REGEXP_FIRST_CAPTURE + 1 |
42 ); | 43 ); |
43 | 44 |
44 // ------------------------------------------------------------------- | 45 // ------------------------------------------------------------------- |
45 | 46 |
46 // A recursive descent parser for Patterns according to the grammar of | 47 function IsRegExp(o) { |
47 // ECMA-262 15.10.1, with deviations noted below. | 48 if (!IS_OBJECT(o)) return false; |
48 function DoConstructRegExp(object, pattern, flags) { | 49 var is_regexp = o[matchSymbol]; |
49 // RegExp : Called as constructor; see ECMA-262, section 15.10.4. | 50 if (!IS_UNDEFINED(is_regexp)) return TO_BOOLEAN(is_regexp); |
50 if (IS_REGEXP(pattern)) { | 51 return IS_REGEXP(o); |
51 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags); | 52 } |
52 flags = (REGEXP_GLOBAL(pattern) ? 'g' : '') | |
53 + (REGEXP_IGNORE_CASE(pattern) ? 'i' : '') | |
54 + (REGEXP_MULTILINE(pattern) ? 'm' : '') | |
55 + (REGEXP_UNICODE(pattern) ? 'u' : '') | |
56 + (REGEXP_STICKY(pattern) ? 'y' : ''); | |
57 pattern = REGEXP_SOURCE(pattern); | |
58 } | |
59 | 53 |
| 54 |
| 55 // ES6 section 21.2.3.2.2 |
| 56 function RegExpInitialize(object, pattern, flags) { |
60 pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern); | 57 pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern); |
61 flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags); | 58 flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags); |
| 59 %RegExpInitializeAndCompile(object, pattern, flags); |
| 60 return object; |
| 61 } |
62 | 62 |
63 %RegExpInitializeAndCompile(object, pattern, flags); | 63 |
| 64 function PatternFlags(pattern) { |
| 65 return (REGEXP_GLOBAL(pattern) ? 'g' : '') + |
| 66 (REGEXP_IGNORE_CASE(pattern) ? 'i' : '') + |
| 67 (REGEXP_MULTILINE(pattern) ? 'm' : '') + |
| 68 (REGEXP_UNICODE(pattern) ? 'u' : '') + |
| 69 (REGEXP_STICKY(pattern) ? 'y' : ''); |
64 } | 70 } |
65 | 71 |
66 | 72 |
67 function RegExpConstructor(pattern, flags) { | 73 function RegExpConstructor(pattern, flags) { |
68 if (%_IsConstructCall()) { | 74 var newtarget = new.target; |
69 DoConstructRegExp(this, pattern, flags); | 75 var pattern_is_regexp = IsRegExp(pattern); |
70 } else { | 76 |
71 // RegExp : Called as function; see ECMA-262, section 15.10.3.1. | 77 if (IS_UNDEFINED(newtarget)) { |
72 if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) { | 78 newtarget = GlobalRegExp; |
| 79 |
| 80 // ES6 section 21.2.3.1 step 3.b |
| 81 if (pattern_is_regexp && IS_UNDEFINED(flags) && |
| 82 pattern.constructor === newtarget) { |
73 return pattern; | 83 return pattern; |
74 } | 84 } |
75 return new GlobalRegExp(pattern, flags); | |
76 } | 85 } |
77 } | |
78 | 86 |
79 // Deprecated RegExp.prototype.compile method. We behave like the constructor | 87 if (IS_REGEXP(pattern)) { |
80 // were called again. In SpiderMonkey, this method returns the regexp object. | 88 if (IS_UNDEFINED(flags)) flags = PatternFlags(pattern); |
81 // In JSC, it returns undefined. For compatibility with JSC, we match their | 89 pattern = REGEXP_SOURCE(pattern); |
82 // behavior. | 90 |
83 function RegExpCompileJS(pattern, flags) { | 91 } else if (pattern_is_regexp) { |
84 // Both JSC and SpiderMonkey treat a missing pattern argument as the | 92 var input_pattern = pattern; |
85 // empty subject string, and an actual undefined value passed as the | 93 pattern = pattern.source; |
86 // pattern as the string 'undefined'. Note that JSC is inconsistent | 94 if (IS_UNDEFINED(flags)) flags = input_pattern.flags; |
87 // here, treating undefined values differently in | |
88 // RegExp.prototype.compile and in the constructor, where they are | |
89 // the empty string. For compatibility with JSC, we match their | |
90 // behavior. | |
91 if (this == GlobalRegExp.prototype) { | |
92 // We don't allow recompiling RegExp.prototype. | |
93 throw MakeTypeError(kIncompatibleMethodReceiver, | |
94 'RegExp.prototype.compile', this); | |
95 } | 95 } |
96 if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) { | 96 |
97 DoConstructRegExp(this, 'undefined', flags); | 97 var object = %NewObject(GlobalRegExp, newtarget); |
98 } else { | 98 return RegExpInitialize(object, pattern, flags); |
99 DoConstructRegExp(this, pattern, flags); | |
100 } | |
101 } | 99 } |
102 | 100 |
103 | 101 |
| 102 function RegExpCompileJS(pattern, flags) { |
| 103 if (!IS_REGEXP(this)) { |
| 104 throw MakeTypeError(kIncompatibleMethodReceiver, |
| 105 "RegExp.prototype.compile", this); |
| 106 } |
| 107 |
| 108 if (IS_REGEXP(pattern)) { |
| 109 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags); |
| 110 |
| 111 flags = PatternFlags(pattern); |
| 112 pattern = REGEXP_SOURCE(pattern); |
| 113 } |
| 114 |
| 115 return RegExpInitialize(this, pattern, flags); |
| 116 } |
| 117 |
| 118 |
104 function DoRegExpExec(regexp, string, index) { | 119 function DoRegExpExec(regexp, string, index) { |
105 var result = %_RegExpExec(regexp, string, index, RegExpLastMatchInfo); | 120 var result = %_RegExpExec(regexp, string, index, RegExpLastMatchInfo); |
106 return result; | 121 return result; |
107 } | 122 } |
108 | 123 |
109 | 124 |
110 // This is kind of performance sensitive, so we want to avoid unnecessary | 125 // This is kind of performance sensitive, so we want to avoid unnecessary |
111 // type checks on inputs. But we also don't want to inline it several times | 126 // type checks on inputs. But we also don't want to inline it several times |
112 // manually, so we use a macro :-) | 127 // manually, so we use a macro :-) |
113 macro RETURN_NEW_RESULT_FROM_MATCH_INFO(MATCHINFO, STRING) | 128 macro RETURN_NEW_RESULT_FROM_MATCH_INFO(MATCHINFO, STRING) |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 // Exports | 532 // Exports |
518 | 533 |
519 utils.Export(function(to) { | 534 utils.Export(function(to) { |
520 to.RegExpExec = DoRegExpExec; | 535 to.RegExpExec = DoRegExpExec; |
521 to.RegExpExecNoTests = RegExpExecNoTests; | 536 to.RegExpExecNoTests = RegExpExecNoTests; |
522 to.RegExpLastMatchInfo = RegExpLastMatchInfo; | 537 to.RegExpLastMatchInfo = RegExpLastMatchInfo; |
523 to.RegExpTest = RegExpTest; | 538 to.RegExpTest = RegExpTest; |
524 }); | 539 }); |
525 | 540 |
526 }) | 541 }) |
OLD | NEW |