Remove Painless Type from e-nodes in favor of Java Class (#28364)

This commit is contained in:
Jack Conradson 2018-01-29 12:44:50 -08:00 committed by GitHub
parent 43d1dcb919
commit f13da9f534
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 593 additions and 677 deletions

View File

@ -452,60 +452,60 @@ public final class Definition {
return getTypeInternal(struct, dimensions); return getTypeInternal(struct, dimensions);
} }
public Type getBoxedType(Type unboxed) { public static Class<?> getBoxedType(Class<?> clazz) {
if (unboxed.clazz == boolean.class) { if (clazz == boolean.class) {
return BooleanType; return Boolean.class;
} else if (unboxed.clazz == byte.class) { } else if (clazz == byte.class) {
return ByteType; return Byte.class;
} else if (unboxed.clazz == short.class) { } else if (clazz == short.class) {
return ShortType; return Short.class;
} else if (unboxed.clazz == char.class) { } else if (clazz == char.class) {
return CharacterType; return Character.class;
} else if (unboxed.clazz == int.class) { } else if (clazz == int.class) {
return IntegerType; return Integer.class;
} else if (unboxed.clazz == long.class) { } else if (clazz == long.class) {
return LongType; return Long.class;
} else if (unboxed.clazz == float.class) { } else if (clazz == float.class) {
return FloatType; return Float.class;
} else if (unboxed.clazz == double.class) { } else if (clazz == double.class) {
return DoubleType; return Double.class;
} }
return unboxed; return clazz;
} }
public Type getUnboxedType(Type boxed) { public static Class<?> getUnboxedype(Class<?> clazz) {
if (boxed.clazz == Boolean.class) { if (clazz == Boolean.class) {
return booleanType; return boolean.class;
} else if (boxed.clazz == Byte.class) { } else if (clazz == Byte.class) {
return byteType; return byte.class;
} else if (boxed.clazz == Short.class) { } else if (clazz == Short.class) {
return shortType; return short.class;
} else if (boxed.clazz == Character.class) { } else if (clazz == Character.class) {
return charType; return char.class;
} else if (boxed.clazz == Integer.class) { } else if (clazz == Integer.class) {
return intType; return int.class;
} else if (boxed.clazz == Long.class) { } else if (clazz == Long.class) {
return longType; return long.class;
} else if (boxed.clazz == Float.class) { } else if (clazz == Float.class) {
return floatType; return float.class;
} else if (boxed.clazz == Double.class) { } else if (clazz == Double.class) {
return doubleType; return double.class;
} }
return boxed; return clazz;
} }
public static boolean isConstantType(Type constant) { public static boolean isConstantType(Class<?> clazz) {
return constant.clazz == boolean.class || return clazz == boolean.class ||
constant.clazz == byte.class || clazz == byte.class ||
constant.clazz == short.class || clazz == short.class ||
constant.clazz == char.class || clazz == char.class ||
constant.clazz == int.class || clazz == int.class ||
constant.clazz == long.class || clazz == long.class ||
constant.clazz == float.class || clazz == float.class ||
constant.clazz == double.class || clazz == double.class ||
constant.clazz == String.class; clazz == String.class;
} }
public static Class<?> ObjectClassTodefClass(Class<?> clazz) { public static Class<?> ObjectClassTodefClass(Class<?> clazz) {
@ -579,7 +579,7 @@ public final class Definition {
} }
if (component == def.class) { if (component == def.class) {
StringBuilder builder = new StringBuilder("def"); StringBuilder builder = new StringBuilder(def.class.getSimpleName());
for (int dimension = 0; dimension < dimensions; dimensions++) { for (int dimension = 0; dimension < dimensions; dimensions++) {
builder.append("[]"); builder.append("[]");
@ -588,7 +588,7 @@ public final class Definition {
return builder.toString(); return builder.toString();
} }
} else if (clazz == def.class) { } else if (clazz == def.class) {
return "def"; return def.class.getSimpleName();
} }
return clazz.getCanonicalName().replace('$', '.'); return clazz.getCanonicalName().replace('$', '.');
@ -606,20 +606,20 @@ public final class Definition {
++dimensions; ++dimensions;
} }
if (clazz == def.class) { if (component == def.class) {
return getType(structsMap.get("def"), dimensions); return getType(structsMap.get(def.class.getSimpleName()), dimensions);
} else { } else {
return getType(runtimeMap.get(clazz).struct, dimensions); return getType(runtimeMap.get(component).struct, dimensions);
} }
} else if (clazz == def.class) { } else if (clazz == def.class) {
return getType(structsMap.get("def"), 0); return getType(structsMap.get(def.class.getSimpleName()), 0);
} }
return getType(structsMap.get(ClassToName(clazz)), 0); return getType(structsMap.get(ClassToName(clazz)), 0);
} }
public static Class<?> TypeToClass(Type type) { public static Class<?> TypeToClass(Type type) {
if (type.dynamic) { if (def.class.getSimpleName().equals(type.struct.name)) {
return ObjectClassTodefClass(type.clazz); return ObjectClassTodefClass(type.clazz);
} }
@ -672,7 +672,8 @@ public final class Definition {
String origin = null; String origin = null;
// add the universal def type // add the universal def type
structsMap.put("def", new Struct("def", Object.class, org.objectweb.asm.Type.getType(Object.class))); structsMap.put(def.class.getSimpleName(),
new Struct(def.class.getSimpleName(), Object.class, org.objectweb.asm.Type.getType(Object.class)));
try { try {
// first iteration collects all the Painless type names that // first iteration collects all the Painless type names that
@ -777,7 +778,7 @@ public final class Definition {
copyStruct(painlessStruct.name, painlessSuperStructs); copyStruct(painlessStruct.name, painlessSuperStructs);
// copies methods and fields from Object into interface types // copies methods and fields from Object into interface types
if (painlessStruct.clazz.isInterface() || ("def").equals(painlessStruct.name)) { if (painlessStruct.clazz.isInterface() || (def.class.getSimpleName()).equals(painlessStruct.name)) {
Struct painlessObjectStruct = javaClassesToPainlessStructs.get(Object.class); Struct painlessObjectStruct = javaClassesToPainlessStructs.get(Object.class);
if (painlessObjectStruct != null) { if (painlessObjectStruct != null) {
@ -835,7 +836,7 @@ public final class Definition {
charType = getType("char"); charType = getType("char");
CharacterType = getType("Character"); CharacterType = getType("Character");
ObjectType = getType("Object"); ObjectType = getType("Object");
DefType = getType("def"); DefType = getType(def.class.getSimpleName());
NumberType = getType("Number"); NumberType = getType("Number");
StringType = getType("String"); StringType = getType("String");
ExceptionType = getType("Exception"); ExceptionType = getType("Exception");
@ -1409,7 +1410,7 @@ public final class Definition {
} }
} }
return new Type(name, dimensions, "def".equals(name), struct, clazz, type); return new Type(name, dimensions, def.class.getSimpleName().equals(name), struct, clazz, type);
} }
private int getDimensions(String name) { private int getDimensions(String name) {

View File

@ -22,7 +22,6 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -60,7 +59,7 @@ public abstract class AExpression extends ANode {
* Set to the expected type this node needs to be. Note this variable * Set to the expected type this node needs to be. Note this variable
* is always set by the parent as input and should never be read from. * is always set by the parent as input and should never be read from.
*/ */
Type expected = null; Class<?> expected = null;
/** /**
* Set to the actual type this node is. Note this variable is always * Set to the actual type this node is. Note this variable is always
@ -68,7 +67,7 @@ public abstract class AExpression extends ANode {
* node itself. <b>Also, actual can always be read after a cast is * node itself. <b>Also, actual can always be read after a cast is
* called on this node to get the type of the node after the cast.</b> * called on this node to get the type of the node after the cast.</b>
*/ */
Type actual = null; Class<?> actual = null;
/** /**
* Set by {@link EExplicit} if a cast made on an expression node should be * Set by {@link EExplicit} if a cast made on an expression node should be
@ -119,8 +118,7 @@ public abstract class AExpression extends ANode {
* @return The new child node for the parent node calling this method. * @return The new child node for the parent node calling this method.
*/ */
AExpression cast(Locals locals) { AExpression cast(Locals locals) {
Cast cast = Cast cast = AnalyzerCaster.getLegalCast(location, actual, expected, explicit, internal);
AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(actual), Definition.TypeToClass(expected), explicit, internal);
if (cast == null) { if (cast == null) {
if (constant == null || this instanceof EConstant) { if (constant == null || this instanceof EConstant) {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -86,7 +85,7 @@ abstract class AStoreable extends AExpression {
* actual will be set to this value. This is used for an optimization * actual will be set to this value. This is used for an optimization
* during assignment to def type targets. * during assignment to def type targets.
*/ */
abstract void updateActual(Type actual); abstract void updateActual(Class<?> actual);
/** /**
* Called before a storeable node is loaded or stored. Used to load prefixes and * Called before a storeable node is loaded or stored. Used to load prefixes and

View File

@ -22,9 +22,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Definition.def; import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
@ -49,11 +47,10 @@ public final class EAssignment extends AExpression {
private Operation operation; private Operation operation;
private boolean cat = false; private boolean cat = false;
private Type promote = null; private Class<?> promote = null;
private Type shiftDistance; // for shifts, the RHS is promoted independently private Class<?> shiftDistance; // for shifts, the RHS is promoted independently
private Cast there = null; private Cast there = null;
private Cast back = null; private Cast back = null;
private Type DefType = null;
public EAssignment(Location location, AExpression lhs, AExpression rhs, boolean pre, boolean post, Operation operation) { public EAssignment(Location location, AExpression lhs, AExpression rhs, boolean pre, boolean post, Operation operation) {
super(location); super(location);
@ -83,8 +80,6 @@ public final class EAssignment extends AExpression {
} else { } else {
throw new IllegalStateException("Illegal tree structure."); throw new IllegalStateException("Illegal tree structure.");
} }
DefType = locals.getDefinition().DefType;
} }
private void analyzeLHS(Locals locals) { private void analyzeLHS(Locals locals) {
@ -108,11 +103,11 @@ public final class EAssignment extends AExpression {
} }
if (operation == Operation.INCR) { if (operation == Operation.INCR) {
if (lhs.actual.clazz == double.class) { if (lhs.actual == double.class) {
rhs = new EConstant(location, 1D); rhs = new EConstant(location, 1D);
} else if (lhs.actual.clazz == float.class) { } else if (lhs.actual == float.class) {
rhs = new EConstant(location, 1F); rhs = new EConstant(location, 1F);
} else if (lhs.actual.clazz == long.class) { } else if (lhs.actual == long.class) {
rhs = new EConstant(location, 1L); rhs = new EConstant(location, 1L);
} else { } else {
rhs = new EConstant(location, 1); rhs = new EConstant(location, 1);
@ -120,11 +115,11 @@ public final class EAssignment extends AExpression {
operation = Operation.ADD; operation = Operation.ADD;
} else if (operation == Operation.DECR) { } else if (operation == Operation.DECR) {
if (lhs.actual.clazz == double.class) { if (lhs.actual == double.class) {
rhs = new EConstant(location, 1D); rhs = new EConstant(location, 1D);
} else if (lhs.actual.clazz == float.class) { } else if (lhs.actual == float.class) {
rhs = new EConstant(location, 1F); rhs = new EConstant(location, 1F);
} else if (lhs.actual.clazz == long.class) { } else if (lhs.actual == long.class) {
rhs = new EConstant(location, 1L); rhs = new EConstant(location, 1L);
} else { } else {
rhs = new EConstant(location, 1); rhs = new EConstant(location, 1);
@ -143,41 +138,33 @@ public final class EAssignment extends AExpression {
boolean shift = false; boolean shift = false;
if (operation == Operation.MUL) { if (operation == Operation.MUL) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
} else if (operation == Operation.DIV) { } else if (operation == Operation.DIV) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
} else if (operation == Operation.REM) { } else if (operation == Operation.REM) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
} else if (operation == Operation.ADD) { } else if (operation == Operation.ADD) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteAdd(lhs.actual, rhs.actual);
AnalyzerCaster.promoteAdd(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
} else if (operation == Operation.SUB) { } else if (operation == Operation.SUB) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
} else if (operation == Operation.LSH) { } else if (operation == Operation.LSH) {
promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
shift = true; shift = true;
} else if (operation == Operation.RSH) { } else if (operation == Operation.RSH) {
promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
shift = true; shift = true;
} else if (operation == Operation.USH) { } else if (operation == Operation.USH) {
promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
shift = true; shift = true;
} else if (operation == Operation.BWAND) { } else if (operation == Operation.BWAND) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
} else if (operation == Operation.XOR) { } else if (operation == Operation.XOR) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
} else if (operation == Operation.BWOR) { } else if (operation == Operation.BWOR) {
promote = locals.getDefinition().ClassToType( promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
@ -187,20 +174,20 @@ public final class EAssignment extends AExpression {
"[" + operation.symbol + "=] to types [" + lhs.actual + "] and [" + rhs.actual + "].")); "[" + operation.symbol + "=] to types [" + lhs.actual + "] and [" + rhs.actual + "]."));
} }
cat = operation == Operation.ADD && promote.clazz == String.class; cat = operation == Operation.ADD && promote == String.class;
if (cat) { if (cat) {
if (rhs instanceof EBinary && ((EBinary)rhs).operation == Operation.ADD && rhs.actual.clazz == String.class) { if (rhs instanceof EBinary && ((EBinary)rhs).operation == Operation.ADD && rhs.actual == String.class) {
((EBinary)rhs).cat = true; ((EBinary)rhs).cat = true;
} }
rhs.expected = rhs.actual; rhs.expected = rhs.actual;
} else if (shift) { } else if (shift) {
if (promote.dynamic) { if (promote == def.class) {
// shifts are promoted independently, but for the def type, we need object. // shifts are promoted independently, but for the def type, we need object.
rhs.expected = promote; rhs.expected = promote;
} else if (shiftDistance.clazz == long.class) { } else if (shiftDistance == long.class) {
rhs.expected = locals.getDefinition().intType; rhs.expected = int.class;
rhs.explicit = true; rhs.explicit = true;
} else { } else {
rhs.expected = shiftDistance; rhs.expected = shiftDistance;
@ -211,11 +198,11 @@ public final class EAssignment extends AExpression {
rhs = rhs.cast(locals); rhs = rhs.cast(locals);
there = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(lhs.actual), Definition.TypeToClass(promote), false, false); there = AnalyzerCaster.getLegalCast(location, lhs.actual, promote, false, false);
back = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(promote), Definition.TypeToClass(lhs.actual), true, false); back = AnalyzerCaster.getLegalCast(location, promote, lhs.actual, true, false);
this.statement = true; this.statement = true;
this.actual = read ? lhs.actual : locals.getDefinition().voidType; this.actual = read ? lhs.actual : void.class;
} }
private void analyzeSimple(Locals locals) { private void analyzeSimple(Locals locals) {
@ -225,7 +212,7 @@ public final class EAssignment extends AExpression {
if (lhs.isDefOptimized()) { if (lhs.isDefOptimized()) {
rhs.analyze(locals); rhs.analyze(locals);
if (rhs.actual.clazz == void.class) { if (rhs.actual == void.class) {
throw createError(new IllegalArgumentException("Right-hand side cannot be a [void] type for assignment.")); throw createError(new IllegalArgumentException("Right-hand side cannot be a [void] type for assignment."));
} }
@ -240,7 +227,7 @@ public final class EAssignment extends AExpression {
rhs = rhs.cast(locals); rhs = rhs.cast(locals);
this.statement = true; this.statement = true;
this.actual = read ? lhs.actual : locals.getDefinition().voidType; this.actual = read ? lhs.actual : void.class;
} }
/** /**
@ -275,19 +262,19 @@ public final class EAssignment extends AExpression {
writer.writeDup(lhs.accessElementCount(), catElementStackSize); // dup the top element and insert it writer.writeDup(lhs.accessElementCount(), catElementStackSize); // dup the top element and insert it
// before concat helper on stack // before concat helper on stack
lhs.load(writer, globals); // read the current lhs's value lhs.load(writer, globals); // read the current lhs's value
writer.writeAppendStrings(Definition.TypeToClass(lhs.actual)); // append the lhs's value using the StringBuilder writer.writeAppendStrings(lhs.actual); // append the lhs's value using the StringBuilder
rhs.write(writer, globals); // write the bytecode for the rhs rhs.write(writer, globals); // write the bytecode for the rhs
if (!(rhs instanceof EBinary) || !((EBinary)rhs).cat) { // check to see if the rhs has already done a concatenation if (!(rhs instanceof EBinary) || !((EBinary)rhs).cat) { // check to see if the rhs has already done a concatenation
writer.writeAppendStrings(Definition.TypeToClass(rhs.actual)); // append the rhs's value since it's hasn't already writer.writeAppendStrings(rhs.actual); // append the rhs's value since it's hasn't already
} }
writer.writeToStrings(); // put the value for string concat onto the stack writer.writeToStrings(); // put the value for string concat onto the stack
writer.writeCast(back); // if necessary, cast the String to the lhs actual type writer.writeCast(back); // if necessary, cast the String to the lhs actual type
if (lhs.read) { if (lhs.read) {
writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // if this lhs is also read writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // if this lhs is also read
// from dup the value onto the stack // from dup the value onto the stack
} }
@ -301,7 +288,7 @@ public final class EAssignment extends AExpression {
lhs.load(writer, globals); // load the current lhs's value lhs.load(writer, globals); // load the current lhs's value
if (lhs.read && post) { if (lhs.read && post) {
writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // dup the value if the lhs is also writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs is also
// read from and is a post increment // read from and is a post increment
} }
@ -312,18 +299,19 @@ public final class EAssignment extends AExpression {
// XXX: fix these types, but first we need def compound assignment tests. // XXX: fix these types, but first we need def compound assignment tests.
// its tricky here as there are possibly explicit casts, too. // its tricky here as there are possibly explicit casts, too.
// write the operation instruction for compound assignment // write the operation instruction for compound assignment
if (promote.dynamic) { if (promote == def.class) {
writer.writeDynamicBinaryInstruction( writer.writeDynamicBinaryInstruction(
location, Definition.TypeToClass(promote), def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); location, promote, def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT);
} else { } else {
writer.writeBinaryInstruction(location, Definition.TypeToClass(promote), operation); writer.writeBinaryInstruction(location, promote, operation);
} }
writer.writeCast(back); // if necessary cast the promotion type value back to the lhs's type writer.writeCast(back); // if necessary cast the promotion type value back to the lhs's type
if (lhs.read && !post) { if (lhs.read && !post) {
writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // dup the value if the lhs is also writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs is also
// read from and is not a post increment // read from and is not a post
// increment
} }
lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array
@ -333,7 +321,8 @@ public final class EAssignment extends AExpression {
rhs.write(writer, globals); // write the bytecode for the rhs rhs rhs.write(writer, globals); // write the bytecode for the rhs rhs
if (lhs.read) { if (lhs.read) {
writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // dup the value if the lhs is also read from writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs
// is also read from
} }
lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array

View File

@ -22,7 +22,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -44,8 +44,8 @@ public final class EBinary extends AExpression {
private AExpression left; private AExpression left;
private AExpression right; private AExpression right;
private Type promote = null; // promoted type private Class<?> promote = null; // promoted type
private Type shiftDistance = null; // for shifts, the rhs is promoted independently private Class<?> shiftDistance = null; // for shifts, the rhs is promoted independently
boolean cat = false; boolean cat = false;
private boolean originallyExplicit = false; // record whether there was originally an explicit cast private boolean originallyExplicit = false; // record whether there was originally an explicit cast
@ -102,17 +102,16 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply multiply [*] to types " + throw createError(new ClassCastException("Cannot apply multiply [*] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote; actual = promote;
if (promote.dynamic) { if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
if (expected != null) { if (expected != null) {
@ -127,15 +126,13 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = (int)left.constant * (int)right.constant; constant = (int)left.constant * (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant * (long)right.constant; constant = (long)left.constant * (long)right.constant;
} else if (sort == float.class) { } else if (promote == float.class) {
constant = (float)left.constant * (float)right.constant; constant = (float)left.constant * (float)right.constant;
} else if (sort == double.class) { } else if (promote == double.class) {
constant = (double)left.constant * (double)right.constant; constant = (double)left.constant * (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -147,17 +144,16 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply divide [/] to types " + throw createError(new ClassCastException("Cannot apply divide [/] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote; actual = promote;
if (promote.dynamic) { if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -173,16 +169,14 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promote.clazz;
try { try {
if (sort == int.class) { if (promote == int.class) {
constant = (int)left.constant / (int)right.constant; constant = (int)left.constant / (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant / (long)right.constant; constant = (long)left.constant / (long)right.constant;
} else if (sort == float.class) { } else if (promote == float.class) {
constant = (float)left.constant / (float)right.constant; constant = (float)left.constant / (float)right.constant;
} else if (sort == double.class) { } else if (promote == double.class) {
constant = (double)left.constant / (double)right.constant; constant = (double)left.constant / (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -197,17 +191,16 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply remainder [%] to types " + throw createError(new ClassCastException("Cannot apply remainder [%] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote; actual = promote;
if (promote.dynamic) { if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -223,16 +216,14 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promote.clazz;
try { try {
if (sort == int.class) { if (promote == int.class) {
constant = (int)left.constant % (int)right.constant; constant = (int)left.constant % (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant % (long)right.constant; constant = (long)left.constant % (long)right.constant;
} else if (sort == float.class) { } else if (promote == float.class) {
constant = (float)left.constant % (float)right.constant; constant = (float)left.constant % (float)right.constant;
} else if (sort == double.class) { } else if (promote == double.class) {
constant = (double)left.constant % (double)right.constant; constant = (double)left.constant % (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -247,31 +238,28 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
AnalyzerCaster.promoteAdd(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply add [+] to types " + throw createError(new ClassCastException("Cannot apply add [+] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
Class<?> sort = promote.clazz;
actual = promote; actual = promote;
if (sort == String.class) { if (promote == String.class) {
left.expected = left.actual; left.expected = left.actual;
if (left instanceof EBinary && ((EBinary)left).operation == Operation.ADD && left.actual.clazz == String.class) { if (left instanceof EBinary && ((EBinary)left).operation == Operation.ADD && left.actual == String.class) {
((EBinary)left).cat = true; ((EBinary)left).cat = true;
} }
right.expected = right.actual; right.expected = right.actual;
if (right instanceof EBinary && ((EBinary)right).operation == Operation.ADD && right.actual.clazz == String.class) { if (right instanceof EBinary && ((EBinary)right).operation == Operation.ADD && right.actual == String.class) {
((EBinary)right).cat = true; ((EBinary)right).cat = true;
} }
} else if (promote.dynamic) { } else if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -287,15 +275,15 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
if (sort == int.class) { if (promote == int.class) {
constant = (int)left.constant + (int)right.constant; constant = (int)left.constant + (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant + (long)right.constant; constant = (long)left.constant + (long)right.constant;
} else if (sort == float.class) { } else if (promote == float.class) {
constant = (float)left.constant + (float)right.constant; constant = (float)left.constant + (float)right.constant;
} else if (sort == double.class) { } else if (promote == double.class) {
constant = (double)left.constant + (double)right.constant; constant = (double)left.constant + (double)right.constant;
} else if (sort == String.class) { } else if (promote == String.class) {
constant = left.constant.toString() + right.constant.toString(); constant = left.constant.toString() + right.constant.toString();
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -308,17 +296,16 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply subtract [-] to types " + throw createError(new ClassCastException("Cannot apply subtract [-] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote; actual = promote;
if (promote.dynamic) { if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -334,15 +321,13 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = (int)left.constant - (int)right.constant; constant = (int)left.constant - (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant - (long)right.constant; constant = (long)left.constant - (long)right.constant;
} else if (sort == float.class) { } else if (promote == float.class) {
constant = (float)left.constant - (float)right.constant; constant = (float)left.constant - (float)right.constant;
} else if (sort == double.class) { } else if (promote == double.class) {
constant = (double)left.constant - (double)right.constant; constant = (double)left.constant - (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -354,32 +339,32 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
left.expected = variables.getDefinition().StringType; left.expected = String.class;
right.expected = variables.getDefinition().PatternType; right.expected = Pattern.class;
left = left.cast(variables); left = left.cast(variables);
right = right.cast(variables); right = right.cast(variables);
promote = variables.getDefinition().booleanType; promote = boolean.class;
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeLSH(Locals variables) { private void analyzeLSH(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
if (lhspromote == null || rhspromote == null) { if (lhspromote == null || rhspromote == null) {
throw createError(new ClassCastException("Cannot apply left shift [<<] to types " + throw createError(new ClassCastException("Cannot apply left shift [<<] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote = lhspromote; actual = promote = lhspromote;
shiftDistance = rhspromote; shiftDistance = rhspromote;
if (lhspromote.dynamic || rhspromote.dynamic) { if (lhspromote == def.class || rhspromote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -389,8 +374,8 @@ public final class EBinary extends AExpression {
} else { } else {
left.expected = lhspromote; left.expected = lhspromote;
if (rhspromote.clazz == long.class) { if (rhspromote == long.class) {
right.expected = variables.getDefinition().intType; right.expected = int.class;
right.explicit = true; right.explicit = true;
} else { } else {
right.expected = rhspromote; right.expected = rhspromote;
@ -401,11 +386,9 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = lhspromote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = (int)left.constant << (int)right.constant; constant = (int)left.constant << (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant << (int)right.constant; constant = (long)left.constant << (int)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -417,18 +400,18 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
if (lhspromote == null || rhspromote == null) { if (lhspromote == null || rhspromote == null) {
throw createError(new ClassCastException("Cannot apply right shift [>>] to types " + throw createError(new ClassCastException("Cannot apply right shift [>>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote = lhspromote; actual = promote = lhspromote;
shiftDistance = rhspromote; shiftDistance = rhspromote;
if (lhspromote.dynamic || rhspromote.dynamic) { if (lhspromote == def.class || rhspromote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -438,8 +421,8 @@ public final class EBinary extends AExpression {
} else { } else {
left.expected = lhspromote; left.expected = lhspromote;
if (rhspromote.clazz == long.class) { if (rhspromote == long.class) {
right.expected = variables.getDefinition().intType; right.expected = int.class;
right.explicit = true; right.explicit = true;
} else { } else {
right.expected = rhspromote; right.expected = rhspromote;
@ -450,11 +433,9 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = lhspromote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = (int)left.constant >> (int)right.constant; constant = (int)left.constant >> (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant >> (int)right.constant; constant = (long)left.constant >> (int)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -466,18 +447,18 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
actual = promote = lhspromote; actual = promote = lhspromote;
shiftDistance = rhspromote; shiftDistance = rhspromote;
if (lhspromote == null || rhspromote == null) { if (lhspromote == null || rhspromote == null) {
throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " + throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
if (lhspromote.dynamic || rhspromote.dynamic) { if (lhspromote == def.class || rhspromote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -487,8 +468,8 @@ public final class EBinary extends AExpression {
} else { } else {
left.expected = lhspromote; left.expected = lhspromote;
if (rhspromote.clazz == long.class) { if (rhspromote == long.class) {
right.expected = variables.getDefinition().intType; right.expected = int.class;
right.explicit = true; right.explicit = true;
} else { } else {
right.expected = rhspromote; right.expected = rhspromote;
@ -499,11 +480,9 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = lhspromote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = (int)left.constant >>> (int)right.constant; constant = (int)left.constant >>> (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant >>> (int)right.constant; constant = (long)left.constant >>> (int)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -515,17 +494,16 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply and [&] to types " + throw createError(new ClassCastException("Cannot apply and [&] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote; actual = promote;
if (promote.dynamic) { if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
@ -541,11 +519,9 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = (int)left.constant & (int)right.constant; constant = (int)left.constant & (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant & (long)right.constant; constant = (long)left.constant & (long)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -557,17 +533,16 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
AnalyzerCaster.promoteXor(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply xor [^] to types " + throw createError(new ClassCastException("Cannot apply xor [^] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote; actual = promote;
if (promote.dynamic) { if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
if (expected != null) { if (expected != null) {
@ -582,13 +557,11 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promote.clazz; if (promote == boolean.class) {
if (sort == boolean.class) {
constant = (boolean)left.constant ^ (boolean)right.constant; constant = (boolean)left.constant ^ (boolean)right.constant;
} else if (sort == int.class) { } else if (promote == int.class) {
constant = (int)left.constant ^ (int)right.constant; constant = (int)left.constant ^ (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant ^ (long)right.constant; constant = (long)left.constant ^ (long)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -600,17 +573,16 @@ public final class EBinary extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promote = variables.getDefinition().ClassToType( promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false));
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply or [|] to types " + throw createError(new ClassCastException("Cannot apply or [|] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
actual = promote; actual = promote;
if (promote.dynamic) { if (promote == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
if (expected != null) { if (expected != null) {
@ -625,11 +597,9 @@ public final class EBinary extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = (int)left.constant | (int)right.constant; constant = (int)left.constant | (int)right.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = (long)left.constant | (long)right.constant; constant = (long)left.constant | (long)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -641,7 +611,7 @@ public final class EBinary extends AExpression {
void write(MethodWriter writer, Globals globals) { void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
if (promote.clazz == String.class && operation == Operation.ADD) { if (promote == String.class && operation == Operation.ADD) {
if (!cat) { if (!cat) {
writer.writeNewStrings(); writer.writeNewStrings();
} }
@ -649,13 +619,13 @@ public final class EBinary extends AExpression {
left.write(writer, globals); left.write(writer, globals);
if (!(left instanceof EBinary) || !((EBinary)left).cat) { if (!(left instanceof EBinary) || !((EBinary)left).cat) {
writer.writeAppendStrings(Definition.TypeToClass(left.actual)); writer.writeAppendStrings(left.actual);
} }
right.write(writer, globals); right.write(writer, globals);
if (!(right instanceof EBinary) || !((EBinary)right).cat) { if (!(right instanceof EBinary) || !((EBinary)right).cat) {
writer.writeAppendStrings(Definition.TypeToClass(right.actual)); writer.writeAppendStrings(right.actual);
} }
if (!cat) { if (!cat) {
@ -677,17 +647,16 @@ public final class EBinary extends AExpression {
left.write(writer, globals); left.write(writer, globals);
right.write(writer, globals); right.write(writer, globals);
if (promote.dynamic || (shiftDistance != null && shiftDistance.dynamic)) { if (promote == def.class || (shiftDistance != null && shiftDistance == def.class)) {
// def calls adopt the wanted return value. if there was a narrowing cast, // def calls adopt the wanted return value. if there was a narrowing cast,
// we need to flag that so that its done at runtime. // we need to flag that so that its done at runtime.
int flags = 0; int flags = 0;
if (originallyExplicit) { if (originallyExplicit) {
flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST;
} }
writer.writeDynamicBinaryInstruction(location, Definition.TypeToClass(actual), writer.writeDynamicBinaryInstruction(location, actual, left.actual, right.actual, operation, flags);
Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), operation, flags);
} else { } else {
writer.writeBinaryInstruction(location, Definition.TypeToClass(actual), operation); writer.writeBinaryInstruction(location, actual, operation);
} }
} }
} }

View File

@ -19,19 +19,17 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.MethodWriter;
import org.objectweb.asm.Opcodes;
/** /**
* Represents a boolean expression. * Represents a boolean expression.
*/ */
@ -57,11 +55,11 @@ public final class EBool extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
left.expected = locals.getDefinition().booleanType; left.expected = boolean.class;
left.analyze(locals); left.analyze(locals);
left = left.cast(locals); left = left.cast(locals);
right.expected = locals.getDefinition().booleanType; right.expected = boolean.class;
right.analyze(locals); right.analyze(locals);
right = right.cast(locals); right = right.cast(locals);
@ -75,7 +73,7 @@ public final class EBool extends AExpression {
} }
} }
actual = locals.getDefinition().booleanType; actual = boolean.class;
} }
@Override @Override

View File

@ -19,10 +19,9 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Set; import java.util.Set;
@ -49,7 +48,7 @@ public final class EBoolean extends AExpression {
throw createError(new IllegalArgumentException("Must read from constant [" + constant + "].")); throw createError(new IllegalArgumentException("Must read from constant [" + constant + "]."));
} }
actual = locals.getDefinition().booleanType; actual = boolean.class;
} }
@Override @Override

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.MethodKey; import org.elasticsearch.painless.Definition.MethodKey;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
@ -68,14 +69,14 @@ public final class ECallLocal extends AExpression {
for (int argument = 0; argument < arguments.size(); ++argument) { for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument); AExpression expression = arguments.get(argument);
expression.expected = method.arguments.get(argument); expression.expected = Definition.TypeToClass(method.arguments.get(argument));
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
arguments.set(argument, expression.cast(locals)); arguments.set(argument, expression.cast(locals));
} }
statement = true; statement = true;
actual = method.rtn; actual = Definition.TypeToClass(method.rtn);
} }
@Override @Override

View File

@ -70,13 +70,14 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
// typed implementation // typed implementation
defPointer = "S" + captured.type.name + "." + call + ",1"; defPointer = "S" + captured.type.name + "." + call + ",1";
} }
actual = locals.getDefinition().getType("String"); actual = String.class;
} else { } else {
defPointer = null; defPointer = null;
// static case // static case
if (captured.type.dynamic == false) { if (captured.type.dynamic == false) {
try { try {
ref = new FunctionRef(locals.getDefinition(), expected, captured.type.name, call, 1); ref = new FunctionRef(
locals.getDefinition(), locals.getDefinition().ClassToType(expected), captured.type.name, call, 1);
// check casts between the interface method and the delegate method are legal // check casts between the interface method and the delegate method are legal
for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) { for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) {
@ -108,8 +109,8 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
} else if (ref == null) { } else if (ref == null) {
// typed interface, dynamic implementation // typed interface, dynamic implementation
writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot()); writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot());
Type methodType = Type.getMethodType(expected.type, captured.type.type); Type methodType = Type.getMethodType(MethodWriter.getType(expected), captured.type.type);
writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, expected.name); writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, Definition.ClassToName(expected));
} else { } else {
// typed interface, typed implementation // typed interface, typed implementation
writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot()); writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot());

