diff --git a/modules/lang-painless/src/main/antlr/PainlessLexer.g4 b/modules/lang-painless/src/main/antlr/PainlessLexer.g4 index 6ab6a86113595..fe58984fa8712 100644 --- a/modules/lang-painless/src/main/antlr/PainlessLexer.g4 +++ b/modules/lang-painless/src/main/antlr/PainlessLexer.g4 @@ -19,14 +19,14 @@ lexer grammar PainlessLexer; -@members{ +@members { /** * Check against the current whitelist to determine whether a token is a type * or not. Called by the {@code TYPE} token defined in {@code PainlessLexer.g4}. * See also * The lexer hack. */ -protected abstract boolean isSimpleType(String name); +protected abstract boolean isType(String name); /** * Is the preceding {@code /} a the beginning of a regex (true) or a division @@ -133,7 +133,7 @@ NULL: 'null'; // or not. Note this works by processing one character at a time // and the rule is added or removed as this happens. This is also known // as "the lexer hack." See (https://en.wikipedia.org/wiki/The_lexer_hack). -TYPE: ID ( DOT ID )* { isSimpleType(getText()) }?; +TYPE: ID ( DOT ID )* { isType(getText()) }?; ID: [_a-zA-Z] [_a-zA-Z0-9]*; mode AFTER_DOT; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index 988a31a24ee27..8694ff7903859 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -185,7 +185,7 @@ static Method lookupMethodInternal(Definition definition, Class receiverClass Definition.MethodKey key = new Definition.MethodKey(name, arity); // check whitelist for matching method for (Class clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) { - Struct struct = definition.RuntimeClassToStruct(clazz); + Struct struct = definition.getPainlessStructFromJavaClass(clazz); if (struct != null) { Method method = struct.methods.get(key); @@ -195,7 +195,7 @@ static Method lookupMethodInternal(Definition definition, Class receiverClass } for (Class iface : clazz.getInterfaces()) { - struct = definition.RuntimeClassToStruct(iface); + struct = definition.getPainlessStructFromJavaClass(iface); if (struct != null) { Method method = struct.methods.get(key); @@ -279,7 +279,7 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp captures[capture] = callSiteType.parameterType(i + 1 + capture); } MethodHandle filter; - Definition.Type interfaceType = definition.ClassToType(method.arguments.get(i - 1 - replaced)); + Class interfaceType = method.arguments.get(i - 1 - replaced); if (signature.charAt(0) == 'S') { // the implementation is strongly typed, now that we know the interface type, // we have everything. @@ -293,14 +293,14 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp // the interface type is now known, but we need to get the implementation. // this is dynamically based on the receiver type (and cached separately, underneath // this cache). It won't blow up since we never nest here (just references) - MethodType nestedType = MethodType.methodType(interfaceType.clazz, captures); + MethodType nestedType = MethodType.methodType(interfaceType, captures); CallSite nested = DefBootstrap.bootstrap(definition, lookup, call, nestedType, 0, DefBootstrap.REFERENCE, - interfaceType.name); + Definition.ClassToName(interfaceType)); filter = nested.dynamicInvoker(); } else { throw new AssertionError(); @@ -324,8 +324,8 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp */ static MethodHandle lookupReference(Definition definition, Lookup lookup, String interfaceClass, Class receiverClass, String name) throws Throwable { - Definition.Type interfaceType = definition.getType(interfaceClass); - Method interfaceMethod = interfaceType.struct.functionalMethod; + Class interfaceType = definition.getJavaClassFromPainlessType(interfaceClass); + Method interfaceMethod = definition.getPainlessStructFromJavaClass(interfaceType).functionalMethod; if (interfaceMethod == null) { throw new IllegalArgumentException("Class [" + interfaceClass + "] is not a functional interface"); } @@ -337,15 +337,15 @@ static MethodHandle lookupReference(Definition definition, Lookup lookup, String /** Returns a method handle to an implementation of clazz, given method reference signature. */ private static MethodHandle lookupReferenceInternal(Definition definition, Lookup lookup, - Definition.Type clazz, String type, String call, Class... captures) + Class clazz, String type, String call, Class... captures) throws Throwable { final FunctionRef ref; if ("this".equals(type)) { // user written method - Method interfaceMethod = clazz.struct.functionalMethod; + Method interfaceMethod = definition.getPainlessStructFromJavaClass(clazz).functionalMethod; if (interfaceMethod == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + - "to [" + clazz.name + "], not a functional interface"); + "to [" + Definition.ClassToName(clazz) + "], not a functional interface"); } int arity = interfaceMethod.arguments.size() + captures.length; final MethodHandle handle; @@ -359,14 +359,14 @@ private static MethodHandle lookupReferenceInternal(Definition definition, Looku // because the arity does not match the expected interface type. if (call.contains("$")) { throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name + - "] in [" + clazz.clazz + "]"); + "] in [" + clazz + "]"); } throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments."); } - ref = new FunctionRef(clazz.clazz, interfaceMethod, call, handle.type(), captures.length); + ref = new FunctionRef(clazz, interfaceMethod, call, handle.type(), captures.length); } else { // whitelist lookup - ref = new FunctionRef(definition, clazz.clazz, type, call, captures.length); + ref = new FunctionRef(definition, clazz, type, call, captures.length); } final CallSite callSite = LambdaBootstrap.lambdaBootstrap( lookup, @@ -379,7 +379,7 @@ private static MethodHandle lookupReferenceInternal(Definition definition, Looku ref.delegateMethodType, ref.isDelegateInterface ? 1 : 0 ); - return callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz, captures)); + return callSite.dynamicInvoker().asType(MethodType.methodType(clazz, captures)); } /** gets the field name used to lookup up the MethodHandle for a function. */ @@ -416,7 +416,7 @@ public static String getUserFunctionHandleFieldName(String name, int arity) { static MethodHandle lookupGetter(Definition definition, Class receiverClass, String name) { // first try whitelist for (Class clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) { - Struct struct = definition.RuntimeClassToStruct(clazz); + Struct struct = definition.getPainlessStructFromJavaClass(clazz); if (struct != null) { MethodHandle handle = struct.getters.get(name); @@ -426,7 +426,7 @@ static MethodHandle lookupGetter(Definition definition, Class receiverClass, } for (final Class iface : clazz.getInterfaces()) { - struct = definition.RuntimeClassToStruct(iface); + struct = definition.getPainlessStructFromJavaClass(iface); if (struct != null) { MethodHandle handle = struct.getters.get(name); @@ -487,7 +487,7 @@ static MethodHandle lookupGetter(Definition definition, Class receiverClass, static MethodHandle lookupSetter(Definition definition, Class receiverClass, String name) { // first try whitelist for (Class clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) { - Struct struct = definition.RuntimeClassToStruct(clazz); + Struct struct = definition.getPainlessStructFromJavaClass(clazz); if (struct != null) { MethodHandle handle = struct.setters.get(name); @@ -497,7 +497,7 @@ static MethodHandle lookupSetter(Definition definition, Class receiverClass, } for (final Class iface : clazz.getInterfaces()) { - struct = definition.RuntimeClassToStruct(iface); + struct = definition.getPainlessStructFromJavaClass(iface); if (struct != null) { MethodHandle handle = struct.setters.get(name); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java index 31fba8f757954..9c7c7f631b68d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java @@ -1,7 +1,3 @@ -package org.elasticsearch.painless; - -import org.elasticsearch.common.SuppressForbidden; - /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with @@ -21,6 +17,10 @@ * under the License. */ +package org.elasticsearch.painless; + +import org.elasticsearch.common.SuppressForbidden; + import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -72,16 +72,16 @@ private DefBootstrap() {} // no instance! public static final int SHIFT_OPERATOR = 9; /** static bootstrap parameter indicating a request to normalize an index for array-like-access */ public static final int INDEX_NORMALIZE = 10; - + // constants for the flags parameter of operators - /** - * static bootstrap parameter indicating the binary operator allows nulls (e.g. == and +) + /** + * static bootstrap parameter indicating the binary operator allows nulls (e.g. == and +) *

* requires additional {@link MethodHandles#catchException} guard, which will invoke * the fallback if a null is encountered. */ public static final int OPERATOR_ALLOWS_NULL = 1 << 0; - + /** * static bootstrap parameter indicating the binary operator is part of compound assignment (e.g. +=). *

@@ -89,7 +89,7 @@ private DefBootstrap() {} // no instance! * to cast back to the receiver's type, depending on types seen. */ public static final int OPERATOR_COMPOUND_ASSIGNMENT = 1 << 1; - + /** * static bootstrap parameter indicating an explicit cast to the return type. *

@@ -129,7 +129,7 @@ static final class PIC extends MutableCallSite { setTarget(fallback); } - + /** * guard method for inline caching: checks the receiver's class is the same * as the cached class @@ -162,7 +162,7 @@ private MethodHandle lookup(int flavor, String name, Class receiver) throws T default: throw new AssertionError(); } } - + /** * Creates the {@link MethodHandle} for the megamorphic call site * using {@link ClassValue} and {@link MethodHandles#exactInvoker(MethodType)}: @@ -182,7 +182,7 @@ protected MethodHandle computeValue(Class receiverType) { } }; return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), - MEGAMORPHIC_LOOKUP.bindTo(megamorphicCache)); + MEGAMORPHIC_LOOKUP.bindTo(megamorphicCache)); } /** @@ -195,18 +195,18 @@ Object fallback(final Object[] callArgs) throws Throwable { if (depth >= MAX_DEPTH) { // we revert the whole cache and build a new megamorphic one final MethodHandle target = this.createMegamorphicHandle(); - + setTarget(target); - return target.invokeWithArguments(callArgs); + return target.invokeWithArguments(callArgs); } else { final Class receiver = callArgs[0].getClass(); final MethodHandle target = lookup(flavor, name, receiver).asType(type()); - + MethodHandle test = CHECK_CLASS.bindTo(receiver); MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget()); - + depth++; - + setTarget(guard); return target.invokeWithArguments(callArgs); } @@ -225,7 +225,7 @@ Object fallback(final Object[] callArgs) throws Throwable { MethodType.methodType(Object.class, Object[].class)); MethodHandle mh = publicLookup.findVirtual(ClassValue.class, "get", MethodType.methodType(Object.class, Class.class)); - mh = MethodHandles.filterArguments(mh, 1, + mh = MethodHandles.filterArguments(mh, 1, publicLookup.findVirtual(Object.class, "getClass", MethodType.methodType(Class.class))); MEGAMORPHIC_LOOKUP = mh.asType(mh.type().changeReturnType(MethodHandle.class)); } catch (ReflectiveOperationException e) { @@ -233,7 +233,7 @@ Object fallback(final Object[] callArgs) throws Throwable { } } } - + /** * CallSite that implements the monomorphic inlining cache (for operators). */ @@ -252,14 +252,14 @@ static final class MIC extends MutableCallSite { if (initialDepth > 0) { initialized = true; } - + MethodHandle fallback = FALLBACK.bindTo(this) .asCollector(Object[].class, type.parameterCount()) .asType(type); setTarget(fallback); } - + /** * Does a slow lookup for the operator */ @@ -290,7 +290,7 @@ private MethodHandle lookup(Object[] args) throws Throwable { default: throw new AssertionError(); } } - + private MethodHandle lookupGeneric() { MethodHandle target = DefMath.lookupGeneric(name); if ((flags & OPERATOR_EXPLICIT_CAST) != 0) { @@ -302,7 +302,7 @@ private MethodHandle lookupGeneric() { } return target; } - + /** * Called when a new type is encountered or if cached type does not match. * In that case we revert to a generic, but slower operator handling. @@ -315,7 +315,7 @@ Object fallback(Object[] args) throws Throwable { setTarget(generic.asType(type())); return generic.invokeWithArguments(args); } - + final MethodType type = type(); MethodHandle target = lookup(args); // for math operators: WrongMethodType can be confusing. convert into a ClassCastException if they screw up. @@ -361,18 +361,18 @@ Object fallback(Object[] args) throws Throwable { // very special cases, where even the receiver can be null (see JLS rules for string concat) // we wrap + with an NPE catcher, and use our generic method in that case. if (flavor == BINARY_OPERATOR && (flags & OPERATOR_ALLOWS_NULL) != 0) { - MethodHandle handler = MethodHandles.dropArguments(lookupGeneric().asType(type()), - 0, + MethodHandle handler = MethodHandles.dropArguments(lookupGeneric().asType(type()), + 0, NullPointerException.class); guard = MethodHandles.catchException(guard, NullPointerException.class, handler); } - + initialized = true; setTarget(guard); return target.invokeWithArguments(args); } - + /** * guard method for inline caching: checks the receiver's class is the same * as the cached class @@ -388,7 +388,7 @@ static boolean checkLHS(Class clazz, Object leftObject) { static boolean checkRHS(Class left, Class right, Object leftObject, Object rightObject) { return rightObject.getClass() == right; } - + /** * guard method for inline caching: checks the receiver's class and the first argument * are the same as the cached receiver and first argument. @@ -396,7 +396,7 @@ static boolean checkRHS(Class left, Class right, Object leftObject, Object static boolean checkBoth(Class left, Class right, Object leftObject, Object rightObject) { return leftObject.getClass() == left && rightObject.getClass() == right; } - + private static final MethodHandle CHECK_LHS; private static final MethodHandle CHECK_RHS; private static final MethodHandle CHECK_BOTH; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java index 6628484660699..f903c0571b2bd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java @@ -21,8 +21,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -31,38 +31,38 @@ import java.util.stream.Stream; /** - * Dynamic operators for painless. + * Dynamic operators for painless. *

* Each operator must "support" the following types: - * {@code int,long,float,double,boolean,Object}. Operators can throw exceptions if + * {@code int,long,float,double,boolean,Object}. Operators can throw exceptions if * the type is illegal. The {@code Object} type must be a "generic" handler that * handles all legal types: it must be convertible to every possible legal signature. */ @SuppressWarnings("unused") public class DefMath { - + // Unary not: only applicable to integral types private static int not(int v) { return ~v; } - + private static long not(long v) { return ~v; } - + private static float not(float v) { throw new ClassCastException("Cannot apply not [~] to type [float]"); } - + private static double not(double v) { throw new ClassCastException("Cannot apply not [~] to type [double]"); } - + private static boolean not(boolean v) { throw new ClassCastException("Cannot apply not [~] to type [boolean]"); } - + private static Object not(Object unary) { if (unary instanceof Long) { return ~(Long)unary; @@ -79,29 +79,29 @@ private static Object not(Object unary) { throw new ClassCastException("Cannot apply [~] operation to type " + "[" + unary.getClass().getCanonicalName() + "]."); } - + // unary negation and plus: applicable to all numeric types private static int neg(int v) { return -v; } - + private static long neg(long v) { return -v; } - + private static float neg(float v) { return -v; } - + private static double neg(double v) { return -v; } - + private static boolean neg(boolean v) { throw new ClassCastException("Cannot apply [-] operation to type [boolean]"); } - + private static Object neg(final Object unary) { if (unary instanceof Double) { return -(double)unary; @@ -122,27 +122,27 @@ private static Object neg(final Object unary) { throw new ClassCastException("Cannot apply [-] operation to type " + "[" + unary.getClass().getCanonicalName() + "]."); } - + private static int plus(int v) { return +v; } - + private static long plus(long v) { return +v; } - + private static float plus(float v) { return +v; } - + private static double plus(double v) { return +v; } - + private static boolean plus(boolean v) { throw new ClassCastException("Cannot apply [+] operation to type [boolean]"); } - + private static Object plus(final Object unary) { if (unary instanceof Double) { return +(double)unary; @@ -163,29 +163,29 @@ private static Object plus(final Object unary) { throw new ClassCastException("Cannot apply [+] operation to type " + "[" + unary.getClass().getCanonicalName() + "]."); } - + // multiplication/division/remainder/subtraction: applicable to all integer types - + private static int mul(int a, int b) { return a * b; } - + private static long mul(long a, long b) { return a * b; } - + private static float mul(float a, float b) { return a * b; } - + private static double mul(double a, double b) { return a * b; } - + private static boolean mul(boolean a, boolean b) { throw new ClassCastException("Cannot apply [*] operation to type [boolean]"); } - + private static Object mul(Object left, Object right) { if (left instanceof Number) { if (right instanceof Number) { @@ -228,27 +228,27 @@ private static Object mul(Object left, Object right) { throw new ClassCastException("Cannot apply [*] operation to types " + "[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "]."); } - + private static int div(int a, int b) { return a / b; } - + private static long div(long a, long b) { return a / b; } - + private static float div(float a, float b) { return a / b; } - + private static double div(double a, double b) { return a / b; } - + private static boolean div(boolean a, boolean b) { throw new ClassCastException("Cannot apply [/] operation to type [boolean]"); } - + private static Object div(Object left, Object right) { if (left instanceof Number) { if (right instanceof Number) { @@ -291,27 +291,27 @@ private static Object div(Object left, Object right) { throw new ClassCastException("Cannot apply [/] operation to types " + "[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "]."); } - + private static int rem(int a, int b) { return a % b; } - + private static long rem(long a, long b) { return a % b; } - + private static float rem(float a, float b) { return a % b; } - + private static double rem(double a, double b) { return a % b; } - + private static boolean rem(boolean a, boolean b) { throw new ClassCastException("Cannot apply [%] operation to type [boolean]"); } - + private static Object rem(Object left, Object right) { if (left instanceof Number) { if (right instanceof Number) { @@ -354,30 +354,30 @@ private static Object rem(Object left, Object right) { throw new ClassCastException("Cannot apply [%] operation to types " + "[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "]."); } - + // addition: applicable to all numeric types. // additionally, if either type is a string, the other type can be any arbitrary type (including null) - + private static int add(int a, int b) { return a + b; } - + private static long add(long a, long b) { return a + b; } - + private static float add(float a, float b) { return a + b; } - + private static double add(double a, double b) { return a + b; } - + private static boolean add(boolean a, boolean b) { throw new ClassCastException("Cannot apply [+] operation to type [boolean]"); } - + private static Object add(Object left, Object right) { if (left instanceof String) { return (String) left + right; @@ -424,27 +424,27 @@ private static Object add(Object left, Object right) { throw new ClassCastException("Cannot apply [+] operation to types " + "[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "]."); } - + private static int sub(int a, int b) { return a - b; } - + private static long sub(long a, long b) { return a - b; } - + private static float sub(float a, float b) { return a - b; } - + private static double sub(double a, double b) { return a - b; } - + private static boolean sub(boolean a, boolean b) { throw new ClassCastException("Cannot apply [-] operation to type [boolean]"); } - + private static Object sub(Object left, Object right) { if (left instanceof Number) { if (right instanceof Number) { @@ -487,29 +487,29 @@ private static Object sub(Object left, Object right) { throw new ClassCastException("Cannot apply [-] operation to types " + "[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "]."); } - + // eq: applicable to any arbitrary type, including nulls for both arguments!!! private static boolean eq(int a, int b) { return a == b; } - + private static boolean eq(long a, long b) { return a == b; } - + private static boolean eq(float a, float b) { return a == b; } - + private static boolean eq(double a, double b) { return a == b; } - + private static boolean eq(boolean a, boolean b) { return a == b; } - + private static boolean eq(Object left, Object right) { if (left != null && right != null) { if (left instanceof Double) { @@ -565,29 +565,29 @@ private static boolean eq(Object left, Object right) { return left == null && right == null; } - + // comparison operators: applicable for any numeric type private static boolean lt(int a, int b) { return a < b; } - + private static boolean lt(long a, long b) { return a < b; } - + private static boolean lt(float a, float b) { return a < b; } - + private static boolean lt(double a, double b) { return a < b; } - + private static boolean lt(boolean a, boolean b) { - throw new ClassCastException("Cannot apply [<] operation to type [boolean]"); + throw new ClassCastException("Cannot apply [<] operation to type [boolean]"); } - + private static boolean lt(Object left, Object right) { if (left instanceof Number) { if (right instanceof Number) { @@ -634,23 +634,23 @@ private static boolean lt(Object left, Object right) { private static boolean lte(int a, int b) { return a <= b; } - + private static boolean lte(long a, long b) { return a <= b; } - + private static boolean lte(float a, float b) { return a <= b; } - + private static boolean lte(double a, double b) { return a <= b; } - + private static boolean lte(boolean a, boolean b) { - throw new ClassCastException("Cannot apply [<=] operation to type [boolean]"); + throw new ClassCastException("Cannot apply [<=] operation to type [boolean]"); } - + private static boolean lte(Object left, Object right) { if (left instanceof Number) { if (right instanceof Number) { @@ -697,23 +697,23 @@ private static boolean lte(Object left, Object right) { private static boolean gt(int a, int b) { return a > b; } - + private static boolean gt(long a, long b) { return a > b; } - + private static boolean gt(float a, float b) { return a > b; } - + private static boolean gt(double a, double b) { return a > b; } - + private static boolean gt(boolean a, boolean b) { - throw new ClassCastException("Cannot apply [>] operation to type [boolean]"); + throw new ClassCastException("Cannot apply [>] operation to type [boolean]"); } - + private static boolean gt(Object left, Object right) { if (left instanceof Number) { if (right instanceof Number) { @@ -756,25 +756,25 @@ private static boolean gt(Object left, Object right) { throw new ClassCastException("Cannot apply [>] operation to types " + "[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "]."); } - + private static boolean gte(int a, int b) { return a >= b; } - + private static boolean gte(long a, long b) { return a >= b; } - + private static boolean gte(float a, float b) { return a >= b; } - + private static boolean gte(double a, double b) { return a >= b; } - + private static boolean gte(boolean a, boolean b) { - throw new ClassCastException("Cannot apply [>=] operation to type [boolean]"); + throw new ClassCastException("Cannot apply [>=] operation to type [boolean]"); } private static boolean gte(Object left, Object right) { @@ -819,10 +819,10 @@ private static boolean gte(Object left, Object right) { throw new ClassCastException("Cannot apply [>] operation to types " + "[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "]."); } - + // helper methods to convert an integral according to numeric promotion // this is used by the generic code for bitwise and shift operators - + private static long longIntegralValue(Object o) { if (o instanceof Long) { return (long)o; @@ -834,7 +834,7 @@ private static long longIntegralValue(Object o) { throw new ClassCastException("Cannot convert [" + o.getClass().getCanonicalName() + "] to an integral value."); } } - + private static int intIntegralValue(Object o) { if (o instanceof Integer || o instanceof Short || o instanceof Byte) { return ((Number)o).intValue(); @@ -844,29 +844,29 @@ private static int intIntegralValue(Object o) { throw new ClassCastException("Cannot convert [" + o.getClass().getCanonicalName() + "] to an integral value."); } } - + // bitwise operators: valid only for integral types private static int and(int a, int b) { return a & b; } - + private static long and(long a, long b) { return a & b; } - + private static float and(float a, float b) { - throw new ClassCastException("Cannot apply [&] operation to type [float]"); + throw new ClassCastException("Cannot apply [&] operation to type [float]"); } - + private static double and(double a, double b) { - throw new ClassCastException("Cannot apply [&] operation to type [float]"); + throw new ClassCastException("Cannot apply [&] operation to type [float]"); } - + private static boolean and(boolean a, boolean b) { return a & b; } - + private static Object and(Object left, Object right) { if (left instanceof Boolean && right instanceof Boolean) { return (boolean)left & (boolean)right; @@ -876,23 +876,23 @@ private static Object and(Object left, Object right) { return intIntegralValue(left) & intIntegralValue(right); } } - + private static int xor(int a, int b) { return a ^ b; } - + private static long xor(long a, long b) { return a ^ b; } - + private static float xor(float a, float b) { - throw new ClassCastException("Cannot apply [^] operation to type [float]"); + throw new ClassCastException("Cannot apply [^] operation to type [float]"); } - + private static double xor(double a, double b) { - throw new ClassCastException("Cannot apply [^] operation to type [float]"); + throw new ClassCastException("Cannot apply [^] operation to type [float]"); } - + private static boolean xor(boolean a, boolean b) { return a ^ b; } @@ -910,23 +910,23 @@ private static Object xor(Object left, Object right) { private static int or(int a, int b) { return a | b; } - + private static long or(long a, long b) { return a | b; } - + private static float or(float a, float b) { - throw new ClassCastException("Cannot apply [|] operation to type [float]"); + throw new ClassCastException("Cannot apply [|] operation to type [float]"); } - + private static double or(double a, double b) { - throw new ClassCastException("Cannot apply [|] operation to type [float]"); + throw new ClassCastException("Cannot apply [|] operation to type [float]"); } - + private static boolean or(boolean a, boolean b) { return a | b; } - + private static Object or(Object left, Object right) { if (left instanceof Boolean && right instanceof Boolean) { return (boolean)left | (boolean)right; @@ -936,30 +936,30 @@ private static Object or(Object left, Object right) { return intIntegralValue(left) | intIntegralValue(right); } } - + // shift operators, valid for any integral types, but does not promote. // we implement all shifts as long shifts, because the extra bits are ignored anyway. - + private static int lsh(int a, long b) { return a << b; } - + private static long lsh(long a, long b) { return a << b; } - + private static float lsh(float a, long b) { - throw new ClassCastException("Cannot apply [<<] operation to type [float]"); + throw new ClassCastException("Cannot apply [<<] operation to type [float]"); } - + private static double lsh(double a, long b) { - throw new ClassCastException("Cannot apply [<<] operation to type [double]"); + throw new ClassCastException("Cannot apply [<<] operation to type [double]"); } - + private static boolean lsh(boolean a, long b) { - throw new ClassCastException("Cannot apply [<<] operation to type [boolean]"); + throw new ClassCastException("Cannot apply [<<] operation to type [boolean]"); } - + public static Object lsh(Object left, long right) { if (left instanceof Long) { return (long)(left) << right; @@ -967,25 +967,25 @@ public static Object lsh(Object left, long right) { return intIntegralValue(left) << right; } } - + private static int rsh(int a, long b) { return a >> b; } - + private static long rsh(long a, long b) { return a >> b; } - + private static float rsh(float a, long b) { - throw new ClassCastException("Cannot apply [>>] operation to type [float]"); + throw new ClassCastException("Cannot apply [>>] operation to type [float]"); } - + private static double rsh(double a, long b) { - throw new ClassCastException("Cannot apply [>>] operation to type [double]"); + throw new ClassCastException("Cannot apply [>>] operation to type [double]"); } - + private static boolean rsh(boolean a, long b) { - throw new ClassCastException("Cannot apply [>>] operation to type [boolean]"); + throw new ClassCastException("Cannot apply [>>] operation to type [boolean]"); } public static Object rsh(Object left, long right) { @@ -995,25 +995,25 @@ public static Object rsh(Object left, long right) { return intIntegralValue(left) >> right; } } - + private static int ush(int a, long b) { return a >>> b; } - + private static long ush(long a, long b) { return a >>> b; } - + private static float ush(float a, long b) { - throw new ClassCastException("Cannot apply [>>>] operation to type [float]"); + throw new ClassCastException("Cannot apply [>>>] operation to type [float]"); } - + private static double ush(double a, long b) { - throw new ClassCastException("Cannot apply [>>>] operation to type [double]"); + throw new ClassCastException("Cannot apply [>>>] operation to type [double]"); } - + private static boolean ush(boolean a, long b) { - throw new ClassCastException("Cannot apply [>>>] operation to type [boolean]"); + throw new ClassCastException("Cannot apply [>>>] operation to type [boolean]"); } public static Object ush(Object left, long right) { @@ -1023,15 +1023,15 @@ public static Object ush(Object left, long right) { return intIntegralValue(left) >>> right; } } - - /** - * unboxes a class to its primitive type, or returns the original + + /** + * unboxes a class to its primitive type, or returns the original * class if its not a boxed type. */ private static Class unbox(Class clazz) { return MethodType.methodType(clazz).unwrap().returnType(); } - + /** Unary promotion. All Objects are promoted to Object. */ private static Class promote(Class clazz) { // if either is a non-primitive type -> Object. @@ -1039,25 +1039,25 @@ private static Class promote(Class clazz) { return Object.class; } // always promoted to integer - if (clazz == byte.class || clazz == short.class || clazz == char.class || clazz == int.class) { - return int.class; - } else { - return clazz; - } + if (clazz == byte.class || clazz == short.class || clazz == char.class || clazz == int.class) { + return int.class; + } else { + return clazz; + } } - + /** Binary promotion. */ private static Class promote(Class a, Class b) { // if either is a non-primitive type -> Object. if (a.isPrimitive() == false || b.isPrimitive() == false) { return Object.class; } - + // boolean -> boolean if (a == boolean.class && b == boolean.class) { return boolean.class; } - + // ordinary numeric promotion if (a == double.class || b == double.class) { return double.class; @@ -1069,7 +1069,7 @@ private static Class promote(Class a, Class b) { return int.class; } } - + private static final Lookup PRIV_LOOKUP = MethodHandles.lookup(); private static final Map,Map> TYPE_OP_MAPPING = Collections.unmodifiableMap( @@ -1107,7 +1107,7 @@ private static Class promote(Class a, Class b) { } })) ); - + /** Returns an appropriate method handle for a unary or shift operator, based only on the receiver (LHS) */ public static MethodHandle lookupUnary(Class receiverClass, String name) { MethodHandle handle = TYPE_OP_MAPPING.get(promote(unbox(receiverClass))).get(name); @@ -1116,7 +1116,7 @@ public static MethodHandle lookupUnary(Class receiverClass, String name) { } return handle; } - + /** Returns an appropriate method handle for a binary operator, based on promotion of the LHS and RHS arguments */ public static MethodHandle lookupBinary(Class classA, Class classB, String name) { MethodHandle handle = TYPE_OP_MAPPING.get(promote(promote(unbox(classA)), promote(unbox(classB)))).get(name); @@ -1125,7 +1125,7 @@ public static MethodHandle lookupBinary(Class classA, Class classB, String } return handle; } - + /** Returns a generic method handle for any operator, that can handle all valid signatures, nulls, corner cases */ public static MethodHandle lookupGeneric(String name) { return TYPE_OP_MAPPING.get(Object.class).get(name); @@ -1143,7 +1143,7 @@ static Object dynamicReceiverCast(Object returnValue, Object lhs) { return returnValue; } } - + /** * Slow dynamic cast: casts {@code value} to an instance of {@code clazz} * based upon inspection. If {@code lhs} is null, no cast takes place. @@ -1173,7 +1173,7 @@ static Object dynamicCast(Class clazz, Object value) { return value; } } - + /** Slowly returns a Number for o. Just for supporting dynamicCast */ static Number getNumber(Object o) { if (o instanceof Number) { @@ -1184,17 +1184,17 @@ static Number getNumber(Object o) { throw new ClassCastException("Cannot convert [" + o.getClass() + "] to a Number"); } } - + private static final MethodHandle DYNAMIC_CAST; private static final MethodHandle DYNAMIC_RECEIVER_CAST; static { final Lookup lookup = MethodHandles.lookup(); try { - DYNAMIC_CAST = lookup.findStatic(lookup.lookupClass(), - "dynamicCast", + DYNAMIC_CAST = lookup.findStatic(lookup.lookupClass(), + "dynamicCast", MethodType.methodType(Object.class, Class.class, Object.class)); - DYNAMIC_RECEIVER_CAST = lookup.findStatic(lookup.lookupClass(), - "dynamicReceiverCast", + DYNAMIC_RECEIVER_CAST = lookup.findStatic(lookup.lookupClass(), + "dynamicReceiverCast", MethodType.methodType(Object.class, Object.class, Object.class)); } catch (ReflectiveOperationException e) { throw new AssertionError(e); @@ -1204,7 +1204,7 @@ static Number getNumber(Object o) { /** Looks up generic method, with a dynamic cast to the receiver's type. (compound assignment) */ public static MethodHandle dynamicCast(MethodHandle target) { // adapt dynamic receiver cast to the generic method - MethodHandle cast = DYNAMIC_RECEIVER_CAST.asType(MethodType.methodType(target.type().returnType(), + MethodHandle cast = DYNAMIC_RECEIVER_CAST.asType(MethodType.methodType(target.type().returnType(), target.type().returnType(), target.type().parameterType(0))); // drop the RHS parameter @@ -1212,7 +1212,7 @@ public static MethodHandle dynamicCast(MethodHandle target) { // combine: f(x,y) -> g(f(x,y), x, y); return MethodHandles.foldArguments(cast, target); } - + /** Looks up generic method, with a dynamic cast to the specified type. (explicit assignment) */ public static MethodHandle dynamicCast(MethodHandle target, Class desired) { // adapt dynamic cast to the generic method @@ -1221,23 +1221,23 @@ public static MethodHandle dynamicCast(MethodHandle target, Class desired) { MethodHandle cast = DYNAMIC_CAST.bindTo(desired); return MethodHandles.filterReturnValue(target, cast); } - + /** Forces a cast to class A for target (only if types differ) */ public static MethodHandle cast(Class classA, MethodHandle target) { MethodType newType = MethodType.methodType(classA).unwrap(); MethodType targetType = MethodType.methodType(target.type().returnType()).unwrap(); - + // don't do a conversion if types are the same. explicitCastArguments has this opto, // but we do it explicitly, to make the boolean check simpler if (newType.returnType() == targetType.returnType()) { return target; } - + // we don't allow the to/from boolean conversions of explicitCastArguments if (newType.returnType() == boolean.class || targetType.returnType() == boolean.class) { throw new ClassCastException("Cannot cast " + targetType.returnType() + " to " + newType.returnType()); } - + // null return values are not possible for our arguments. return MethodHandles.explicitCastArguments(target, target.type().changeReturnType(newType.returnType())); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java index 75575d6f12568..25145a44b5853 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.spi.Whitelist; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -48,35 +49,6 @@ public final class Definition { private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][._a-zA-Z0-9]*$"); - /** Some native types as constants: */ - public final Type voidType; - public final Type booleanType; - public final Type BooleanType; - public final Type byteType; - public final Type ByteType; - public final Type shortType; - public final Type ShortType; - public final Type intType; - public final Type IntegerType; - public final Type longType; - public final Type LongType; - public final Type floatType; - public final Type FloatType; - public final Type doubleType; - public final Type DoubleType; - public final Type charType; - public final Type CharacterType; - public final Type ObjectType; - public final Type DefType; - public final Type NumberType; - public final Type StringType; - public final Type ExceptionType; - public final Type PatternType; - public final Type MatcherType; - public final Type IteratorType; - public final Type ArrayListType; - public final Type HashMapType; - /** Marker class for def type to be used during type analysis. */ public static final class def { private def() { @@ -84,53 +56,6 @@ private def() { } } - public static final class Type { - public final String name; - public final int dimensions; - public final boolean dynamic; - public final Struct struct; - public final Class clazz; - public final org.objectweb.asm.Type type; - - private Type(final String name, final int dimensions, final boolean dynamic, - final Struct struct, final Class clazz, final org.objectweb.asm.Type type) { - this.name = name; - this.dimensions = dimensions; - this.dynamic = dynamic; - this.struct = struct; - this.clazz = clazz; - this.type = type; - } - - @Override - public boolean equals(final Object object) { - if (this == object) { - return true; - } - - if (object == null || getClass() != object.getClass()) { - return false; - } - - final Type type = (Type)object; - - return this.type.equals(type.type) && struct.equals(type.struct); - } - - @Override - public int hashCode() { - int result = struct.hashCode(); - result = 31 * result + type.hashCode(); - - return result; - } - - @Override - public String toString() { - return name; - } - } - public static class Method { public final String name; public final Struct owner; @@ -431,21 +356,6 @@ private Cast(Class from, Class to, boolean explicit, Class unboxFrom, C } } - /** Returns whether or not a non-array type exists. */ - public boolean isSimpleType(final String name) { - return structsMap.containsKey(name); - } - - /** Gets the type given by its name */ - public Type getType(final String name) { - return getTypeInternal(name); - } - - /** Creates an array type from the given Struct. */ - public Type getType(final Struct struct, final int dimensions) { - return getTypeInternal(struct, dimensions); - } - public static Class getBoxedType(Class clazz) { if (clazz == boolean.class) { return Boolean.class; @@ -502,6 +412,10 @@ public static boolean isConstantType(Class clazz) { clazz == String.class; } + public Class getClassFromBinaryName(String painlessType) { + return painlessTypesToJavaClasses.get(painlessType.replace('$', '.')); + } + public static Class ObjectClassTodefClass(Class clazz) { if (clazz.isArray()) { Class component = clazz.getComponentType(); @@ -590,53 +504,6 @@ public static String ClassToName(Class clazz) { return clazz.getCanonicalName().replace('$', '.'); } - public Type ClassToType(Class clazz) { - if (clazz == null) { - return null; - } else if (clazz.isArray()) { - Class component = clazz.getComponentType(); - int dimensions = 1; - - while (component.isArray()) { - component = component.getComponentType(); - ++dimensions; - } - - if (component == def.class) { - return getType(structsMap.get(def.class.getSimpleName()), dimensions); - } else { - return getType(structsMap.get(ClassToName(component)), dimensions); - } - } else if (clazz == def.class) { - return getType(structsMap.get(def.class.getSimpleName()), 0); - } - - return getType(structsMap.get(ClassToName(clazz)), 0); - } - - public Struct RuntimeClassToStruct(Class clazz) { - return structsMap.get(ClassToName(clazz)); - } - - public static Class TypeToClass(Type type) { - if (def.class.getSimpleName().equals(type.struct.name)) { - return ObjectClassTodefClass(type.clazz); - } - - return type.clazz; - } - - public Class getClassFromBinaryName(String name) { - Struct struct = structsMap.get(name.replace('$', '.')); - - return struct == null ? null : struct.clazz; - } - - /** Collection of all simple types. Used by {@code PainlessDocGenerator} to generate an API reference. */ - Collection allSimpleTypes() { - return simpleTypesMap.values(); - } - private static String buildMethodCacheKey(String structName, String methodName, List> arguments) { StringBuilder key = new StringBuilder(); key.append(structName); @@ -653,21 +520,21 @@ private static String buildFieldCacheKey(String structName, String fieldName, St return structName + fieldName + typeName; } - // INTERNAL IMPLEMENTATION: + public Collection getStructs() { + return javaClassesToPainlessStructs.values(); + } - private final Map structsMap; - private final Map simpleTypesMap; + private final Map> painlessTypesToJavaClasses; + private final Map, Struct> javaClassesToPainlessStructs; public Definition(List whitelists) { - structsMap = new HashMap<>(); - simpleTypesMap = new HashMap<>(); + painlessTypesToJavaClasses = new HashMap<>(); + javaClassesToPainlessStructs = new HashMap<>(); - Map, Struct> javaClassesToPainlessStructs = new HashMap<>(); String origin = null; - // add the universal def type - structsMap.put(def.class.getSimpleName(), - new Struct(def.class.getSimpleName(), Object.class, org.objectweb.asm.Type.getType(Object.class))); + painlessTypesToJavaClasses.put("def", def.class); + javaClassesToPainlessStructs.put(def.class, new Struct("def", Object.class, Type.getType(Object.class))); try { // first iteration collects all the Painless type names that @@ -675,7 +542,7 @@ public Definition(List whitelists) { for (Whitelist whitelist : whitelists) { for (Whitelist.Struct whitelistStruct : whitelist.whitelistStructs) { String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.'); - Struct painlessStruct = structsMap.get(painlessTypeName); + Struct painlessStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(painlessTypeName)); if (painlessStruct != null && painlessStruct.clazz.getName().equals(whitelistStruct.javaClassName) == false) { throw new IllegalArgumentException("struct [" + painlessStruct.name + "] cannot represent multiple classes " + @@ -685,7 +552,7 @@ public Definition(List whitelists) { origin = whitelistStruct.origin; addStruct(whitelist.javaClassLoader, whitelistStruct); - painlessStruct = structsMap.get(painlessTypeName); + painlessStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(painlessTypeName)); javaClassesToPainlessStructs.put(painlessStruct.clazz, painlessStruct); } } @@ -719,13 +586,8 @@ public Definition(List whitelists) { // goes through each Painless struct and determines the inheritance list, // and then adds all inherited types to the Painless struct's whitelist - for (Map.Entry painlessNameStructEntry : structsMap.entrySet()) { - String painlessStructName = painlessNameStructEntry.getKey(); - Struct painlessStruct = painlessNameStructEntry.getValue(); - - if (painlessStruct.name.equals(painlessStructName) == false) { - continue; - } + for (Class javaClass : javaClassesToPainlessStructs.keySet()) { + Struct painlessStruct = javaClassesToPainlessStructs.get(javaClass); List painlessSuperStructs = new ArrayList<>(); Class javaSuperClass = painlessStruct.clazz.getSuperclass(); @@ -782,52 +644,14 @@ public Definition(List whitelists) { } // precompute runtime classes - for (String painlessStructName : structsMap.keySet()) { - Struct painlessStruct = structsMap.get(painlessStructName); - - if (painlessStruct.name.equals(painlessStructName) == false) { - continue; - } - + for (Struct painlessStruct : javaClassesToPainlessStructs.values()) { addRuntimeClass(painlessStruct); } // copy all structs to make them unmodifiable for outside users: - for (Map.Entry entry : structsMap.entrySet()) { - if (entry.getKey().equals(entry.getValue().name) == false) { - continue; - } - + for (Map.Entry,Struct> entry : javaClassesToPainlessStructs.entrySet()) { entry.setValue(entry.getValue().freeze(computeFunctionalInterfaceMethod(entry.getValue()))); } - - voidType = getType("void"); - booleanType = getType("boolean"); - BooleanType = getType("Boolean"); - byteType = getType("byte"); - ByteType = getType("Byte"); - shortType = getType("short"); - ShortType = getType("Short"); - intType = getType("int"); - IntegerType = getType("Integer"); - longType = getType("long"); - LongType = getType("Long"); - floatType = getType("float"); - FloatType = getType("Float"); - doubleType = getType("double"); - DoubleType = getType("Double"); - charType = getType("char"); - CharacterType = getType("Character"); - ObjectType = getType("Object"); - DefType = getType(def.class.getSimpleName()); - NumberType = getType("Number"); - StringType = getType("String"); - ExceptionType = getType("Exception"); - PatternType = getType("Pattern"); - MatcherType = getType("Matcher"); - IteratorType = getType("Iterator"); - ArrayListType = getType("ArrayList"); - HashMapType = getType("HashMap"); } private void addStruct(ClassLoader whitelistClassLoader, Whitelist.Struct whitelistStruct) { @@ -864,35 +688,45 @@ private void addStruct(ClassLoader whitelistClassLoader, Whitelist.Struct whitel } } - Struct existingStruct = structsMap.get(painlessTypeName); + Struct existingStruct = javaClassesToPainlessStructs.get(javaClass); if (existingStruct == null) { Struct struct = new Struct(painlessTypeName, javaClass, org.objectweb.asm.Type.getType(javaClass)); - structsMap.put(painlessTypeName, struct); - - if (whitelistStruct.onlyFQNJavaClassName) { - simpleTypesMap.put(painlessTypeName, getType(painlessTypeName)); - } else if (simpleTypesMap.containsKey(importedPainlessTypeName) == false) { - simpleTypesMap.put(importedPainlessTypeName, getType(painlessTypeName)); - structsMap.put(importedPainlessTypeName, struct); - } else { - throw new IllegalArgumentException("duplicate short name [" + importedPainlessTypeName + "] " + - "found for struct [" + painlessTypeName + "]"); - } + painlessTypesToJavaClasses.put(painlessTypeName, javaClass); + javaClassesToPainlessStructs.put(javaClass, struct); } else if (existingStruct.clazz.equals(javaClass) == false) { throw new IllegalArgumentException("struct [" + painlessTypeName + "] is used to " + "illegally represent multiple java classes [" + whitelistStruct.javaClassName + "] and " + "[" + existingStruct.clazz.getName() + "]"); - } else if (whitelistStruct.onlyFQNJavaClassName && simpleTypesMap.containsKey(importedPainlessTypeName) && - simpleTypesMap.get(importedPainlessTypeName).clazz == javaClass || - whitelistStruct.onlyFQNJavaClassName == false && (simpleTypesMap.containsKey(importedPainlessTypeName) == false || - simpleTypesMap.get(importedPainlessTypeName).clazz != javaClass)) { - throw new IllegalArgumentException("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]"); + } + + if (painlessTypeName.equals(importedPainlessTypeName)) { + if (whitelistStruct.onlyFQNJavaClassName == false) { + throw new IllegalArgumentException("must use only_fqn parameter on type [" + painlessTypeName + "] with no package"); + } + } else { + Class importedJavaClass = painlessTypesToJavaClasses.get(importedPainlessTypeName); + + if (importedJavaClass == null) { + if (whitelistStruct.onlyFQNJavaClassName == false) { + if (existingStruct != null) { + throw new IllegalArgumentException("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]"); + } + + painlessTypesToJavaClasses.put(importedPainlessTypeName, javaClass); + } + } else if (importedJavaClass.equals(javaClass) == false) { + throw new IllegalArgumentException("imported name [" + painlessTypeName + "] is used to " + + "illegally represent multiple java classes [" + whitelistStruct.javaClassName + "] " + + "and [" + importedJavaClass.getName() + "]"); + } else if (whitelistStruct.onlyFQNJavaClassName) { + throw new IllegalArgumentException("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]"); + } } } private void addConstructor(String ownerStructName, Whitelist.Constructor whitelistConstructor) { - Struct ownerStruct = structsMap.get(ownerStructName); + Struct ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); if (ownerStruct == null) { throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for constructor with " + @@ -906,7 +740,7 @@ private void addConstructor(String ownerStructName, Whitelist.Constructor whitel String painlessParameterTypeName = whitelistConstructor.painlessParameterTypeNames.get(parameterCount); try { - Class painlessParameterClass = TypeToClass(getTypeInternal(painlessParameterTypeName)); + Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); painlessParametersTypes.add(painlessParameterClass); javaClassParameters[parameterCount] = defClassToObjectClass(painlessParameterClass); @@ -952,7 +786,7 @@ private void addConstructor(String ownerStructName, Whitelist.Constructor whitel } private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, Whitelist.Method whitelistMethod) { - Struct ownerStruct = structsMap.get(ownerStructName); + Struct ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); if (ownerStruct == null) { throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " + @@ -991,7 +825,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, String painlessParameterTypeName = whitelistMethod.painlessParameterTypeNames.get(parameterCount); try { - Class painlessParameterClass = TypeToClass(getTypeInternal(painlessParameterTypeName)); + Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); painlessParametersTypes.add(painlessParameterClass); javaClassParameters[parameterCount + augmentedOffset] = defClassToObjectClass(painlessParameterClass); @@ -1016,7 +850,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, Class painlessReturnClass; try { - painlessReturnClass = TypeToClass(getTypeInternal(whitelistMethod.painlessReturnTypeName)); + painlessReturnClass = getJavaClassFromPainlessType(whitelistMethod.painlessReturnTypeName); } catch (IllegalArgumentException iae) { throw new IllegalArgumentException("struct not defined for return type [" + whitelistMethod.painlessReturnTypeName + "] " + "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " + @@ -1088,7 +922,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, } private void addField(String ownerStructName, Whitelist.Field whitelistField) { - Struct ownerStruct = structsMap.get(ownerStructName); + Struct ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); if (ownerStruct == null) { throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " + @@ -1112,7 +946,7 @@ private void addField(String ownerStructName, Whitelist.Field whitelistField) { Class painlessFieldClass; try { - painlessFieldClass = TypeToClass(getTypeInternal(whitelistField.painlessFieldTypeName)); + painlessFieldClass = getJavaClassFromPainlessType(whitelistField.painlessFieldTypeName); } catch (IllegalArgumentException iae) { throw new IllegalArgumentException("struct not defined for return type [" + whitelistField.painlessFieldTypeName + "] " + "with owner struct [" + ownerStructName + "] and field with name [" + whitelistField.javaFieldName + "]", iae); @@ -1169,14 +1003,14 @@ private void addField(String ownerStructName, Whitelist.Field whitelistField) { } private void copyStruct(String struct, List children) { - final Struct owner = structsMap.get(struct); + final Struct owner = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(struct)); if (owner == null) { throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for copy."); } for (int count = 0; count < children.size(); ++count) { - final Struct child = structsMap.get(children.get(count)); + final Struct child = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(children.get(count))); if (child == null) { throw new IllegalArgumentException("Child struct [" + children.get(count) + "]" + @@ -1340,71 +1174,68 @@ private Method computeFunctionalInterfaceMethod(Struct clazz) { return painless; } - private Type getTypeInternal(String name) { - // simple types (e.g. 0 array dimensions) are a simple hash lookup for speed - Type simple = simpleTypesMap.get(name); + public boolean isSimplePainlessType(String painlessType) { + return painlessTypesToJavaClasses.containsKey(painlessType); + } - if (simple != null) { - return simple; - } + public Struct getPainlessStructFromJavaClass(Class clazz) { + return javaClassesToPainlessStructs.get(clazz); + } - int dimensions = getDimensions(name); - String structstr = dimensions == 0 ? name : name.substring(0, name.indexOf('[')); - Struct struct = structsMap.get(structstr); + public Class getJavaClassFromPainlessType(String painlessType) { + Class javaClass = painlessTypesToJavaClasses.get(painlessType); - if (struct == null) { - throw new IllegalArgumentException("The struct with name [" + name + "] has not been defined."); + if (javaClass != null) { + return javaClass; } + int arrayDimensions = 0; + int arrayIndex = painlessType.indexOf('['); - return getTypeInternal(struct, dimensions); - } - - private Type getTypeInternal(Struct struct, int dimensions) { - String name = struct.name; - org.objectweb.asm.Type type = struct.type; - Class clazz = struct.clazz; + if (arrayIndex != -1) { + int length = painlessType.length(); - if (dimensions > 0) { - StringBuilder builder = new StringBuilder(name); - char[] brackets = new char[dimensions]; - - for (int count = 0; count < dimensions; ++count) { - builder.append("[]"); - brackets[count] = '['; + while (arrayIndex < length) { + if (painlessType.charAt(arrayIndex) == '[' && ++arrayIndex < length && painlessType.charAt(arrayIndex++) == ']') { + ++arrayDimensions; + } else { + throw new IllegalArgumentException("invalid painless type [" + painlessType + "]."); + } } - String descriptor = new String(brackets) + struct.type.getDescriptor(); - - name = builder.toString(); - type = org.objectweb.asm.Type.getType(descriptor); - - try { - clazz = Class.forName(type.getInternalName().replace('/', '.')); - } catch (ClassNotFoundException exception) { - throw new IllegalArgumentException("The class [" + type.getInternalName() + "]" + - " could not be found to create type [" + name + "]."); + painlessType = painlessType.substring(0, painlessType.indexOf('[')); + javaClass = painlessTypesToJavaClasses.get(painlessType); + + char braces[] = new char[arrayDimensions]; + Arrays.fill(braces, '['); + String descriptor = new String(braces); + + if (javaClass == boolean.class) { + descriptor += "Z"; + } else if (javaClass == byte.class) { + descriptor += "B"; + } else if (javaClass == short.class) { + descriptor += "S"; + } else if (javaClass == char.class) { + descriptor += "C"; + } else if (javaClass == int.class) { + descriptor += "I"; + } else if (javaClass == long.class) { + descriptor += "J"; + } else if (javaClass == float.class) { + descriptor += "F"; + } else if (javaClass == double.class) { + descriptor += "D"; + } else { + descriptor += "L" + javaClass.getName() + ";"; } - } - - return new Type(name, dimensions, def.class.getSimpleName().equals(name), struct, clazz, type); - } - private int getDimensions(String name) { - int dimensions = 0; - int index = name.indexOf('['); - - if (index != -1) { - int length = name.length(); - - while (index < length) { - if (name.charAt(index) == '[' && ++index < length && name.charAt(index++) == ']') { - ++dimensions; - } else { - throw new IllegalArgumentException("Invalid array braces in canonical name [" + name + "]."); - } + try { + return Class.forName(descriptor); + } catch (ClassNotFoundException cnfe) { + throw new IllegalStateException("invalid painless type [" + painlessType + "]", cnfe); } } - return dimensions; + throw new IllegalArgumentException("invalid painless type [" + painlessType + "]"); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java index 0b698dd244192..1b438965538ce 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java @@ -78,7 +78,7 @@ public class FunctionRef { * @param numCaptures number of captured arguments */ public FunctionRef(Definition definition, Class expected, String type, String call, int numCaptures) { - this(expected, definition.ClassToType(expected).struct.functionalMethod, + this(expected, definition.getPainlessStructFromJavaClass(expected).functionalMethod, lookup(definition, expected, type, call, numCaptures > 0), numCaptures); } @@ -162,14 +162,14 @@ private static Definition.Method lookup(Definition definition, Class expected String type, String call, boolean receiverCaptured) { // check its really a functional interface // for e.g. Comparable - Method method = definition.ClassToType(expected).struct.functionalMethod; + Method method = definition.getPainlessStructFromJavaClass(expected).functionalMethod; if (method == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + "to [" + Definition.ClassToName(expected) + "], not a functional interface"); } // lookup requested method - Definition.Struct struct = definition.getType(type).struct; + Definition.Struct struct = definition.getPainlessStructFromJavaClass(definition.getJavaClassFromPainlessType(type)); final Definition.Method impl; // ctor ref if ("new".equals(call)) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessExplainError.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessExplainError.java index 0b2fdf35890a0..7ae93eba22632 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessExplainError.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessExplainError.java @@ -54,7 +54,7 @@ public Map> getHeaders(Definition definition) { if (objectToExplain != null) { toString = objectToExplain.toString(); javaClassName = objectToExplain.getClass().getName(); - Definition.Struct struct = definition.ClassToType(objectToExplain.getClass()).struct; + Definition.Struct struct = definition.getPainlessStructFromJavaClass(objectToExplain.getClass()); if (struct != null) { painlessClassName = struct.name; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java index 4ebcf8bfb82d2..833ff0eac4134 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java @@ -31,8 +31,8 @@ import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.painless.spi.PainlessExtension; import org.elasticsearch.painless.spi.Whitelist; -import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.painless.spi.WhitelistLoader; +import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.ExtensiblePlugin; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.ScriptPlugin; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java index 60ce1d033532a..0ec806282db2f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java @@ -179,22 +179,18 @@ private MethodArgument methodArgument(Definition definition, Class clazz, Str private static Class definitionTypeForClass(Definition definition, Class type, Function, String> unknownErrorMessageSource) { - int dimensions = 0; + type = Definition.ObjectClassTodefClass(type); Class componentType = type; + while (componentType.isArray()) { - dimensions++; componentType = componentType.getComponentType(); } - Definition.Struct struct; - if (componentType == Object.class) { - struct = definition.getType("def").struct; - } else { - if (definition.RuntimeClassToStruct(componentType) == null) { - throw new IllegalArgumentException(unknownErrorMessageSource.apply(componentType)); - } - struct = definition.RuntimeClassToStruct(componentType); + + if (definition.getPainlessStructFromJavaClass(componentType) == null) { + throw new IllegalArgumentException(unknownErrorMessageSource.apply(componentType)); } - return Definition.TypeToClass(definition.getType(struct, dimensions)); + + return type; } private static String[] readArgumentNamesConstant(Class iface) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java index cf24a47386603..add3aaabe51e0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java @@ -74,8 +74,8 @@ public void recover(final LexerNoViableAltException lnvae) { } @Override - protected boolean isSimpleType(String name) { - return definition.isSimpleType(name); + protected boolean isType(String name) { + return definition.isSimplePainlessType(name); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java index dd62701b86e4d..7fa10f6e9fbf2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java @@ -1,9 +1,16 @@ // ANTLR GENERATED CODE: DO NOT EDIT package org.elasticsearch.painless.antlr; -import org.antlr.v4.runtime.Lexer; + import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.RuntimeMetaData; +import org.antlr.v4.runtime.Vocabulary; +import org.antlr.v4.runtime.VocabularyImpl; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.LexerATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; import org.antlr.v4.runtime.dfa.DFA; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) @@ -14,16 +21,16 @@ abstract class PainlessLexer extends Lexer { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - WS=1, COMMENT=2, LBRACK=3, RBRACK=4, LBRACE=5, RBRACE=6, LP=7, RP=8, DOT=9, - NSDOT=10, COMMA=11, SEMICOLON=12, IF=13, IN=14, ELSE=15, WHILE=16, DO=17, - FOR=18, CONTINUE=19, BREAK=20, RETURN=21, NEW=22, TRY=23, CATCH=24, THROW=25, - THIS=26, INSTANCEOF=27, BOOLNOT=28, BWNOT=29, MUL=30, DIV=31, REM=32, - ADD=33, SUB=34, LSH=35, RSH=36, USH=37, LT=38, LTE=39, GT=40, GTE=41, - EQ=42, EQR=43, NE=44, NER=45, BWAND=46, XOR=47, BWOR=48, BOOLAND=49, BOOLOR=50, - COND=51, COLON=52, ELVIS=53, REF=54, ARROW=55, FIND=56, MATCH=57, INCR=58, - DECR=59, ASSIGN=60, AADD=61, ASUB=62, AMUL=63, ADIV=64, AREM=65, AAND=66, - AXOR=67, AOR=68, ALSH=69, ARSH=70, AUSH=71, OCTAL=72, HEX=73, INTEGER=74, - DECIMAL=75, STRING=76, REGEX=77, TRUE=78, FALSE=79, NULL=80, TYPE=81, + WS=1, COMMENT=2, LBRACK=3, RBRACK=4, LBRACE=5, RBRACE=6, LP=7, RP=8, DOT=9, + NSDOT=10, COMMA=11, SEMICOLON=12, IF=13, IN=14, ELSE=15, WHILE=16, DO=17, + FOR=18, CONTINUE=19, BREAK=20, RETURN=21, NEW=22, TRY=23, CATCH=24, THROW=25, + THIS=26, INSTANCEOF=27, BOOLNOT=28, BWNOT=29, MUL=30, DIV=31, REM=32, + ADD=33, SUB=34, LSH=35, RSH=36, USH=37, LT=38, LTE=39, GT=40, GTE=41, + EQ=42, EQR=43, NE=44, NER=45, BWAND=46, XOR=47, BWOR=48, BOOLAND=49, BOOLOR=50, + COND=51, COLON=52, ELVIS=53, REF=54, ARROW=55, FIND=56, MATCH=57, INCR=58, + DECR=59, ASSIGN=60, AADD=61, ASUB=62, AMUL=63, ADIV=64, AREM=65, AAND=66, + AXOR=67, AOR=68, ALSH=69, ARSH=70, AUSH=71, OCTAL=72, HEX=73, INTEGER=74, + DECIMAL=75, STRING=76, REGEX=77, TRUE=78, FALSE=79, NULL=80, TYPE=81, ID=82, DOTINTEGER=83, DOTID=84; public static final int AFTER_DOT = 1; public static String[] modeNames = { @@ -31,39 +38,39 @@ abstract class PainlessLexer extends Lexer { }; public static final String[] ruleNames = { - "WS", "COMMENT", "LBRACK", "RBRACK", "LBRACE", "RBRACE", "LP", "RP", "DOT", - "NSDOT", "COMMA", "SEMICOLON", "IF", "IN", "ELSE", "WHILE", "DO", "FOR", - "CONTINUE", "BREAK", "RETURN", "NEW", "TRY", "CATCH", "THROW", "THIS", - "INSTANCEOF", "BOOLNOT", "BWNOT", "MUL", "DIV", "REM", "ADD", "SUB", "LSH", - "RSH", "USH", "LT", "LTE", "GT", "GTE", "EQ", "EQR", "NE", "NER", "BWAND", - "XOR", "BWOR", "BOOLAND", "BOOLOR", "COND", "COLON", "ELVIS", "REF", "ARROW", - "FIND", "MATCH", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", "AMUL", "ADIV", - "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", "OCTAL", "HEX", - "INTEGER", "DECIMAL", "STRING", "REGEX", "TRUE", "FALSE", "NULL", "TYPE", + "WS", "COMMENT", "LBRACK", "RBRACK", "LBRACE", "RBRACE", "LP", "RP", "DOT", + "NSDOT", "COMMA", "SEMICOLON", "IF", "IN", "ELSE", "WHILE", "DO", "FOR", + "CONTINUE", "BREAK", "RETURN", "NEW", "TRY", "CATCH", "THROW", "THIS", + "INSTANCEOF", "BOOLNOT", "BWNOT", "MUL", "DIV", "REM", "ADD", "SUB", "LSH", + "RSH", "USH", "LT", "LTE", "GT", "GTE", "EQ", "EQR", "NE", "NER", "BWAND", + "XOR", "BWOR", "BOOLAND", "BOOLOR", "COND", "COLON", "ELVIS", "REF", "ARROW", + "FIND", "MATCH", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", "AMUL", "ADIV", + "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", "OCTAL", "HEX", + "INTEGER", "DECIMAL", "STRING", "REGEX", "TRUE", "FALSE", "NULL", "TYPE", "ID", "DOTINTEGER", "DOTID" }; private static final String[] _LITERAL_NAMES = { - null, null, null, "'{'", "'}'", "'['", "']'", "'('", "')'", "'.'", "'?.'", - "','", "';'", "'if'", "'in'", "'else'", "'while'", "'do'", "'for'", "'continue'", - "'break'", "'return'", "'new'", "'try'", "'catch'", "'throw'", "'this'", - "'instanceof'", "'!'", "'~'", "'*'", "'/'", "'%'", "'+'", "'-'", "'<<'", - "'>>'", "'>>>'", "'<'", "'<='", "'>'", "'>='", "'=='", "'==='", "'!='", - "'!=='", "'&'", "'^'", "'|'", "'&&'", "'||'", "'?'", "':'", "'?:'", "'::'", - "'->'", "'=~'", "'==~'", "'++'", "'--'", "'='", "'+='", "'-='", "'*='", - "'/='", "'%='", "'&='", "'^='", "'|='", "'<<='", "'>>='", "'>>>='", null, + null, null, null, "'{'", "'}'", "'['", "']'", "'('", "')'", "'.'", "'?.'", + "','", "';'", "'if'", "'in'", "'else'", "'while'", "'do'", "'for'", "'continue'", + "'break'", "'return'", "'new'", "'try'", "'catch'", "'throw'", "'this'", + "'instanceof'", "'!'", "'~'", "'*'", "'/'", "'%'", "'+'", "'-'", "'<<'", + "'>>'", "'>>>'", "'<'", "'<='", "'>'", "'>='", "'=='", "'==='", "'!='", + "'!=='", "'&'", "'^'", "'|'", "'&&'", "'||'", "'?'", "':'", "'?:'", "'::'", + "'->'", "'=~'", "'==~'", "'++'", "'--'", "'='", "'+='", "'-='", "'*='", + "'/='", "'%='", "'&='", "'^='", "'|='", "'<<='", "'>>='", "'>>>='", null, null, null, null, null, null, "'true'", "'false'", "'null'" }; private static final String[] _SYMBOLIC_NAMES = { - null, "WS", "COMMENT", "LBRACK", "RBRACK", "LBRACE", "RBRACE", "LP", "RP", - "DOT", "NSDOT", "COMMA", "SEMICOLON", "IF", "IN", "ELSE", "WHILE", "DO", - "FOR", "CONTINUE", "BREAK", "RETURN", "NEW", "TRY", "CATCH", "THROW", - "THIS", "INSTANCEOF", "BOOLNOT", "BWNOT", "MUL", "DIV", "REM", "ADD", - "SUB", "LSH", "RSH", "USH", "LT", "LTE", "GT", "GTE", "EQ", "EQR", "NE", - "NER", "BWAND", "XOR", "BWOR", "BOOLAND", "BOOLOR", "COND", "COLON", "ELVIS", - "REF", "ARROW", "FIND", "MATCH", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", - "AMUL", "ADIV", "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", - "OCTAL", "HEX", "INTEGER", "DECIMAL", "STRING", "REGEX", "TRUE", "FALSE", + null, "WS", "COMMENT", "LBRACK", "RBRACK", "LBRACE", "RBRACE", "LP", "RP", + "DOT", "NSDOT", "COMMA", "SEMICOLON", "IF", "IN", "ELSE", "WHILE", "DO", + "FOR", "CONTINUE", "BREAK", "RETURN", "NEW", "TRY", "CATCH", "THROW", + "THIS", "INSTANCEOF", "BOOLNOT", "BWNOT", "MUL", "DIV", "REM", "ADD", + "SUB", "LSH", "RSH", "USH", "LT", "LTE", "GT", "GTE", "EQ", "EQR", "NE", + "NER", "BWAND", "XOR", "BWOR", "BOOLAND", "BOOLOR", "COND", "COLON", "ELVIS", + "REF", "ARROW", "FIND", "MATCH", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", + "AMUL", "ADIV", "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", + "OCTAL", "HEX", "INTEGER", "DECIMAL", "STRING", "REGEX", "TRUE", "FALSE", "NULL", "TYPE", "ID", "DOTINTEGER", "DOTID" }; public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); @@ -106,7 +113,7 @@ public Vocabulary getVocabulary() { * See also * The lexer hack. */ - protected abstract boolean isSimpleType(String name); + protected abstract boolean isType(String name); /** * Is the preceding {@code /} a the beginning of a regex (true) or a division @@ -164,7 +171,7 @@ private boolean REGEX_sempred(RuleContext _localctx, int predIndex) { private boolean TYPE_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 2: - return isSimpleType(getText()) ; + return isType(getText()) ; } return true; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java index 9cd3334aa51da..bef57d22e9ea9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java @@ -1,9 +1,24 @@ // ANTLR GENERATED CODE: DO NOT EDIT package org.elasticsearch.painless.antlr; -import org.antlr.v4.runtime.atn.*; + +import org.antlr.v4.runtime.FailedPredicateException; +import org.antlr.v4.runtime.NoViableAltException; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.RuntimeMetaData; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.Vocabulary; +import org.antlr.v4.runtime.VocabularyImpl; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.ParserATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; +import org.antlr.v4.runtime.tree.TerminalNode; + import java.util.List; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) @@ -14,57 +29,57 @@ class PainlessParser extends Parser { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - WS=1, COMMENT=2, LBRACK=3, RBRACK=4, LBRACE=5, RBRACE=6, LP=7, RP=8, DOT=9, - NSDOT=10, COMMA=11, SEMICOLON=12, IF=13, IN=14, ELSE=15, WHILE=16, DO=17, - FOR=18, CONTINUE=19, BREAK=20, RETURN=21, NEW=22, TRY=23, CATCH=24, THROW=25, - THIS=26, INSTANCEOF=27, BOOLNOT=28, BWNOT=29, MUL=30, DIV=31, REM=32, - ADD=33, SUB=34, LSH=35, RSH=36, USH=37, LT=38, LTE=39, GT=40, GTE=41, - EQ=42, EQR=43, NE=44, NER=45, BWAND=46, XOR=47, BWOR=48, BOOLAND=49, BOOLOR=50, - COND=51, COLON=52, ELVIS=53, REF=54, ARROW=55, FIND=56, MATCH=57, INCR=58, - DECR=59, ASSIGN=60, AADD=61, ASUB=62, AMUL=63, ADIV=64, AREM=65, AAND=66, - AXOR=67, AOR=68, ALSH=69, ARSH=70, AUSH=71, OCTAL=72, HEX=73, INTEGER=74, - DECIMAL=75, STRING=76, REGEX=77, TRUE=78, FALSE=79, NULL=80, TYPE=81, + WS=1, COMMENT=2, LBRACK=3, RBRACK=4, LBRACE=5, RBRACE=6, LP=7, RP=8, DOT=9, + NSDOT=10, COMMA=11, SEMICOLON=12, IF=13, IN=14, ELSE=15, WHILE=16, DO=17, + FOR=18, CONTINUE=19, BREAK=20, RETURN=21, NEW=22, TRY=23, CATCH=24, THROW=25, + THIS=26, INSTANCEOF=27, BOOLNOT=28, BWNOT=29, MUL=30, DIV=31, REM=32, + ADD=33, SUB=34, LSH=35, RSH=36, USH=37, LT=38, LTE=39, GT=40, GTE=41, + EQ=42, EQR=43, NE=44, NER=45, BWAND=46, XOR=47, BWOR=48, BOOLAND=49, BOOLOR=50, + COND=51, COLON=52, ELVIS=53, REF=54, ARROW=55, FIND=56, MATCH=57, INCR=58, + DECR=59, ASSIGN=60, AADD=61, ASUB=62, AMUL=63, ADIV=64, AREM=65, AAND=66, + AXOR=67, AOR=68, ALSH=69, ARSH=70, AUSH=71, OCTAL=72, HEX=73, INTEGER=74, + DECIMAL=75, STRING=76, REGEX=77, TRUE=78, FALSE=79, NULL=80, TYPE=81, ID=82, DOTINTEGER=83, DOTID=84; public static final int - RULE_source = 0, RULE_function = 1, RULE_parameters = 2, RULE_statement = 3, - RULE_rstatement = 4, RULE_dstatement = 5, RULE_trailer = 6, RULE_block = 7, - RULE_empty = 8, RULE_initializer = 9, RULE_afterthought = 10, RULE_declaration = 11, - RULE_decltype = 12, RULE_declvar = 13, RULE_trap = 14, RULE_expression = 15, - RULE_unary = 16, RULE_chain = 17, RULE_primary = 18, RULE_postfix = 19, - RULE_postdot = 20, RULE_callinvoke = 21, RULE_fieldaccess = 22, RULE_braceaccess = 23, - RULE_arrayinitializer = 24, RULE_listinitializer = 25, RULE_mapinitializer = 26, - RULE_maptoken = 27, RULE_arguments = 28, RULE_argument = 29, RULE_lambda = 30, + RULE_source = 0, RULE_function = 1, RULE_parameters = 2, RULE_statement = 3, + RULE_rstatement = 4, RULE_dstatement = 5, RULE_trailer = 6, RULE_block = 7, + RULE_empty = 8, RULE_initializer = 9, RULE_afterthought = 10, RULE_declaration = 11, + RULE_decltype = 12, RULE_declvar = 13, RULE_trap = 14, RULE_expression = 15, + RULE_unary = 16, RULE_chain = 17, RULE_primary = 18, RULE_postfix = 19, + RULE_postdot = 20, RULE_callinvoke = 21, RULE_fieldaccess = 22, RULE_braceaccess = 23, + RULE_arrayinitializer = 24, RULE_listinitializer = 25, RULE_mapinitializer = 26, + RULE_maptoken = 27, RULE_arguments = 28, RULE_argument = 29, RULE_lambda = 30, RULE_lamtype = 31, RULE_funcref = 32; public static final String[] ruleNames = { - "source", "function", "parameters", "statement", "rstatement", "dstatement", - "trailer", "block", "empty", "initializer", "afterthought", "declaration", - "decltype", "declvar", "trap", "expression", "unary", "chain", "primary", - "postfix", "postdot", "callinvoke", "fieldaccess", "braceaccess", "arrayinitializer", - "listinitializer", "mapinitializer", "maptoken", "arguments", "argument", + "source", "function", "parameters", "statement", "rstatement", "dstatement", + "trailer", "block", "empty", "initializer", "afterthought", "declaration", + "decltype", "declvar", "trap", "expression", "unary", "chain", "primary", + "postfix", "postdot", "callinvoke", "fieldaccess", "braceaccess", "arrayinitializer", + "listinitializer", "mapinitializer", "maptoken", "arguments", "argument", "lambda", "lamtype", "funcref" }; private static final String[] _LITERAL_NAMES = { - null, null, null, "'{'", "'}'", "'['", "']'", "'('", "')'", "'.'", "'?.'", - "','", "';'", "'if'", "'in'", "'else'", "'while'", "'do'", "'for'", "'continue'", - "'break'", "'return'", "'new'", "'try'", "'catch'", "'throw'", "'this'", - "'instanceof'", "'!'", "'~'", "'*'", "'/'", "'%'", "'+'", "'-'", "'<<'", - "'>>'", "'>>>'", "'<'", "'<='", "'>'", "'>='", "'=='", "'==='", "'!='", - "'!=='", "'&'", "'^'", "'|'", "'&&'", "'||'", "'?'", "':'", "'?:'", "'::'", - "'->'", "'=~'", "'==~'", "'++'", "'--'", "'='", "'+='", "'-='", "'*='", - "'/='", "'%='", "'&='", "'^='", "'|='", "'<<='", "'>>='", "'>>>='", null, + null, null, null, "'{'", "'}'", "'['", "']'", "'('", "')'", "'.'", "'?.'", + "','", "';'", "'if'", "'in'", "'else'", "'while'", "'do'", "'for'", "'continue'", + "'break'", "'return'", "'new'", "'try'", "'catch'", "'throw'", "'this'", + "'instanceof'", "'!'", "'~'", "'*'", "'/'", "'%'", "'+'", "'-'", "'<<'", + "'>>'", "'>>>'", "'<'", "'<='", "'>'", "'>='", "'=='", "'==='", "'!='", + "'!=='", "'&'", "'^'", "'|'", "'&&'", "'||'", "'?'", "':'", "'?:'", "'::'", + "'->'", "'=~'", "'==~'", "'++'", "'--'", "'='", "'+='", "'-='", "'*='", + "'/='", "'%='", "'&='", "'^='", "'|='", "'<<='", "'>>='", "'>>>='", null, null, null, null, null, null, "'true'", "'false'", "'null'" }; private static final String[] _SYMBOLIC_NAMES = { - null, "WS", "COMMENT", "LBRACK", "RBRACK", "LBRACE", "RBRACE", "LP", "RP", - "DOT", "NSDOT", "COMMA", "SEMICOLON", "IF", "IN", "ELSE", "WHILE", "DO", - "FOR", "CONTINUE", "BREAK", "RETURN", "NEW", "TRY", "CATCH", "THROW", - "THIS", "INSTANCEOF", "BOOLNOT", "BWNOT", "MUL", "DIV", "REM", "ADD", - "SUB", "LSH", "RSH", "USH", "LT", "LTE", "GT", "GTE", "EQ", "EQR", "NE", - "NER", "BWAND", "XOR", "BWOR", "BOOLAND", "BOOLOR", "COND", "COLON", "ELVIS", - "REF", "ARROW", "FIND", "MATCH", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", - "AMUL", "ADIV", "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", - "OCTAL", "HEX", "INTEGER", "DECIMAL", "STRING", "REGEX", "TRUE", "FALSE", + null, "WS", "COMMENT", "LBRACK", "RBRACK", "LBRACE", "RBRACE", "LP", "RP", + "DOT", "NSDOT", "COMMA", "SEMICOLON", "IF", "IN", "ELSE", "WHILE", "DO", + "FOR", "CONTINUE", "BREAK", "RETURN", "NEW", "TRY", "CATCH", "THROW", + "THIS", "INSTANCEOF", "BOOLNOT", "BWNOT", "MUL", "DIV", "REM", "ADD", + "SUB", "LSH", "RSH", "USH", "LT", "LTE", "GT", "GTE", "EQ", "EQR", "NE", + "NER", "BWAND", "XOR", "BWOR", "BOOLAND", "BOOLOR", "COND", "COLON", "ELVIS", + "REF", "ARROW", "FIND", "MATCH", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", + "AMUL", "ADIV", "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", + "OCTAL", "HEX", "INTEGER", "DECIMAL", "STRING", "REGEX", "TRUE", "FALSE", "NULL", "TYPE", "ID", "DOTINTEGER", "DOTID" }; public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); @@ -162,7 +177,7 @@ public final SourceContext source() throws RecognitionException { setState(66); function(); } - } + } } setState(71); _errHandler.sync(this); @@ -178,7 +193,7 @@ public final SourceContext source() throws RecognitionException { setState(72); statement(); } - } + } } setState(77); _errHandler.sync(this); @@ -426,7 +441,7 @@ public RstatementContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_rstatement; } - + public RstatementContext() { } public void copyFrom(RstatementContext ctx) { super.copyFrom(ctx); @@ -805,7 +820,7 @@ public final RstatementContext rstatement() throws RecognitionException { match(TRY); setState(164); block(); - setState(166); + setState(166); _errHandler.sync(this); _alt = 1; do { @@ -821,7 +836,7 @@ public final RstatementContext rstatement() throws RecognitionException { default: throw new NoViableAltException(this); } - setState(168); + setState(168); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,12,_ctx); } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ); @@ -845,7 +860,7 @@ public DstatementContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_dstatement; } - + public DstatementContext() { } public void copyFrom(DstatementContext ctx) { super.copyFrom(ctx); @@ -1148,7 +1163,7 @@ public final BlockContext block() throws RecognitionException { setState(194); statement(); } - } + } } setState(199); _errHandler.sync(this); @@ -1407,7 +1422,7 @@ public final DecltypeContext decltype() throws RecognitionException { setState(224); match(RBRACE); } - } + } } setState(229); _errHandler.sync(this); @@ -1532,7 +1547,7 @@ public ExpressionContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_expression; } - + public ExpressionContext() { } public void copyFrom(ExpressionContext ctx) { super.copyFrom(ctx); @@ -1943,7 +1958,7 @@ private ExpressionContext expression(int _p) throws RecognitionException { } break; } - } + } } setState(297); _errHandler.sync(this); @@ -1967,7 +1982,7 @@ public UnaryContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_unary; } - + public UnaryContext() { } public void copyFrom(UnaryContext ctx) { super.copyFrom(ctx); @@ -2135,7 +2150,7 @@ public ChainContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_chain; } - + public ChainContext() { } public void copyFrom(ChainContext ctx) { super.copyFrom(ctx); @@ -2214,7 +2229,7 @@ public final ChainContext chain() throws RecognitionException { setState(314); postfix(); } - } + } } setState(319); _errHandler.sync(this); @@ -2240,7 +2255,7 @@ public final ChainContext chain() throws RecognitionException { setState(322); postfix(); } - } + } } setState(327); _errHandler.sync(this); @@ -2274,7 +2289,7 @@ public PrimaryContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_primary; } - + public PrimaryContext() { } public void copyFrom(PrimaryContext ctx) { super.copyFrom(ctx); @@ -2799,7 +2814,7 @@ public ArrayinitializerContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_arrayinitializer; } - + public ArrayinitializerContext() { } public void copyFrom(ArrayinitializerContext ctx) { super.copyFrom(ctx); @@ -2886,7 +2901,7 @@ public final ArrayinitializerContext arrayinitializer() throws RecognitionExcept match(NEW); setState(372); match(TYPE); - setState(377); + setState(377); _errHandler.sync(this); _alt = 1; do { @@ -2906,7 +2921,7 @@ public final ArrayinitializerContext arrayinitializer() throws RecognitionExcept default: throw new NoViableAltException(this); } - setState(379); + setState(379); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,31,_ctx); } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ); @@ -2927,7 +2942,7 @@ public final ArrayinitializerContext arrayinitializer() throws RecognitionExcept setState(382); postfix(); } - } + } } setState(387); _errHandler.sync(this); @@ -2989,7 +3004,7 @@ public final ArrayinitializerContext arrayinitializer() throws RecognitionExcept setState(406); postfix(); } - } + } } setState(411); _errHandler.sync(this); @@ -3542,7 +3557,7 @@ public FuncrefContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_funcref; } - + public FuncrefContext() { } public void copyFrom(FuncrefContext ctx) { super.copyFrom(ctx); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java index 3ac6cb7fd37c4..a481c99a99d12 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java @@ -986,19 +986,20 @@ public AExpression visitBraceaccess(BraceaccessContext ctx, AExpression prefix) @Override public ANode visitNewstandardarray(NewstandardarrayContext ctx) { - String type = ctx.TYPE().getText(); + StringBuilder type = new StringBuilder(ctx.TYPE().getText()); List expressions = new ArrayList<>(); for (ExpressionContext expression : ctx.expression()) { + type.append("[]"); expressions.add((AExpression)visit(expression)); } - return buildPostfixChain(new ENewArray(location(ctx), type, expressions, false), ctx.postdot(), ctx.postfix()); + return buildPostfixChain(new ENewArray(location(ctx), type.toString(), expressions, false), ctx.postdot(), ctx.postfix()); } @Override public ANode visitNewinitializedarray(NewinitializedarrayContext ctx) { - String type = ctx.TYPE().getText(); + String type = ctx.TYPE().getText() + "[]"; List expressions = new ArrayList<>(); for (ExpressionContext expression : ctx.expression()) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java index eaf8045bf1c65..5a897e04a8d98 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; @@ -51,7 +50,7 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { try { - actual = Definition.TypeToClass(locals.getDefinition().getType(type)); + actual = locals.getDefinition().getJavaClassFromPainlessType(type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + type + "].")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index c82b1003a55f1..21bef9aa2ed5d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -66,7 +66,7 @@ void analyze(Locals locals) { try { if ("this".equals(type)) { // user's own function - Method interfaceMethod = locals.getDefinition().ClassToType(expected).struct.functionalMethod; + Method interfaceMethod = locals.getDefinition().getPainlessStructFromJavaClass(expected).functionalMethod; if (interfaceMethod == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + "to [" + Definition.ClassToName(expected) + "], not a functional interface"); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java index 54403b51f04bd..5296d79e214ed 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java @@ -58,7 +58,7 @@ void analyze(Locals locals) { // ensure the specified type is part of the definition try { - clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); + clazz = locals.getDefinition().getJavaClassFromPainlessType(this.type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index a7213e75ca485..e40d21ab110ab 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -120,7 +120,7 @@ void analyze(Locals locals) { } } else { // we know the method statically, infer return type and any unknown/def types - interfaceMethod = locals.getDefinition().ClassToType(expected).struct.functionalMethod; + interfaceMethod = locals.getDefinition().getPainlessStructFromJavaClass(expected).functionalMethod; if (interfaceMethod == null) { throw createError(new IllegalArgumentException("Cannot pass lambda to [" + Definition.ClassToName(expected) + "], not a functional interface")); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index d957be0aadb50..05b10796cb4f9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -61,13 +61,13 @@ void analyze(Locals locals) { actual = ArrayList.class; - constructor = locals.getDefinition().ClassToType(actual).struct.constructors.get(new MethodKey("", 0)); + constructor = locals.getDefinition().getPainlessStructFromJavaClass(actual).constructors.get(new MethodKey("", 0)); if (constructor == null) { throw createError(new IllegalStateException("Illegal tree structure.")); } - method = locals.getDefinition().ClassToType(actual).struct.methods.get(new MethodKey("add", 1)); + method = locals.getDefinition().getPainlessStructFromJavaClass(actual).methods.get(new MethodKey("add", 1)); if (method == null) { throw createError(new IllegalStateException("Illegal tree structure.")); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index 2cd864da24b65..f5763042b8191 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -67,13 +67,13 @@ void analyze(Locals locals) { actual = HashMap.class; - constructor = locals.getDefinition().ClassToType(actual).struct.constructors.get(new MethodKey("", 0)); + constructor = locals.getDefinition().getPainlessStructFromJavaClass(actual).constructors.get(new MethodKey("", 0)); if (constructor == null) { throw createError(new IllegalStateException("Illegal tree structure.")); } - method = locals.getDefinition().ClassToType(actual).struct.methods.get(new MethodKey("put", 2)); + method = locals.getDefinition().getPainlessStructFromJavaClass(actual).methods.get(new MethodKey("put", 2)); if (method == null) { throw createError(new IllegalStateException("Illegal tree structure.")); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java index c1d58cb2f2ad9..1a0a718ae7fc8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; @@ -38,8 +37,6 @@ public final class ENewArray extends AExpression { private final List arguments; private final boolean initialize; - private Class array; - public ENewArray(Location location, String type, List arguments, boolean initialize) { super(location); @@ -64,7 +61,7 @@ void analyze(Locals locals) { Class clazz; try { - clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); + clazz = locals.getDefinition().getJavaClassFromPainlessType(this.type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } @@ -72,15 +69,13 @@ void analyze(Locals locals) { for (int argument = 0; argument < arguments.size(); ++argument) { AExpression expression = arguments.get(argument); - expression.expected = initialize ? clazz : int.class; + expression.expected = initialize ? clazz.getComponentType() : int.class; expression.internal = true; expression.analyze(locals); arguments.set(argument, expression.cast(locals)); } - actual = Definition.TypeToClass(locals.getDefinition().getType( - locals.getDefinition().ClassToType(clazz).struct, initialize ? 1 : arguments.size())); - array = Definition.defClassToObjectClass(actual); + actual = clazz; } @Override @@ -89,7 +84,7 @@ void write(MethodWriter writer, Globals globals) { if (initialize) { writer.push(arguments.size()); - writer.newArray(MethodWriter.getType(array.getComponentType())); + writer.newArray(MethodWriter.getType(actual.getComponentType())); for (int index = 0; index < arguments.size(); ++index) { AExpression argument = arguments.get(index); @@ -97,7 +92,7 @@ void write(MethodWriter writer, Globals globals) { writer.dup(); writer.push(index); argument.write(writer, globals); - writer.arrayStore(MethodWriter.getType(array.getComponentType())); + writer.arrayStore(MethodWriter.getType(actual.getComponentType())); } } else { for (AExpression argument : arguments) { @@ -105,9 +100,9 @@ void write(MethodWriter writer, Globals globals) { } if (arguments.size() > 1) { - writer.visitMultiANewArrayInsn(MethodWriter.getType(array).getDescriptor(), arguments.size()); + writer.visitMultiANewArrayInsn(MethodWriter.getType(actual).getDescriptor(), arguments.size()); } else { - writer.newArray(MethodWriter.getType(array.getComponentType())); + writer.newArray(MethodWriter.getType(actual.getComponentType())); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java index 2a96d68bcb417..e3a926ef2244b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java @@ -58,12 +58,12 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { try { - actual = Definition.TypeToClass(locals.getDefinition().getType(this.type)); + actual = locals.getDefinition().getJavaClassFromPainlessType(this.type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } - Struct struct = locals.getDefinition().ClassToType(actual).struct; + Struct struct = locals.getDefinition().getPainlessStructFromJavaClass(actual); constructor = struct.constructors.get(new Definition.MethodKey("", arguments.size())); if (constructor != null) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java index 5c3b4cadf6ee9..fa249b9df6237 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java @@ -72,7 +72,7 @@ void analyze(Locals locals) { } constant = new Constant( - location, locals.getDefinition().PatternType.type, "regexAt$" + location.getOffset(), this::initializeConstant); + location, MethodWriter.getType(Pattern.class), "regexAt$" + location.getOffset(), this::initializeConstant); actual = Pattern.class; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java index f5c2c6e9da354..5ebf30f5781cf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; @@ -49,7 +48,7 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { try { - actual = Definition.TypeToClass(locals.getDefinition().getType(type)); + actual = locals.getDefinition().getJavaClassFromPainlessType(type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + type + "].")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java index 6712eccd914c5..0e2ab70897fe5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java @@ -63,9 +63,9 @@ void analyze(Locals locals) { } else if (prefix.actual == def.class) { sub = new PSubDefArray(location, index); } else if (Map.class.isAssignableFrom(prefix.actual)) { - sub = new PSubMapShortcut(location, locals.getDefinition().ClassToType(prefix.actual).struct, index); + sub = new PSubMapShortcut(location, locals.getDefinition().getPainlessStructFromJavaClass(prefix.actual), index); } else if (List.class.isAssignableFrom(prefix.actual)) { - sub = new PSubListShortcut(location, locals.getDefinition().ClassToType(prefix.actual).struct, index); + sub = new PSubListShortcut(location, locals.getDefinition().getPainlessStructFromJavaClass(prefix.actual), index); } else { throw createError( new IllegalArgumentException("Illegal array access on type [" + Definition.ClassToName(prefix.actual) + "].")); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java index 498fb83239395..6fff5a8e93f3e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java @@ -71,10 +71,10 @@ void analyze(Locals locals) { throw createError(new IllegalArgumentException("Illegal call [" + name + "] on array type.")); } - Struct struct = locals.getDefinition().ClassToType(prefix.actual).struct; + Struct struct = locals.getDefinition().getPainlessStructFromJavaClass(prefix.actual); if (prefix.actual.isPrimitive()) { - struct = locals.getDefinition().ClassToType(Definition.getBoxedType(prefix.actual)).struct; + struct = locals.getDefinition().getPainlessStructFromJavaClass(Definition.getBoxedType(prefix.actual)); } MethodKey methodKey = new MethodKey(name, arguments.size()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java index 1f492758af618..de2c05dfa9b28 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java @@ -67,7 +67,7 @@ void analyze(Locals locals) { } else if (prefix.actual == def.class) { sub = new PSubDefField(location, value); } else { - Struct struct = locals.getDefinition().ClassToType(prefix.actual).struct; + Struct struct = locals.getDefinition().getPainlessStructFromJavaClass(prefix.actual); Field field = prefix instanceof EStatic ? struct.staticMembers.get(value) : struct.members.get(value); if (field != null) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index d98c2f2276eaa..6428e47d1bacc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -20,7 +20,6 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.DefBootstrap; - import org.elasticsearch.painless.Definition.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java index 535ad5235b07c..98e45ca29f416 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; @@ -68,7 +67,7 @@ void analyze(Locals locals) { Class clazz; try { - clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); + clazz = locals.getDefinition().getJavaClassFromPainlessType(this.type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java index f00db583ceae4..9f3f86abf438b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; @@ -63,7 +62,7 @@ void analyze(Locals locals) { Class clazz; try { - clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); + clazz = locals.getDefinition().getJavaClassFromPainlessType(this.type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java index 04de0c0696e96..a3c8319825a26 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java @@ -71,7 +71,7 @@ void analyze(Locals locals) { Class clazz; try { - clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); + clazz = locals.getDefinition().getJavaClassFromPainlessType(this.type); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java index 5fa62f27e94dc..1b1e6bd2ef84b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java @@ -119,7 +119,7 @@ void extractVariables(Set variables) { void generateSignature(Definition definition) { try { - rtnType = Definition.TypeToClass(definition.getType(rtnTypeStr)); + rtnType = definition.getJavaClassFromPainlessType(rtnTypeStr); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Illegal return type [" + rtnTypeStr + "] for function [" + name + "].")); } @@ -133,7 +133,7 @@ void generateSignature(Definition definition) { for (int param = 0; param < this.paramTypeStrs.size(); ++param) { try { - Class paramType = Definition.TypeToClass(definition.getType(this.paramTypeStrs.get(param))); + Class paramType = definition.getJavaClassFromPainlessType(this.paramTypeStrs.get(param)); paramClasses[param] = Definition.defClassToObjectClass(paramType); paramTypes.add(paramType); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java index ca30d641e7468..11e0f15d7e4f8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java @@ -25,7 +25,6 @@ import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.MethodKey; -import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; @@ -78,12 +77,11 @@ void analyze(Locals locals) { if (expression.actual == def.class) { method = null; } else { - Type actualType = locals.getDefinition().ClassToType(expression.actual); - method = actualType.struct.methods.get(new MethodKey("iterator", 0)); + method = locals.getDefinition().getPainlessStructFromJavaClass(expression.actual).methods.get(new MethodKey("iterator", 0)); if (method == null) { throw createError(new IllegalArgumentException( - "Unable to create iterator for the type [" + actualType.name + "].")); + "Unable to create iterator for the type [" + Definition.ClassToName(expression.actual) + "].")); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java index 8fd96d67d5b53..52528c358fc82 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java @@ -1,5 +1,3 @@ -package org.elasticsearch.painless; - /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with @@ -19,6 +17,8 @@ * under the License. */ +package org.elasticsearch.painless; + import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java index ed38f4c511f59..309b6be97f20b 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java @@ -26,9 +26,6 @@ import org.elasticsearch.painless.Definition.Field; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Struct; -import org.elasticsearch.painless.Definition.Type; -import org.elasticsearch.painless.spi.Whitelist; - import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Modifier; @@ -44,12 +41,14 @@ import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; +import static org.elasticsearch.painless.spi.Whitelist.BASE_WHITELISTS; /** * Generates an API reference from the method and type whitelists in {@link Definition}. */ public class PainlessDocGenerator { - private static final Definition definition = new Definition(Whitelist.BASE_WHITELISTS); + + private static final Definition definition = new Definition(BASE_WHITELISTS); private static final Logger logger = ESLoggerFactory.getLogger(PainlessDocGenerator.class); private static final Comparator FIELD_NAME = comparing(f -> f.name); private static final Comparator METHOD_NAME = comparing(m -> m.name); @@ -68,41 +67,41 @@ public static void main(String[] args) throws IOException { Files.newOutputStream(indexPath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE), false, StandardCharsets.UTF_8.name())) { emitGeneratedWarning(indexStream); - List types = definition.allSimpleTypes().stream().sorted(comparing(t -> t.name)).collect(toList()); - for (Type type : types) { - if (type.clazz.isPrimitive()) { + List structs = definition.getStructs().stream().sorted(comparing(t -> t.name)).collect(toList()); + for (Struct struct : structs) { + if (struct.clazz.isPrimitive()) { // Primitives don't have methods to reference continue; } - if ("def".equals(type.name)) { + if ("def".equals(struct.name)) { // def is special but doesn't have any methods all of its own. continue; } indexStream.print("include::"); - indexStream.print(type.struct.name); + indexStream.print(struct.name); indexStream.println(".asciidoc[]"); - Path typePath = apiRootPath.resolve(type.struct.name + ".asciidoc"); - logger.info("Writing [{}.asciidoc]", type.name); + Path typePath = apiRootPath.resolve(struct.name + ".asciidoc"); + logger.info("Writing [{}.asciidoc]", struct.name); try (PrintStream typeStream = new PrintStream( Files.newOutputStream(typePath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE), false, StandardCharsets.UTF_8.name())) { emitGeneratedWarning(typeStream); typeStream.print("[["); - emitAnchor(typeStream, type.struct); + emitAnchor(typeStream, struct); typeStream.print("]]++"); - typeStream.print(type.name); + typeStream.print(struct.name); typeStream.println("++::"); Consumer documentField = field -> PainlessDocGenerator.documentField(typeStream, field); Consumer documentMethod = method -> PainlessDocGenerator.documentMethod(typeStream, method); - type.struct.staticMembers.values().stream().sorted(FIELD_NAME).forEach(documentField); - type.struct.members.values().stream().sorted(FIELD_NAME).forEach(documentField); - type.struct.staticMethods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(documentMethod); - type.struct.constructors.values().stream().sorted(NUMBER_OF_ARGS).forEach(documentMethod); + struct.staticMembers.values().stream().sorted(FIELD_NAME).forEach(documentField); + struct.members.values().stream().sorted(FIELD_NAME).forEach(documentField); + struct.staticMethods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(documentMethod); + struct.constructors.values().stream().sorted(NUMBER_OF_ARGS).forEach(documentMethod); Map inherited = new TreeMap<>(); - type.struct.methods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(method -> { - if (method.owner == type.struct) { + struct.methods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(method -> { + if (method.owner == struct) { documentMethod(typeStream, method); } else { inherited.put(method.owner.name, method.owner); @@ -139,7 +138,7 @@ private static void documentField(PrintStream stream, Field field) { stream.print("static "); } - emitType(stream, definition.ClassToType(field.clazz)); + emitType(stream, field.clazz); stream.print(' '); String javadocRoot = javadocRoot(field); @@ -170,7 +169,7 @@ private static void documentMethod(PrintStream stream, Method method) { } if (false == method.name.equals("")) { - emitType(stream, definition.ClassToType(method.rtn)); + emitType(stream, method.rtn); stream.print(' '); } @@ -188,7 +187,7 @@ private static void documentMethod(PrintStream stream, Method method) { } else { stream.print(", "); } - emitType(stream, definition.ClassToType(arg)); + emitType(stream, arg); } stream.print(")++"); @@ -234,19 +233,19 @@ private static String methodName(Method method) { } /** - * Emit a {@link Type}. If the type is primitive or an array of primitives this just emits the name of the type. Otherwise this emits an - * internal link with the text. + * Emit a {@link Class}. If the type is primitive or an array of primitives this just emits the name of the type. Otherwise this emits + an internal link with the text. */ - private static void emitType(PrintStream stream, Type type) { - emitStruct(stream, type.struct); - for (int i = 0; i < type.dimensions; i++) { + private static void emitType(PrintStream stream, Class clazz) { + emitStruct(stream, definition.getPainlessStructFromJavaClass(clazz)); + while ((clazz = clazz.getComponentType()) != null) { stream.print("[]"); } } /** - * Emit a {@link Struct}. If the {@linkplain Struct} is primitive or def this just emits the name of the struct. Otherwise this emits an - * internal link with the name. + * Emit a {@link Struct}. If the {@linkplain Struct} is primitive or def this just emits the name of the struct. Otherwise this emits + * an internal link with the name. */ private static void emitStruct(PrintStream stream, Struct struct) { if (false == struct.clazz.isPrimitive() && false == struct.name.equals("def")) { @@ -279,14 +278,13 @@ private static void emitJavadocLink(PrintStream stream, String root, Method meth stream.print(method.owner.clazz.getName()); } for (Class clazz: method.arguments) { - Type arg = definition.ClassToType(clazz); if (first) { first = false; } else { stream.print("%2D"); } - stream.print(arg.struct.clazz.getName()); - if (arg.dimensions > 0) { + stream.print(clazz.getName()); + if (clazz.isArray()) { stream.print(":A"); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java index 6dbe480d4b5a3..fd8190aa2c2eb 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java @@ -284,12 +284,12 @@ public void testEMapInit() { } public void testENewArray() { - assertToString("(SSource (SReturn (ENewArray int dims (Args (ENumeric 10)))))", "return new int[10]"); - assertToString("(SSource (SReturn (ENewArray int dims (Args (ENumeric 10) (ENumeric 4) (ENumeric 5)))))", + assertToString("(SSource (SReturn (ENewArray int[] dims (Args (ENumeric 10)))))", "return new int[10]"); + assertToString("(SSource (SReturn (ENewArray int[][][] dims (Args (ENumeric 10) (ENumeric 4) (ENumeric 5)))))", "return new int[10][4][5]"); - assertToString("(SSource (SReturn (ENewArray int init (Args (ENumeric 1) (ENumeric 2) (ENumeric 3)))))", + assertToString("(SSource (SReturn (ENewArray int[] init (Args (ENumeric 1) (ENumeric 2) (ENumeric 3)))))", "return new int[] {1, 2, 3}"); - assertToString("(SSource (SReturn (ENewArray def init (Args (ENumeric 1) (ENumeric 2) (EString 'bird')))))", + assertToString("(SSource (SReturn (ENewArray def[] init (Args (ENumeric 1) (ENumeric 2) (EString 'bird')))))", "return new def[] {1, 2, 'bird'}"); } @@ -372,7 +372,7 @@ public void testPField() { assertToString("(SSource (SReturn (PField nullSafe (EVariable params) a)))", "return params?.a"); assertToString( "(SSource\n" - + " (SDeclBlock (SDeclaration int[] a (ENewArray int dims (Args (ENumeric 10)))))\n" + + " (SDeclBlock (SDeclaration int[] a (ENewArray int[] dims (Args (ENumeric 10)))))\n" + " (SReturn (PField (EVariable a) length)))", "int[] a = new int[10];\n" + "return a.length"); @@ -403,7 +403,7 @@ public void testPSubBrace() { public void testPSubCallInvoke() { Location l = new Location(getTestName(), 0); - Struct c = definition.ClassToType(Integer.class).struct; + Struct c = definition.getPainlessStructFromJavaClass(Integer.class); Method m = c.methods.get(new MethodKey("toString", 0)); PSubCallInvoke node = new PSubCallInvoke(l, m, null, emptyList()); node.prefix = new EVariable(l, "a"); @@ -458,7 +458,7 @@ public void testPSubDefField() { public void testPSubField() { Location l = new Location(getTestName(), 0); - Struct s = definition.getType(Boolean.class.getSimpleName()).struct; + Struct s = definition.getPainlessStructFromJavaClass(Boolean.class); Field f = s.staticMembers.get("TRUE"); PSubField node = new PSubField(l, f); node.prefix = new EStatic(l, "Boolean"); @@ -468,7 +468,7 @@ public void testPSubField() { public void testPSubListShortcut() { Location l = new Location(getTestName(), 0); - Struct s = definition.getType(List.class.getSimpleName()).struct; + Struct s = definition.getPainlessStructFromJavaClass(List.class); PSubListShortcut node = new PSubListShortcut(l, s, new EConstant(l, 1)); node.prefix = new EVariable(l, "a"); assertEquals("(PSubListShortcut (EVariable a) (EConstant Integer 1))", node.toString()); @@ -476,7 +476,7 @@ public void testPSubListShortcut() { new PSubNullSafeCallInvoke(l, node).toString()); l = new Location(getTestName(), 0); - s = definition.getType(List.class.getSimpleName()).struct; + s = definition.getPainlessStructFromJavaClass(List.class); node = new PSubListShortcut(l, s, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4))); node.prefix = new EVariable(l, "a"); assertEquals("(PSubListShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString()); @@ -484,7 +484,7 @@ public void testPSubListShortcut() { public void testPSubMapShortcut() { Location l = new Location(getTestName(), 0); - Struct s = definition.getType(Map.class.getSimpleName()).struct; + Struct s = definition.getPainlessStructFromJavaClass(Map.class); PSubMapShortcut node = new PSubMapShortcut(l, s, new EConstant(l, "cat")); node.prefix = new EVariable(l, "a"); assertEquals("(PSubMapShortcut (EVariable a) (EConstant String 'cat'))", node.toString()); @@ -492,7 +492,7 @@ public void testPSubMapShortcut() { new PSubNullSafeCallInvoke(l, node).toString()); l = new Location(getTestName(), 1); - s = definition.getType(Map.class.getSimpleName()).struct; + s = definition.getPainlessStructFromJavaClass(Map.class); node = new PSubMapShortcut(l, s, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4))); node.prefix = new EVariable(l, "a"); assertEquals("(PSubMapShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString()); @@ -500,7 +500,7 @@ public void testPSubMapShortcut() { public void testPSubShortcut() { Location l = new Location(getTestName(), 0); - Struct s = definition.getType(FeatureTest.class.getName()).struct; + Struct s = definition.getPainlessStructFromJavaClass(FeatureTest.class); Method getter = s.methods.get(new MethodKey("getX", 0)); Method setter = s.methods.get(new MethodKey("setX", 1)); PSubShortcut node = new PSubShortcut(l, "x", FeatureTest.class.getName(), getter, setter);