8007619: Add support for deprecated properties of RegExp constructor
Reviewed-by: lagergren, hannesw
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java Wed Feb 06 10:31:58 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java Wed Feb 06 17:56:12 2013 +0530
@@ -1351,6 +1351,13 @@
final ScriptObject regExpProto = getRegExpPrototype();
regExpProto.addBoundProperties(DEFAULT_REGEXP);
+ // add hook to support "deprecated" "static" properties of RegExp constructor object
+ final ScriptFunction handler = ScriptFunctionImpl.makeFunction(NO_SUCH_METHOD_NAME, NativeRegExp.REGEXP_STATICS_HANDLER);
+ builtinRegExp.addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, handler);
+
+ // add initial undefined "last successful match" property RegExp
+ builtinRegExp.addOwnProperty(NativeRegExp.LAST_REGEXP_MATCH, Attribute.NOT_ENUMERABLE, UNDEFINED);
+
// Error stuff
initErrorObjects();
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java Wed Feb 06 10:31:58 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java Wed Feb 06 17:56:12 2013 +0530
@@ -27,7 +27,10 @@
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -54,6 +57,8 @@
*/
@ScriptClass("RegExp")
public final class NativeRegExp extends ScriptObject {
+ static final MethodHandle REGEXP_STATICS_HANDLER = findOwnMH("regExpStaticsHandler", Object.class, Object.class, Object.class);
+
/** ECMA 15.10.7.5 lastIndex property */
@Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public Object lastIndex;
@@ -75,6 +80,9 @@
private BitVector groupsInNegativeLookahead;
+ // RegExp constructor object. Needed to support RegExp "static" properties,
+ private Object constructor;
+
/*
public NativeRegExp() {
init();
@@ -420,10 +428,81 @@
final RegExpMatch m = execInner(string);
// the input string
if (m == null) {
- return null;
+ return setLastRegExpMatch(null);
}
- return new NativeRegExpExecResult(m);
+ return setLastRegExpMatch(new NativeRegExpExecResult(m));
+ }
+
+ // Name of the "last successful match" property of the RegExp constructor
+ static final String LAST_REGEXP_MATCH = "__last_regexp_match__";
+
+ /**
+ * Handles "static" properties of RegExp constructor. These are "deprecated"
+ * properties of RegExp constructor.
+ *
+ * @param self self object passed to this method
+ * @param name name of the property being searched
+ *
+ * @return value of the specified property or undefined if not found
+ */
+ public static Object regExpStaticsHandler(final Object self, final Object name) {
+ final String propName = JSType.toString(name);
+ if (self instanceof ScriptObject) {
+ final ScriptObject sobj = (ScriptObject)self;
+ final Object value = sobj.get(LAST_REGEXP_MATCH);
+ if (! (value instanceof NativeRegExpExecResult)) {
+ return UNDEFINED;
+ }
+
+ // get the last match object
+ final NativeRegExpExecResult lastMatch = (NativeRegExpExecResult)value;
+
+ // look for $1... $9
+ if (propName.length() > 0 && propName.charAt(0) == '$') {
+ int index = 0;
+ try {
+ index = Integer.parseInt(propName.substring(1));
+ } catch (final Exception ignored) {
+ return UNDEFINED;
+ }
+
+ // index out of range
+ if (index < 1 && index > 9) {
+ return UNDEFINED;
+ }
+
+ // retrieve indexed value from last match object.
+ return lastMatch.get(index);
+ }
+
+ // misc. "static" properties supported
+ switch (propName) {
+ case "input": {
+ return lastMatch.input;
+ }
+
+ case "lastMatch": {
+ return lastMatch.get(0);
+ }
+
+ case "lastParen": {
+ final int len = ((Number)NativeRegExpExecResult.length(lastMatch)).intValue();
+ return (len > 0)? lastMatch.get(len - 1) : UNDEFINED;
+ }
+ }
+ }
+
+ return UNDEFINED;
+ }
+
+ // Support for RegExp static properties. We set last successful match
+ // to the RegExp constructor object.
+ private Object setLastRegExpMatch(final Object match) {
+ if (constructor instanceof ScriptObject) {
+ ((ScriptObject)constructor).set(LAST_REGEXP_MATCH, match, isStrictContext());
+ }
+ return match;
}
/**
@@ -665,20 +744,15 @@
* @return Index of match.
*/
Object search(final String string) {
- final Matcher matcher = pattern.matcher(string);
-
- int start = 0;
- if (global) {
- start = getLastIndex();
+ final RegExpMatch m = execInner(string);
+ // the input string
+ if (m == null) {
+ setLastRegExpMatch(null);
+ return -1;
}
- start = matcher.find(start) ? matcher.start() : -1;
-
- if (global) {
- setLastIndex(start == -1? -1 : matcher.end());
- }
-
- return start;
+ setLastRegExpMatch(new NativeRegExpExecResult(m));
+ return m.getIndex();
}
/**
@@ -706,7 +780,10 @@
}
private void init() {
- this.setProto(Global.instance().getRegExpPrototype());
+ final ScriptObject proto = Global.instance().getRegExpPrototype();
+ this.setProto(proto);
+ // retrieve constructor to support "static" properties of RegExp
+ this.constructor = PrototypeObject.getConstructor(proto);
}
private static NativeRegExp checkRegExp(final Object self) {
@@ -769,4 +846,7 @@
this.groupsInNegativeLookahead = groupsInNegativeLookahead;
}
+ private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
+ return MH.findStatic(MethodHandles.publicLookup(), NativeRegExp.class, name, MH.type(rtype, types));
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Feb 06 10:31:58 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Feb 06 17:56:12 2013 +0530
@@ -89,10 +89,10 @@
public abstract class ScriptObject extends PropertyListenerManager implements PropertyAccess {
/** Search fall back routine name for "no such method" */
- static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__";
+ public static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__";
/** Search fall back routine name for "no such property" */
- static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
+ public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
/** Per ScriptObject flag - is this a scope object? */
public static final int IS_SCOPE = 0b0000_0001;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8007619.js Wed Feb 06 17:56:12 2013 +0530
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8007619: Add support for deprecated properties of RegExp constructor
+ *
+ * @test
+ * @run
+ */
+
+
+var emailPattern = /(\w+)@(\w+)\.(\w+)/g;
+var input= "Please send mail to foo@acme.com and bar@gov.in ASAP!";
+
+var match = emailPattern.exec(input);
+
+while (match != null) {
+ print("Match = " + match);
+ print("RegExp.lastMatch = " + RegExp.lastMatch);
+
+ print("RegExp.$1 = " + RegExp.$1);
+ print("RegExp.$2 = " + RegExp.$2);
+ print("RegExp.$3 = " + RegExp.$3);
+
+ print("RegExp.lastParen = " + RegExp.lastParen)
+ print("RegExp.input = " + RegExp.input);
+
+ match = emailPattern.exec(input);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8007619.js.EXPECTED Wed Feb 06 17:56:12 2013 +0530
@@ -0,0 +1,14 @@
+Match = foo@acme.com,foo,acme,com
+RegExp.lastMatch = foo@acme.com
+RegExp.$1 = foo
+RegExp.$2 = acme
+RegExp.$3 = com
+RegExp.lastParen = com
+RegExp.input = Please send mail to foo@acme.com and bar@gov.in ASAP!
+Match = bar@gov.in,bar,gov,in
+RegExp.lastMatch = bar@gov.in
+RegExp.$1 = bar
+RegExp.$2 = gov
+RegExp.$3 = in
+RegExp.lastParen = in
+RegExp.input = Please send mail to foo@acme.com and bar@gov.in ASAP!