View File

@ -21,15 +21,14 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.MethodWriter;
/** /**
* Represents a cast that is inserted into the tree replacing other casts. (Internal only.) * Represents a cast that is inserted into the tree replacing other casts. (Internal only.)
*/ */

View File

@ -19,23 +19,23 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.MethodWriter;
import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE;
import static org.elasticsearch.painless.WriterConstants.EQUALS; import static org.elasticsearch.painless.WriterConstants.EQUALS;
import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE;
/** /**
* Represents a comparison expression. * Represents a comparison expression.
@ -46,7 +46,7 @@ public final class EComp extends AExpression {
private AExpression left; private AExpression left;
private AExpression right; private AExpression right;
private Type promotedType; private Class<?> promotedType;
public EComp(Location location, Operation operation, AExpression left, AExpression right) { public EComp(Location location, Operation operation, AExpression left, AExpression right) {
super(location); super(location);
@ -89,15 +89,14 @@ public final class EComp extends AExpression {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply equals [==] to types " + throw createError(new ClassCastException("Cannot apply equals [==] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
if (promotedType.dynamic) { if (promotedType == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
} else { } else {
@ -113,17 +112,15 @@ public final class EComp extends AExpression {
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Class<?> sort = promotedType.clazz; if (promotedType == boolean.class) {
if (sort == boolean.class) {
constant = (boolean)left.constant == (boolean)right.constant; constant = (boolean)left.constant == (boolean)right.constant;
} else if (sort == int.class) { } else if (promotedType == int.class) {
constant = (int)left.constant == (int)right.constant; constant = (int)left.constant == (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant == (long)right.constant; constant = (long)left.constant == (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant == (float)right.constant; constant = (float)left.constant == (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant == (double)right.constant; constant = (double)left.constant == (double)right.constant;
} else if (!left.isNull) { } else if (!left.isNull) {
constant = left.constant.equals(right.constant); constant = left.constant.equals(right.constant);
@ -134,19 +131,18 @@ public final class EComp extends AExpression {
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeEqR(Locals variables) { private void analyzeEqR(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply reference equals [===] to types " + throw createError(new ClassCastException("Cannot apply reference equals [===] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
left.expected = promotedType; left.expected = promotedType;
@ -160,39 +156,36 @@ public final class EComp extends AExpression {
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Class<?> sort = promotedType.clazz; if (promotedType == boolean.class) {
if (sort == boolean.class) {
constant = (boolean)left.constant == (boolean)right.constant; constant = (boolean)left.constant == (boolean)right.constant;
} else if (sort == int.class) { } else if (promotedType == int.class) {
constant = (int)left.constant == (int)right.constant; constant = (int)left.constant == (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant == (long)right.constant; constant = (long)left.constant == (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant == (float)right.constant; constant = (float)left.constant == (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant == (double)right.constant; constant = (double)left.constant == (double)right.constant;
} else { } else {
constant = left.constant == right.constant; constant = left.constant == right.constant;
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeNE(Locals variables) { private void analyzeNE(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply not equals [!=] to types " + throw createError(new ClassCastException("Cannot apply not equals [!=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
if (promotedType.dynamic) { if (promotedType == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
} else { } else {
@ -208,17 +201,15 @@ public final class EComp extends AExpression {
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Class<?> sort = promotedType.clazz; if (promotedType == boolean.class) {
if (sort == boolean.class) {
constant = (boolean)left.constant != (boolean)right.constant; constant = (boolean)left.constant != (boolean)right.constant;
} else if (sort == int.class) { } else if (promotedType == int.class) {
constant = (int)left.constant != (int)right.constant; constant = (int)left.constant != (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant != (long)right.constant; constant = (long)left.constant != (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant != (float)right.constant; constant = (float)left.constant != (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant != (double)right.constant; constant = (double)left.constant != (double)right.constant;
} else if (!left.isNull) { } else if (!left.isNull) {
constant = !left.constant.equals(right.constant); constant = !left.constant.equals(right.constant);
@ -229,19 +220,18 @@ public final class EComp extends AExpression {
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeNER(Locals variables) { private void analyzeNER(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " + throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
left.expected = promotedType; left.expected = promotedType;
@ -255,39 +245,36 @@ public final class EComp extends AExpression {
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Class<?> sort = promotedType.clazz; if (promotedType == boolean.class) {
if (sort == boolean.class) {
constant = (boolean)left.constant != (boolean)right.constant; constant = (boolean)left.constant != (boolean)right.constant;
} else if (sort == int.class) { } else if (promotedType == int.class) {
constant = (int)left.constant != (int)right.constant; constant = (int)left.constant != (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant != (long)right.constant; constant = (long)left.constant != (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant != (float)right.constant; constant = (float)left.constant != (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant != (double)right.constant; constant = (double)left.constant != (double)right.constant;
} else { } else {
constant = left.constant != right.constant; constant = left.constant != right.constant;
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeGTE(Locals variables) { private void analyzeGTE(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " + throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
if (promotedType.dynamic) { if (promotedType == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
} else { } else {
@ -299,37 +286,34 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promotedType.clazz; if (promotedType == int.class) {
if (sort == int.class) {
constant = (int)left.constant >= (int)right.constant; constant = (int)left.constant >= (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant >= (long)right.constant; constant = (long)left.constant >= (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant >= (float)right.constant; constant = (float)left.constant >= (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant >= (double)right.constant; constant = (double)left.constant >= (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeGT(Locals variables) { private void analyzeGT(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply greater than [>] to types " + throw createError(new ClassCastException("Cannot apply greater than [>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
if (promotedType.dynamic) { if (promotedType == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
} else { } else {
@ -341,37 +325,34 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promotedType.clazz; if (promotedType == int.class) {
if (sort == int.class) {
constant = (int)left.constant > (int)right.constant; constant = (int)left.constant > (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant > (long)right.constant; constant = (long)left.constant > (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant > (float)right.constant; constant = (float)left.constant > (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant > (double)right.constant; constant = (double)left.constant > (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeLTE(Locals variables) { private void analyzeLTE(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " + throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
if (promotedType.dynamic) { if (promotedType == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
} else { } else {
@ -383,37 +364,34 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promotedType.clazz; if (promotedType == int.class) {
if (sort == int.class) {
constant = (int)left.constant <= (int)right.constant; constant = (int)left.constant <= (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant <= (long)right.constant; constant = (long)left.constant <= (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant <= (float)right.constant; constant = (float)left.constant <= (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant <= (double)right.constant; constant = (double)left.constant <= (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
private void analyzeLT(Locals variables) { private void analyzeLT(Locals variables) {
left.analyze(variables); left.analyze(variables);
right.analyze(variables); right.analyze(variables);
promotedType = variables.getDefinition().ClassToType( promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
if (promotedType == null) { if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply less than [>=] to types " + throw createError(new ClassCastException("Cannot apply less than [>=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
} }
if (promotedType.dynamic) { if (promotedType == def.class) {
left.expected = left.actual; left.expected = left.actual;
right.expected = right.actual; right.expected = right.actual;
} else { } else {
@ -425,22 +403,20 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Class<?> sort = promotedType.clazz; if (promotedType == int.class) {
if (sort == int.class) {
constant = (int)left.constant < (int)right.constant; constant = (int)left.constant < (int)right.constant;
} else if (sort == long.class) { } else if (promotedType == long.class) {
constant = (long)left.constant < (long)right.constant; constant = (long)left.constant < (long)right.constant;
} else if (sort == float.class) { } else if (promotedType == float.class) {
constant = (float)left.constant < (float)right.constant; constant = (float)left.constant < (float)right.constant;
} else if (sort == double.class) { } else if (promotedType == double.class) {
constant = (double)left.constant < (double)right.constant; constant = (double)left.constant < (double)right.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
@Override @Override
@ -465,30 +441,30 @@ public final class EComp extends AExpression {
boolean writejump = true; boolean writejump = true;
Class<?> sort = promotedType.clazz; Type type = MethodWriter.getType(promotedType);
if (sort == void.class || sort == byte.class || sort == short.class || sort == char.class) { if (promotedType == void.class || promotedType == byte.class || promotedType == short.class || promotedType == char.class) {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} else if (sort == boolean.class) { } else if (promotedType == boolean.class) {
if (eq) writer.ifCmp(promotedType.type, MethodWriter.EQ, jump); if (eq) writer.ifCmp(type, MethodWriter.EQ, jump);
else if (ne) writer.ifCmp(promotedType.type, MethodWriter.NE, jump); else if (ne) writer.ifCmp(type, MethodWriter.NE, jump);
else { else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} else if (sort == int.class || sort == long.class || sort == float.class || sort == double.class) { } else if (promotedType == int.class || promotedType == long.class || promotedType == float.class || promotedType == double.class) {
if (eq) writer.ifCmp(promotedType.type, MethodWriter.EQ, jump); if (eq) writer.ifCmp(type, MethodWriter.EQ, jump);
else if (ne) writer.ifCmp(promotedType.type, MethodWriter.NE, jump); else if (ne) writer.ifCmp(type, MethodWriter.NE, jump);
else if (lt) writer.ifCmp(promotedType.type, MethodWriter.LT, jump); else if (lt) writer.ifCmp(type, MethodWriter.LT, jump);
else if (lte) writer.ifCmp(promotedType.type, MethodWriter.LE, jump); else if (lte) writer.ifCmp(type, MethodWriter.LE, jump);
else if (gt) writer.ifCmp(promotedType.type, MethodWriter.GT, jump); else if (gt) writer.ifCmp(type, MethodWriter.GT, jump);
else if (gte) writer.ifCmp(promotedType.type, MethodWriter.GE, jump); else if (gte) writer.ifCmp(type, MethodWriter.GE, jump);
else { else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} else if (promotedType.dynamic) { } else if (promotedType == def.class) {
org.objectweb.asm.Type booleanType = org.objectweb.asm.Type.getType(boolean.class); Type booleanType = Type.getType(boolean.class);
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(booleanType, left.actual.type, right.actual.type); Type descriptor = Type.getMethodType(booleanType, MethodWriter.getType(left.actual), MethodWriter.getType(right.actual));
if (eq) { if (eq) {
if (right.isNull) { if (right.isNull) {
@ -497,7 +473,7 @@ public final class EComp extends AExpression {
writer.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); writer.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL);
writejump = false; writejump = false;
} else { } else {
writer.ifCmp(promotedType.type, MethodWriter.EQ, jump); writer.ifCmp(type, MethodWriter.EQ, jump);
} }
} else if (ne) { } else if (ne) {
if (right.isNull) { if (right.isNull) {
@ -506,7 +482,7 @@ public final class EComp extends AExpression {
writer.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); writer.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL);
writer.ifZCmp(MethodWriter.EQ, jump); writer.ifZCmp(MethodWriter.EQ, jump);
} else { } else {
writer.ifCmp(promotedType.type, MethodWriter.NE, jump); writer.ifCmp(type, MethodWriter.NE, jump);
} }
} else if (lt) { } else if (lt) {
writer.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); writer.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0);
@ -531,7 +507,7 @@ public final class EComp extends AExpression {
writer.invokeStatic(OBJECTS_TYPE, EQUALS); writer.invokeStatic(OBJECTS_TYPE, EQUALS);
writejump = false; writejump = false;
} else { } else {
writer.ifCmp(promotedType.type, MethodWriter.EQ, jump); writer.ifCmp(type, MethodWriter.EQ, jump);
} }
} else if (ne) { } else if (ne) {
if (right.isNull) { if (right.isNull) {
@ -540,7 +516,7 @@ public final class EComp extends AExpression {
writer.invokeStatic(OBJECTS_TYPE, EQUALS); writer.invokeStatic(OBJECTS_TYPE, EQUALS);
writer.ifZCmp(MethodWriter.EQ, jump); writer.ifZCmp(MethodWriter.EQ, jump);
} else { } else {
writer.ifCmp(promotedType.type, MethodWriter.NE, jump); writer.ifCmp(type, MethodWriter.NE, jump);
} }
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));

View File

@ -19,20 +19,17 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.MethodWriter;
import org.objectweb.asm.Opcodes;
/** /**
* Represents a conditional expression. * Represents a conditional expression.
*/ */
@ -59,7 +56,7 @@ public final class EConditional extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
condition.expected = locals.getDefinition().booleanType; condition.expected = boolean.class;
condition.analyze(locals); condition.analyze(locals);
condition = condition.cast(locals); condition = condition.cast(locals);
@ -79,8 +76,7 @@ public final class EConditional extends AExpression {
right.analyze(locals); right.analyze(locals);
if (expected == null) { if (expected == null) {
Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional( Class<?> promote = AnalyzerCaster.promoteConditional(left.actual, right.actual, left.constant, right.constant);
Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), left.constant, right.constant));
left.expected = promote; left.expected = promote;
right.expected = promote; right.expected = promote;

View File

@ -19,15 +19,13 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.MethodWriter;
/** /**
* Represents a constant inserted into the tree replacing * Represents a constant inserted into the tree replacing
* other constants during constant folding. (Internal only.) * other constants during constant folding. (Internal only.)
@ -48,23 +46,23 @@ final class EConstant extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
if (constant instanceof String) { if (constant instanceof String) {
actual = locals.getDefinition().StringType; actual = String.class;
} else if (constant instanceof Double) { } else if (constant instanceof Double) {
actual = locals.getDefinition().doubleType; actual = double.class;
} else if (constant instanceof Float) { } else if (constant instanceof Float) {
actual = locals.getDefinition().floatType; actual = float.class;
} else if (constant instanceof Long) { } else if (constant instanceof Long) {
actual = locals.getDefinition().longType; actual = long.class;
} else if (constant instanceof Integer) { } else if (constant instanceof Integer) {
actual = locals.getDefinition().intType; actual = int.class;
} else if (constant instanceof Character) { } else if (constant instanceof Character) {
actual = locals.getDefinition().charType; actual = char.class;
} else if (constant instanceof Short) { } else if (constant instanceof Short) {
actual = locals.getDefinition().shortType; actual = short.class;
} else if (constant instanceof Byte) { } else if (constant instanceof Byte) {
actual = locals.getDefinition().byteType; actual = byte.class;
} else if (constant instanceof Boolean) { } else if (constant instanceof Boolean) {
actual = locals.getDefinition().booleanType; actual = boolean.class;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
@ -72,15 +70,15 @@ final class EConstant extends AExpression {
@Override @Override
void write(MethodWriter writer, Globals globals) { void write(MethodWriter writer, Globals globals) {
if (actual.clazz == String.class) writer.push((String)constant); if (actual == String.class) writer.push((String)constant);
else if (actual.clazz == double.class) writer.push((double)constant); else if (actual == double.class) writer.push((double)constant);
else if (actual.clazz == float.class) writer.push((float)constant); else if (actual == float.class) writer.push((float)constant);
else if (actual.clazz == long.class) writer.push((long)constant); else if (actual == long.class) writer.push((long)constant);
else if (actual.clazz == int.class) writer.push((int)constant); else if (actual == int.class) writer.push((int)constant);
else if (actual.clazz == char.class) writer.push((char)constant); else if (actual == char.class) writer.push((char)constant);
else if (actual.clazz == short.class) writer.push((short)constant); else if (actual == short.class) writer.push((short)constant);
else if (actual.clazz == byte.class) writer.push((byte)constant); else if (actual == byte.class) writer.push((byte)constant);
else if (actual.clazz == boolean.class) writer.push((boolean)constant); else if (actual == boolean.class) writer.push((boolean)constant);
else { else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }

View File

@ -19,10 +19,9 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Objects; import java.util.Objects;
@ -53,7 +52,7 @@ public final class EDecimal extends AExpression {
if (value.endsWith("f") || value.endsWith("F")) { if (value.endsWith("f") || value.endsWith("F")) {
try { try {
constant = Float.parseFloat(value.substring(0, value.length() - 1)); constant = Float.parseFloat(value.substring(0, value.length() - 1));
actual = locals.getDefinition().floatType; actual = float.class;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw createError(new IllegalArgumentException("Invalid float constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid float constant [" + value + "]."));
} }
@ -64,7 +63,7 @@ public final class EDecimal extends AExpression {
} }
try { try {
constant = Double.parseDouble(toParse); constant = Double.parseDouble(toParse);
actual = locals.getDefinition().doubleType; actual = double.class;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw createError(new IllegalArgumentException("Invalid double constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid double constant [" + value + "]."));
} }

View File

@ -20,8 +20,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -55,7 +53,7 @@ public class EElvis extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
if (expected != null && expected.clazz.isPrimitive()) { if (expected != null && expected.isPrimitive()) {
throw createError(new IllegalArgumentException("Elvis operator cannot return primitives")); throw createError(new IllegalArgumentException("Elvis operator cannot return primitives"));
} }
lhs.expected = expected; lhs.expected = expected;
@ -74,7 +72,7 @@ public class EElvis extends AExpression {
if (lhs.constant != null) { if (lhs.constant != null) {
throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a constant.")); throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a constant."));
} }
if (lhs.actual.clazz.isPrimitive()) { if (lhs.actual.isPrimitive()) {
throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a primitive.")); throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a primitive."));
} }
if (rhs.isNull) { if (rhs.isNull) {
@ -82,8 +80,7 @@ public class EElvis extends AExpression {
} }
if (expected == null) { if (expected == null) {
Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional( Class<?> promote = AnalyzerCaster.promoteConditional(lhs.actual, rhs.actual, lhs.constant, rhs.constant);
Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), lhs.constant, rhs.constant));
lhs.expected = promote; lhs.expected = promote;
rhs.expected = promote; rhs.expected = promote;

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -50,9 +51,9 @@ public final class EExplicit extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
try { try {
actual = locals.getDefinition().getType(type); actual = Definition.TypeToClass(locals.getDefinition().getType(type));
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
} }
child.expected = actual; child.expected = actual;

View File

@ -59,24 +59,24 @@ public final class EFunctionRef extends AExpression implements ILambda {
void analyze(Locals locals) { void analyze(Locals locals) {
if (expected == null) { if (expected == null) {
ref = null; ref = null;
actual = locals.getDefinition().getType("String"); actual = String.class;
defPointer = "S" + type + "." + call + ",0"; defPointer = "S" + type + "." + call + ",0";
} else { } else {
defPointer = null; defPointer = null;
try { try {
if ("this".equals(type)) { if ("this".equals(type)) {
// user's own function // user's own function
Method interfaceMethod = expected.struct.getFunctionalMethod(); Method interfaceMethod = locals.getDefinition().ClassToType(expected).struct.getFunctionalMethod();
if (interfaceMethod == null) { if (interfaceMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + expected.name + "], not a functional interface"); "to [" + Definition.ClassToName(expected) + "], not a functional interface");
} }
Method delegateMethod = locals.getMethod(new MethodKey(call, interfaceMethod.arguments.size())); Method delegateMethod = locals.getMethod(new MethodKey(call, interfaceMethod.arguments.size()));
if (delegateMethod == null) { if (delegateMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + expected.name + "], function not found"); "to [" + Definition.ClassToName(expected) + "], function not found");
} }
ref = new FunctionRef(expected, interfaceMethod, delegateMethod, 0); ref = new FunctionRef(locals.getDefinition().ClassToType(expected), interfaceMethod, delegateMethod, 0);
// check casts between the interface method and the delegate method are legal // check casts between the interface method and the delegate method are legal
for (int i = 0; i < interfaceMethod.arguments.size(); ++i) { for (int i = 0; i < interfaceMethod.arguments.size(); ++i) {
@ -91,7 +91,7 @@ public final class EFunctionRef extends AExpression implements ILambda {
} }
} else { } else {
// whitelist lookup // whitelist lookup
ref = new FunctionRef(locals.getDefinition(), expected, type, call, 0); ref = new FunctionRef(locals.getDefinition(), locals.getDefinition().ClassToType(expected), type, call, 0);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {

View File

@ -20,7 +20,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -55,17 +54,17 @@ public final class EInstanceof extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
final Type type; Class<?> clazz;
// ensure the specified type is part of the definition // ensure the specified type is part of the definition
try { try {
type = locals.getDefinition().getType(this.type); clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type));
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
// map to wrapped type for primitive types // map to wrapped type for primitive types
resolvedType = type.clazz.isPrimitive() ? locals.getDefinition().getBoxedType(type).clazz : type.clazz; resolvedType = clazz.isPrimitive() ? Definition.getBoxedType(clazz) : Definition.defClassToObjectClass(clazz);
// analyze and cast the expression // analyze and cast the expression
expression.analyze(locals); expression.analyze(locals);
@ -73,11 +72,12 @@ public final class EInstanceof extends AExpression {
expression = expression.cast(locals); expression = expression.cast(locals);
// record if the expression returns a primitive // record if the expression returns a primitive
primitiveExpression = expression.actual.clazz.isPrimitive(); primitiveExpression = expression.actual.isPrimitive();
// map to wrapped type for primitive types // map to wrapped type for primitive types
expressionType = expression.actual.clazz.isPrimitive() ? locals.getDefinition().getBoxedType(expression.actual).clazz : type.clazz; expressionType = expression.actual.isPrimitive() ?
Definition.getBoxedType(expression.actual) : Definition.defClassToObjectClass(clazz);
actual = locals.getDefinition().booleanType; actual = boolean.class;
} }
@Override @Override
@ -87,7 +87,7 @@ public final class EInstanceof extends AExpression {
// run the expression anyway (who knows what it does) // run the expression anyway (who knows what it does)
expression.write(writer, globals); expression.write(writer, globals);
// discard its result // discard its result
writer.writePop(expression.actual.type.getSize()); writer.writePop(MethodWriter.getType(expression.actual).getSize());
// push our result: its a primitive so it cannot be null. // push our result: its a primitive so it cannot be null.
writer.push(resolvedType.isAssignableFrom(expressionType)); writer.push(resolvedType.isAssignableFrom(expressionType));
} else { } else {

View File

@ -120,15 +120,15 @@ public final class ELambda extends AExpression implements ILambda {
} }
} else { } else {
// we know the method statically, infer return type and any unknown/def types // we know the method statically, infer return type and any unknown/def types
interfaceMethod = expected.struct.getFunctionalMethod(); interfaceMethod = locals.getDefinition().ClassToType(expected).struct.getFunctionalMethod();
if (interfaceMethod == null) { if (interfaceMethod == null) {
throw createError(new IllegalArgumentException("Cannot pass lambda to [" + expected.name + throw createError(new IllegalArgumentException("Cannot pass lambda to [" + Definition.ClassToName(expected) +
"], not a functional interface")); "], not a functional interface"));
} }
// check arity before we manipulate parameters // check arity before we manipulate parameters
if (interfaceMethod.arguments.size() != paramTypeStrs.size()) if (interfaceMethod.arguments.size() != paramTypeStrs.size())
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name + throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name +
"] in [" + expected.clazz + "]"); "] in [" + Definition.ClassToName(expected) + "]");
// for method invocation, its allowed to ignore the return value // for method invocation, its allowed to ignore the return value
if (interfaceMethod.rtn.equals(locals.getDefinition().voidType)) { if (interfaceMethod.rtn.equals(locals.getDefinition().voidType)) {
returnType = locals.getDefinition().DefType; returnType = locals.getDefinition().DefType;
@ -178,12 +178,12 @@ public final class ELambda extends AExpression implements ILambda {
// setup method reference to synthetic method // setup method reference to synthetic method
if (expected == null) { if (expected == null) {
ref = null; ref = null;
actual = locals.getDefinition().getType("String"); actual = String.class;
defPointer = "Sthis." + name + "," + captures.size(); defPointer = "Sthis." + name + "," + captures.size();
} else { } else {
defPointer = null; defPointer = null;
try { try {
ref = new FunctionRef(expected, interfaceMethod, desugared.method, captures.size()); ref = new FunctionRef(locals.getDefinition().ClassToType(expected), interfaceMethod, desugared.method, captures.size());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw createError(e); throw createError(e);
} }

View File

@ -19,14 +19,15 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.MethodKey; import org.elasticsearch.painless.Definition.MethodKey;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -58,15 +59,15 @@ public final class EListInit extends AExpression {
throw createError(new IllegalArgumentException("Must read from list initializer.")); throw createError(new IllegalArgumentException("Must read from list initializer."));
} }
actual = locals.getDefinition().ArrayListType; actual = ArrayList.class;
constructor = actual.struct.constructors.get(new MethodKey("<init>", 0)); constructor = locals.getDefinition().ClassToType(actual).struct.constructors.get(new MethodKey("<init>", 0));
if (constructor == null) { if (constructor == null) {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
method = actual.struct.methods.get(new MethodKey("add", 1)); method = locals.getDefinition().ClassToType(actual).struct.methods.get(new MethodKey("add", 1));
if (method == null) { if (method == null) {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -75,7 +76,7 @@ public final class EListInit extends AExpression {
for (int index = 0; index < values.size(); ++index) { for (int index = 0; index < values.size(); ++index) {
AExpression expression = values.get(index); AExpression expression = values.get(index);
expression.expected = locals.getDefinition().DefType; expression.expected = def.class;
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
values.set(index, expression.cast(locals)); values.set(index, expression.cast(locals));
@ -86,7 +87,7 @@ public final class EListInit extends AExpression {
void write(MethodWriter writer, Globals globals) { void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
writer.newInstance(actual.type); writer.newInstance(MethodWriter.getType(actual));
writer.dup(); writer.dup();
writer.invokeConstructor(constructor.owner.type, constructor.method); writer.invokeConstructor(constructor.owner.type, constructor.method);

View File

@ -19,14 +19,15 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.MethodKey; import org.elasticsearch.painless.Definition.MethodKey;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -64,15 +65,15 @@ public final class EMapInit extends AExpression {
throw createError(new IllegalArgumentException("Must read from map initializer.")); throw createError(new IllegalArgumentException("Must read from map initializer."));
} }
actual = locals.getDefinition().HashMapType; actual = HashMap.class;
constructor = actual.struct.constructors.get(new MethodKey("<init>", 0)); constructor = locals.getDefinition().ClassToType(actual).struct.constructors.get(new MethodKey("<init>", 0));
if (constructor == null) { if (constructor == null) {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
method = actual.struct.methods.get(new MethodKey("put", 2)); method = locals.getDefinition().ClassToType(actual).struct.methods.get(new MethodKey("put", 2));
if (method == null) { if (method == null) {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
@ -85,7 +86,7 @@ public final class EMapInit extends AExpression {
for (int index = 0; index < keys.size(); ++index) { for (int index = 0; index < keys.size(); ++index) {
AExpression expression = keys.get(index); AExpression expression = keys.get(index);
expression.expected = locals.getDefinition().DefType; expression.expected = def.class;
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
keys.set(index, expression.cast(locals)); keys.set(index, expression.cast(locals));
@ -94,7 +95,7 @@ public final class EMapInit extends AExpression {
for (int index = 0; index < values.size(); ++index) { for (int index = 0; index < values.size(); ++index) {
AExpression expression = values.get(index); AExpression expression = values.get(index);
expression.expected = locals.getDefinition().DefType; expression.expected = def.class;
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
values.set(index, expression.cast(locals)); values.set(index, expression.cast(locals));
@ -105,7 +106,7 @@ public final class EMapInit extends AExpression {
void write(MethodWriter writer, Globals globals) { void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
writer.newInstance(actual.type); writer.newInstance(MethodWriter.getType(actual));
writer.dup(); writer.dup();
writer.invokeConstructor(constructor.owner.type, constructor.method); writer.invokeConstructor(constructor.owner.type, constructor.method);

View File

@ -20,7 +20,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -39,6 +38,8 @@ public final class ENewArray extends AExpression {
private final List<AExpression> arguments; private final List<AExpression> arguments;
private final boolean initialize; private final boolean initialize;
private Class<?> array;
public ENewArray(Location location, String type, List<AExpression> arguments, boolean initialize) { public ENewArray(Location location, String type, List<AExpression> arguments, boolean initialize) {
super(location); super(location);
@ -60,10 +61,10 @@ public final class ENewArray extends AExpression {
throw createError(new IllegalArgumentException("A newly created array must be read from.")); throw createError(new IllegalArgumentException("A newly created array must be read from."));
} }
final Type type; Class<?> clazz;
try { try {
type = locals.getDefinition().getType(this.type); clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type));
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
@ -71,13 +72,15 @@ public final class ENewArray extends AExpression {
for (int argument = 0; argument < arguments.size(); ++argument) { for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument); AExpression expression = arguments.get(argument);
expression.expected = initialize ? locals.getDefinition().getType(type.struct, 0) : locals.getDefinition().intType; expression.expected = initialize ? clazz : int.class;
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
arguments.set(argument, expression.cast(locals)); arguments.set(argument, expression.cast(locals));
} }
actual = locals.getDefinition().getType(type.struct, initialize ? 1 : arguments.size()); actual = Definition.TypeToClass(locals.getDefinition().getType(
locals.getDefinition().ClassToType(clazz).struct, initialize ? 1 : arguments.size()));
array = Definition.defClassToObjectClass(actual);
} }
@Override @Override
@ -86,7 +89,7 @@ public final class ENewArray extends AExpression {
if (initialize) { if (initialize) {
writer.push(arguments.size()); writer.push(arguments.size());
writer.newArray(actual.struct.type); writer.newArray(MethodWriter.getType(array.getComponentType()));
for (int index = 0; index < arguments.size(); ++index) { for (int index = 0; index < arguments.size(); ++index) {
AExpression argument = arguments.get(index); AExpression argument = arguments.get(index);
@ -94,7 +97,7 @@ public final class ENewArray extends AExpression {
writer.dup(); writer.dup();
writer.push(index); writer.push(index);
argument.write(writer, globals); argument.write(writer, globals);
writer.arrayStore(actual.struct.type); writer.arrayStore(MethodWriter.getType(array.getComponentType()));
} }
} else { } else {
for (AExpression argument : arguments) { for (AExpression argument : arguments) {
@ -102,9 +105,9 @@ public final class ENewArray extends AExpression {
} }
if (arguments.size() > 1) { if (arguments.size() > 1) {
writer.visitMultiANewArrayInsn(actual.type.getDescriptor(), actual.type.getDimensions()); writer.visitMultiANewArrayInsn(MethodWriter.getType(array).getDescriptor(), arguments.size());
} else { } else {
writer.newArray(actual.struct.type); writer.newArray(MethodWriter.getType(array.getComponentType()));
} }
} }
} }

View File

@ -58,15 +58,13 @@ public final class ENewObj extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
final Type type;
try { try {
type = locals.getDefinition().getType(this.type); actual = Definition.TypeToClass(locals.getDefinition().getType(this.type));
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
Struct struct = type.struct; Struct struct = locals.getDefinition().ClassToType(actual).struct;
constructor = struct.constructors.get(new Definition.MethodKey("<init>", arguments.size())); constructor = struct.constructors.get(new Definition.MethodKey("<init>", arguments.size()));
if (constructor != null) { if (constructor != null) {
@ -81,14 +79,13 @@ public final class ENewObj extends AExpression {
for (int argument = 0; argument < arguments.size(); ++argument) { for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument); AExpression expression = arguments.get(argument);
expression.expected = types[argument]; expression.expected = Definition.TypeToClass(types[argument]);
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
arguments.set(argument, expression.cast(locals)); arguments.set(argument, expression.cast(locals));
} }
statement = true; statement = true;
actual = type;
} else { } else {
throw createError(new IllegalArgumentException("Unknown new call on type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Unknown new call on type [" + struct.name + "]."));
} }
@ -98,7 +95,7 @@ public final class ENewObj extends AExpression {
void write(MethodWriter writer, Globals globals) { void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
writer.newInstance(actual.type); writer.newInstance(MethodWriter.getType(actual));
if (read) { if (read) {
writer.dup(); writer.dup();

View File

@ -21,14 +21,13 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.MethodWriter;
/** /**
* Represents a null constant. * Represents a null constant.
*/ */
@ -52,13 +51,14 @@ public final class ENull extends AExpression {
isNull = true; isNull = true;
if (expected != null) { if (expected != null) {
if (expected.clazz.isPrimitive()) { if (expected.isPrimitive()) {
throw createError(new IllegalArgumentException("Cannot cast null to a primitive type [" + expected.name + "].")); throw createError(new IllegalArgumentException(
"Cannot cast null to a primitive type [" + Definition.ClassToName(expected) + "]."));
} }
actual = expected; actual = expected;
} else { } else {
actual = locals.getDefinition().ObjectType; actual = Object.class;
} }
} }

