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

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

Issue 1419823010: Implement flag and source getters on RegExp.prototype. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@rproto
Patch Set: new webkit expectations Created 5 years, 1 month 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 %CheckIsBootstrapping(); 7 %CheckIsBootstrapping();
8 8
9 // ------------------------------------------------------------------- 9 // -------------------------------------------------------------------
10 // Imports 10 // Imports
11 11
12 var FLAG_harmony_regexps;
13 var FLAG_harmony_tolength; 12 var FLAG_harmony_tolength;
14 var FLAG_harmony_unicode_regexps;
15 var GlobalObject = global.Object; 13 var GlobalObject = global.Object;
16 var GlobalRegExp = global.RegExp; 14 var GlobalRegExp = global.RegExp;
17 var InternalPackedArray = utils.InternalPackedArray; 15 var InternalPackedArray = utils.InternalPackedArray;
18 var MakeTypeError; 16 var MakeTypeError;
17 var regExpFlagsSymbol = utils.ImportNow("regexp_flags_symbol");
18 var regExpSourceSymbol = utils.ImportNow("regexp_source_symbol");
19 19
20 utils.ImportFromExperimental(function(from) { 20 utils.ImportFromExperimental(function(from) {
21 FLAG_harmony_regexps = from.FLAG_harmony_regexps;
22 FLAG_harmony_tolength = from.FLAG_harmony_tolength; 21 FLAG_harmony_tolength = from.FLAG_harmony_tolength;
23 FLAG_harmony_unicode_regexps = from.FLAG_harmony_unicode_regexps;
24 }); 22 });
25 23
26 utils.Import(function(from) { 24 utils.Import(function(from) {
27 MakeTypeError = from.MakeTypeError; 25 MakeTypeError = from.MakeTypeError;
28 }); 26 });
29 27
30 // ------------------------------------------------------------------- 28 // -------------------------------------------------------------------
31 29
32 // Property of the builtins object for recording the result of the last 30 // Property of the builtins object for recording the result of the last
33 // regexp match. The property RegExpLastMatchInfo includes the matchIndices 31 // regexp match. The property RegExpLastMatchInfo includes the matchIndices
(...skipping 10 matching lines...) Expand all
44 ); 42 );
45 43
46 // ------------------------------------------------------------------- 44 // -------------------------------------------------------------------
47 45
48 // A recursive descent parser for Patterns according to the grammar of 46 // A recursive descent parser for Patterns according to the grammar of
49 // ECMA-262 15.10.1, with deviations noted below. 47 // ECMA-262 15.10.1, with deviations noted below.
50 function DoConstructRegExp(object, pattern, flags) { 48 function DoConstructRegExp(object, pattern, flags) {
51 // RegExp : Called as constructor; see ECMA-262, section 15.10.4. 49 // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
52 if (IS_REGEXP(pattern)) { 50 if (IS_REGEXP(pattern)) {
53 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags); 51 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags);
54 flags = (pattern.global ? 'g' : '') 52 flags = (REGEXP_GLOBAL(pattern) ? 'g' : '')
55 + (pattern.ignoreCase ? 'i' : '') 53 + (REGEXP_IGNORE_CASE(pattern) ? 'i' : '')
56 + (pattern.multiline ? 'm' : ''); 54 + (REGEXP_MULTILINE(pattern) ? 'm' : '')
57 if (FLAG_harmony_unicode_regexps) 55 + (REGEXP_UNICODE(pattern) ? 'u' : '')
58 flags += (pattern.unicode ? 'u' : ''); 56 + (REGEXP_STICKY(pattern) ? 'y' : '');
59 if (FLAG_harmony_regexps) 57 pattern = REGEXP_SOURCE(pattern);
60 flags += (pattern.sticky ? 'y' : '');
61 pattern = pattern.source;
62 } 58 }
63 59
64 pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern); 60 pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern);
65 flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags); 61 flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags);
66 62
67 %RegExpInitializeAndCompile(object, pattern, flags); 63 %RegExpInitializeAndCompile(object, pattern, flags);
68 } 64 }
69 65
70 66
71 function RegExpConstructor(pattern, flags) { 67 function RegExpConstructor(pattern, flags) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 } 131 }
136 return result; 132 return result;
137 endmacro 133 endmacro
138 134
139 135
140 function RegExpExecNoTests(regexp, string, start) { 136 function RegExpExecNoTests(regexp, string, start) {
141 // Must be called with RegExp, string and positive integer as arguments. 137 // Must be called with RegExp, string and positive integer as arguments.
142 var matchInfo = %_RegExpExec(regexp, string, start, RegExpLastMatchInfo); 138 var matchInfo = %_RegExpExec(regexp, string, start, RegExpLastMatchInfo);
143 if (matchInfo !== null) { 139 if (matchInfo !== null) {
144 // ES6 21.2.5.2.2 step 18. 140 // ES6 21.2.5.2.2 step 18.
145 if (FLAG_harmony_regexps && regexp.sticky) { 141 if (REGEXP_STICKY(regexp)) regexp.lastIndex = matchInfo[CAPTURE1];
146 regexp.lastIndex = matchInfo[CAPTURE1];
147 }
148 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string); 142 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string);
149 } 143 }
150 regexp.lastIndex = 0; 144 regexp.lastIndex = 0;
151 return null; 145 return null;
152 } 146 }
153 147
154 148
155 function RegExpExecJS(string) { 149 function RegExpExecJS(string) {
156 if (!IS_REGEXP(this)) { 150 if (!IS_REGEXP(this)) {
157 throw MakeTypeError(kIncompatibleMethodReceiver, 151 throw MakeTypeError(kIncompatibleMethodReceiver,
158 'RegExp.prototype.exec', this); 152 'RegExp.prototype.exec', this);
159 } 153 }
160 154
161 string = TO_STRING(string); 155 string = TO_STRING(string);
162 var lastIndex = this.lastIndex; 156 var lastIndex = this.lastIndex;
163 157
164 // Conversion is required by the ES2015 specification (RegExpBuiltinExec 158 // Conversion is required by the ES2015 specification (RegExpBuiltinExec
165 // algorithm, step 4) even if the value is discarded for non-global RegExps. 159 // algorithm, step 4) even if the value is discarded for non-global RegExps.
166 var i = TO_LENGTH_OR_INTEGER(lastIndex); 160 var i = TO_LENGTH_OR_INTEGER(lastIndex);
167 161
168 var updateLastIndex = this.global || (FLAG_harmony_regexps && this.sticky); 162 var updateLastIndex = REGEXP_GLOBAL(this) || REGEXP_STICKY(this);
169 if (updateLastIndex) { 163 if (updateLastIndex) {
170 if (i < 0 || i > string.length) { 164 if (i < 0 || i > string.length) {
171 this.lastIndex = 0; 165 this.lastIndex = 0;
172 return null; 166 return null;
173 } 167 }
174 } else { 168 } else {
175 i = 0; 169 i = 0;
176 } 170 }
177 171
178 // matchIndices is either null or the RegExpLastMatchInfo array. 172 // matchIndices is either null or the RegExpLastMatchInfo array.
(...skipping 26 matching lines...) Expand all
205 'RegExp.prototype.test', this); 199 'RegExp.prototype.test', this);
206 } 200 }
207 string = TO_STRING(string); 201 string = TO_STRING(string);
208 202
209 var lastIndex = this.lastIndex; 203 var lastIndex = this.lastIndex;
210 204
211 // Conversion is required by the ES2015 specification (RegExpBuiltinExec 205 // Conversion is required by the ES2015 specification (RegExpBuiltinExec
212 // algorithm, step 4) even if the value is discarded for non-global RegExps. 206 // algorithm, step 4) even if the value is discarded for non-global RegExps.
213 var i = TO_LENGTH_OR_INTEGER(lastIndex); 207 var i = TO_LENGTH_OR_INTEGER(lastIndex);
214 208
215 if (this.global || (FLAG_harmony_regexps && this.sticky)) { 209 if (REGEXP_GLOBAL(this) || REGEXP_STICKY(this)) {
216 if (i < 0 || i > string.length) { 210 if (i < 0 || i > string.length) {
217 this.lastIndex = 0; 211 this.lastIndex = 0;
218 return false; 212 return false;
219 } 213 }
220 // matchIndices is either null or the RegExpLastMatchInfo array. 214 // matchIndices is either null or the RegExpLastMatchInfo array.
221 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); 215 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo);
222 if (IS_NULL(matchIndices)) { 216 if (IS_NULL(matchIndices)) {
223 this.lastIndex = 0; 217 this.lastIndex = 0;
224 return false; 218 return false;
225 } 219 }
226 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; 220 this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
227 return true; 221 return true;
228 } else { 222 } else {
229 // Non-global, non-sticky regexp. 223 // Non-global, non-sticky regexp.
230 // Remove irrelevant preceeding '.*' in a test regexp. The expression 224 // Remove irrelevant preceeding '.*' in a test regexp. The expression
231 // checks whether this.source starts with '.*' and that the third char is 225 // checks whether this.source starts with '.*' and that the third char is
232 // not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560 226 // not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560
233 var regexp = this; 227 var regexp = this;
234 if (regexp.source.length >= 3 && 228 var source = REGEXP_SOURCE(regexp);
235 %_StringCharCodeAt(regexp.source, 0) == 46 && // '.' 229 if (regexp.length >= 3 &&
236 %_StringCharCodeAt(regexp.source, 1) == 42 && // '*' 230 %_StringCharCodeAt(regexp, 0) == 46 && // '.'
237 %_StringCharCodeAt(regexp.source, 2) != 63) { // '?' 231 %_StringCharCodeAt(regexp, 1) == 42 && // '*'
232 %_StringCharCodeAt(regexp, 2) != 63) { // '?'
238 regexp = TrimRegExp(regexp); 233 regexp = TrimRegExp(regexp);
239 } 234 }
240 // matchIndices is either null or the RegExpLastMatchInfo array. 235 // matchIndices is either null or the RegExpLastMatchInfo array.
241 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo); 236 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo);
242 if (IS_NULL(matchIndices)) { 237 if (IS_NULL(matchIndices)) {
243 this.lastIndex = 0; 238 this.lastIndex = 0;
244 return false; 239 return false;
245 } 240 }
246 return true; 241 return true;
247 } 242 }
248 } 243 }
249 244
250 function TrimRegExp(regexp) { 245 function TrimRegExp(regexp) {
251 if (!%_ObjectEquals(regexp_key, regexp)) { 246 if (!%_ObjectEquals(regexp_key, regexp)) {
252 regexp_key = regexp; 247 regexp_key = regexp;
253 regexp_val = 248 regexp_val =
254 new GlobalRegExp(%_SubString(regexp.source, 2, regexp.source.length), 249 new GlobalRegExp(
255 (regexp.ignoreCase ? regexp.multiline ? "im" : "i" 250 %_SubString(REGEXP_SOURCE(regexp), 2, REGEXP_SOURCE(regexp).length),
256 : regexp.multiline ? "m" : "")); 251 (REGEXP_IGNORE_CASE(regexp) ? REGEXP_MULTILINE(regexp) ? "im" : "i"
252 : REGEXP_MULTILINE(regexp) ? "m" : ""));
257 } 253 }
258 return regexp_val; 254 return regexp_val;
259 } 255 }
260 256
261 257
262 function RegExpToString() { 258 function RegExpToString() {
263 if (!IS_REGEXP(this)) { 259 if (!IS_REGEXP(this)) {
264 throw MakeTypeError(kIncompatibleMethodReceiver, 260 throw MakeTypeError(kIncompatibleMethodReceiver,
265 'RegExp.prototype.toString', this); 261 'RegExp.prototype.toString', this);
266 } 262 }
267 var result = '/' + this.source + '/'; 263 var result = '/' + REGEXP_SOURCE(this) + '/';
268 if (this.global) result += 'g'; 264 if (REGEXP_GLOBAL(this)) result += 'g';
269 if (this.ignoreCase) result += 'i'; 265 if (REGEXP_IGNORE_CASE(this)) result += 'i';
270 if (this.multiline) result += 'm'; 266 if (REGEXP_MULTILINE(this)) result += 'm';
271 if (FLAG_harmony_unicode_regexps && this.unicode) result += 'u'; 267 if (REGEXP_UNICODE(this)) result += 'u';
272 if (FLAG_harmony_regexps && this.sticky) result += 'y'; 268 if (REGEXP_STICKY(this)) result += 'y';
273 return result; 269 return result;
274 } 270 }
275 271
276 272
277 // Getters for the static properties lastMatch, lastParen, leftContext, and 273 // Getters for the static properties lastMatch, lastParen, leftContext, and
278 // rightContext of the RegExp constructor. The properties are computed based 274 // rightContext of the RegExp constructor. The properties are computed based
279 // on the captures array of the last successful match and the subject string 275 // on the captures array of the last successful match and the subject string
280 // of the last successful match. 276 // of the last successful match.
281 function RegExpGetLastMatch() { 277 function RegExpGetLastMatch() {
282 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); 278 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 return function foo() { 323 return function foo() {
328 var index = n * 2; 324 var index = n * 2;
329 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return ''; 325 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return '';
330 var matchStart = RegExpLastMatchInfo[CAPTURE(index)]; 326 var matchStart = RegExpLastMatchInfo[CAPTURE(index)];
331 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)]; 327 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)];
332 if (matchStart == -1 || matchEnd == -1) return ''; 328 if (matchStart == -1 || matchEnd == -1) return '';
333 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd); 329 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd);
334 }; 330 };
335 } 331 }
336 332
333
334 // ES6 21.2.5.4.
335 function RegExpGetGlobal() {
336 if (!IS_REGEXP(this)) {
337 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global");
338 }
339 return !!REGEXP_GLOBAL(this);
340 }
341 %FunctionSetName(RegExpGetGlobal, "RegExp.prototype.global");
342 %SetNativeFlag(RegExpGetGlobal);
343
344
345 // ES6 21.2.5.5.
346 function RegExpGetIgnoreCase() {
347 if (!IS_REGEXP(this)) {
348 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase");
349 }
350 return !!REGEXP_IGNORE_CASE(this);
351 }
352 %FunctionSetName(RegExpGetIgnoreCase, "RegExp.prototype.ignoreCase");
353 %SetNativeFlag(RegExpGetIgnoreCase);
354
355
356 // ES6 21.2.5.7.
357 function RegExpGetMultiline() {
358 if (!IS_REGEXP(this)) {
359 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline");
360 }
361 return !!REGEXP_MULTILINE(this);
362 }
363 %FunctionSetName(RegExpGetMultiline, "RegExp.prototype.multiline");
364 %SetNativeFlag(RegExpGetMultiline);
365
366
367 // ES6 21.2.5.10.
368 function RegExpGetSource() {
369 if (!IS_REGEXP(this)) {
370 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source");
371 }
372 return REGEXP_SOURCE(this);
373 }
374 %FunctionSetName(RegExpGetSource, "RegExp.prototype.source");
375 %SetNativeFlag(RegExpGetSource);
376
337 // ------------------------------------------------------------------- 377 // -------------------------------------------------------------------
338 378
339 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp'); 379 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
340 %FunctionSetPrototype(GlobalRegExp, new GlobalObject()); 380 %FunctionSetPrototype(GlobalRegExp, new GlobalObject());
341 %AddNamedProperty( 381 %AddNamedProperty(
342 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM); 382 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
343 %SetCode(GlobalRegExp, RegExpConstructor); 383 %SetCode(GlobalRegExp, RegExpConstructor);
344 384
345 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ 385 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
346 "exec", RegExpExecJS, 386 "exec", RegExpExecJS,
347 "test", RegExpTest, 387 "test", RegExpTest,
348 "toString", RegExpToString, 388 "toString", RegExpToString,
349 "compile", RegExpCompileJS 389 "compile", RegExpCompileJS
350 ]); 390 ]);
351 391
392 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "global",
393 RegExpGetGlobal, DONT_ENUM);
394 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "ignoreCase",
395 RegExpGetIgnoreCase, DONT_ENUM);
396 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "multiline",
397 RegExpGetMultiline, DONT_ENUM);
398 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "source",
399 RegExpGetSource, DONT_ENUM);
400
352 // The length of compile is 1 in SpiderMonkey. 401 // The length of compile is 1 in SpiderMonkey.
353 %FunctionSetLength(GlobalRegExp.prototype.compile, 1); 402 %FunctionSetLength(GlobalRegExp.prototype.compile, 1);
354 403
355 // The properties `input` and `$_` are aliases for each other. When this 404 // The properties `input` and `$_` are aliases for each other. When this
356 // value is set the value it is set to is coerced to a string. 405 // value is set the value it is set to is coerced to a string.
357 // Getter and setter for the input. 406 // Getter and setter for the input.
358 var RegExpGetInput = function() { 407 var RegExpGetInput = function() {
359 var regExpInput = LAST_INPUT(RegExpLastMatchInfo); 408 var regExpInput = LAST_INPUT(RegExpLastMatchInfo);
360 return IS_UNDEFINED(regExpInput) ? "" : regExpInput; 409 return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
361 }; 410 };
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 // Exports 471 // Exports
423 472
424 utils.Export(function(to) { 473 utils.Export(function(to) {
425 to.RegExpExec = DoRegExpExec; 474 to.RegExpExec = DoRegExpExec;
426 to.RegExpExecNoTests = RegExpExecNoTests; 475 to.RegExpExecNoTests = RegExpExecNoTests;
427 to.RegExpLastMatchInfo = RegExpLastMatchInfo; 476 to.RegExpLastMatchInfo = RegExpLastMatchInfo;
428 to.RegExpTest = RegExpTest; 477 to.RegExpTest = RegExpTest;
429 }); 478 });
430 479
431 }) 480 })
OLDNEW
« src/bootstrapper.cc ('K') | « src/js/prologue.js ('k') | src/js/string.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698