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

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: fix windows build 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; 12 var FLAG_harmony_regexps;
13 var FLAG_harmony_tolength; 13 var FLAG_harmony_tolength;
14 var FLAG_harmony_unicode_regexps; 14 var FLAG_harmony_unicode_regexps;
15 var GlobalObject = global.Object; 15 var GlobalObject = global.Object;
16 var GlobalRegExp = global.RegExp; 16 var GlobalRegExp = global.RegExp;
17 var InternalPackedArray = utils.InternalPackedArray; 17 var InternalPackedArray = utils.InternalPackedArray;
18 var MakeTypeError; 18 var MakeTypeError;
19 var regExpFlagsSymbol = utils.ImportNow("regexp_flags_symbol");
20 var regExpSourceSymbol = utils.ImportNow("regexp_source_symbol");
19 21
20 utils.ImportFromExperimental(function(from) { 22 utils.ImportFromExperimental(function(from) {
21 FLAG_harmony_regexps = from.FLAG_harmony_regexps; 23 FLAG_harmony_regexps = from.FLAG_harmony_regexps;
22 FLAG_harmony_tolength = from.FLAG_harmony_tolength; 24 FLAG_harmony_tolength = from.FLAG_harmony_tolength;
23 FLAG_harmony_unicode_regexps = from.FLAG_harmony_unicode_regexps; 25 FLAG_harmony_unicode_regexps = from.FLAG_harmony_unicode_regexps;
24 }); 26 });
25 27
26 utils.Import(function(from) { 28 utils.Import(function(from) {
27 MakeTypeError = from.MakeTypeError; 29 MakeTypeError = from.MakeTypeError;
28 }); 30 });
(...skipping 15 matching lines...) Expand all
44 ); 46 );
45 47
46 // ------------------------------------------------------------------- 48 // -------------------------------------------------------------------
47 49
48 // A recursive descent parser for Patterns according to the grammar of 50 // A recursive descent parser for Patterns according to the grammar of
49 // ECMA-262 15.10.1, with deviations noted below. 51 // ECMA-262 15.10.1, with deviations noted below.
50 function DoConstructRegExp(object, pattern, flags) { 52 function DoConstructRegExp(object, pattern, flags) {
51 // RegExp : Called as constructor; see ECMA-262, section 15.10.4. 53 // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
52 if (IS_REGEXP(pattern)) { 54 if (IS_REGEXP(pattern)) {
53 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags); 55 if (!IS_UNDEFINED(flags)) throw MakeTypeError(kRegExpFlags);
54 flags = (pattern.global ? 'g' : '') 56 flags = (REGEXP_GLOBAL(pattern) ? 'g' : '')
55 + (pattern.ignoreCase ? 'i' : '') 57 + (REGEXP_IGNORE_CASE(pattern) ? 'i' : '')
56 + (pattern.multiline ? 'm' : ''); 58 + (REGEXP_MULTILINE(pattern) ? 'm' : '');
57 if (FLAG_harmony_unicode_regexps) 59 if (FLAG_harmony_unicode_regexps)
58 flags += (pattern.unicode ? 'u' : ''); 60 flags += (REGEXP_UNICODE(pattern) ? 'u' : '');
59 if (FLAG_harmony_regexps) 61 if (FLAG_harmony_regexps)
60 flags += (pattern.sticky ? 'y' : ''); 62 flags += (REGEXP_STICKY(pattern) ? 'y' : '');
61 pattern = pattern.source; 63 pattern = REGEXP_SOURCE(pattern);
62 } 64 }
63 65
64 pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern); 66 pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern);
65 flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags); 67 flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags);
66 68
67 %RegExpInitializeAndCompile(object, pattern, flags); 69 %RegExpInitializeAndCompile(object, pattern, flags);
68 } 70 }
69 71
70 72
71 function RegExpConstructor(pattern, flags) { 73 function RegExpConstructor(pattern, flags) {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 'RegExp.prototype.exec', this); 160 'RegExp.prototype.exec', this);
159 } 161 }
160 162
161 string = TO_STRING(string); 163 string = TO_STRING(string);
162 var lastIndex = this.lastIndex; 164 var lastIndex = this.lastIndex;
163 165
164 // Conversion is required by the ES2015 specification (RegExpBuiltinExec 166 // Conversion is required by the ES2015 specification (RegExpBuiltinExec
165 // algorithm, step 4) even if the value is discarded for non-global RegExps. 167 // algorithm, step 4) even if the value is discarded for non-global RegExps.
166 var i = TO_LENGTH_OR_INTEGER(lastIndex); 168 var i = TO_LENGTH_OR_INTEGER(lastIndex);
167 169
168 var updateLastIndex = this.global || (FLAG_harmony_regexps && this.sticky); 170 var updateLastIndex = REGEXP_GLOBAL(this) ||
171 (FLAG_harmony_regexps && REGEXP_STICKY(this));
169 if (updateLastIndex) { 172 if (updateLastIndex) {
170 if (i < 0 || i > string.length) { 173 if (i < 0 || i > string.length) {
171 this.lastIndex = 0; 174 this.lastIndex = 0;
172 return null; 175 return null;
173 } 176 }
174 } else { 177 } else {
175 i = 0; 178 i = 0;
176 } 179 }
177 180
178 // matchIndices is either null or the RegExpLastMatchInfo array. 181 // matchIndices is either null or the RegExpLastMatchInfo array.
(...skipping 26 matching lines...) Expand all
205 'RegExp.prototype.test', this); 208 'RegExp.prototype.test', this);
206 } 209 }
207 string = TO_STRING(string); 210 string = TO_STRING(string);
208 211
209 var lastIndex = this.lastIndex; 212 var lastIndex = this.lastIndex;
210 213
211 // Conversion is required by the ES2015 specification (RegExpBuiltinExec 214 // Conversion is required by the ES2015 specification (RegExpBuiltinExec
212 // algorithm, step 4) even if the value is discarded for non-global RegExps. 215 // algorithm, step 4) even if the value is discarded for non-global RegExps.
213 var i = TO_LENGTH_OR_INTEGER(lastIndex); 216 var i = TO_LENGTH_OR_INTEGER(lastIndex);
214 217
215 if (this.global || (FLAG_harmony_regexps && this.sticky)) { 218 if (REGEXP_GLOBAL(this) || (FLAG_harmony_regexps && REGEXP_STICKY(this))) {
216 if (i < 0 || i > string.length) { 219 if (i < 0 || i > string.length) {
217 this.lastIndex = 0; 220 this.lastIndex = 0;
218 return false; 221 return false;
219 } 222 }
220 // matchIndices is either null or the RegExpLastMatchInfo array. 223 // matchIndices is either null or the RegExpLastMatchInfo array.
221 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); 224 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo);
222 if (IS_NULL(matchIndices)) { 225 if (IS_NULL(matchIndices)) {
223 this.lastIndex = 0; 226 this.lastIndex = 0;
224 return false; 227 return false;
225 } 228 }
226 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; 229 this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
227 return true; 230 return true;
228 } else { 231 } else {
229 // Non-global, non-sticky regexp. 232 // Non-global, non-sticky regexp.
230 // Remove irrelevant preceeding '.*' in a test regexp. The expression 233 // Remove irrelevant preceeding '.*' in a test regexp. The expression
231 // checks whether this.source starts with '.*' and that the third char is 234 // 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 235 // not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560
233 var regexp = this; 236 var regexp = this;
234 if (regexp.source.length >= 3 && 237 var source = REGEXP_SOURCE(regexp);
235 %_StringCharCodeAt(regexp.source, 0) == 46 && // '.' 238 if (regexp.length >= 3 &&
236 %_StringCharCodeAt(regexp.source, 1) == 42 && // '*' 239 %_StringCharCodeAt(regexp, 0) == 46 && // '.'
237 %_StringCharCodeAt(regexp.source, 2) != 63) { // '?' 240 %_StringCharCodeAt(regexp, 1) == 42 && // '*'
241 %_StringCharCodeAt(regexp, 2) != 63) { // '?'
238 regexp = TrimRegExp(regexp); 242 regexp = TrimRegExp(regexp);
239 } 243 }
240 // matchIndices is either null or the RegExpLastMatchInfo array. 244 // matchIndices is either null or the RegExpLastMatchInfo array.
241 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo); 245 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo);
242 if (IS_NULL(matchIndices)) { 246 if (IS_NULL(matchIndices)) {
243 this.lastIndex = 0; 247 this.lastIndex = 0;
244 return false; 248 return false;
245 } 249 }
246 return true; 250 return true;
247 } 251 }
248 } 252 }
249 253
250 function TrimRegExp(regexp) { 254 function TrimRegExp(regexp) {
251 if (!%_ObjectEquals(regexp_key, regexp)) { 255 if (!%_ObjectEquals(regexp_key, regexp)) {
252 regexp_key = regexp; 256 regexp_key = regexp;
253 regexp_val = 257 regexp_val =
254 new GlobalRegExp(%_SubString(regexp.source, 2, regexp.source.length), 258 new GlobalRegExp(
255 (regexp.ignoreCase ? regexp.multiline ? "im" : "i" 259 %_SubString(REGEXP_SOURCE(regexp), 2, REGEXP_SOURCE(regexp).length),
256 : regexp.multiline ? "m" : "")); 260 (REGEXP_IGNORE_CASE(regexp) ? REGEXP_MULTILINE(regexp) ? "im" : "i"
261 : REGEXP_MULTILINE(regexp) ? "m" : ""));
257 } 262 }
258 return regexp_val; 263 return regexp_val;
259 } 264 }
260 265
261 266
262 function RegExpToString() { 267 function RegExpToString() {
263 if (!IS_REGEXP(this)) { 268 if (!IS_REGEXP(this)) {
264 throw MakeTypeError(kIncompatibleMethodReceiver, 269 throw MakeTypeError(kIncompatibleMethodReceiver,
265 'RegExp.prototype.toString', this); 270 'RegExp.prototype.toString', this);
266 } 271 }
267 var result = '/' + this.source + '/'; 272 var result = '/' + REGEXP_SOURCE(this) + '/';
268 if (this.global) result += 'g'; 273 if (REGEXP_GLOBAL(this)) result += 'g';
269 if (this.ignoreCase) result += 'i'; 274 if (REGEXP_IGNORE_CASE(this)) result += 'i';
270 if (this.multiline) result += 'm'; 275 if (REGEXP_MULTILINE(this)) result += 'm';
271 if (FLAG_harmony_unicode_regexps && this.unicode) result += 'u'; 276 if (FLAG_harmony_unicode_regexps && REGEXP_UNICODE(this)) result += 'u';
272 if (FLAG_harmony_regexps && this.sticky) result += 'y'; 277 if (FLAG_harmony_regexps && REGEXP_STICKY(this)) result += 'y';
273 return result; 278 return result;
274 } 279 }
275 280
276 281
277 // Getters for the static properties lastMatch, lastParen, leftContext, and 282 // Getters for the static properties lastMatch, lastParen, leftContext, and
278 // rightContext of the RegExp constructor. The properties are computed based 283 // rightContext of the RegExp constructor. The properties are computed based
279 // on the captures array of the last successful match and the subject string 284 // on the captures array of the last successful match and the subject string
280 // of the last successful match. 285 // of the last successful match.
281 function RegExpGetLastMatch() { 286 function RegExpGetLastMatch() {
282 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); 287 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 return function foo() { 332 return function foo() {
328 var index = n * 2; 333 var index = n * 2;
329 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return ''; 334 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return '';
330 var matchStart = RegExpLastMatchInfo[CAPTURE(index)]; 335 var matchStart = RegExpLastMatchInfo[CAPTURE(index)];
331 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)]; 336 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)];
332 if (matchStart == -1 || matchEnd == -1) return ''; 337 if (matchStart == -1 || matchEnd == -1) return '';
333 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd); 338 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd);
334 }; 339 };
335 } 340 }
336 341
342
343 // ES6 21.2.5.4, 21.2.5.5, 21.2.5.7, 21.2.5.12, 21.2.5.15.
344 function GetRegExpFlagGetter(name, mask) {
345 var getter = function() {
346 if (!IS_SPEC_OBJECT(this)) {
347 throw MakeTypeError(kRegExpNonObject, name, TO_STRING(this));
348 }
349 var flags = this[regExpFlagsSymbol];
350 if (IS_UNDEFINED(flags)) {
351 throw MakeTypeError(kRegExpNonRegExp, TO_STRING(this));
352 }
353 return !!(flags & mask);
354 };
355 %FunctionSetName(getter, name);
356 %SetNativeFlag(getter);
357 return getter;
358 }
359
360
361 // ES6 21.2.5.10.
362 function RegExpGetSource() {
363 if (!IS_SPEC_OBJECT(this)) {
364 throw MakeTypeError(kRegExpNonObject, "RegExp.prototype.source",
365 TO_STRING(this));
366 }
367 var source = this[regExpSourceSymbol];
368 if (IS_UNDEFINED(source)) {
369 throw MakeTypeError(kRegExpNonRegExp, TO_STRING(this));
370 }
371 return source;
372 }
373
374 %SetNativeFlag(RegExpGetSource);
375
337 // ------------------------------------------------------------------- 376 // -------------------------------------------------------------------
338 377
339 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp'); 378 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
340 %FunctionSetPrototype(GlobalRegExp, new GlobalObject()); 379 %FunctionSetPrototype(GlobalRegExp, new GlobalObject());
341 %AddNamedProperty( 380 %AddNamedProperty(
342 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM); 381 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
343 %SetCode(GlobalRegExp, RegExpConstructor); 382 %SetCode(GlobalRegExp, RegExpConstructor);
344 383
345 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ 384 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
346 "exec", RegExpExecJS, 385 "exec", RegExpExecJS,
347 "test", RegExpTest, 386 "test", RegExpTest,
348 "toString", RegExpToString, 387 "toString", RegExpToString,
349 "compile", RegExpCompileJS 388 "compile", RegExpCompileJS
350 ]); 389 ]);
351 390
391 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "global",
392 GetRegExpFlagGetter("RegExp.prototype.global", 1), DONT_ENUM);
393 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "ignoreCase",
394 GetRegExpFlagGetter("RegExp.prototype.ignoreCase", 2), DONT_ENUM);
395 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "multiline",
396 GetRegExpFlagGetter("RegExp.prototype.multiline", 4), DONT_ENUM);
397 %DefineGetterPropertyUnchecked(GlobalRegExp.prototype, "source",
398 RegExpGetSource, DONT_ENUM);
399
352 // The length of compile is 1 in SpiderMonkey. 400 // The length of compile is 1 in SpiderMonkey.
353 %FunctionSetLength(GlobalRegExp.prototype.compile, 1); 401 %FunctionSetLength(GlobalRegExp.prototype.compile, 1);
354 402
355 // The properties `input` and `$_` are aliases for each other. When this 403 // 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. 404 // value is set the value it is set to is coerced to a string.
357 // Getter and setter for the input. 405 // Getter and setter for the input.
358 var RegExpGetInput = function() { 406 var RegExpGetInput = function() {
359 var regExpInput = LAST_INPUT(RegExpLastMatchInfo); 407 var regExpInput = LAST_INPUT(RegExpLastMatchInfo);
360 return IS_UNDEFINED(regExpInput) ? "" : regExpInput; 408 return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
361 }; 409 };
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 %DefineAccessorPropertyUnchecked(GlobalRegExp, '$' + i, 463 %DefineAccessorPropertyUnchecked(GlobalRegExp, '$' + i,
416 RegExpMakeCaptureGetter(i), NoOpSetter, 464 RegExpMakeCaptureGetter(i), NoOpSetter,
417 DONT_DELETE); 465 DONT_DELETE);
418 } 466 }
419 %ToFastProperties(GlobalRegExp); 467 %ToFastProperties(GlobalRegExp);
420 468
421 // ------------------------------------------------------------------- 469 // -------------------------------------------------------------------
422 // Exports 470 // Exports
423 471
424 utils.Export(function(to) { 472 utils.Export(function(to) {
473 to.GetRegExpFlagGetter = GetRegExpFlagGetter;
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

Powered by Google App Engine
This is Rietveld 408576698