View File

@ -19,16 +19,14 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.MethodWriter;
/** /**
* Represents a non-decimal numeric constant. * Represents a non-decimal numeric constant.
*/ */
@ -62,7 +60,7 @@ public final class ENumeric extends AExpression {
try { try {
constant = Double.parseDouble(value.substring(0, value.length() - 1)); constant = Double.parseDouble(value.substring(0, value.length() - 1));
actual = locals.getDefinition().doubleType; actual = double.class;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw createError(new IllegalArgumentException("Invalid double constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid double constant [" + value + "]."));
} }
@ -73,34 +71,34 @@ public final class ENumeric extends AExpression {
try { try {
constant = Float.parseFloat(value.substring(0, value.length() - 1)); constant = Float.parseFloat(value.substring(0, value.length() - 1));
actual = locals.getDefinition().floatType; actual = float.class;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw createError(new IllegalArgumentException("Invalid float constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid float constant [" + value + "]."));
} }
} else if (value.endsWith("l") || value.endsWith("L")) { } else if (value.endsWith("l") || value.endsWith("L")) {
try { try {
constant = Long.parseLong(value.substring(0, value.length() - 1), radix); constant = Long.parseLong(value.substring(0, value.length() - 1), radix);
actual = locals.getDefinition().longType; actual = long.class;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw createError(new IllegalArgumentException("Invalid long constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid long constant [" + value + "]."));
} }
} else { } else {
try { try {
Class<?> sort = expected == null ? int.class : expected.clazz; Class<?> sort = expected == null ? int.class : expected;
int integer = Integer.parseInt(value, radix); int integer = Integer.parseInt(value, radix);
if (sort == byte.class && integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) { if (sort == byte.class && integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) {
constant = (byte)integer; constant = (byte)integer;
actual = locals.getDefinition().byteType; actual = byte.class;
} else if (sort == char.class && integer >= Character.MIN_VALUE && integer <= Character.MAX_VALUE) { } else if (sort == char.class && integer >= Character.MIN_VALUE && integer <= Character.MAX_VALUE) {
constant = (char)integer; constant = (char)integer;
actual = locals.getDefinition().charType; actual = char.class;
} else if (sort == short.class && integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) { } else if (sort == short.class && integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) {
constant = (short)integer; constant = (short)integer;
actual = locals.getDefinition().shortType; actual = short.class;
} else { } else {
constant = integer; constant = integer;
actual = locals.getDefinition().intType; actual = int.class;
} }
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
try { try {

View File

@ -20,18 +20,16 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Constant;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.WriterConstants;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.WriterConstants;
/** /**
* Represents a regex constant. All regexes are constants. * Represents a regex constant. All regexes are constants.
*/ */
@ -75,7 +73,7 @@ public final class ERegex extends AExpression {
constant = new Constant( constant = new Constant(
location, locals.getDefinition().PatternType.type, "regexAt$" + location.getOffset(), this::initializeConstant); location, locals.getDefinition().PatternType.type, "regexAt$" + location.getOffset(), this::initializeConstant);
actual = locals.getDefinition().PatternType; actual = Pattern.class;
} }
@Override @Override

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -48,7 +49,7 @@ public final class EStatic extends AExpression {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
try { try {
actual = locals.getDefinition().getType(type); actual = Definition.TypeToClass(locals.getDefinition().getType(type));
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + type + "].")); throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
} }

View File

@ -19,10 +19,9 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Objects; import java.util.Objects;
@ -50,7 +49,7 @@ public final class EString extends AExpression {
throw createError(new IllegalArgumentException("Must read from constant [" + constant + "].")); throw createError(new IllegalArgumentException("Must read from constant [" + constant + "]."));
} }
actual = locals.getDefinition().StringType; actual = String.class;
} }
@Override @Override

View File

@ -19,22 +19,22 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.MethodWriter;
import org.objectweb.asm.Opcodes;
/** /**
* Represents a unary math expression. * Represents a unary math expression.
*/ */
@ -43,7 +43,7 @@ public final class EUnary extends AExpression {
private final Operation operation; private final Operation operation;
private AExpression child; private AExpression child;
private Type promote; private Class<?> promote;
private boolean originallyExplicit = false; // record whether there was originally an explicit cast private boolean originallyExplicit = false; // record whether there was originally an explicit cast
public EUnary(Location location, Operation operation, AExpression child) { public EUnary(Location location, Operation operation, AExpression child) {
@ -76,7 +76,7 @@ public final class EUnary extends AExpression {
} }
void analyzeNot(Locals variables) { void analyzeNot(Locals variables) {
child.expected = variables.getDefinition().booleanType; child.expected = boolean.class;
child.analyze(variables); child.analyze(variables);
child = child.cast(variables); child = child.cast(variables);
@ -84,34 +84,32 @@ public final class EUnary extends AExpression {
constant = !(boolean)child.constant; constant = !(boolean)child.constant;
} }
actual = variables.getDefinition().booleanType; actual = boolean.class;
} }
void analyzeBWNot(Locals variables) { void analyzeBWNot(Locals variables) {
child.analyze(variables); child.analyze(variables);
promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), false)); promote = AnalyzerCaster.promoteNumeric(child.actual, false);
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply not [~] to type [" + child.actual.name + "].")); throw createError(new ClassCastException("Cannot apply not [~] to type [" + Definition.ClassToName(child.actual) + "]."));
} }
child.expected = promote; child.expected = promote;
child = child.cast(variables); child = child.cast(variables);
if (child.constant != null) { if (child.constant != null) {
Class<?> sort = promote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = ~(int)child.constant; constant = ~(int)child.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = ~(long)child.constant; constant = ~(long)child.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
if (promote.dynamic && expected != null) { if (promote == def.class && expected != null) {
actual = expected; actual = expected;
} else { } else {
actual = promote; actual = promote;
@ -121,32 +119,30 @@ public final class EUnary extends AExpression {
void analyzerAdd(Locals variables) { void analyzerAdd(Locals variables) {
child.analyze(variables); child.analyze(variables);
promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true)); promote = AnalyzerCaster.promoteNumeric(child.actual, true);
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply positive [+] to type [" + child.actual.name + "].")); throw createError(new ClassCastException("Cannot apply positive [+] to type [" + Definition.ClassToName(child.actual) + "]."));
} }
child.expected = promote; child.expected = promote;
child = child.cast(variables); child = child.cast(variables);
if (child.constant != null) { if (child.constant != null) {
Class<?> sort = promote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = +(int)child.constant; constant = +(int)child.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = +(long)child.constant; constant = +(long)child.constant;
} else if (sort == float.class) { } else if (promote == float.class) {
constant = +(float)child.constant; constant = +(float)child.constant;
} else if (sort == double.class) { } else if (promote == double.class) {
constant = +(double)child.constant; constant = +(double)child.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
if (promote.dynamic && expected != null) { if (promote == def.class && expected != null) {
actual = expected; actual = expected;
} else { } else {
actual = promote; actual = promote;
@ -156,32 +152,30 @@ public final class EUnary extends AExpression {
void analyzerSub(Locals variables) { void analyzerSub(Locals variables) {
child.analyze(variables); child.analyze(variables);
promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true)); promote = AnalyzerCaster.promoteNumeric(child.actual, true);
if (promote == null) { if (promote == null) {
throw createError(new ClassCastException("Cannot apply negative [-] to type [" + child.actual.name + "].")); throw createError(new ClassCastException("Cannot apply negative [-] to type [" + Definition.ClassToName(child.actual) + "]."));
} }
child.expected = promote; child.expected = promote;
child = child.cast(variables); child = child.cast(variables);
if (child.constant != null) { if (child.constant != null) {
Class<?> sort = promote.clazz; if (promote == int.class) {
if (sort == int.class) {
constant = -(int)child.constant; constant = -(int)child.constant;
} else if (sort == long.class) { } else if (promote == long.class) {
constant = -(long)child.constant; constant = -(long)child.constant;
} else if (sort == float.class) { } else if (promote == float.class) {
constant = -(float)child.constant; constant = -(float)child.constant;
} else if (sort == double.class) { } else if (promote == double.class) {
constant = -(double)child.constant; constant = -(double)child.constant;
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
if (promote.dynamic && expected != null) { if (promote == def.class && expected != null) {
actual = expected; actual = expected;
} else { } else {
actual = promote; actual = promote;
@ -205,7 +199,6 @@ public final class EUnary extends AExpression {
writer.push(true); writer.push(true);
writer.mark(end); writer.mark(end);
} else { } else {
Class<?> sort = promote.clazz;
child.write(writer, globals); child.write(writer, globals);
// Def calls adopt the wanted return value. If there was a narrowing cast, // Def calls adopt the wanted return value. If there was a narrowing cast,
@ -216,31 +209,34 @@ public final class EUnary extends AExpression {
defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST;
} }
Type actualType = MethodWriter.getType(actual);
Type childType = MethodWriter.getType(child.actual);
if (operation == Operation.BWNOT) { if (operation == Operation.BWNOT) {
if (promote.dynamic) { if (promote == def.class) {
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actual.type, child.actual.type); org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType);
writer.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); writer.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags);
} else { } else {
if (sort == int.class) { if (promote == int.class) {
writer.push(-1); writer.push(-1);
} else if (sort == long.class) { } else if (promote == long.class) {
writer.push(-1L); writer.push(-1L);
} else { } else {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
writer.math(MethodWriter.XOR, actual.type); writer.math(MethodWriter.XOR, actualType);
} }
} else if (operation == Operation.SUB) { } else if (operation == Operation.SUB) {
if (promote.dynamic) { if (promote == def.class) {
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actual.type, child.actual.type); org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType);
writer.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); writer.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags);
} else { } else {
writer.math(MethodWriter.NEG, actual.type); writer.math(MethodWriter.NEG, actualType);
} }
} else if (operation == Operation.ADD) { } else if (operation == Operation.ADD) {
if (promote.dynamic) { if (promote == def.class) {
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actual.type, child.actual.type); org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType);
writer.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); writer.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags);
} }
} else { } else {

View File

@ -19,7 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Locals.Variable;
@ -58,12 +58,12 @@ public final class EVariable extends AStoreable {
throw createError(new IllegalArgumentException("Variable [" + variable.name + "] is read-only.")); throw createError(new IllegalArgumentException("Variable [" + variable.name + "] is read-only."));
} }
actual = variable.type; actual = Definition.TypeToClass(variable.type);
} }
@Override @Override
void write(MethodWriter writer, Globals globals) { void write(MethodWriter writer, Globals globals) {
writer.visitVarInsn(actual.type.getOpcode(Opcodes.ILOAD), variable.getSlot()); writer.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ILOAD), variable.getSlot());
} }
@Override @Override
@ -77,7 +77,7 @@ public final class EVariable extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
throw new IllegalArgumentException("Illegal tree structure."); throw new IllegalArgumentException("Illegal tree structure.");
} }
@ -88,12 +88,12 @@ public final class EVariable extends AStoreable {
@Override @Override
void load(MethodWriter writer, Globals globals) { void load(MethodWriter writer, Globals globals) {
writer.visitVarInsn(actual.type.getOpcode(Opcodes.ILOAD), variable.getSlot()); writer.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ILOAD), variable.getSlot());
} }
@Override @Override
void store(MethodWriter writer, Globals globals) { void store(MethodWriter writer, Globals globals) {
writer.visitVarInsn(actual.type.getOpcode(Opcodes.ISTORE), variable.getSlot()); writer.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ISTORE), variable.getSlot());
} }
@Override @Override

