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

Side by Side Diff: src/regexp.js

Issue 580123002: Revert "RegExp: Add support for the ES6-proposed sticky flag" (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 3 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/objects.h ('k') | src/runtime.h » ('j') | 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 // 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 // This file relies on the fact that the following declaration has been made 5 // This file relies on the fact that the following declaration has been made
6 // in runtime.js: 6 // in runtime.js:
7 // var $Object = global.Object; 7 // var $Object = global.Object;
8 // var $Array = global.Array; 8 // var $Array = global.Array;
9 9
10 var $RegExp = global.RegExp; 10 var $RegExp = global.RegExp;
11 11
12 // ------------------------------------------------------------------- 12 // -------------------------------------------------------------------
13 13
14 // A recursive descent parser for Patterns according to the grammar of 14 // A recursive descent parser for Patterns according to the grammar of
15 // ECMA-262 15.10.1, with deviations noted below. 15 // ECMA-262 15.10.1, with deviations noted below.
16 function DoConstructRegExp(object, pattern, flags) { 16 function DoConstructRegExp(object, pattern, flags) {
17 // RegExp : Called as constructor; see ECMA-262, section 15.10.4. 17 // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
18 if (IS_REGEXP(pattern)) { 18 if (IS_REGEXP(pattern)) {
19 if (!IS_UNDEFINED(flags)) { 19 if (!IS_UNDEFINED(flags)) {
20 throw MakeTypeError('regexp_flags', []); 20 throw MakeTypeError('regexp_flags', []);
21 } 21 }
22 flags = (pattern.global ? 'g' : '') 22 flags = (pattern.global ? 'g' : '')
23 + (pattern.ignoreCase ? 'i' : '') 23 + (pattern.ignoreCase ? 'i' : '')
24 + (pattern.multiline ? 'm' : ''); 24 + (pattern.multiline ? 'm' : '');
25 if (harmony_regexps)
26 flags += (pattern.sticky ? 'y' : '');
27 pattern = pattern.source; 25 pattern = pattern.source;
28 } 26 }
29 27
30 pattern = IS_UNDEFINED(pattern) ? '' : ToString(pattern); 28 pattern = IS_UNDEFINED(pattern) ? '' : ToString(pattern);
31 flags = IS_UNDEFINED(flags) ? '' : ToString(flags); 29 flags = IS_UNDEFINED(flags) ? '' : ToString(flags);
32 30
33 var global = false; 31 var global = false;
34 var ignoreCase = false; 32 var ignoreCase = false;
35 var multiline = false; 33 var multiline = false;
36 var sticky = false;
37 for (var i = 0; i < flags.length; i++) { 34 for (var i = 0; i < flags.length; i++) {
38 var c = %_CallFunction(flags, i, StringCharAt); 35 var c = %_CallFunction(flags, i, StringCharAt);
39 switch (c) { 36 switch (c) {
40 case 'g': 37 case 'g':
41 if (global) { 38 if (global) {
42 throw MakeSyntaxError("invalid_regexp_flags", [flags]); 39 throw MakeSyntaxError("invalid_regexp_flags", [flags]);
43 } 40 }
44 global = true; 41 global = true;
45 break; 42 break;
46 case 'i': 43 case 'i':
47 if (ignoreCase) { 44 if (ignoreCase) {
48 throw MakeSyntaxError("invalid_regexp_flags", [flags]); 45 throw MakeSyntaxError("invalid_regexp_flags", [flags]);
49 } 46 }
50 ignoreCase = true; 47 ignoreCase = true;
51 break; 48 break;
52 case 'm': 49 case 'm':
53 if (multiline) { 50 if (multiline) {
54 throw MakeSyntaxError("invalid_regexp_flags", [flags]); 51 throw MakeSyntaxError("invalid_regexp_flags", [flags]);
55 } 52 }
56 multiline = true; 53 multiline = true;
57 break; 54 break;
58 case 'y':
59 if (!harmony_regexps || sticky) {
60 throw MakeSyntaxError("invalid_regexp_flags", [flags]);
61 }
62 sticky = true;
63 break;
64 default: 55 default:
65 throw MakeSyntaxError("invalid_regexp_flags", [flags]); 56 throw MakeSyntaxError("invalid_regexp_flags", [flags]);
66 } 57 }
67 } 58 }
68 59
69 %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline, sticky ); 60 %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline);
70 61
71 // Call internal function to compile the pattern. 62 // Call internal function to compile the pattern.
72 %RegExpCompile(object, pattern, flags); 63 %RegExpCompile(object, pattern, flags);
73 } 64 }
74 65
75 66
76 function RegExpConstructor(pattern, flags) { 67 function RegExpConstructor(pattern, flags) {
77 if (%_IsConstructCall()) { 68 if (%_IsConstructCall()) {
78 DoConstructRegExp(this, pattern, flags); 69 DoConstructRegExp(this, pattern, flags);
79 } else { 70 } else {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 ['RegExp.prototype.exec', this]); 152 ['RegExp.prototype.exec', this]);
162 } 153 }
163 154
164 string = TO_STRING_INLINE(string); 155 string = TO_STRING_INLINE(string);
165 var lastIndex = this.lastIndex; 156 var lastIndex = this.lastIndex;
166 157
167 // Conversion is required by the ES5 specification (RegExp.prototype.exec 158 // Conversion is required by the ES5 specification (RegExp.prototype.exec
168 // algorithm, step 5) even if the value is discarded for non-global RegExps. 159 // algorithm, step 5) even if the value is discarded for non-global RegExps.
169 var i = TO_INTEGER(lastIndex); 160 var i = TO_INTEGER(lastIndex);
170 161
171 var updateLastIndex = this.global || (harmony_regexps && this.sticky); 162 var global = this.global;
172 if (updateLastIndex) { 163 if (global) {
173 if (i < 0 || i > string.length) { 164 if (i < 0 || i > string.length) {
174 this.lastIndex = 0; 165 this.lastIndex = 0;
175 return null; 166 return null;
176 } 167 }
177 } else { 168 } else {
178 i = 0; 169 i = 0;
179 } 170 }
180 171
181 // matchIndices is either null or the lastMatchInfo array. 172 // matchIndices is either null or the lastMatchInfo array.
182 var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo); 173 var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
183 174
184 if (IS_NULL(matchIndices)) { 175 if (IS_NULL(matchIndices)) {
185 this.lastIndex = 0; 176 this.lastIndex = 0;
186 return null; 177 return null;
187 } 178 }
188 179
189 // Successful match. 180 // Successful match.
190 lastMatchInfoOverride = null; 181 lastMatchInfoOverride = null;
191 if (updateLastIndex) { 182 if (global) {
192 this.lastIndex = lastMatchInfo[CAPTURE1]; 183 this.lastIndex = lastMatchInfo[CAPTURE1];
193 } 184 }
194 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); 185 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
195 } 186 }
196 187
197 188
198 // One-element cache for the simplified test regexp. 189 // One-element cache for the simplified test regexp.
199 var regexp_key; 190 var regexp_key;
200 var regexp_val; 191 var regexp_val;
201 192
202 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be 193 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
203 // that test is defined in terms of String.prototype.exec. However, it probably 194 // that test is defined in terms of String.prototype.exec. However, it probably
204 // means the original value of String.prototype.exec, which is what everybody 195 // means the original value of String.prototype.exec, which is what everybody
205 // else implements. 196 // else implements.
206 function RegExpTest(string) { 197 function RegExpTest(string) {
207 if (!IS_REGEXP(this)) { 198 if (!IS_REGEXP(this)) {
208 throw MakeTypeError('incompatible_method_receiver', 199 throw MakeTypeError('incompatible_method_receiver',
209 ['RegExp.prototype.test', this]); 200 ['RegExp.prototype.test', this]);
210 } 201 }
211 string = TO_STRING_INLINE(string); 202 string = TO_STRING_INLINE(string);
212 203
213 var lastIndex = this.lastIndex; 204 var lastIndex = this.lastIndex;
214 205
215 // Conversion is required by the ES5 specification (RegExp.prototype.exec 206 // Conversion is required by the ES5 specification (RegExp.prototype.exec
216 // algorithm, step 5) even if the value is discarded for non-global RegExps. 207 // algorithm, step 5) even if the value is discarded for non-global RegExps.
217 var i = TO_INTEGER(lastIndex); 208 var i = TO_INTEGER(lastIndex);
218 209
219 if (this.global || (harmony_regexps && this.sticky)) { 210 if (this.global) {
220 if (i < 0 || i > string.length) { 211 if (i < 0 || i > string.length) {
221 this.lastIndex = 0; 212 this.lastIndex = 0;
222 return false; 213 return false;
223 } 214 }
224 // matchIndices is either null or the lastMatchInfo array. 215 // matchIndices is either null or the lastMatchInfo array.
225 var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo); 216 var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
226 if (IS_NULL(matchIndices)) { 217 if (IS_NULL(matchIndices)) {
227 this.lastIndex = 0; 218 this.lastIndex = 0;
228 return false; 219 return false;
229 } 220 }
230 lastMatchInfoOverride = null; 221 lastMatchInfoOverride = null;
231 this.lastIndex = lastMatchInfo[CAPTURE1]; 222 this.lastIndex = lastMatchInfo[CAPTURE1];
232 return true; 223 return true;
233 } else { 224 } else {
234 // Non-global, non-sticky regexp. 225 // Non-global regexp.
235 // Remove irrelevant preceeding '.*' in a test regexp. The expression 226 // Remove irrelevant preceeding '.*' in a non-global test regexp.
236 // checks whether this.source starts with '.*' and that the third char is 227 // The expression checks whether this.source starts with '.*' and
237 // not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560 228 // that the third char is not a '?'.
238 var regexp = this; 229 var regexp = this;
239 if (regexp.source.length >= 3 && 230 if (%_StringCharCodeAt(regexp.source, 0) == 46 && // '.'
240 %_StringCharCodeAt(regexp.source, 0) == 46 && // '.'
241 %_StringCharCodeAt(regexp.source, 1) == 42 && // '*' 231 %_StringCharCodeAt(regexp.source, 1) == 42 && // '*'
242 %_StringCharCodeAt(regexp.source, 2) != 63) { // '?' 232 %_StringCharCodeAt(regexp.source, 2) != 63) { // '?'
243 regexp = TrimRegExp(regexp); 233 regexp = TrimRegExp(regexp);
244 } 234 }
245 // matchIndices is either null or the lastMatchInfo array. 235 // matchIndices is either null or the lastMatchInfo array.
246 var matchIndices = %_RegExpExec(regexp, string, 0, lastMatchInfo); 236 var matchIndices = %_RegExpExec(regexp, string, 0, lastMatchInfo);
247 if (IS_NULL(matchIndices)) { 237 if (IS_NULL(matchIndices)) {
248 this.lastIndex = 0; 238 this.lastIndex = 0;
249 return false; 239 return false;
250 } 240 }
(...skipping 16 matching lines...) Expand all
267 257
268 function RegExpToString() { 258 function RegExpToString() {
269 if (!IS_REGEXP(this)) { 259 if (!IS_REGEXP(this)) {
270 throw MakeTypeError('incompatible_method_receiver', 260 throw MakeTypeError('incompatible_method_receiver',
271 ['RegExp.prototype.toString', this]); 261 ['RegExp.prototype.toString', this]);
272 } 262 }
273 var result = '/' + this.source + '/'; 263 var result = '/' + this.source + '/';
274 if (this.global) result += 'g'; 264 if (this.global) result += 'g';
275 if (this.ignoreCase) result += 'i'; 265 if (this.ignoreCase) result += 'i';
276 if (this.multiline) result += 'm'; 266 if (this.multiline) result += 'm';
277 if (harmony_regexps && this.sticky) result += 'y';
278 return result; 267 return result;
279 } 268 }
280 269
281 270
282 // Getters for the static properties lastMatch, lastParen, leftContext, and 271 // Getters for the static properties lastMatch, lastParen, leftContext, and
283 // rightContext of the RegExp constructor. The properties are computed based 272 // rightContext of the RegExp constructor. The properties are computed based
284 // on the captures array of the last successful match and the subject string 273 // on the captures array of the last successful match and the subject string
285 // of the last successful match. 274 // of the last successful match.
286 function RegExpGetLastMatch() { 275 function RegExpGetLastMatch() {
287 if (lastMatchInfoOverride !== null) { 276 if (lastMatchInfoOverride !== null) {
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 455
467 for (var i = 1; i < 10; ++i) { 456 for (var i = 1; i < 10; ++i) {
468 %DefineAccessorPropertyUnchecked($RegExp, '$' + i, 457 %DefineAccessorPropertyUnchecked($RegExp, '$' + i,
469 RegExpMakeCaptureGetter(i), NoOpSetter, 458 RegExpMakeCaptureGetter(i), NoOpSetter,
470 DONT_DELETE); 459 DONT_DELETE);
471 } 460 }
472 %ToFastProperties($RegExp); 461 %ToFastProperties($RegExp);
473 } 462 }
474 463
475 SetUpRegExp(); 464 SetUpRegExp();
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698