diff --git a/make/build.xml b/make/build.xml index 9df9d89fccbd4eb009a349665be3bfd561f343a7..34f56e4602b5f74ef1c23309c16cbc32f40ed5f5 100644 --- a/make/build.xml +++ b/make/build.xml @@ -21,7 +21,7 @@ or visit www.oracle.com if you need additional information or have any questions. --> - + diff --git a/make/project.properties b/make/project.properties index 0d85d02942b46e3053d247db008ca8328cfe9406..c4d0b943cd764fe29d1ee59c53cd0fa920c4b805 100644 --- a/make/project.properties +++ b/make/project.properties @@ -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 --git a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java index 8fc76f049af4221523c22306f587f787dde4b543..702c1509fd484996fab360c9adf9f49437c3ee4a 100644 --- a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java +++ b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java @@ -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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { // 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { } } + 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 --git a/src/jdk/internal/dynalink/beans/BeansLinker.java b/src/jdk/internal/dynalink/beans/BeansLinker.java index 706d89f07c99e4d62291dd8e6e023ce2ed9fa215..85811235699dc842d8abd3b492a09dbb186f991c 100644 --- a/src/jdk/internal/dynalink/beans/BeansLinker.java +++ b/src/jdk/internal/dynalink/beans/BeansLinker.java @@ -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 @@ import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; *
    *
  • 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 --git a/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/src/jdk/nashorn/internal/codegen/ClassEmitter.java index 3b6433dd83b41970cf4d4b30c6a196016a348357..f99d8af1b54e9d56e504297dfbc2d0889bdd0b24 100644 --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java @@ -95,7 +95,7 @@ import jdk.nashorn.internal.runtime.Source; *

    * 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 --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 380ecaff57d841c747355d3b27c73f1149a11e89..2ffb5bd887db81fdc1b572e2f6663e6e5444206d 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -46,7 +46,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; 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 @@ final class CodeGenerator extends NodeOperatorVisitor { 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 --git a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java index e70d295289595a49ec15d1e174a536aae3d9eb79..c0308b6ee531aa103be36727f496be855ee1ab50 100644 --- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java +++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java @@ -112,7 +112,7 @@ public final class ObjectClassGenerator { 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 @@ public final class ObjectClassGenerator { /** * 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 --git a/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java b/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java index efa8e141590181770c02d1a054ef7f5479864c35..116bdd61364c73510c8c117ba62496769620a706 100644 --- a/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java +++ b/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java @@ -459,120 +459,120 @@ public final class RuntimeCallSite extends MutableCallSite { } /** - * 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 --git a/src/jdk/nashorn/internal/ir/Assignment.java b/src/jdk/nashorn/internal/ir/Assignment.java index 142a7062d4c15f457df694f31f727c25d930c2df..8107a8725f096d41e99a7058c3e051160b388b55 100644 --- a/src/jdk/nashorn/internal/ir/Assignment.java +++ b/src/jdk/nashorn/internal/ir/Assignment.java @@ -46,18 +46,4 @@ public interface Assignment { * @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 --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java index d1db336d8a44c5f73e9e41b95c8dd65cf75cfb47..26964ba5ca5f529132005561fe2eb4fa40525ed0 100644 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java @@ -139,21 +139,11 @@ public class BinaryNode extends UnaryNode { return isAssignment() ? lhs() : null; } - @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)) { diff --git a/src/jdk/nashorn/internal/ir/RuntimeNode.java b/src/jdk/nashorn/internal/ir/RuntimeNode.java index 474da4998e4f2483e521f7621b0af244ab30dbc6..bfc47d1871aa0f468d9ee6b49d15327e7a027c78 100644 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java @@ -64,17 +64,17 @@ public class RuntimeNode extends Node implements TypeOverride { 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 @@ public class RuntimeNode extends Node implements TypeOverride { /** * If this request can be reversed, return the reverse request - * Eq EQ -> NE. + * Eq EQ {@literal ->} NE. * * @param request request to reverse * diff --git a/src/jdk/nashorn/internal/ir/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java index 99a749903e17b6403667a0bad56ef68f2382e55d..7b608edf7ac488612630c5c8660e3da05094f16a 100644 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java @@ -108,16 +108,6 @@ public class UnaryNode extends Node implements Assignment { return getAssignmentDest(); } - @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)) { diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java index 82ab493fc36fb9d40853ff06534a840c89f37298..07b6f8eca50fe4a1ae86139278eecceb4e6894b9 100644 --- a/src/jdk/nashorn/internal/ir/VarNode.java +++ b/src/jdk/nashorn/internal/ir/VarNode.java @@ -82,21 +82,11 @@ public class VarNode extends Node implements Assignment { return isAssignment() ? name : null; } - @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 --git a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java index b4ffe6c09b59fd7373f22e48502719bffc50a33c..6856282e0690753d6a766668fe7ee73d3c746146 100644 --- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java +++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java @@ -542,7 +542,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering && operator + * Binary enter - callback for entering {@literal &&} operator * * @param binaryNode the node * @return processed node @@ -552,7 +552,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering &= operator + * Binary enter - callback for entering {@literal &=} operator * * @param binaryNode the node * @return processed node @@ -612,7 +612,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering >>= operator + * Binary enter - callback for entering {@literal >>=} operator * * @param binaryNode the node * @return processed node @@ -732,7 +732,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering >>>= operator + * Binary enter - callback for entering {@literal >>>=} operator * * @param binaryNode the node * @return processed node @@ -772,7 +772,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering & operator + * Binary enter - callback for entering {@literal &} operator * * @param binaryNode the node * @return processed node @@ -832,7 +832,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering >= operator + * Binary enter - callback for entering {@literal >=} operator * * @param binaryNode the node * @return processed node @@ -996,7 +996,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering > operator + * Binary enter - callback for entering {@literal >} operator * * @param binaryNode the node * @return processed node @@ -1016,7 +1016,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering <= operator + * Binary enter - callback for entering {@literal <=} operator * * @param binaryNode the node * @return processed node @@ -1076,7 +1076,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering < operator + * Binary enter - callback for entering {@literal <} operator * * @param binaryNode the node * @return processed node @@ -1096,7 +1096,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering >> operator + * Binary enter - callback for entering {@literal >>} operator * * @param binaryNode the node * @return processed node @@ -1215,7 +1215,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * Binary enter - callback for entering << operator + * Binary enter - callback for entering {@literal <<} operator * * @param binaryNode the node * @return processed node @@ -1235,7 +1235,7 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 @@ public class NodeOperatorVisitor extends NodeVisitor { 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 @@ public class NodeOperatorVisitor extends NodeVisitor { } /** - * 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 --git a/src/jdk/nashorn/internal/objects/DateParser.java b/src/jdk/nashorn/internal/objects/DateParser.java index db0f74d0ccb0f9c8fc2d0f93119fb8fd8473ccb7..544525b1de101791d4a34c2978ca362e72a5618e 100644 --- a/src/jdk/nashorn/internal/objects/DateParser.java +++ b/src/jdk/nashorn/internal/objects/DateParser.java @@ -221,7 +221,7 @@ public class DateParser { * *

    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 --git a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index edef6241a0fdeb7b6e8e593f877d485219014c19..1a2b2769df28635e39ac42ae614e1819df508f0b 100644 --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -74,13 +74,16 @@ import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; * 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 --git a/src/jdk/nashorn/internal/objects/NativeJava.java b/src/jdk/nashorn/internal/objects/NativeJava.java
    index c50a568779f3c9712d1b2ae7479fe837562fc7a2..fc16962e1853e83302fa19b1d6988ef2bc1ca63f 100644
    --- a/src/jdk/nashorn/internal/objects/NativeJava.java
    +++ b/src/jdk/nashorn/internal/objects/NativeJava.java
    @@ -65,6 +65,7 @@ public final class NativeJava {
         }
     
         /**
    +     * 

    * 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 @@ public final class NativeJava { * 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 @@ public final class NativeJava {
          * 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 @@ public final class NativeJava {
          *     }
          * }
          * 
    + *

    * 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 @@ public final class NativeJava {
          * 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 @@ public final class NativeJava {
          * 
  • 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 --git a/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/src/jdk/nashorn/internal/runtime/CodeInstaller.java index 4622f3f0121670c67d1804848d1c95537a672a5f..5fd16528e22c82c56704b3cf4f5a8608fe3419ca 100644 --- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java +++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java @@ -30,7 +30,7 @@ package jdk.nashorn.internal.runtime; * 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 --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index 9145d9fc294e2fc7e84e3925b7bdf15971f68d28..7e5d48b52156d1815dbea6f95c46ff1639a1dd08 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -509,7 +509,7 @@ public final class Context { * * @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 @@ public final class Context { * * @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 --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 45ed7f436b21ee40f369500bed3d021e4cd5cc85..c95471d6d2b0207a13bc3157f941913e6b9be98c 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -1463,7 +1463,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } /** - * 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 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * 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 --git a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index c6f5167c78aadd4e9173c8105a7cbc10ab0e7e81..216b381c41b409364a6ae4e83c5e12ed074fb480 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -815,7 +815,7 @@ public final class ScriptRuntime { } /** - * 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 @@ public final class ScriptRuntime { } /** - * 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 @@ public final class ScriptRuntime { } /** - * 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 @@ public final class ScriptRuntime { } /** - * 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 --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index 190ada59d8250743f9646deb8757a2efb9a671fd..b5305d97b5b38bf420011e98d06716217de3a6f1 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -87,7 +87,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; 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 --git a/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java index a4fbc0740c3b294f676d83ae322beacc9f5fc9b9..a2513912441ca7185cf7b62705d35204f3d94a02 100644 --- a/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java +++ b/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java @@ -43,8 +43,6 @@ public class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor { 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 @@ public class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor { /** * 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 --git a/src/jdk/nashorn/internal/runtime/options/Options.java b/src/jdk/nashorn/internal/runtime/options/Options.java index 7cca54122df6e25f1cc3f198d32f31477b62649c..0f30b1a171da53f96e44e3e790e64109a988147e 100644 --- a/src/jdk/nashorn/internal/runtime/options/Options.java +++ b/src/jdk/nashorn/internal/runtime/options/Options.java @@ -200,7 +200,7 @@ public final class Options { /** * 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 --git a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java index 918ec20f30c4cc929c881a06665bb0dc4495d1c3..f8c35bfe99ddb6eef0077922ab825f19cdc1f60c 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java +++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java @@ -117,10 +117,6 @@ public class JoniRegExp extends RegExp { return new JoniRegExp(pattern, flags); } - @Override - protected String replaceToken(final String str) { - return str.equals("[^]") ? "[\\s\\S]" : str; - } } class JoniMatcher implements RegExpMatcher { diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java index 2cf65be76be5004b9bbec0dd9323628b4afe2a77..367cc85b28a99a2d7dbabebb0b422d554ba2b435 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java @@ -67,25 +67,6 @@ public class RegExpFactory { return new DefaultRegExp(pattern, flags); } - /** - * 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}. * @@ -98,16 +79,6 @@ public class RegExpFactory { return instance.compile(pattern, flags); } - /** - * 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}. * @@ -120,4 +91,13 @@ public class RegExpFactory { 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 --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java index bad878cd7378d7d43d60fabfd921514c3597234f..55f323dd71b1f0d408ad9fb9e89b85052b9ed523 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java @@ -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 @@ import jdk.nashorn.internal.runtime.BitVector; 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { } String getJavaPattern() { - return javaPattern; + return sb.toString(); } BitVector getGroupsInNegativeLookahead() { @@ -527,11 +175,10 @@ final class RegExpScanner extends Scanner { /** * 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 @@ final class RegExpScanner extends Scanner { assert false : "Should not reach here"; } - if (token == null) { - return null; - } - - return token.add(sb.substring(startIn, sb.length())); + return true; } /** @@ -586,36 +229,21 @@ final class RegExpScanner extends Scanner { * Recursive descent tokenizer starts below. */ - /* - * 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 @@ final class RegExpScanner extends Scanner { * [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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { * ( ? = 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { } restart(startIn, startOut); - - return null; + return false; } /* @@ -752,17 +356,14 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { * { 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 @@ final class RegExpScanner extends Scanner { * ( ? : 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(); - } - } + commit(1); - token.add(child); - - // 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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { 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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { * (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 @@ final class RegExpScanner extends Scanner { * [ [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 @@ final class RegExpScanner extends Scanner { * [empty] * NonemptyClassRanges */ - private Token classRanges() { - return new Token(Token.Type.CLASSRANGES).add(nonemptyClassRanges()); + private boolean classRanges() { + nonemptyClassRanges(); + return true; } /* @@ -1202,40 +791,27 @@ final class RegExpScanner extends Scanner { * 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); - - final Token child1 = classAtom(); - final Token child2 = classRanges(); - if (child1 != null && child2 != null) { - token.add(child1); - token.add(child2); + commit(1); - 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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { * 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 @@ final class RegExpScanner extends Scanner { * 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); - } - - child = characterEscape(); - if (child != null) { - return token.add(child); - } - - child = characterClassEscape(); - if (child != null) { - return token.add(child); + sb.setLength(sb.length() - 1); + sb.append('\b'); + skip(1); + return true; } - 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; } - final Token token = new Token(Token.Type.DECIMALDIGITS); while (isDecimalDigit(ch0)) { - commit(token, 1); + commit(1); } - return token; + 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'); + } + sb.append(hex); } private static boolean isDecimalDigit(final char ch) { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java b/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java index 04d67c2e17731ecb5cce51aba8139cd770d854cc..d3e54947aeae2e8f6bb44e3c0ebfbd28949f95db 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java @@ -219,7 +219,7 @@ public class EncodingHelper { } /** - * @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;