View File

@ -19,7 +19,8 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -57,16 +58,17 @@ public final class PBrace extends AStoreable {
prefix.expected = prefix.actual; prefix.expected = prefix.actual;
prefix = prefix.cast(locals); prefix = prefix.cast(locals);
if (prefix.actual.dimensions > 0) { if (prefix.actual.isArray()) {
sub = new PSubBrace(location, prefix.actual, index); sub = new PSubBrace(location, prefix.actual, index);
} else if (prefix.actual.dynamic) { } else if (prefix.actual == def.class) {
sub = new PSubDefArray(location, index); sub = new PSubDefArray(location, index);
} else if (Map.class.isAssignableFrom(prefix.actual.clazz)) { } else if (Map.class.isAssignableFrom(prefix.actual)) {
sub = new PSubMapShortcut(location, prefix.actual.struct, index); sub = new PSubMapShortcut(location, locals.getDefinition().ClassToType(prefix.actual).struct, index);
} else if (List.class.isAssignableFrom(prefix.actual.clazz)) { } else if (List.class.isAssignableFrom(prefix.actual)) {
sub = new PSubListShortcut(location, prefix.actual.struct, index); sub = new PSubListShortcut(location, locals.getDefinition().ClassToType(prefix.actual).struct, index);
} else { } else {
throw createError(new IllegalArgumentException("Illegal array access on type [" + prefix.actual.name + "].")); throw createError(
new IllegalArgumentException("Illegal array access on type [" + Definition.ClassToName(prefix.actual) + "]."));
} }
sub.write = write; sub.write = write;
@ -89,7 +91,7 @@ public final class PBrace extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
sub.updateActual(actual); sub.updateActual(actual);
this.actual = actual; this.actual = actual;
} }

