327 * ECMA 15.10.7.1 source |
323 * ECMA 15.10.7.1 source |
328 * |
324 * |
329 * @param self self reference |
325 * @param self self reference |
330 * @return the input string for the regexp |
326 * @return the input string for the regexp |
331 */ |
327 */ |
332 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) |
328 @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
333 public static Object source(final Object self) { |
329 public static Object source(final Object self) { |
334 return checkRegExp(self).input; |
330 return checkRegExp(self).input; |
335 } |
331 } |
336 |
332 |
337 /** |
333 /** |
338 * ECMA 15.10.7.2 global |
334 * ECMA 15.10.7.2 global |
339 * |
335 * |
340 * @param self self reference |
336 * @param self self reference |
341 * @return true if this regexp is flagged global, false otherwise |
337 * @return true if this regexp is flagged global, false otherwise |
342 */ |
338 */ |
343 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) |
339 @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
344 public static Object global(final Object self) { |
340 public static Object global(final Object self) { |
345 return checkRegExp(self).global; |
341 return checkRegExp(self).global; |
346 } |
342 } |
347 |
343 |
348 /** |
344 /** |
349 * ECMA 15.10.7.3 ignoreCase |
345 * ECMA 15.10.7.3 ignoreCase |
350 * |
346 * |
351 * @param self self reference |
347 * @param self self reference |
352 * @return true if this regexp if flagged to ignore case, false otherwise |
348 * @return true if this regexp if flagged to ignore case, false otherwise |
353 */ |
349 */ |
354 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) |
350 @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
355 public static Object ignoreCase(final Object self) { |
351 public static Object ignoreCase(final Object self) { |
356 return checkRegExp(self).ignoreCase; |
352 return checkRegExp(self).ignoreCase; |
357 } |
353 } |
358 |
354 |
359 /** |
355 /** |
360 * ECMA 15.10.7.4 multiline |
356 * ECMA 15.10.7.4 multiline |
361 * |
357 * |
362 * @param self self reference |
358 * @param self self reference |
363 * @return true if this regexp is flagged to be multiline, false otherwise |
359 * @return true if this regexp is flagged to be multiline, false otherwise |
364 */ |
360 */ |
365 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) |
361 @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
366 public static Object multiline(final Object self) { |
362 public static Object multiline(final Object self) { |
367 return checkRegExp(self).multiline; |
363 return checkRegExp(self).multiline; |
|
364 } |
|
365 |
|
366 /** |
|
367 * Getter for non-standard RegExp.input property. |
|
368 * @param self self object |
|
369 * @return last regexp input |
|
370 */ |
|
371 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "input") |
|
372 public static Object getLastInput(Object self) { |
|
373 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
374 return match == null ? "" : match.getInput(); |
|
375 } |
|
376 |
|
377 /** |
|
378 * Getter for non-standard RegExp.multiline property. |
|
379 * @param self self object |
|
380 * @return last regexp input |
|
381 */ |
|
382 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "multiline") |
|
383 public static Object getLastMultiline(Object self) { |
|
384 return false; // doesn't ever seem to become true and isn't documented anyhwere |
|
385 } |
|
386 |
|
387 /** |
|
388 * Getter for non-standard RegExp.lastMatch property. |
|
389 * @param self self object |
|
390 * @return last regexp input |
|
391 */ |
|
392 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastMatch") |
|
393 public static Object getLastMatch(Object self) { |
|
394 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
395 return match == null ? "" : match.getGroup(0); |
|
396 } |
|
397 |
|
398 /** |
|
399 * Getter for non-standard RegExp.lastParen property. |
|
400 * @param self self object |
|
401 * @return last regexp input |
|
402 */ |
|
403 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastParen") |
|
404 public static Object getLastParen(Object self) { |
|
405 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
406 return match == null ? "" : match.getLastParen(); |
|
407 } |
|
408 |
|
409 /** |
|
410 * Getter for non-standard RegExp.leftContext property. |
|
411 * @param self self object |
|
412 * @return last regexp input |
|
413 */ |
|
414 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "leftContext") |
|
415 public static Object getLeftContext(Object self) { |
|
416 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
417 return match == null ? "" : match.getInput().substring(0, match.getIndex()); |
|
418 } |
|
419 |
|
420 /** |
|
421 * Getter for non-standard RegExp.rightContext property. |
|
422 * @param self self object |
|
423 * @return last regexp input |
|
424 */ |
|
425 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "rightContext") |
|
426 public static Object getRightContext(Object self) { |
|
427 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
428 return match == null ? "" : match.getInput().substring(match.getIndex() + match.length()); |
|
429 } |
|
430 |
|
431 /** |
|
432 * Getter for non-standard RegExp.$1 property. |
|
433 * @param self self object |
|
434 * @return last regexp input |
|
435 */ |
|
436 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$1") |
|
437 public static Object getGroup1(Object self) { |
|
438 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
439 return match == null ? "" : match.getGroup(1); |
|
440 } |
|
441 |
|
442 /** |
|
443 * Getter for non-standard RegExp.$2 property. |
|
444 * @param self self object |
|
445 * @return last regexp input |
|
446 */ |
|
447 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$2") |
|
448 public static Object getGroup2(Object self) { |
|
449 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
450 return match == null ? "" : match.getGroup(2); |
|
451 } |
|
452 |
|
453 /** |
|
454 * Getter for non-standard RegExp.$3 property. |
|
455 * @param self self object |
|
456 * @return last regexp input |
|
457 */ |
|
458 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$3") |
|
459 public static Object getGroup3(Object self) { |
|
460 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
461 return match == null ? "" : match.getGroup(3); |
|
462 } |
|
463 |
|
464 /** |
|
465 * Getter for non-standard RegExp.$4 property. |
|
466 * @param self self object |
|
467 * @return last regexp input |
|
468 */ |
|
469 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$4") |
|
470 public static Object getGroup4(Object self) { |
|
471 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
472 return match == null ? "" : match.getGroup(4); |
|
473 } |
|
474 |
|
475 /** |
|
476 * Getter for non-standard RegExp.$5 property. |
|
477 * @param self self object |
|
478 * @return last regexp input |
|
479 */ |
|
480 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$5") |
|
481 public static Object getGroup5(Object self) { |
|
482 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
483 return match == null ? "" : match.getGroup(5); |
|
484 } |
|
485 |
|
486 /** |
|
487 * Getter for non-standard RegExp.$6 property. |
|
488 * @param self self object |
|
489 * @return last regexp input |
|
490 */ |
|
491 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$6") |
|
492 public static Object getGroup6(Object self) { |
|
493 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
494 return match == null ? "" : match.getGroup(6); |
|
495 } |
|
496 |
|
497 /** |
|
498 * Getter for non-standard RegExp.$7 property. |
|
499 * @param self self object |
|
500 * @return last regexp input |
|
501 */ |
|
502 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$7") |
|
503 public static Object getGroup7(Object self) { |
|
504 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
505 return match == null ? "" : match.getGroup(7); |
|
506 } |
|
507 |
|
508 /** |
|
509 * Getter for non-standard RegExp.$8 property. |
|
510 * @param self self object |
|
511 * @return last regexp input |
|
512 */ |
|
513 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$8") |
|
514 public static Object getGroup8(Object self) { |
|
515 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
516 return match == null ? "" : match.getGroup(8); |
|
517 } |
|
518 |
|
519 /** |
|
520 * Getter for non-standard RegExp.$9 property. |
|
521 * @param self self object |
|
522 * @return last regexp input |
|
523 */ |
|
524 @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$9") |
|
525 public static Object getGroup9(Object self) { |
|
526 final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
|
527 return match == null ? "" : match.getGroup(9); |
368 } |
528 } |
369 |
529 |
370 private RegExpMatch execInner(final String string) { |
530 private RegExpMatch execInner(final String string) { |
371 if (this.pattern == null) { |
531 if (this.pattern == null) { |
372 return null; // never matches or similar, e.g. a[] |
532 return null; // never matches or similar, e.g. a[] |
423 * |
585 * |
424 * @param string String to match. |
586 * @param string String to match. |
425 * @return NativeArray of matches, string or null. |
587 * @return NativeArray of matches, string or null. |
426 */ |
588 */ |
427 public Object exec(final String string) { |
589 public Object exec(final String string) { |
428 final RegExpMatch m = execInner(string); |
590 final RegExpMatch match = execInner(string); |
429 // the input string |
591 |
430 if (m == null) { |
592 if (match == null) { |
431 return setLastRegExpMatch(null); |
593 return null; |
432 } |
594 } |
433 |
595 |
434 return setLastRegExpMatch(new NativeRegExpExecResult(m)); |
596 return new NativeRegExpExecResult(match); |
435 } |
|
436 |
|
437 // Name of the "last successful match" property of the RegExp constructor |
|
438 static final String LAST_REGEXP_MATCH = "__last_regexp_match__"; |
|
439 |
|
440 /** |
|
441 * Handles "static" properties of RegExp constructor. These are "deprecated" |
|
442 * properties of RegExp constructor. |
|
443 * |
|
444 * @param self self object passed to this method |
|
445 * @param name name of the property being searched |
|
446 * |
|
447 * @return value of the specified property or undefined if not found |
|
448 */ |
|
449 public static Object regExpStaticsHandler(final Object self, final Object name) { |
|
450 final String propName = JSType.toString(name); |
|
451 if (self instanceof ScriptObject) { |
|
452 final ScriptObject sobj = (ScriptObject)self; |
|
453 final Object value = sobj.get(LAST_REGEXP_MATCH); |
|
454 if (! (value instanceof NativeRegExpExecResult)) { |
|
455 return UNDEFINED; |
|
456 } |
|
457 |
|
458 // get the last match object |
|
459 final NativeRegExpExecResult lastMatch = (NativeRegExpExecResult)value; |
|
460 |
|
461 // look for $1... $9 |
|
462 if (propName.length() > 0 && propName.charAt(0) == '$') { |
|
463 int index = 0; |
|
464 try { |
|
465 index = Integer.parseInt(propName.substring(1)); |
|
466 } catch (final Exception ignored) { |
|
467 return UNDEFINED; |
|
468 } |
|
469 |
|
470 // index out of range |
|
471 if (index < 1 && index > 9) { |
|
472 return UNDEFINED; |
|
473 } |
|
474 |
|
475 // retrieve indexed value from last match object. |
|
476 return lastMatch.get(index); |
|
477 } |
|
478 |
|
479 // misc. "static" properties supported |
|
480 switch (propName) { |
|
481 case "input": { |
|
482 return lastMatch.input; |
|
483 } |
|
484 |
|
485 case "lastMatch": { |
|
486 return lastMatch.get(0); |
|
487 } |
|
488 |
|
489 case "lastParen": { |
|
490 final int len = ((Number)NativeRegExpExecResult.length(lastMatch)).intValue(); |
|
491 return (len > 0)? lastMatch.get(len - 1) : UNDEFINED; |
|
492 } |
|
493 } |
|
494 } |
|
495 |
|
496 return UNDEFINED; |
|
497 } |
|
498 |
|
499 // Support for RegExp static properties. We set last successful match |
|
500 // to the RegExp constructor object. |
|
501 private Object setLastRegExpMatch(final Object match) { |
|
502 if (constructor instanceof ScriptObject) { |
|
503 ((ScriptObject)constructor).set(LAST_REGEXP_MATCH, match, isStrictContext()); |
|
504 } |
|
505 return match; |
|
506 } |
597 } |
507 |
598 |
508 /** |
599 /** |
509 * Executes a search for a match within a string based on a regular |
600 * Executes a search for a match within a string based on a regular |
510 * expression. |
601 * expression. |