# HG changeset patch # User jlaskey # Date 1362238007 14400 # Node ID 8cfcd914d26df83df3b995a380b89c608ddb0a74 # Parent 5ddfc1208ef397d3f49021560c25b10b5d8db7e6# Parent 675a0caf75bc5ecb95525154afc7dbc322683bb5 Merge diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/make/build.xml --- a/nashorn/make/build.xml Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/make/build.xml Sat Mar 02 11:26:47 2013 -0400 @@ -21,7 +21,7 @@ or visit www.oracle.com if you need additional information or have any questions. --> - + diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/make/project.properties --- a/nashorn/make/project.properties Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/make/project.properties Sat Mar 02 11:26:47 2013 -0400 @@ -24,7 +24,7 @@ application.title=nashorn # location of JDK embedded ASM sources -jdk.asm.src.dir=../jdk/src/share/classes/jdk/internal +jdk.asm.src.dir=../jdk/src/share/classes/jdk/internal/org/objectweb/asm # source and target levels build.compiler=modern diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Sat Mar 02 11:26:47 2013 -0400 @@ -83,7 +83,6 @@ package jdk.internal.dynalink.beans; -import java.beans.Introspector; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -136,16 +135,16 @@ // Add the method as a property getter and/or setter if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { // Property getter - setPropertyGetter(Introspector.decapitalize(name.substring(3)), introspector.unreflect( + setPropertyGetter(decapitalize(name.substring(3)), introspector.unreflect( getMostGenericGetter(method)), ValidationType.INSTANCE_OF); } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && method.getReturnType() == boolean.class) { // Boolean property getter - setPropertyGetter(Introspector.decapitalize(name.substring(2)), introspector.unreflect( + setPropertyGetter(decapitalize(name.substring(2)), introspector.unreflect( getMostGenericGetter(method)), ValidationType.INSTANCE_OF); } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { // Property setter - addMember(Introspector.decapitalize(name.substring(3)), methodHandle, propertySetters); + addMember(decapitalize(name.substring(3)), methodHandle, propertySetters); } } @@ -170,6 +169,27 @@ } } + private static String decapitalize(String str) { + assert str != null; + if(str.isEmpty()) { + return str; + } + + final char c0 = str.charAt(0); + if(Character.isLowerCase(c0)) { + return str; + } + + // If it has two consecutive upper-case characters, i.e. "URL", don't decapitalize + if(str.length() > 1 && Character.isUpperCase(str.charAt(1))) { + return str; + } + + final char c[] = str.toCharArray(); + c[0] = Character.toLowerCase(c0); + return new String(c); + } + abstract FacetIntrospector createFacetIntrospector(); void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) { diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java Sat Mar 02 11:26:47 2013 -0400 @@ -83,7 +83,6 @@ package jdk.internal.dynalink.beans; -import java.beans.BeanInfo; import java.lang.invoke.MethodHandles; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.DynamicLinkerFactory; @@ -99,11 +98,9 @@ *
    *
  • expose all public methods of form {@code setXxx()}, {@code getXxx()}, and {@code isXxx()} as property setters and * getters for {@code dyn:setProp} and {@code dyn:getProp} operations;
  • - *
  • expose all property getters and setters declared by the class' {@link BeanInfo};
  • - *
  • expose all public methods and methods declared by the class' {@link BeanInfo} for invocation through - * {@code dyn:callMethod} operation;
  • - *
  • expose all public methods and methods declared by the class' {@link BeanInfo} for retrieval for - * {@code dyn:getMethod} operation; the methods thus retrieved can then be invoked using {@code dyn:call};
  • + *
  • expose all public methods for invocation through {@code dyn:callMethod} operation;
  • + *
  • expose all public methods for retrieval for {@code dyn:getMethod} operation; the methods thus retrieved can then + * be invoked using {@code dyn:call};
  • *
  • expose all public fields as properties, unless there are getters or setters for the properties of the same name;
  • *
  • expose {@code dyn:getLength}, {@code dyn:getElem} and {@code dyn:setElem} on native Java arrays, as well as * {@link java.util.List} and {@link java.util.Map} objects; ({@code dyn:getLength} works on any diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java --- a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java Sat Mar 02 11:26:47 2013 -0400 @@ -95,7 +95,7 @@ *

    * There is also a very nice debug interface that can emit formatted * bytecodes that have been written. This is enabled by setting the - * environment "nashorn.codegen.debug" to true, or --log=codegen: + * environment "nashorn.codegen.debug" to true, or --log=codegen:{@literal } *

    * A ClassEmitter implements an Emitter - i.e. it needs to have * well defined start and end calls for whatever it is generating. Assertions diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Sat Mar 02 11:26:47 2013 -0400 @@ -46,7 +46,6 @@ import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE; -import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FUNCTION_DECLARATION; import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_SCOPE; import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; @@ -2052,9 +2051,6 @@ if (needsScope) { int flags = CALLSITE_SCOPE | getCallSiteFlags(); - if (varNode.isFunctionVarNode()) { - flags |= CALLSITE_FUNCTION_DECLARATION; - } final IdentNode identNode = varNode.getName(); final Type type = identNode.getType(); if (varSymbol.isFastScope(getCurrentFunctionNode())) { diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java --- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Sat Mar 02 11:26:47 2013 -0400 @@ -112,7 +112,7 @@ private final Context context; /** - * The list of available accessor types in width order. This order is used for type guesses narrow->wide + * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide * in the dual--fields world */ public static final List ACCESSOR_TYPES = Collections.unmodifiableList( @@ -184,7 +184,7 @@ /** * Return the accessor type based on its index in [0..getNumberOfAccessorTypes()) - * Indexes are ordered narrower->wider / optimistic->pessimistic. Invalidations always + * Indexes are ordered narrower{@literal ->}wider / optimistic{@literal ->}pessimistic. Invalidations always * go to a type of higher index * * @param index accessor type index diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java --- a/nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java Sat Mar 02 11:26:47 2013 -0400 @@ -459,120 +459,120 @@ } /** - * Specialized version of < operator for two int arguments. Do not call directly. + * Specialized version of {@literal <} operator for two int arguments. Do not call directly. * @param a int * @param b int - * @return a < b + * @return a {@code <} b */ public static boolean LT(final int a, final int b) { return a < b; } /** - * Specialized version of < operator for two double arguments. Do not call directly. + * Specialized version of {@literal <} operator for two double arguments. Do not call directly. * @param a double * @param b double - * @return a < b + * @return a {@literal <} b */ public static boolean LT(final double a, final double b) { return a < b; } /** - * Specialized version of < operator for two long arguments. Do not call directly. + * Specialized version of {@literal <} operator for two long arguments. Do not call directly. * @param a long * @param b long - * @return a < b + * @return a {@literal <} b */ public static boolean LT(final long a, final long b) { return a < b; } /** - * Specialized version of <= operator for two int arguments. Do not call directly. + * Specialized version of {@literal <=} operator for two int arguments. Do not call directly. * @param a int * @param b int - * @return a <= b + * @return a {@literal <=} b */ public static boolean LE(final int a, final int b) { return a <= b; } /** - * Specialized version of <= operator for two double arguments. Do not call directly. + * Specialized version of {@literal <=} operator for two double arguments. Do not call directly. * @param a double * @param b double - * @return a <= b + * @return a {@literal <=} b */ public static boolean LE(final double a, final double b) { return a <= b; } /** - * Specialized version of <= operator for two long arguments. Do not call directly. + * Specialized version of {@literal <=} operator for two long arguments. Do not call directly. * @param a long * @param b long - * @return a <= b + * @return a {@literal <=} b */ public static boolean LE(final long a, final long b) { return a <= b; } /** - * Specialized version of > operator for two int arguments. Do not call directly. + * Specialized version of {@literal >} operator for two int arguments. Do not call directly. * @param a int * @param b int - * @return a > b + * @return a {@literal >} b */ public static boolean GT(final int a, final int b) { return a > b; } /** - * Specialized version of > operator for two double arguments. Do not call directly. + * Specialized version of {@literal >} operator for two double arguments. Do not call directly. * @param a double * @param b double - * @return a > b + * @return a {@literal >} b */ public static boolean GT(final double a, final double b) { return a > b; } /** - * Specialized version of > operator for two long arguments. Do not call directly. + * Specialized version of {@literal >} operator for two long arguments. Do not call directly. * @param a long * @param b long - * @return a > b + * @return a {@literal >} b */ public static boolean GT(final long a, final long b) { return a > b; } /** - * Specialized version of >= operator for two int arguments. Do not call directly. + * Specialized version of {@literal >=} operator for two int arguments. Do not call directly. * @param a int * @param b int - * @return a >= b + * @return a {@literal >=} b */ public static boolean GE(final int a, final int b) { return a >= b; } /** - * Specialized version of >= operator for two double arguments. Do not call directly. + * Specialized version of {@literal >=} operator for two double arguments. Do not call directly. * @param a double * @param b double - * @return a >= b + * @return a {@literal >=} b */ public static boolean GE(final double a, final double b) { return a >= b; } /** - * Specialized version of >= operator for two long arguments. Do not call directly. + * Specialized version of {@literal >=} operator for two long arguments. Do not call directly. * @param a long * @param b long - * @return a >= b + * @return a {@code >=} b */ public static boolean GE(final long a, final long b) { return a >= b; diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/ir/Assignment.java --- a/nashorn/src/jdk/nashorn/internal/ir/Assignment.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/ir/Assignment.java Sat Mar 02 11:26:47 2013 -0400 @@ -46,18 +46,4 @@ * @return get the assignment source node */ public Node getAssignmentSource(); - - /** - * Reset the assignment source - * - * @param newSource new source node - */ - public void setAssignmentSource(final Node newSource); - - /** - * Reset the assignment destination - * - * @param newDest new destination node - */ - public void setAssignmentDest(final D newDest); } diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Sat Mar 02 11:26:47 2013 -0400 @@ -140,21 +140,11 @@ } @Override - public void setAssignmentDest(final Node node) { - setLHS(node); - } - - @Override public Node getAssignmentSource() { return rhs(); } @Override - public void setAssignmentSource(final Node source) { - setRHS(source); - } - - @Override public boolean equals(final Object other) { if (!super.equals(other)) { return false; diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Sat Mar 02 11:26:47 2013 -0400 @@ -64,17 +64,17 @@ EQ_STRICT(TokenType.EQ_STRICT, Type.BOOLEAN, 2, true), /** == operator with at least one object */ EQ(TokenType.EQ, Type.BOOLEAN, 2, true), - /** >= operator with at least one object */ + /** {@literal >=} operator with at least one object */ GE(TokenType.GE, Type.BOOLEAN, 2, true), - /** > operator with at least one object */ + /** {@literal >} operator with at least one object */ GT(TokenType.GT, Type.BOOLEAN, 2, true), /** in operator */ IN(TokenType.IN, Type.BOOLEAN, 2), /** instanceof operator */ INSTANCEOF(TokenType.INSTANCEOF, Type.BOOLEAN, 2), - /** <= operator with at least one object */ + /** {@literal <=} operator with at least one object */ LE(TokenType.LE, Type.BOOLEAN, 2, true), - /** < operator with at least one object */ + /** {@literal <} operator with at least one object */ LT(TokenType.LT, Type.BOOLEAN, 2, true), /** !== operator with at least one object */ NE_STRICT(TokenType.NE_STRICT, Type.BOOLEAN, 2, true), @@ -184,7 +184,7 @@ /** * If this request can be reversed, return the reverse request - * Eq EQ -> NE. + * Eq EQ {@literal ->} NE. * * @param request request to reverse * diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Sat Mar 02 11:26:47 2013 -0400 @@ -109,16 +109,6 @@ } @Override - public void setAssignmentSource(final Node source) { - setAssignmentDest(source); - } - - @Override - public void setAssignmentDest(final Node source) { - setRHS(source); - } - - @Override public boolean equals(final Object other) { if (!super.equals(other)) { return false; diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/ir/VarNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Sat Mar 02 11:26:47 2013 -0400 @@ -83,20 +83,10 @@ } @Override - public void setAssignmentDest(final IdentNode node) { - setName(name); - } - - @Override public Node getAssignmentSource() { return isAssignment() ? getInit() : null; } - @Override - public void setAssignmentSource(final Node source) { - setInit(source); - } - /** * Does this variable declaration have an init value * @return true if an init exists, false otherwise diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java --- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Sat Mar 02 11:26:47 2013 -0400 @@ -542,7 +542,7 @@ } /** - * Binary enter - callback for entering && operator + * Binary enter - callback for entering {@literal &&} operator * * @param binaryNode the node * @return processed node @@ -552,7 +552,7 @@ } /** - * Binary leave - callback for leaving a && operator + * Binary leave - callback for leaving a {@literal &&} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -602,7 +602,7 @@ } /** - * Binary enter - callback for entering &= operator + * Binary enter - callback for entering {@literal &=} operator * * @param binaryNode the node * @return processed node @@ -612,7 +612,7 @@ } /** - * Binary leave - callback for leaving a &= operator + * Binary leave - callback for leaving a {@literal &=} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -722,7 +722,7 @@ } /** - * Binary enter - callback for entering >>= operator + * Binary enter - callback for entering {@literal >>=} operator * * @param binaryNode the node * @return processed node @@ -732,7 +732,7 @@ } /** - * Binary leave - callback for leaving a >>= operator + * Binary leave - callback for leaving a {@literal >>=} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -742,7 +742,7 @@ } /** - * Binary enter - callback for entering a <<= operator + * Binary enter - callback for entering a {@literal <<=} operator * * @param binaryNode the node * @return processed node @@ -752,7 +752,7 @@ } /** - * Binary leave - callback for leaving a <<= operator + * Binary leave - callback for leaving a {@literal <<=} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -762,7 +762,7 @@ } /** - * Binary enter - callback for entering >>>= operator + * Binary enter - callback for entering {@literal >>>=} operator * * @param binaryNode the node * @return processed node @@ -772,7 +772,7 @@ } /** - * Binary leave - callback for leaving a >>>= operator + * Binary leave - callback for leaving a {@literal >>>=} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -822,7 +822,7 @@ } /** - * Binary enter - callback for entering & operator + * Binary enter - callback for entering {@literal &} operator * * @param binaryNode the node * @return processed node @@ -832,7 +832,7 @@ } /** - * Binary leave - callback for leaving a & operator + * Binary leave - callback for leaving a {@literal &} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -986,7 +986,7 @@ } /** - * Binary enter - callback for entering >= operator + * Binary enter - callback for entering {@literal >=} operator * * @param binaryNode the node * @return processed node @@ -996,7 +996,7 @@ } /** - * Binary leave - callback for leaving >= operator + * Binary leave - callback for leaving {@literal >=} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -1006,7 +1006,7 @@ } /** - * Binary enter - callback for entering > operator + * Binary enter - callback for entering {@literal >} operator * * @param binaryNode the node * @return processed node @@ -1016,7 +1016,7 @@ } /** - * Binary leave - callback for leaving > operator + * Binary leave - callback for leaving {@literal >} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -1066,7 +1066,7 @@ } /** - * Binary enter - callback for entering <= operator + * Binary enter - callback for entering {@literal <=} operator * * @param binaryNode the node * @return processed node @@ -1076,7 +1076,7 @@ } /** - * Binary leave - callback for leaving <= operator + * Binary leave - callback for leaving {@literal <=} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -1086,7 +1086,7 @@ } /** - * Binary enter - callback for entering < operator + * Binary enter - callback for entering {@literal <} operator * * @param binaryNode the node * @return processed node @@ -1096,7 +1096,7 @@ } /** - * Binary leave - callback for leaving < operator + * Binary leave - callback for leaving {@literal <} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -1205,7 +1205,7 @@ } /** - * Binary enter - callback for entering >> operator + * Binary enter - callback for entering {@literal >>} operator * * @param binaryNode the node * @return processed node @@ -1215,7 +1215,7 @@ } /** - * Binary leave - callback for leaving >> operator + * Binary leave - callback for leaving {@literal >>} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -1225,7 +1225,7 @@ } /** - * Binary enter - callback for entering << operator + * Binary enter - callback for entering {@literal <<} operator * * @param binaryNode the node * @return processed node @@ -1235,7 +1235,7 @@ } /** - * Binary leave - callback for leaving << operator + * Binary leave - callback for leaving {@literal <<} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node @@ -1244,7 +1244,7 @@ return leaveDefault(binaryNode); } /** - * Binary enter - callback for entering >>> operator + * Binary enter - callback for entering {@literal >>>} operator * * @param binaryNode the node * @return processed node @@ -1254,7 +1254,7 @@ } /** - * Binary leave - callback for leaving >>> operator + * Binary leave - callback for leaving {@literal >>>} operator * * @param binaryNode the node * @return processed node, which will replace the original one, or the original node diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/objects/DateParser.java --- a/nashorn/src/jdk/nashorn/internal/objects/DateParser.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/objects/DateParser.java Sat Mar 02 11:26:47 2013 -0400 @@ -221,7 +221,7 @@ * *

    English month names and selected time zone names as well as AM/PM markers are recognized * and handled properly. Additionally, numeric time zone offsets such as (+|-)hh:mm or - * (+|-)hhmm are recognized. If the string does not contain a time zone offset + * (+|-)hhmm are recognized. If the string does not contain a time zone offset * the TIMEZONEfield is left undefined, meaning the local time zone should be applied.

    * *

    English weekday names are recognized but ignored. All text in parentheses is ignored as well. diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Sat Mar 02 11:26:47 2013 -0400 @@ -74,13 +74,16 @@ * delete x.p; // calls y.__delete__ * for (i in x) { print(i); } // calls y.__getIds__ * + *

    * JavaScript caller of adapter object is isolated from the fact that the property access/mutation/deletion are really * calls to JavaScript methods on adaptee. - *

    + *

    + *

    * JSAdapter constructor can optionally receive an "overrides" object. Properties of overrides object is copied to * JSAdapter instance. When user accessed property is one of these, then adaptee's methods like {@code __get__}, * {@code __put__} etc. are not called for those. This can be used to make certain "preferred" properties that can be * accessed in the usual/faster way avoiding proxy mechanism. Example: + *

    *
      *     var x = new JSAdapter({ foo: 444, bar: 6546 }) {
      *          __get__: function(name) { return name; }
    diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/objects/NativeJava.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java	Wed Feb 27 14:12:45 2013 +0000
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java	Sat Mar 02 11:26:47 2013 -0400
    @@ -65,6 +65,7 @@
         }
     
         /**
    +     * 

    * Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects * used to represent Java types in Nashorn is not {@link java.lang.Class} but rather {@link StaticClass}. They are * the objects that you can use with the {@code new} operator to create new instances of the class as well as to @@ -75,7 +76,8 @@ * different expression (e.g. {@code java.io.File}) as an argument in "new" and to address statics, and it is * distinct from the {@code Class} object (e.g. {@code java.io.File.class}). Below we cover in details the * properties of the type objects. - *

    Constructing Java objects

    + *

    + *

    Constructing Java objects

    * Examples: *
          * var arrayListType = Java.type("java.util.ArrayList")
    @@ -104,19 +106,24 @@
          * var arctype = Java.type("java.awt.geom.Arc2D")
          * var ftype = arctype.Float
          * 
    + *

    * You can access both static and non-static inner classes. If you want to create an instance of a non-static * inner class, remember to pass an instance of its outer class as the first argument to the constructor. - *

    + *

    + *

    * If the type is abstract, you can instantiate an anonymous subclass of it using an argument list that is * applicable to any of its public or protected constructors, but inserting a JavaScript object with functions * properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the * JavaScript function will provide implementation for all overloads. E.g.: + *

    *
          * var TimerTask =  Java.type("java.util.TimerTask")
          * var task = new TimerTask({ run: function() { print("Hello World!") } })
          * 
    + *

    * Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to * invoking the constructor and passing the argument to it, so you can write the above example also as: + *

    *
          * var task = new TimerTask {
          *     run: function() {
    @@ -124,30 +131,38 @@
          *     }
          * }
          * 
    + *

    * which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract * type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share * the same overloaded name), then instead of an object, you can just pass a function, so the above example can * become even more simplified to: + *

    *
          * var task = new TimerTask(function() { print("Hello World!") })
          * 
    + *

    * Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors * that take some arguments, you can invoke those simply by specifying the arguments after the initial * implementation object or function. - *

    The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, + *

    + *

    The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, * you can just pass in a function object, and Nashorn will know what you meant: + *

    *
          * var timer = new Java.type("java.util.Timer")
          * timer.schedule(function() { print("Hello World!") })
          * 
    + *

    * Here, {@code Timer.schedule()} expects a {@code TimerTask} as its argument, so Nashorn creates an instance of a * {@code TimerTask} subclass and uses the passed function to implement its only abstract method, {@code run()}. In * this usage though, you can't use non-default constructors; the type must be either an interface, or must have a * protected or public no-arg constructor. - *

    + *

    + *

    * You can also subclass non-abstract classes; for that you will need to use the {@link #extend(Object, Object...)} * method. - *

    Accessing static members

    + *

    + *

    Accessing static members

    * Examples: *
          * var File = Java.type("java.io.File")
    @@ -176,7 +191,7 @@
          * var File = Java.type("java.io.File")
          * print(File.class.static === File) // prints true
          * 
    - *

    {@code instanceof} operator

    + *

    {@code instanceof} operator

    * The standard ECMAScript {@code instanceof} operator is extended to recognize Java objects and their type objects: *
          * var File = Java.type("java.io.File")
    @@ -368,6 +383,7 @@
          * 
  • If the Java method is overloaded (as in the above example {@code List.add()}), then your JavaScript adapter * must be prepared to deal with all overloads.
  • *
  • You can't invoke {@code super.*()} from adapters for now.
  • + *
* @param self not used * @param types the original types. The caller must pass at least one Java type object of class {@link StaticClass} * representing either a public interface or a non-final public class with at least one public or protected diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java --- a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java Sat Mar 02 11:26:47 2013 -0400 @@ -30,7 +30,7 @@ * As only the code generating package (i.e. Context) knows about * the ScriptLoader and it would be a security hazard otherwise * the Compiler is given an installation interface for its code. - *

> + *

* The compiler still retains most of the state around code emission * and management internally, so this is to avoid passing around any * logic that isn't directly related to installing a class diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/Context.java --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java Sat Mar 02 11:26:47 2013 -0400 @@ -509,7 +509,7 @@ * * @param fullName full name of class, e.g. jdk.nashorn.internal.objects.JO$2P1 contains 2 fields and 1 parameter. * - * @return the Class for this structure + * @return the {@code Class} for this structure * * @throws ClassNotFoundException if structure class cannot be resolved */ @@ -523,7 +523,7 @@ * * @param fullName full name of class to load * - * @return the Class for the name + * @return the {@code Class} for the name * * @throws ClassNotFoundException if class cannot be resolved */ diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Sat Mar 02 11:26:47 2013 -0400 @@ -1463,7 +1463,7 @@ } /** - * Returns the set of entries that make up this + * Returns the set of {@literal } entries that make up this * ScriptObject's properties * (java.util.Map-like method to help ScriptObjectMirror implementation) * @@ -1524,7 +1524,7 @@ * of their keys to their values * (java.util.Map-like method to help ScriptObjectMirror implementation) * - * @param otherMap a map of properties to add + * @param otherMap a {@literal } map of properties to add */ public void putAll(final Map otherMap) { final boolean strict = getContext()._strict; diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Sat Mar 02 11:26:47 2013 -0400 @@ -815,7 +815,7 @@ } /** - * ECMA 11.8.1 - The less than operator (<) - generic implementation + * ECMA 11.8.1 - The less than operator ({@literal <}) - generic implementation * * @param x first object to compare * @param y second object to compare @@ -828,7 +828,7 @@ } /** - * ECMA 11.8.2 - The greater than operator (>) - generic implementation + * ECMA 11.8.2 - The greater than operator ({@literal >}) - generic implementation * * @param x first object to compare * @param y second object to compare @@ -841,7 +841,7 @@ } /** - * ECMA 11.8.3 - The less than or equal operator (<=) - generic implementation + * ECMA 11.8.3 - The less than or equal operator ({@literal <=}) - generic implementation * * @param x first object to compare * @param y second object to compare @@ -854,7 +854,7 @@ } /** - * ECMA 11.8.4 - The greater than or equal operator (>=) - generic implementation + * ECMA 11.8.4 - The greater than or equal operator ({@literal >=}) - generic implementation * * @param x first object to compare * @param y second object to compare diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Sat Mar 02 11:26:47 2013 -0400 @@ -87,7 +87,7 @@ import jdk.nashorn.internal.runtime.Undefined; /** - * A factory class that generates adapter classes. Adapter classes allow implementation of Java interfaces and + *

A factory class that generates adapter classes. Adapter classes allow implementation of Java interfaces and * extending of Java classes from JavaScript. For every combination of a superclass to extend and interfaces to * implement (collectively: "original types"), exactly one adapter class is generated that extends the specified * superclass and implements the specified interfaces. diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Sat Mar 02 11:26:47 2013 -0400 @@ -43,8 +43,6 @@ public static final int CALLSITE_SCOPE = 0x01; /** Flags that the call site is in code that uses ECMAScript strict mode. */ public static final int CALLSITE_STRICT = 0x02; - /** Flags that a property setter call site is part of a function declaration that assigns the function object to a name. */ - public static final int CALLSITE_FUNCTION_DECLARATION = 0x04; /** Flags that a property getter or setter call site references a scope variable that is not in the global scope * (it is in a function lexical scope), and the function's scope object class is fixed and known in advance. Such * getters and setters can often be linked more optimally using these assumptions. */ @@ -182,7 +180,7 @@ /** * Returns the named operand in this descriptor's name. Equivalent to * {@code getNameToken(CallSiteDescriptor.NAME_OPERAND)}. E.g. for operation {@code "dyn:getProp:color"}, returns - * {@code "color"}. For call sites without named operands (e.g. {@link "dyn:new"}) returns null. + * {@code "color"}. For call sites without named operands (e.g. {@code "dyn:new"}) returns null. * @return the named operand in this descriptor's name. */ public String getOperand() { diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/options/Options.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java Sat Mar 02 11:26:47 2013 -0400 @@ -200,7 +200,7 @@ /** * Return an option given its resource key. If the key doesn't begin with - * .option it will be completed using the resource from this + * {@literal }.option it will be completed using the resource from this * instance * * @param key key for option diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Sat Mar 02 11:26:47 2013 -0400 @@ -117,10 +117,6 @@ return new JoniRegExp(pattern, flags); } - @Override - protected String replaceToken(final String str) { - return str.equals("[^]") ? "[\\s\\S]" : str; - } } class JoniMatcher implements RegExpMatcher { diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Sat Mar 02 11:26:47 2013 -0400 @@ -68,25 +68,6 @@ } /** - * Replace a regexp token as suitable for regexp instances created by this factory. - * - * @param str a regular expression token - * @return the replacement token - */ - protected String replaceToken(final String str) { - switch (str) { - case "\\s": - return "[" + Lexer.getWhitespaceRegExp() + "]"; - case "\\S": - return "[^" + Lexer.getWhitespaceRegExp() + "]"; - case "[^]": - return "[\\s\\S]"; - default: - return str; - } - } - - /** * Compile a regexp with the given {@code source} and {@code flags}. * * @param pattern RegExp pattern string @@ -99,16 +80,6 @@ } /** - * Replace a regexp token as needed by the currently installed factory instance. - * - * @param token a regexp token - * @return the replacement token - */ - public static String replace(final String token) { - return instance.replaceToken(token); - } - - /** * Validate a regexp with the given {@code source} and {@code flags}. * * @param pattern RegExp pattern string @@ -120,4 +91,13 @@ public static void validate(final String pattern, final String flags) throws ParserException { instance.compile(pattern, flags); } + + /** + * Returns true if the instance uses the JDK's {@code java.util.regex} package. + * + * @return true if instance uses JDK regex package + */ + public static boolean usesJavaUtilRegex() { + return instance != null && instance.getClass() == RegExpFactory.class; + } } diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Sat Mar 02 11:26:47 2013 -0400 @@ -25,15 +25,15 @@ package jdk.nashorn.internal.runtime.regexp; -import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.PatternSyntaxException; +import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.parser.Scanner; import jdk.nashorn.internal.runtime.BitVector; @@ -44,17 +44,13 @@ final class RegExpScanner extends Scanner { /** - * String builder to accumulate the result - this contains verbatim parsed JavaScript. - * to get the java equivalent we need to create a Pattern token and return its toString() + * String builder used to rewrite the pattern for the currently used regexp factory. */ private final StringBuilder sb; /** Is this the special case of a regexp that never matches anything */ private boolean neverMatches; - /** The resulting java.util.regex pattern string. */ - private String javaPattern; - /** Expected token table */ private final Map expected = new HashMap<>(); @@ -62,11 +58,14 @@ private final List caps = new LinkedList<>(); /** Forward references to capturing parenthesis to be resolved later.*/ - private final Map forwardReferences = new LinkedHashMap<>(); + private final Set forwardReferences = new LinkedHashSet<>(); /** Current level of zero-width negative lookahead assertions. */ private int negativeLookaheadLevel; + /** Are we currently inside a character class? */ + private boolean inCharClass = false; + private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?"; private static class Capture { @@ -74,11 +73,6 @@ * Zero-width negative lookaheads enclosing the capture. */ private final int negativeLookaheadLevel; - /** - * Captures that live inside a negative lookahead are dead after the - * lookahead and will be undefined if referenced from outside. - */ - private boolean isDead; Capture(final int negativeLookaheadLevel) { this.negativeLookaheadLevel = negativeLookaheadLevel; @@ -88,336 +82,6 @@ return negativeLookaheadLevel; } - public boolean isDead() { - return isDead; - } - - public void setDead() { - this.isDead = true; - } - } - - /** - * This is a token - the JavaScript regexp is scanned into a token tree - * A token has other tokens as children as well as "atoms", i.e. Strings. - */ - private static class Token { - - private enum Type { - PATTERN, - DISJUNCTION, - ALTERNATIVE, - TERM, - ASSERTION, - QUANTIFIER, - QUANTIFIER_PREFIX, - ATOM, - PATTERN_CHARACTER, - ATOM_ESCAPE, - CHARACTER_ESCAPE, - CONTROL_ESCAPE, - CONTROL_LETTER, - IDENTITY_ESCAPE, - DECIMAL_ESCAPE, - CHARACTERCLASS_ESCAPE, - CHARACTERCLASS, - CLASSRANGES, - NON_EMPTY_CLASSRANGES, - NON_EMPTY_CLASSRANGES_NODASH, - CLASSATOM, - CLASSATOM_NODASH, - CLASS_ESCAPE, - DECIMALDIGITS, - HEX_ESCAPESEQUENCE, - UNICODE_ESCAPESEQUENCE, - } - - /** - * Token tyoe - */ - private final Token.Type type; - - /** - * Child nodes - */ - private final List children; - - /** - * Parent node - */ - private Token parent; - - /** - * Dead code flag - */ - private boolean isDead; - - private static final Map toStringMap = new HashMap<>(); - private static final ToString DEFAULT_TOSTRING = new ToString(); - - private static String unicode(final int value) { - final StringBuilder sb = new StringBuilder(); - final String hex = Integer.toHexString(value); - sb.append('u'); - for (int i = 0; i < 4 - hex.length(); i++) { - sb.append('0'); - } - sb.append(hex); - - return sb.toString(); - } - - static { - toStringMap.put(Type.CHARACTERCLASS, new ToString() { - @Override - public String toString(final Token token) { - return super.toString(token).replace("\\b", "\b"); - } - }); - - // for some reason java regexps don't like control characters on the - // form "\\ca".match([string with ascii 1 at char0]). Translating - // them to unicode does it though. - toStringMap.put(Type.CHARACTER_ESCAPE, new ToString() { - @Override - public String toString(final Token token) { - final String str = super.toString(token); - if (str.length() == 2) { - return Token.unicode(Character.toLowerCase(str.charAt(1)) - 'a' + 1); - } - return str; - } - }); - - toStringMap.put(Type.DECIMAL_ESCAPE, new ToString() { - @Override - public String toString(final Token token) { - final String str = super.toString(token); - - if ("\0".equals(str)) { - return str; - } - - int value; - - if (!token.hasParentOfType(Type.CLASSRANGES)) { - return str; - } - - value = Integer.parseInt(str, 8); //throws exception that leads to SyntaxError if not octal - if (value > 0xff) { - throw new NumberFormatException(str); - } - - return Token.unicode(value); - } - }); - - } - - /** - * JavaScript Token to Java regex substring framework. - */ - private static class ToString { - String toString(final Token token) { - final Object[] children = token.getChildren(); - - // Allow the installed regexp factory to perform global substitutions. - switch (children.length) { - case 0: - return ""; - case 1: - return RegExpFactory.replace(children[0].toString()); - default: - final StringBuilder sb = new StringBuilder(); - for (final Object child : children) { - sb.append(child); - } - return RegExpFactory.replace(sb.toString()); - } - } - } - - /** - * Token iterator. Doesn't return "atom" children. i.e. string representations, - * just tokens - * - */ - private static class TokenIterator implements Iterator { - private final List preorder; - - private void init(final Token root) { - preorder.add(root); - for (final Object child : root.getChildren()) { - if (child instanceof Token) { - init((Token)child); - } - } - } - - TokenIterator(final Token root) { - preorder = new ArrayList<>(); - init(root); - } - - @Override - public boolean hasNext() { - return !preorder.isEmpty(); - } - - @Override - public Token next() { - return preorder.remove(0); - } - - @Override - public void remove() { - next(); - } - } - - /** - * Constructor - * @param type the token type - */ - Token(final Token.Type type) { - this.type = type; - children = new ArrayList<>(); - } - - /** - * Add a an "atom" child to a token - * @param child the child to add - * @return the token (for chaining) - */ - public Token add(final String child) { - children.add(child); - return this; - } - - /** - * Add a child to a token - * @param child the child - * @return the token (for chaining) - */ - public Token add(final Token child) { - if (child != null) { - children.add(child); - child.setParent(this); - } - return this; - } - - /** - * Remove a child from a token - * @param child the child to remove - * @return true if successful - */ - public boolean remove(final Token child) { - return children.remove(child); - } - - /** - * Remove the last child from a token - * @return the removed child - */ - public Object removeLast() { - return children.remove(children.size() - 1); - } - - /** - * Flag this token as dead code - * @param isDead is it dead or not - */ - private void setIsDead(final boolean isDead) { - this.isDead = isDead; - } - - /** - * Is this token dead code - * @return boolean - */ - private boolean getIsDead() { - return isDead; - } - - /** - * Get the parent of this token - * @return parent token - */ - public Token getParent() { - return parent; - } - - public boolean hasParentOfType(final Token.Type parentType) { - for (Token p = getParent(); p != null; p = p.getParent()) { - if (p.getType() == parentType) { - return true; - } - } - return false; - } - - public boolean hasChildOfType(final Token.Type childType) { - for (final Iterator iter = iterator() ; iter.hasNext() ; ) { - if (iter.next().getType() == childType) { - return true; - } - } - return false; - } - - /** - * Set the parent of this token - * @param parent - */ - private void setParent(final Token parent) { - this.parent = parent; - } - - /** - * Get the children of this token - * @return an array of children, never null - */ - public Object[] getChildren() { - return children.toArray(); - } - - /** - * Reset this token, remove all children - */ - public void reset() { - children.clear(); - } - - /** - * Get a preorder token iterator with this token as root - * @return an iterator - */ - public Iterator iterator() { - return new TokenIterator(this); - } - - /** - * Get the type of this token - * @return type - */ - public Type getType() { - return type; - } - - /** - * Turn this token into Java regexp compatible text - * @return part of a java regexp - */ - @Override - public String toString() { - ToString t = toStringMap.get(getType()); - if (t == null) { - t = DEFAULT_TOSTRING; - } - return t.toString(this); - } } /** @@ -437,13 +101,11 @@ return; } - for (final Map.Entry fwdRef : forwardReferences.entrySet()) { - if (fwdRef.getKey().intValue() > caps.size()) { + for (final Integer ref : forwardReferences) { + if (ref.intValue() > caps.size()) { neverMatches = true; break; } - - fwdRef.getValue().setIsDead(true); } forwardReferences.clear(); @@ -459,12 +121,10 @@ public static RegExpScanner scan(final String string) { final RegExpScanner scanner = new RegExpScanner(string); - Token pattern; - try { - pattern = scanner.pattern(); + scanner.disjunction(); } catch (final Exception e) { - throw new PatternSyntaxException(e.getMessage(), string, scanner.sb.length()); + throw new PatternSyntaxException(e.getMessage(), string, scanner.position); } scanner.processForwardReferences(); @@ -472,24 +132,12 @@ return null; // never matches } - // go over the code and remove dead code - final Iterator iter = pattern.iterator(); - while (iter.hasNext()) { - final Token next = iter.next(); - if (next.getIsDead()) { - next.getParent().remove(next); - } - } - - // turn the pattern into a string, p, the java equivalent string for our js regexp - final String p = pattern.toString(); - // if builder contains all tokens that were sent in, we know - // we correctly parsed the entire JavaScript regexp without syntax errors - if (!string.equals(scanner.getStringBuilder().toString())) { + // Throw syntax error unless we parsed the entire JavaScript regexp without syntax errors + if (scanner.position != string.length()) { + final String p = scanner.getStringBuilder().toString(); throw new PatternSyntaxException(string, p, p.length() + 1); } - scanner.javaPattern = p; return scanner; } @@ -508,7 +156,7 @@ } String getJavaPattern() { - return javaPattern; + return sb.toString(); } BitVector getGroupsInNegativeLookahead() { @@ -527,11 +175,10 @@ /** * Commit n characters to the builder and to a given token - * @param token Uncommitted token. * @param n Number of characters. * @return Committed token */ - private Token commit(final Token token, final int n) { + private boolean commit(final int n) { final int startIn = position; switch (n) { @@ -554,11 +201,7 @@ assert false : "Should not reach here"; } - if (token == null) { - return null; - } - - return token.add(sb.substring(startIn, sb.length())); + return true; } /** @@ -587,35 +230,20 @@ */ /* - * Pattern :: - * Disjunction - */ - private Token pattern() { - final Token token = new Token(Token.Type.PATTERN); - - final Token child = disjunction(); - return token.add(child); - } - - /* * Disjunction :: * Alternative * Alternative | Disjunction */ - private Token disjunction() { - final Token token = new Token(Token.Type.DISJUNCTION); - + private void disjunction() { while (true) { - token.add(alternative()); + alternative(); if (ch0 == '|') { - commit(token, 1); + commit(1); } else { break; } } - - return token; } /* @@ -623,15 +251,10 @@ * [empty] * Alternative Term */ - private Token alternative() { - final Token token = new Token(Token.Type.ALTERNATIVE); - - Token child; - while ((child = term()) != null) { - token.add(child); + private void alternative() { + while (term()) { + // do nothing } - - return token; } /* @@ -640,48 +263,37 @@ * Atom * Atom Quantifier */ - private Token term() { + private boolean term() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.TERM); - Token child; - child = assertion(); - if (child != null) { - return token.add(child); + if (assertion()) { + return true; } - child = atom(); - if (child != null) { + if (atom()) { boolean emptyCharacterClass = false; - if ("[]".equals(child.toString())) { + if (sb.toString().endsWith("[]")) { emptyCharacterClass = true; + } else if (sb.toString().endsWith("[^]")) { + sb.setLength(sb.length() - 2); + sb.append("\\s\\S]"); } - token.add(child); - - final Token quantifier = quantifier(); - if (quantifier != null) { - token.add(quantifier); - } + boolean quantifier = quantifier(); if (emptyCharacterClass) { - if (quantifier == null) { + if (!quantifier) { neverMatches = true; //never matches ever. - } else { - //if we can get away with max zero, remove this entire token - final String qs = quantifier.toString(); - if ("+".equals(qs) || "*".equals(qs) || qs.startsWith("{0,")) { - token.setIsDead(true); - } } + // Note: we could check if quantifier has min zero to mark empty character class as dead. } - return token; + return true; } restart(startIn, startOut); - return null; + return false; } /* @@ -693,19 +305,18 @@ * ( ? = Disjunction ) * ( ? ! Disjunction ) */ - private Token assertion() { + private boolean assertion() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.ASSERTION); switch (ch0) { case '^': case '$': - return commit(token, 1); + return commit(1); case '\\': if (ch1 == 'b' || ch1 == 'B') { - return commit(token, 2); + return commit(2); } break; @@ -717,24 +328,18 @@ break; } final boolean isNegativeLookahead = (ch2 == '!'); - commit(token, 3); + commit(3); if (isNegativeLookahead) { negativeLookaheadLevel++; } - final Token disjunction = disjunction(); + disjunction(); if (isNegativeLookahead) { - for (final Capture cap : caps) { - if (cap.getNegativeLookaheadLevel() >= negativeLookaheadLevel) { - cap.setDead(); - } - } negativeLookaheadLevel--; } - if (disjunction != null && ch0 == ')') { - token.add(disjunction); - return commit(token, 1); + if (ch0 == ')') { + return commit(1); } break; @@ -743,8 +348,7 @@ } restart(startIn, startOut); - - return null; + return false; } /* @@ -752,17 +356,14 @@ * QuantifierPrefix * QuantifierPrefix ? */ - private Token quantifier() { - final Token token = new Token(Token.Type.QUANTIFIER); - final Token child = quantifierPrefix(); - if (child != null) { - token.add(child); + private boolean quantifier() { + if (quantifierPrefix()) { if (ch0 == '?') { - commit(token, 1); + commit(1); } - return token; + return true; } - return null; + return false; } /* @@ -774,45 +375,42 @@ * { DecimalDigits , } * { DecimalDigits , DecimalDigits } */ - private Token quantifierPrefix() { + private boolean quantifierPrefix() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.QUANTIFIER_PREFIX); switch (ch0) { case '*': case '+': case '?': - return commit(token, 1); + return commit(1); case '{': - commit(token, 1); + commit(1); - final Token child = decimalDigits(); - if (child == null) { + if (!decimalDigits()) { break; // not a quantifier - back out } push('}'); - token.add(child); if (ch0 == ',') { - commit(token, 1); - token.add(decimalDigits()); + commit(1); + decimalDigits(); } if (ch0 == '}') { pop('}'); - commit(token, 1); + commit(1); } - return token; + return true; default: break; } restart(startIn, startOut); - return null; + return false; } /* @@ -825,81 +423,51 @@ * ( ? : Disjunction ) * */ - private Token atom() { + private boolean atom() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.ATOM); - Token child; - child = patternCharacter(); - if (child != null) { - return token.add(child); + if (patternCharacter()) { + return true; } if (ch0 == '.') { - return commit(token, 1); + return commit(1); } if (ch0 == '\\') { - commit(token, 1); - child = atomEscape(); - - if (child != null) { - if (child.hasChildOfType(Token.Type.IDENTITY_ESCAPE)) { - final char idEscape = child.toString().charAt(0); - if (NON_IDENT_ESCAPES.indexOf(idEscape) == -1) { - token.reset(); - } - } - - token.add(child); + commit(1); - // forward backreferences always match empty. JavaScript != Java - if (child.hasChildOfType(Token.Type.DECIMAL_ESCAPE) && !"\u0000".equals(child.toString())) { - final int refNum = Integer.parseInt(child.toString()); - - if (refNum - 1 < caps.size() && caps.get(refNum - 1).isDead()) { - // reference to dead in-negative-lookahead capture - token.setIsDead(true); - } else if (caps.size() < refNum) { - // forward reference: always matches against empty string (dead token). - // invalid reference (non-existant capture): pattern never matches. - forwardReferences.put(refNum, token); - } - } - - return token; + if (atomEscape()) { + return true; } } - child = characterClass(); - if (child != null) { - return token.add(child); + if (characterClass()) { + return true; } if (ch0 == '(') { boolean capturingParens = true; - commit(token, 1); + commit(1); if (ch0 == '?' && ch1 == ':') { capturingParens = false; - commit(token, 2); + commit(2); } - child = disjunction(); - if (child != null) { - token.add(child); - if (ch0 == ')') { - final Token atom = commit(token, 1); - if (capturingParens) { - caps.add(new Capture(negativeLookaheadLevel)); - } - return atom; + disjunction(); + + if (ch0 == ')') { + commit(1); + if (capturingParens) { + caps.add(new Capture(negativeLookaheadLevel)); } + return true; } } restart(startIn, startOut); - return null; + return false; } /* @@ -907,9 +475,9 @@ * SourceCharacter but not any of: ^$\.*+?()[]{}| */ @SuppressWarnings("fallthrough") - private Token patternCharacter() { + private boolean patternCharacter() { if (atEOF()) { - return null; + return false; } switch (ch0) { @@ -924,23 +492,26 @@ case ')': case '[': case '|': - return null; + return false; case '}': case ']': final int n = expected.get(ch0); if (n != 0) { - return null; + return false; } case '{': // if not a valid quantifier escape curly brace to match itself // this ensures compatibility with other JS implementations - final Token quant = quantifierPrefix(); - return (quant == null) ? commit(new Token(Token.Type.PATTERN_CHARACTER).add("\\"), 1) : null; + if (!quantifierPrefix()) { + sb.append('\\'); + return commit(1); + } + return false; default: - return commit(new Token(Token.Type.PATTERN_CHARACTER), 1); // SOURCECHARACTER + return commit(1); // SOURCECHARACTER } } @@ -950,27 +521,9 @@ * CharacterEscape * CharacterClassEscape */ - private Token atomEscape() { - final Token token = new Token(Token.Type.ATOM_ESCAPE); - Token child; - - child = decimalEscape(); - if (child != null) { - return token.add(child); - } - - child = characterClassEscape(); - if (child != null) { - return token.add(child); - } - - child = characterEscape(); - if (child != null) { - return token.add(child); - } - - - return null; + private boolean atomEscape() { + // Note that contrary to ES 5.1 spec we put identityEscape() last because it acts as a catch-all + return decimalEscape() || characterClassEscape() || characterEscape() || identityEscape(); } /* @@ -981,48 +534,31 @@ * UnicodeEscapeSequence * IdentityEscape */ - private Token characterEscape() { + private boolean characterEscape() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.CHARACTER_ESCAPE); - Token child; - - child = controlEscape(); - if (child != null) { - return token.add(child); + if (controlEscape()) { + return true; } if (ch0 == 'c') { - commit(token, 1); - child = controlLetter(); - if (child != null) { - return token.add(child); + commit(1); + if (controlLetter()) { + return true; } restart(startIn, startOut); } - child = hexEscapeSequence(); - if (child != null) { - return token.add(child); - } - - child = unicodeEscapeSequence(); - if (child != null) { - return token.add(child); - } - - child = identityEscape(); - if (child != null) { - return token.add(child); + if (hexEscapeSequence() || unicodeEscapeSequence()) { + return true; } restart(startIn, startOut); - - return null; + return false; } - private boolean scanEscapeSequence(final char leader, final int length, final Token token) { + private boolean scanEscapeSequence(final char leader, final int length) { final int startIn = position; final int startOut = sb.length(); @@ -1030,11 +566,11 @@ return false; } - commit(token, 1); + commit(1); for (int i = 0; i < length; i++) { final char ch0l = Character.toLowerCase(ch0); if ((ch0l >= 'a' && ch0l <= 'f') || isDecimalDigit(ch0)) { - commit(token, 1); + commit(1); } else { restart(startIn, startOut); return false; @@ -1044,37 +580,29 @@ return true; } - private Token hexEscapeSequence() { - final Token token = new Token(Token.Type.HEX_ESCAPESEQUENCE); - if (scanEscapeSequence('x', 2, token)) { - return token; - } - return null; + private boolean hexEscapeSequence() { + return scanEscapeSequence('x', 2); } - private Token unicodeEscapeSequence() { - final Token token = new Token(Token.Type.UNICODE_ESCAPESEQUENCE); - if (scanEscapeSequence('u', 4, token)) { - return token; - } - return null; + private boolean unicodeEscapeSequence() { + return scanEscapeSequence('u', 4); } /* * ControlEscape :: * one of fnrtv */ - private Token controlEscape() { + private boolean controlEscape() { switch (ch0) { case 'f': case 'n': case 'r': case 't': case 'v': - return commit(new Token(Token.Type.CONTROL_ESCAPE), 1); + return commit(1); default: - return null; + return false; } } @@ -1083,19 +611,18 @@ * one of abcdefghijklmnopqrstuvwxyz * ABCDEFGHIJKLMNOPQRSTUVWXYZ */ - private Token controlLetter() { + private boolean controlLetter() { final char c = Character.toUpperCase(ch0); if (c >= 'A' && c <= 'Z') { - final Token token = new Token(Token.Type.CONTROL_LETTER); - commit(token, 1); - return token; + // for some reason java regexps don't like control characters on the + // form "\\ca".match([string with ascii 1 at char0]). Translating + // them to unicode does it though. + sb.setLength(sb.length() - 1); + unicode(c - 'A' + 1); + skip(1); + return true; } - return null; - /* - Token token = new Token(Token.Type.CONTROL_LETTER); - commit(null, 1);//add original char to builder not to token - this.neverMatches = c < 'A' || c > 'Z'; - return token.add(""+c);*/ + return false; } /* @@ -1104,56 +631,115 @@ * (200c) * (200d) */ - private Token identityEscape() { - final Token token = new Token(Token.Type.IDENTITY_ESCAPE); - commit(token, 1); - return token; + private boolean identityEscape() { + if (atEOF()) { + throw new RuntimeException("\\ at end of pattern"); // will be converted to PatternSyntaxException + } + // ES 5.1 A.7 requires "not IdentifierPart" here but all major engines accept any character here. + if (NON_IDENT_ESCAPES.indexOf(ch0) == -1) { + sb.setLength(sb.length() - 1); + } + return commit(1); } /* * DecimalEscape :: * DecimalIntegerLiteral [lookahead DecimalDigit] */ - private Token decimalEscape() { - final Token token = new Token(Token.Type.DECIMAL_ESCAPE); + private boolean decimalEscape() { final int startIn = position; final int startOut = sb.length(); if (ch0 == '0' && !isDecimalDigit(ch1)) { - commit(token, 1); - token.removeLast(); + skip(1); // DecimalEscape :: 0. If i is zero, return the EscapeValue consisting of a character (Unicodevalue0000); - return token.add("\u0000"); + sb.append("\u0000"); + return true; } if (isDecimalDigit(ch0)) { - while (isDecimalDigit(ch0)) { - commit(token, 1); + final int num = ch0 - '0'; + + // Single digit escape, treat as backreference. + if (!isDecimalDigit(ch1)) { + if (num <= caps.size() && caps.get(num - 1).getNegativeLookaheadLevel() > 0) { + // Captures that live inside a negative lookahead are dead after the + // lookahead and will be undefined if referenced from outside. + if (caps.get(num - 1).getNegativeLookaheadLevel() > negativeLookaheadLevel) { + sb.setLength(sb.length() - 1); + } else { + sb.append(ch0); + } + skip(1); + return true; + } else if (num > caps.size()) { + // Forward reference to a capture group. Forward references are always undefined so we + // can omit it from the output buffer. Additionally, if the capture group does not exist + // the whole regexp becomes invalid, so register the reference for later processing. + forwardReferences.add(num); + sb.setLength(sb.length() - 1); + skip(1); + return true; + } } - return token; + + if (inCharClass) { + // Convert octal escape to unicode escape if inside character class. + StringBuilder digit = new StringBuilder(4); + while (isDecimalDigit(ch0)) { + digit.append(ch0); + skip(1); + } + + int value = Integer.parseInt(digit.toString(), 8); //throws exception that leads to SyntaxError if not octal + if (value > 0xff) { + throw new NumberFormatException(digit.toString()); + } + + unicode(value); + + } else { + // Copy decimal escape as-is + decimalDigits(); + } + return true; } restart(startIn, startOut); - - return null; + return false; } /* * CharacterClassEscape :: * one of dDsSwW */ - private Token characterClassEscape() { + private boolean characterClassEscape() { switch (ch0) { + // java.util.regex requires translation of \s and \S to explicit character list case 's': + if (RegExpFactory.usesJavaUtilRegex()) { + sb.setLength(sb.length() - 1); + sb.append('[').append(Lexer.getWhitespaceRegExp()).append(']'); + skip(1); + return true; + } + return commit(1); case 'S': + if (RegExpFactory.usesJavaUtilRegex()) { + sb.setLength(sb.length() - 1); + sb.append("[^").append(Lexer.getWhitespaceRegExp()).append(']'); + skip(1); + return true; + } + return commit(1); case 'd': case 'D': case 'w': case 'W': - return commit(new Token(Token.Type.CHARACTERCLASS_ESCAPE), 1); + return commit(1); default: - return null; + return false; } } @@ -1162,29 +748,31 @@ * [ [lookahead {^}] ClassRanges ] * [ ^ ClassRanges ] */ - private Token characterClass() { + private boolean characterClass() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.CHARACTERCLASS); if (ch0 == '[') { - push(']'); - commit(token, 1); + try { + inCharClass = true; + push(']'); + commit(1); - if (ch0 == '^') { - commit(token, 1); - } + if (ch0 == '^') { + commit(1); + } - final Token child = classRanges(); - if (child != null && ch0 == ']') { - pop(']'); - token.add(child); - return commit(token, 1); + if (classRanges() && ch0 == ']') { + pop(']'); + return commit(1); + } + } finally { + inCharClass = false; // no nested character classes in JavaScript } } restart(startIn, startOut); - return null; + return false; } /* @@ -1192,8 +780,9 @@ * [empty] * NonemptyClassRanges */ - private Token classRanges() { - return new Token(Token.Type.CLASSRANGES).add(nonemptyClassRanges()); + private boolean classRanges() { + nonemptyClassRanges(); + return true; } /* @@ -1202,40 +791,27 @@ * ClassAtom NonemptyClassRangesNoDash * ClassAtom - ClassAtom ClassRanges */ - private Token nonemptyClassRanges() { + private boolean nonemptyClassRanges() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.NON_EMPTY_CLASSRANGES); - Token child; - child = classAtom(); - if (child != null) { - token.add(child); + if (classAtom()) { if (ch0 == '-') { - commit(token, 1); + commit(1); - final Token child1 = classAtom(); - final Token child2 = classRanges(); - if (child1 != null && child2 != null) { - token.add(child1); - token.add(child2); - - return token; + if (classAtom() && classRanges()) { + return true; } } - child = nonemptyClassRangesNoDash(); - if (child != null) { - token.add(child); - return token; - } + nonemptyClassRangesNoDash(); - return token; + return true; } restart(startIn, startOut); - return null; + return false; } /* @@ -1244,61 +820,44 @@ * ClassAtomNoDash NonemptyClassRangesNoDash * ClassAtomNoDash - ClassAtom ClassRanges */ - private Token nonemptyClassRangesNoDash() { + private boolean nonemptyClassRangesNoDash() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.NON_EMPTY_CLASSRANGES_NODASH); - Token child; - child = classAtomNoDash(); - if (child != null) { - token.add(child); + if (classAtomNoDash()) { // need to check dash first, as for e.g. [a-b|c-d] will otherwise parse - as an atom if (ch0 == '-') { - commit(token, 1); + commit(1); - final Token child1 = classAtom(); - final Token child2 = classRanges(); - if (child1 != null && child2 != null) { - token.add(child1); - return token.add(child2); + if (classAtom() && classRanges()) { + return true; } //fallthru } - child = nonemptyClassRangesNoDash(); - if (child != null) { - token.add(child); - } - return token; // still a class atom + nonemptyClassRangesNoDash(); + return true; // still a class atom } - child = classAtom(); - if (child != null) { - return token.add(child); + if (classAtom()) { + return true; } restart(startIn, startOut); - return null; + return false; } /* * ClassAtom : - ClassAtomNoDash */ - private Token classAtom() { - final Token token = new Token(Token.Type.CLASSATOM); + private boolean classAtom() { if (ch0 == '-') { - return commit(token, 1); + return commit(1); } - final Token child = classAtomNoDash(); - if (child != null) { - return token.add(child); - } - - return null; + return classAtomNoDash(); } /* @@ -1306,33 +865,32 @@ * SourceCharacter but not one of \ or ] or - * \ ClassEscape */ - private Token classAtomNoDash() { + private boolean classAtomNoDash() { final int startIn = position; final int startOut = sb.length(); - final Token token = new Token(Token.Type.CLASSATOM_NODASH); switch (ch0) { case ']': case '-': case '\0': - return null; + return false; case '[': // unescaped left square bracket - add escape - return commit(token.add("\\"), 1); + sb.append('\\'); + return commit(1); case '\\': - commit(token, 1); - final Token child = classEscape(); - if (child != null) { - return token.add(child); + commit(1); + if (classEscape()) { + return true; } restart(startIn, startOut); - return null; + return false; default: - return commit(token, 1); + return commit(1); } } @@ -1343,46 +901,45 @@ * CharacterEscape * CharacterClassEscape */ - private Token classEscape() { - final Token token = new Token(Token.Type.CLASS_ESCAPE); - Token child; + private boolean classEscape() { - child = decimalEscape(); - if (child != null) { - return token.add(child); + if (decimalEscape()) { + return true; } if (ch0 == 'b') { - return commit(token, 1); + sb.setLength(sb.length() - 1); + sb.append('\b'); + skip(1); + return true; } - child = characterEscape(); - if (child != null) { - return token.add(child); - } - - child = characterClassEscape(); - if (child != null) { - return token.add(child); - } - - return null; + // Note that contrary to ES 5.1 spec we put identityEscape() last because it acts as a catch-all + return characterEscape() || characterClassEscape() || identityEscape(); } /* * DecimalDigits */ - private Token decimalDigits() { + private boolean decimalDigits() { if (!isDecimalDigit(ch0)) { - return null; + return false; + } + + while (isDecimalDigit(ch0)) { + commit(1); } - final Token token = new Token(Token.Type.DECIMALDIGITS); - while (isDecimalDigit(ch0)) { - commit(token, 1); + return true; + } + + private void unicode(final int value) { + final String hex = Integer.toHexString(value); + sb.append('u'); + for (int i = 0; i < 4 - hex.length(); i++) { + sb.append('0'); } - - return token; + sb.append(hex); } private static boolean isDecimalDigit(final char ch) { diff -r 5ddfc1208ef3 -r 8cfcd914d26d nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Wed Feb 27 14:12:45 2013 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Sat Mar 02 11:26:47 2013 -0400 @@ -219,7 +219,7 @@ } /** - * @see [http://www.geocities.jp/kosako3/oniguruma/doc/RE.txt] + * @see http://www.geocities.jp/kosako3/oniguruma/doc/RE.txt */ public static boolean isCodeCType(int code, int ctype) { int type;