View File

@ -23,6 +23,7 @@ import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.MethodKey; import org.elasticsearch.painless.Definition.MethodKey;
import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Struct;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -66,14 +67,14 @@ public final class PCallInvoke extends AExpression {
prefix.expected = prefix.actual; prefix.expected = prefix.actual;
prefix = prefix.cast(locals); prefix = prefix.cast(locals);
if (prefix.actual.dimensions > 0) { if (prefix.actual.isArray()) {
throw createError(new IllegalArgumentException("Illegal call [" + name + "] on array type.")); throw createError(new IllegalArgumentException("Illegal call [" + name + "] on array type."));
} }
Struct struct = prefix.actual.struct; Struct struct = locals.getDefinition().ClassToType(prefix.actual).struct;
if (prefix.actual.clazz.isPrimitive()) { if (prefix.actual.isPrimitive()) {
struct = locals.getDefinition().getBoxedType(prefix.actual).struct; struct = locals.getDefinition().ClassToType(Definition.getBoxedType(prefix.actual)).struct;
} }
MethodKey methodKey = new MethodKey(name, arguments.size()); MethodKey methodKey = new MethodKey(name, arguments.size());
@ -81,7 +82,7 @@ public final class PCallInvoke extends AExpression {
if (method != null) { if (method != null) {
sub = new PSubCallInvoke(location, method, prefix.actual, arguments); sub = new PSubCallInvoke(location, method, prefix.actual, arguments);
} else if (prefix.actual.dynamic) { } else if (prefix.actual == def.class) {
sub = new PSubDefCall(location, name, arguments); sub = new PSubDefCall(location, name, arguments);
} else { } else {
throw createError(new IllegalArgumentException( throw createError(new IllegalArgumentException(

View File

@ -23,7 +23,7 @@ import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Field; import org.elasticsearch.painless.Definition.Field;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Struct;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -62,12 +62,12 @@ public final class PField extends AStoreable {
prefix.expected = prefix.actual; prefix.expected = prefix.actual;
prefix = prefix.cast(locals); prefix = prefix.cast(locals);
if (prefix.actual.dimensions > 0) { if (prefix.actual.isArray()) {
sub = new PSubArrayLength(location, prefix.actual.name, value); sub = new PSubArrayLength(location, Definition.ClassToName(prefix.actual), value);
} else if (prefix.actual.dynamic) { } else if (prefix.actual == def.class) {
sub = new PSubDefField(location, value); sub = new PSubDefField(location, value);
} else { } else {
Struct struct = prefix.actual.struct; Struct struct = locals.getDefinition().ClassToType(prefix.actual).struct;
Field field = prefix instanceof EStatic ? struct.staticMembers.get(value) : struct.members.get(value); Field field = prefix instanceof EStatic ? struct.staticMembers.get(value) : struct.members.get(value);
if (field != null) { if (field != null) {
@ -85,16 +85,16 @@ public final class PField extends AStoreable {
new Definition.MethodKey("set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1)); new Definition.MethodKey("set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
if (getter != null || setter != null) { if (getter != null || setter != null) {
sub = new PSubShortcut(location, value, prefix.actual.name, getter, setter); sub = new PSubShortcut(location, value, Definition.ClassToName(prefix.actual), getter, setter);
} else { } else {
EConstant index = new EConstant(location, value); EConstant index = new EConstant(location, value);
index.analyze(locals); index.analyze(locals);
if (Map.class.isAssignableFrom(prefix.actual.clazz)) { if (Map.class.isAssignableFrom(prefix.actual)) {
sub = new PSubMapShortcut(location, struct, index); sub = new PSubMapShortcut(location, struct, index);
} }
if (List.class.isAssignableFrom(prefix.actual.clazz)) { if (List.class.isAssignableFrom(prefix.actual)) {
sub = new PSubListShortcut(location, struct, index); sub = new PSubListShortcut(location, struct, index);
} }
} }
@ -102,7 +102,8 @@ public final class PField extends AStoreable {
} }
if (sub == null) { if (sub == null) {
throw createError(new IllegalArgumentException("Unknown field [" + value + "] for type [" + prefix.actual.name + "].")); throw createError(new IllegalArgumentException(
"Unknown field [" + value + "] for type [" + Definition.ClassToName(prefix.actual) + "]."));
} }
if (nullSafe) { if (nullSafe) {
@ -129,7 +130,7 @@ public final class PField extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
sub.updateActual(actual); sub.updateActual(actual);
this.actual = actual; this.actual = actual;
} }

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -56,7 +54,7 @@ final class PSubArrayLength extends AStoreable {
throw createError(new IllegalArgumentException("Cannot write to read-only field [length] for an array.")); throw createError(new IllegalArgumentException("Cannot write to read-only field [length] for an array."));
} }
actual = locals.getDefinition().intType; actual = int.class;
} else { } else {
throw createError(new IllegalArgumentException("Field [" + value + "] does not exist for type [" + type + "].")); throw createError(new IllegalArgumentException("Field [" + value + "] does not exist for type [" + type + "]."));
} }
@ -79,7 +77,7 @@ final class PSubArrayLength extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
throw new IllegalStateException("Illegal tree structure."); throw new IllegalStateException("Illegal tree structure.");
} }

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -34,13 +32,13 @@ import java.util.Set;
*/ */
final class PSubBrace extends AStoreable { final class PSubBrace extends AStoreable {
private final Type type; private final Class<?> clazz;
private AExpression index; private AExpression index;
PSubBrace(Location location, Type type, AExpression index) { PSubBrace(Location location, Class<?> clazz, AExpression index) {
super(location); super(location);
this.type = Objects.requireNonNull(type); this.clazz = Objects.requireNonNull(clazz);
this.index = Objects.requireNonNull(index); this.index = Objects.requireNonNull(index);
} }
@ -51,11 +49,11 @@ final class PSubBrace extends AStoreable {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
index.expected = locals.getDefinition().intType; index.expected = int.class;
index.analyze(locals); index.analyze(locals);
index = index.cast(locals); index = index.cast(locals);
actual = locals.getDefinition().getType(type.struct, type.dimensions - 1); actual = clazz.getComponentType();
} }
@Override @Override
@ -75,7 +73,7 @@ final class PSubBrace extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
throw createError(new IllegalStateException("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
@ -88,13 +86,13 @@ final class PSubBrace extends AStoreable {
@Override @Override
void load(MethodWriter writer, Globals globals) { void load(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
writer.arrayLoad(actual.type); writer.arrayLoad(MethodWriter.getType(actual));
} }
@Override @Override
void store(MethodWriter writer, Globals globals) { void store(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
writer.arrayStore(actual.type); writer.arrayStore(MethodWriter.getType(actual));
} }
@Override @Override

View File

@ -19,8 +19,8 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -36,10 +36,10 @@ import java.util.Set;
final class PSubCallInvoke extends AExpression { final class PSubCallInvoke extends AExpression {
private final Method method; private final Method method;
private final Type box; private final Class<?> box;
private final List<AExpression> arguments; private final List<AExpression> arguments;
PSubCallInvoke(Location location, Method method, Type box, List<AExpression> arguments) { PSubCallInvoke(Location location, Method method, Class<?> box, List<AExpression> arguments) {
super(location); super(location);
this.method = Objects.requireNonNull(method); this.method = Objects.requireNonNull(method);
@ -57,22 +57,22 @@ final class PSubCallInvoke extends AExpression {
for (int argument = 0; argument < arguments.size(); ++argument) { for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument); AExpression expression = arguments.get(argument);
expression.expected = method.arguments.get(argument); expression.expected = Definition.TypeToClass(method.arguments.get(argument));
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
arguments.set(argument, expression.cast(locals)); arguments.set(argument, expression.cast(locals));
} }
statement = true; statement = true;
actual = method.rtn; actual = Definition.TypeToClass(method.rtn);
} }
@Override @Override
void write(MethodWriter writer, Globals globals) { void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
if (box.clazz.isPrimitive()) { if (box.isPrimitive()) {
writer.box(box.type); writer.box(MethodWriter.getType(box));
} }
for (AExpression argument : arguments) { for (AExpression argument : arguments) {

View File

@ -20,12 +20,12 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import org.objectweb.asm.Type;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@ -53,7 +53,7 @@ final class PSubDefArray extends AStoreable {
index.expected = index.actual; index.expected = index.actual;
index = index.cast(locals); index = index.cast(locals);
actual = expected == null || explicit ? locals.getDefinition().DefType : expected; actual = expected == null || explicit ? def.class : expected;
} }
@Override @Override
@ -73,7 +73,7 @@ final class PSubDefArray extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
this.actual = actual; this.actual = actual;
} }
@ -82,8 +82,8 @@ final class PSubDefArray extends AStoreable {
// Current stack: def // Current stack: def
writer.dup(); // def, def writer.dup(); // def, def
index.write(writer, globals); // def, def, unnormalized_index index.write(writer, globals); // def, def, unnormalized_index
org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType( Type methodType = Type.getMethodType(
index.actual.type, org.objectweb.asm.Type.getType(Object.class), index.actual.type); MethodWriter.getType(index.actual), Type.getType(Object.class), MethodWriter.getType(index.actual));
writer.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); // def, normalized_index writer.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); // def, normalized_index
} }
@ -91,8 +91,8 @@ final class PSubDefArray extends AStoreable {
void load(MethodWriter writer, Globals globals) { void load(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
org.objectweb.asm.Type methodType = Type methodType =
org.objectweb.asm.Type.getMethodType(actual.type, org.objectweb.asm.Type.getType(Object.class), index.actual.type); Type.getMethodType(MethodWriter.getType(actual), Type.getType(Object.class), MethodWriter.getType(index.actual));
writer.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD); writer.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD);
} }
@ -100,9 +100,9 @@ final class PSubDefArray extends AStoreable {
void store(MethodWriter writer, Globals globals) { void store(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
org.objectweb.asm.Type methodType = Type methodType =
org.objectweb.asm.Type.getMethodType( Type.getMethodType(
org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), index.actual.type, actual.type); Type.getType(void.class), Type.getType(Object.class), MethodWriter.getType(index.actual), MethodWriter.getType(actual));
writer.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE); writer.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE);
} }

View File

@ -20,6 +20,8 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -75,7 +77,7 @@ final class PSubDefCall extends AExpression {
totalCaptures += lambda.getCaptureCount(); totalCaptures += lambda.getCaptureCount();
} }
if (expression.actual.clazz == void.class) { if (expression.actual == void.class) {
throw createError(new IllegalArgumentException("Argument(s) cannot be of [void] type when calling method [" + name + "].")); throw createError(new IllegalArgumentException("Argument(s) cannot be of [void] type when calling method [" + name + "]."));
} }
@ -83,7 +85,7 @@ final class PSubDefCall extends AExpression {
arguments.set(argument, expression.cast(locals)); arguments.set(argument, expression.cast(locals));
} }
actual = expected == null || explicit ? locals.getDefinition().DefType : expected; actual = expected == null || explicit ? def.class : expected;
} }
@Override @Override
@ -97,7 +99,7 @@ final class PSubDefCall extends AExpression {
// append each argument // append each argument
for (AExpression argument : arguments) { for (AExpression argument : arguments) {
parameterTypes.add(argument.actual.type); parameterTypes.add(MethodWriter.getType(argument.actual));
if (argument instanceof ILambda) { if (argument instanceof ILambda) {
ILambda lambda = (ILambda) argument; ILambda lambda = (ILambda) argument;
@ -108,7 +110,7 @@ final class PSubDefCall extends AExpression {
} }
// create method type from return value and arguments // create method type from return value and arguments
Type methodType = Type.getMethodType(actual.type, parameterTypes.toArray(new Type[0])); Type methodType = Type.getMethodType(MethodWriter.getType(actual), parameterTypes.toArray(new Type[0]));
List<Object> args = new ArrayList<>(); List<Object> args = new ArrayList<>();
args.add(recipe.toString()); args.add(recipe.toString());

View File

@ -20,7 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -49,7 +49,7 @@ final class PSubDefField extends AStoreable {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
actual = expected == null || explicit ? locals.getDefinition().DefType : expected; actual = expected == null || explicit ? def.class : expected;
} }
@Override @Override
@ -57,7 +57,7 @@ final class PSubDefField extends AStoreable {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
org.objectweb.asm.Type methodType = org.objectweb.asm.Type methodType =
org.objectweb.asm.Type.getMethodType(actual.type, org.objectweb.asm.Type.getType(Object.class)); org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class));
writer.invokeDefCall(value, methodType, DefBootstrap.LOAD); writer.invokeDefCall(value, methodType, DefBootstrap.LOAD);
} }
@ -72,7 +72,7 @@ final class PSubDefField extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
this.actual = actual; this.actual = actual;
} }
@ -86,7 +86,7 @@ final class PSubDefField extends AStoreable {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
org.objectweb.asm.Type methodType = org.objectweb.asm.Type methodType =
org.objectweb.asm.Type.getMethodType(actual.type, org.objectweb.asm.Type.getType(Object.class)); org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class));
writer.invokeDefCall(value, methodType, DefBootstrap.LOAD); writer.invokeDefCall(value, methodType, DefBootstrap.LOAD);
} }
@ -95,7 +95,7 @@ final class PSubDefField extends AStoreable {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType( org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(
org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), actual.type); org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), MethodWriter.getType(actual));
writer.invokeDefCall(value, methodType, DefBootstrap.STORE); writer.invokeDefCall(value, methodType, DefBootstrap.STORE);
} }

