8007619: Add support for deprecated properties of RegExp constructor

Wed, 06 Feb 2013 17:56:12 +0530

author
sundar
date
Wed, 06 Feb 2013 17:56:12 +0530
changeset 73
fcf541418304
parent 72
f6fae6de6f4f
child 74
ec4d59c9b8d2

8007619: Add support for deprecated properties of RegExp constructor
Reviewed-by: lagergren, hannesw

src/jdk/nashorn/internal/objects/Global.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeRegExp.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
test/script/basic/JDK-8007619.js file | annotate | diff | comparison | revisions
test/script/basic/JDK-8007619.js.EXPECTED file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/objects/Global.java	Wed Feb 06 10:31:58 2013 +0100
     1.2 +++ b/src/jdk/nashorn/internal/objects/Global.java	Wed Feb 06 17:56:12 2013 +0530
     1.3 @@ -1351,6 +1351,13 @@
     1.4          final ScriptObject regExpProto = getRegExpPrototype();
     1.5          regExpProto.addBoundProperties(DEFAULT_REGEXP);
     1.6  
     1.7 +        // add hook to support "deprecated" "static" properties of RegExp constructor object
     1.8 +        final ScriptFunction handler = ScriptFunctionImpl.makeFunction(NO_SUCH_METHOD_NAME, NativeRegExp.REGEXP_STATICS_HANDLER);
     1.9 +        builtinRegExp.addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, handler);
    1.10 +
    1.11 +        // add initial undefined "last successful match" property RegExp
    1.12 +        builtinRegExp.addOwnProperty(NativeRegExp.LAST_REGEXP_MATCH, Attribute.NOT_ENUMERABLE, UNDEFINED);
    1.13 +
    1.14          // Error stuff
    1.15          initErrorObjects();
    1.16  
     2.1 --- a/src/jdk/nashorn/internal/objects/NativeRegExp.java	Wed Feb 06 10:31:58 2013 +0100
     2.2 +++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java	Wed Feb 06 17:56:12 2013 +0530
     2.3 @@ -27,7 +27,10 @@
     2.4  
     2.5  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
     2.6  import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
     2.7 +import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
     2.8  
     2.9 +import java.lang.invoke.MethodHandle;
    2.10 +import java.lang.invoke.MethodHandles;
    2.11  import java.util.ArrayList;
    2.12  import java.util.Arrays;
    2.13  import java.util.List;
    2.14 @@ -54,6 +57,8 @@
    2.15   */
    2.16  @ScriptClass("RegExp")
    2.17  public final class NativeRegExp extends ScriptObject {
    2.18 +    static final MethodHandle REGEXP_STATICS_HANDLER = findOwnMH("regExpStaticsHandler", Object.class, Object.class, Object.class);
    2.19 +
    2.20      /** ECMA 15.10.7.5 lastIndex property */
    2.21      @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
    2.22      public Object lastIndex;
    2.23 @@ -75,6 +80,9 @@
    2.24  
    2.25      private BitVector groupsInNegativeLookahead;
    2.26  
    2.27 +    // RegExp constructor object. Needed to support RegExp "static" properties,
    2.28 +    private Object constructor;
    2.29 +
    2.30      /*
    2.31      public NativeRegExp() {
    2.32          init();
    2.33 @@ -420,10 +428,81 @@
    2.34          final RegExpMatch m = execInner(string);
    2.35          // the input string
    2.36          if (m == null) {
    2.37 -            return null;
    2.38 +            return setLastRegExpMatch(null);
    2.39          }
    2.40  
    2.41 -        return new NativeRegExpExecResult(m);
    2.42 +        return setLastRegExpMatch(new NativeRegExpExecResult(m));
    2.43 +    }
    2.44 +
    2.45 +    // Name of the "last successful match" property of the RegExp constructor
    2.46 +    static final String LAST_REGEXP_MATCH = "__last_regexp_match__";
    2.47 +
    2.48 +    /**
    2.49 +     * Handles "static" properties of RegExp constructor. These are "deprecated"
    2.50 +     * properties of RegExp constructor.
    2.51 +     *
    2.52 +     * @param self self object passed to this method
    2.53 +     * @param name name of the property being searched
    2.54 +     *
    2.55 +     * @return value of the specified property or undefined if not found
    2.56 +     */
    2.57 +    public static Object regExpStaticsHandler(final Object self, final  Object name) {
    2.58 +        final String propName = JSType.toString(name);
    2.59 +        if (self instanceof ScriptObject) {
    2.60 +            final ScriptObject sobj = (ScriptObject)self;
    2.61 +            final Object value = sobj.get(LAST_REGEXP_MATCH);
    2.62 +            if (! (value instanceof NativeRegExpExecResult)) {
    2.63 +                return UNDEFINED;
    2.64 +            }
    2.65 +
    2.66 +            // get the last match object
    2.67 +            final NativeRegExpExecResult lastMatch = (NativeRegExpExecResult)value;
    2.68 +
    2.69 +            // look for $1... $9
    2.70 +            if (propName.length() > 0 && propName.charAt(0) == '$') {
    2.71 +                int index = 0;
    2.72 +                try {
    2.73 +                    index = Integer.parseInt(propName.substring(1));
    2.74 +                } catch (final Exception ignored) {
    2.75 +                    return UNDEFINED;
    2.76 +                }
    2.77 +
    2.78 +                // index out of range
    2.79 +                if (index < 1 && index > 9) {
    2.80 +                    return UNDEFINED;
    2.81 +                }
    2.82 +
    2.83 +                // retrieve indexed value from last match object.
    2.84 +                return lastMatch.get(index);
    2.85 +            }
    2.86 +
    2.87 +            // misc. "static" properties supported
    2.88 +            switch (propName) {
    2.89 +                case "input": {
    2.90 +                    return lastMatch.input;
    2.91 +                }
    2.92 +
    2.93 +                case "lastMatch": {
    2.94 +                    return lastMatch.get(0);
    2.95 +                }
    2.96 +
    2.97 +                case "lastParen": {
    2.98 +                    final int len = ((Number)NativeRegExpExecResult.length(lastMatch)).intValue();
    2.99 +                    return (len > 0)? lastMatch.get(len - 1) : UNDEFINED;
   2.100 +                }
   2.101 +            }
   2.102 +        }
   2.103 +
   2.104 +        return UNDEFINED;
   2.105 +    }
   2.106 +
   2.107 +    // Support for RegExp static properties. We set last successful match
   2.108 +    // to the RegExp constructor object.
   2.109 +    private Object setLastRegExpMatch(final Object match) {
   2.110 +        if (constructor instanceof ScriptObject) {
   2.111 +            ((ScriptObject)constructor).set(LAST_REGEXP_MATCH, match, isStrictContext());
   2.112 +        }
   2.113 +        return match;
   2.114      }
   2.115  
   2.116      /**
   2.117 @@ -665,20 +744,15 @@
   2.118       * @return Index of match.
   2.119       */
   2.120      Object search(final String string) {
   2.121 -        final Matcher matcher = pattern.matcher(string);
   2.122 -
   2.123 -        int start = 0;
   2.124 -        if (global) {
   2.125 -            start = getLastIndex();
   2.126 +        final RegExpMatch m = execInner(string);
   2.127 +        // the input string
   2.128 +        if (m == null) {
   2.129 +            setLastRegExpMatch(null);
   2.130 +            return -1;
   2.131          }
   2.132  
   2.133 -        start = matcher.find(start) ? matcher.start() : -1;
   2.134 -
   2.135 -        if (global) {
   2.136 -            setLastIndex(start == -1? -1 : matcher.end());
   2.137 -        }
   2.138 -
   2.139 -        return start;
   2.140 +        setLastRegExpMatch(new NativeRegExpExecResult(m));
   2.141 +        return m.getIndex();
   2.142      }
   2.143  
   2.144      /**
   2.145 @@ -706,7 +780,10 @@
   2.146      }
   2.147  
   2.148      private void init() {
   2.149 -        this.setProto(Global.instance().getRegExpPrototype());
   2.150 +        final ScriptObject proto = Global.instance().getRegExpPrototype();
   2.151 +        this.setProto(proto);
   2.152 +        // retrieve constructor to support "static" properties of RegExp
   2.153 +        this.constructor = PrototypeObject.getConstructor(proto);
   2.154      }
   2.155  
   2.156      private static NativeRegExp checkRegExp(final Object self) {
   2.157 @@ -769,4 +846,7 @@
   2.158          this.groupsInNegativeLookahead = groupsInNegativeLookahead;
   2.159      }
   2.160  
   2.161 +    private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
   2.162 +        return MH.findStatic(MethodHandles.publicLookup(), NativeRegExp.class, name, MH.type(rtype, types));
   2.163 +    }
   2.164  }
     3.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Feb 06 10:31:58 2013 +0100
     3.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Feb 06 17:56:12 2013 +0530
     3.3 @@ -89,10 +89,10 @@
     3.4  public abstract class ScriptObject extends PropertyListenerManager implements PropertyAccess {
     3.5  
     3.6      /** Search fall back routine name for "no such method" */
     3.7 -    static final String NO_SUCH_METHOD_NAME   = "__noSuchMethod__";
     3.8 +    public static final String NO_SUCH_METHOD_NAME   = "__noSuchMethod__";
     3.9  
    3.10      /** Search fall back routine name for "no such property" */
    3.11 -    static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
    3.12 +    public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
    3.13  
    3.14      /** Per ScriptObject flag - is this a scope object? */
    3.15      public static final int IS_SCOPE       = 0b0000_0001;
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/script/basic/JDK-8007619.js	Wed Feb 06 17:56:12 2013 +0530
     4.3 @@ -0,0 +1,49 @@
     4.4 +/*
     4.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + * 
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.
    4.11 + * 
    4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 + * version 2 for more details (a copy is included in the LICENSE file that
    4.16 + * accompanied this code).
    4.17 + * 
    4.18 + * You should have received a copy of the GNU General Public License version
    4.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + * 
    4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 + * or visit www.oracle.com if you need additional information or have any
    4.24 + * questions.
    4.25 + */
    4.26 +
    4.27 +/**
    4.28 + * JDK-8007619: Add support for deprecated properties of RegExp constructor
    4.29 + *
    4.30 + * @test
    4.31 + * @run
    4.32 + */
    4.33 +
    4.34 +
    4.35 +var emailPattern = /(\w+)@(\w+)\.(\w+)/g;
    4.36 +var input= "Please send mail to foo@acme.com and bar@gov.in ASAP!";
    4.37 +
    4.38 +var match = emailPattern.exec(input);
    4.39 +
    4.40 +while (match != null) {
    4.41 +    print("Match = " + match);
    4.42 +    print("RegExp.lastMatch = " + RegExp.lastMatch);
    4.43 +   
    4.44 +    print("RegExp.$1 = " + RegExp.$1);
    4.45 +    print("RegExp.$2 = " + RegExp.$2);
    4.46 +    print("RegExp.$3 = " + RegExp.$3);
    4.47 + 
    4.48 +    print("RegExp.lastParen = " + RegExp.lastParen)
    4.49 +    print("RegExp.input = " + RegExp.input);
    4.50 +
    4.51 +    match = emailPattern.exec(input);
    4.52 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/script/basic/JDK-8007619.js.EXPECTED	Wed Feb 06 17:56:12 2013 +0530
     5.3 @@ -0,0 +1,14 @@
     5.4 +Match = foo@acme.com,foo,acme,com
     5.5 +RegExp.lastMatch = foo@acme.com
     5.6 +RegExp.$1 = foo
     5.7 +RegExp.$2 = acme
     5.8 +RegExp.$3 = com
     5.9 +RegExp.lastParen = com
    5.10 +RegExp.input = Please send mail to foo@acme.com and bar@gov.in ASAP!
    5.11 +Match = bar@gov.in,bar,gov,in
    5.12 +RegExp.lastMatch = bar@gov.in
    5.13 +RegExp.$1 = bar
    5.14 +RegExp.$2 = gov
    5.15 +RegExp.$3 = in
    5.16 +RegExp.lastParen = in
    5.17 +RegExp.input = Please send mail to foo@acme.com and bar@gov.in ASAP!

mercurial