View File

@ -19,8 +19,8 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Field; import org.elasticsearch.painless.Definition.Field;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -55,7 +55,7 @@ final class PSubField extends AStoreable {
"Cannot write to read-only field [" + field.name + "] for type [" + field.type.name + "].")); "Cannot write to read-only field [" + field.name + "] for type [" + field.type.name + "]."));
} }
actual = field.type; actual = Definition.TypeToClass(field.type);
} }
@Override @Override
@ -80,7 +80,7 @@ final class PSubField extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
throw new IllegalArgumentException("Illegal tree structure."); throw new IllegalArgumentException("Illegal tree structure.");
} }

View File

@ -22,7 +22,6 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Struct;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -75,11 +74,11 @@ final class PSubListShortcut extends AStoreable {
} }
if ((read || write) && (!read || getter != null) && (!write || setter != null)) { if ((read || write) && (!read || getter != null) && (!write || setter != null)) {
index.expected = locals.getDefinition().intType; index.expected = int.class;
index.analyze(locals); index.analyze(locals);
index = index.cast(locals); index = index.cast(locals);
actual = setter != null ? setter.arguments.get(1) : getter.rtn; actual = setter != null ? Definition.TypeToClass(setter.arguments.get(1)) : Definition.TypeToClass(getter.rtn);
} else { } else {
throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + struct.name + "]."));
} }
@ -102,7 +101,7 @@ final class PSubListShortcut extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
throw new IllegalArgumentException("Illegal tree structure."); throw new IllegalArgumentException("Illegal tree structure.");
} }

View File

@ -20,18 +20,16 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Struct;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Struct;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.MethodWriter;
/** /**
* Represents a map load/store shortcut. (Internal only.) * Represents a map load/store shortcut. (Internal only.)
*/ */
@ -74,11 +72,12 @@ final class PSubMapShortcut extends AStoreable {
} }
if ((read || write) && (!read || getter != null) && (!write || setter != null)) { if ((read || write) && (!read || getter != null) && (!write || setter != null)) {
index.expected = setter != null ? setter.arguments.get(0) : getter.arguments.get(0); index.expected = setter != null ?
Definition.TypeToClass(setter.arguments.get(0)) : Definition.TypeToClass(getter.arguments.get(0));
index.analyze(locals); index.analyze(locals);
index = index.cast(locals); index = index.cast(locals);
actual = setter != null ? setter.arguments.get(1) : getter.rtn; actual = setter != null ? Definition.TypeToClass(setter.arguments.get(1)) : Definition.TypeToClass(getter.rtn);
} else { } else {
throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + struct.name + "]."));
} }
@ -108,7 +107,7 @@ final class PSubMapShortcut extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
throw new IllegalArgumentException("Illegal tree structure."); throw new IllegalArgumentException("Illegal tree structure.");
} }

View File

@ -52,7 +52,7 @@ public class PSubNullSafeCallInvoke extends AExpression {
void analyze(Locals locals) { void analyze(Locals locals) {
guarded.analyze(locals); guarded.analyze(locals);
actual = guarded.actual; actual = guarded.actual;
if (actual.clazz.isPrimitive()) { if (actual.isPrimitive()) {
throw new IllegalArgumentException("Result of null safe operator must be nullable"); throw new IllegalArgumentException("Result of null safe operator must be nullable");
} }
} }

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -52,7 +51,7 @@ public class PSubNullSafeField extends AStoreable {
guarded.read = read; guarded.read = read;
guarded.analyze(locals); guarded.analyze(locals);
actual = guarded.actual; actual = guarded.actual;
if (actual.clazz.isPrimitive()) { if (actual.isPrimitive()) {
throw new IllegalArgumentException("Result of null safe operator must be nullable"); throw new IllegalArgumentException("Result of null safe operator must be nullable");
} }
} }
@ -69,7 +68,7 @@ public class PSubNullSafeField extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
guarded.updateActual(actual); guarded.updateActual(actual);
} }

View File

@ -19,8 +19,8 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -69,7 +69,7 @@ final class PSubShortcut extends AStoreable {
} }
if ((getter != null || setter != null) && (!read || getter != null) && (!write || setter != null)) { if ((getter != null || setter != null) && (!read || getter != null) && (!write || setter != null)) {
actual = setter != null ? setter.arguments.get(0) : getter.rtn; actual = setter != null ? Definition.TypeToClass(setter.arguments.get(0)) : Definition.TypeToClass(getter.rtn);
} else { } else {
throw createError(new IllegalArgumentException("Illegal shortcut on field [" + value + "] for type [" + type + "].")); throw createError(new IllegalArgumentException("Illegal shortcut on field [" + value + "] for type [" + type + "]."));
} }
@ -97,7 +97,7 @@ final class PSubShortcut extends AStoreable {
} }
@Override @Override
void updateActual(Type actual) { void updateActual(Class<?> actual) {
throw new IllegalArgumentException("Illegal tree structure."); throw new IllegalArgumentException("Illegal tree structure.");
} }

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
@ -69,7 +70,7 @@ public final class SDeclaration extends AStatement {
} }
if (expression != null) { if (expression != null) {
expression.expected = type; expression.expected = Definition.TypeToClass(type);
expression.analyze(locals); expression.analyze(locals);
expression = expression.cast(locals); expression = expression.cast(locals);
} }

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -73,7 +72,7 @@ public final class SDo extends AStatement {
throw createError(new IllegalArgumentException("Extraneous do while loop.")); throw createError(new IllegalArgumentException("Extraneous do while loop."));
} }
condition.expected = locals.getDefinition().booleanType; condition.expected = boolean.class;
condition.analyze(locals); condition.analyze(locals);
condition = condition.cast(locals); condition = condition.cast(locals);

View File

@ -19,7 +19,9 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Locals.Variable;
@ -78,12 +80,12 @@ public class SEach extends AStatement {
locals = Locals.newLocalScope(locals); locals = Locals.newLocalScope(locals);
Variable variable = locals.addVariable(location, type, name, true); Variable variable = locals.addVariable(location, type, name, true);
if (expression.actual.dimensions > 0) { if (expression.actual.isArray()) {
sub = new SSubEachArray(location, variable, expression, block); sub = new SSubEachArray(location, variable, expression, block);
} else if (expression.actual.dynamic || Iterable.class.isAssignableFrom(expression.actual.clazz)) { } else if (expression.actual == def.class || Iterable.class.isAssignableFrom(expression.actual)) {
sub = new SSubEachIterable(location, variable, expression, block); sub = new SSubEachIterable(location, variable, expression, block);
} else { } else {
throw createError(new IllegalArgumentException("Illegal for each type [" + expression.actual.name + "].")); throw createError(new IllegalArgumentException("Illegal for each type [" + Definition.ClassToName(expression.actual) + "]."));
} }
sub.analyze(locals); sub.analyze(locals);

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
@ -58,9 +59,9 @@ public final class SExpression extends AStatement {
throw createError(new IllegalArgumentException("Not a statement.")); throw createError(new IllegalArgumentException("Not a statement."));
} }
boolean rtn = lastSource && !isVoid && expression.actual.clazz != void.class; boolean rtn = lastSource && !isVoid && expression.actual != void.class;
expression.expected = rtn ? rtnType : expression.actual; expression.expected = rtn ? Definition.TypeToClass(rtnType) : expression.actual;
expression.internal = rtn; expression.internal = rtn;
expression = expression.cast(locals); expression = expression.cast(locals);
@ -78,7 +79,7 @@ public final class SExpression extends AStatement {
if (methodEscape) { if (methodEscape) {
writer.returnValue(); writer.returnValue();
} else { } else {
writer.writePop(expression.expected.type.getSize()); writer.writePop(MethodWriter.getType(expression.expected).getSize());
} }
} }

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -94,7 +93,7 @@ public final class SFor extends AStatement {
} }
if (condition != null) { if (condition != null) {
condition.expected = locals.getDefinition().booleanType; condition.expected = boolean.class;
condition.analyze(locals); condition.analyze(locals);
condition = condition.cast(locals); condition = condition.cast(locals);
@ -161,7 +160,7 @@ public final class SFor extends AStatement {
AExpression initializer = (AExpression)this.initializer; AExpression initializer = (AExpression)this.initializer;
initializer.write(writer, globals); initializer.write(writer, globals);
writer.writePop(initializer.expected.type.getSize()); writer.writePop(MethodWriter.getType(initializer.expected).getSize());
} }
writer.mark(start); writer.mark(start);

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -56,7 +55,7 @@ public final class SIf extends AStatement {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
condition.expected = locals.getDefinition().booleanType; condition.expected = boolean.class;
condition.analyze(locals); condition.analyze(locals);
condition = condition.cast(locals); condition = condition.cast(locals);

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -65,7 +64,7 @@ public final class SIfElse extends AStatement {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
condition.expected = locals.getDefinition().booleanType; condition.expected = boolean.class;
condition.analyze(locals); condition.analyze(locals);
condition = condition.cast(locals); condition = condition.cast(locals);

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -47,7 +48,7 @@ public final class SReturn extends AStatement {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
expression.expected = locals.getReturnType(); expression.expected = Definition.TypeToClass(locals.getReturnType());
expression.internal = true; expression.internal = true;
expression.analyze(locals); expression.analyze(locals);
expression = expression.cast(locals); expression = expression.cast(locals);

View File

@ -64,9 +64,10 @@ final class SSubEachArray extends AStatement {
void analyze(Locals locals) { void analyze(Locals locals) {
// We must store the array and index as variables for securing slots on the stack, and // We must store the array and index as variables for securing slots on the stack, and
// also add the location offset to make the names unique in case of nested for each loops. // also add the location offset to make the names unique in case of nested for each loops.
array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), true); Type actualType = locals.getDefinition().ClassToType(expression.actual);
array = locals.addVariable(location, actualType, "#array" + location.getOffset(), true);
index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), true); index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), true);
indexed = locals.getDefinition().getType(expression.actual.struct, expression.actual.dimensions - 1); indexed = locals.getDefinition().getType(actualType.struct, actualType.dimensions - 1);
cast = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(indexed), Definition.TypeToClass(variable.type), true, true); cast = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(indexed), Definition.TypeToClass(variable.type), true, true);
} }

View File

@ -25,6 +25,7 @@ import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.MethodKey; import org.elasticsearch.painless.Definition.MethodKey;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Definition.def; import org.elasticsearch.painless.Definition.def;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
@ -75,14 +76,15 @@ final class SSubEachIterable extends AStatement {
iterator = locals.addVariable(location, locals.getDefinition().getType("Iterator"), iterator = locals.addVariable(location, locals.getDefinition().getType("Iterator"),
"#itr" + location.getOffset(), true); "#itr" + location.getOffset(), true);
if (expression.actual.dynamic) { if (expression.actual == def.class) {
method = null; method = null;
} else { } else {
method = expression.actual.struct.methods.get(new MethodKey("iterator", 0)); Type actualType = locals.getDefinition().ClassToType(expression.actual);
method = actualType.struct.methods.get(new MethodKey("iterator", 0));
if (method == null) { if (method == null) {
throw createError(new IllegalArgumentException( throw createError(new IllegalArgumentException(
"Unable to create iterator for the type [" + expression.actual.name + "].")); "Unable to create iterator for the type [" + actualType.name + "]."));
} }
} }

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -48,7 +47,7 @@ public final class SThrow extends AStatement {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
expression.expected = locals.getDefinition().ExceptionType; expression.expected = Exception.class;
expression.analyze(locals); expression.analyze(locals);
expression = expression.cast(locals); expression = expression.cast(locals);

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Location;
@ -59,7 +58,7 @@ public final class SWhile extends AStatement {
void analyze(Locals locals) { void analyze(Locals locals) {
locals = Locals.newLocalScope(locals); locals = Locals.newLocalScope(locals);
condition.expected = locals.getDefinition().booleanType; condition.expected = boolean.class;
condition.analyze(locals); condition.analyze(locals);
condition = condition.cast(locals); condition = condition.cast(locals);

View File

@ -397,7 +397,7 @@ public class NodeToStringTests extends ESTestCase {
public void testPSubBrace() { public void testPSubBrace() {
Location l = new Location(getTestName(), 0); Location l = new Location(getTestName(), 0);
PSubBrace node = new PSubBrace(l, definition.intType, new ENumeric(l, "1", 10)); PSubBrace node = new PSubBrace(l, int.class, new ENumeric(l, "1", 10));
node.prefix = new EVariable(l, "a"); node.prefix = new EVariable(l, "a");
assertEquals("(PSubBrace (EVariable a) (ENumeric 1))", node.toString()); assertEquals("(PSubBrace (EVariable a) (ENumeric 1))", node.toString());
} }