Merge pull request #18463 from rmuir/whitelist_cleanup

painless: steps at definition cleanup
This commit is contained in:
Robert Muir 2016-05-20 14:26:41 -04:00
commit a2ff002e2b
80 changed files with 2422 additions and 5043 deletions

View File

@ -26,10 +26,10 @@ import org.elasticsearch.painless.node.SSource;
* Runs the analysis phase of compilation using the Painless AST.
*/
final class Analyzer {
static Variables analyze(final CompilerSettings settings, final Definition definition,
static Variables analyze(final CompilerSettings settings,
final Reserved shortcut, final SSource root) {
final Variables variables = new Variables(settings, definition, shortcut);
root.analyze(settings, definition, variables);
final Variables variables = new Variables(settings, shortcut);
root.analyze(variables);
return variables;
}

View File

@ -112,10 +112,10 @@ final class Compiler {
}
final Reserved reserved = new Reserved();
final SSource root = Walker.buildPainlessTree(source, reserved);
final Variables variables = Analyzer.analyze(settings, Definition.INSTANCE, reserved, root);
final SSource root = Walker.buildPainlessTree(source, reserved, settings);
final Variables variables = Analyzer.analyze(settings, reserved, root);
return Writer.write(settings, Definition.INSTANCE, name, source, variables, root);
return Writer.write(settings, name, source, variables, root);
}
/**

View File

@ -24,47 +24,16 @@ package org.elasticsearch.painless;
*/
public final class CompilerSettings {
/**
* Constant to be used when specifying numeric overflow when compiling a script.
*/
public static final String NUMERIC_OVERFLOW = "numeric_overflow";
/**
* Constant to be used when specifying the maximum loop counter when compiling a script.
*/
public static final String MAX_LOOP_COUNTER = "max_loop_counter";
/**
* Whether or not to allow numeric values to overflow without exception.
*/
private boolean numericOverflow = true;
/**
* The maximum number of statements allowed to be run in a loop.
*/
private int maxLoopCounter = 10000;
/**
* Returns {@code true} if numeric operations should overflow, {@code false}
* if they should signal an exception.
* <p>
* If this value is {@code true} (default), then things behave like java:
* overflow for integer types can result in unexpected values / unexpected
* signs, and overflow for floating point types can result in infinite or
* {@code NaN} values.
*/
public final boolean getNumericOverflow() {
return numericOverflow;
}
/**
* Set {@code true} for numerics to overflow, false to deliver exceptions.
* @see #getNumericOverflow
*/
public final void setNumericOverflow(boolean allow) {
this.numericOverflow = allow;
}
/**
* Returns the value for the cumulative total number of statements that can be made in all loops
* in a script before an exception is thrown. This attempts to prevent infinite loops. Note if

View File

@ -52,9 +52,10 @@ public final class Def {
// TODO: Once Java has a factory for those in java.lang.invoke.MethodHandles, use it:
/** Helper class for isolating MethodHandles and methods to get the length of arrays
* (to emulate a "arraystore" byteoode using MethodHandles).
* (to emulate a "arraystore" bytecode using MethodHandles).
* This should really be a method in {@link MethodHandles} class!
*/
@SuppressWarnings("unused") // getArrayLength() methods are are actually used, javac just does not know :)
private static final class ArrayLengthHelper {
private static final Lookup PRIV_LOOKUP = MethodHandles.lookup();
@ -134,17 +135,16 @@ public final class Def {
* @param receiverClass Class of the object to invoke the method on.
* @param name Name of the method.
* @param type Callsite signature. Need not match exactly, except the number of parameters.
* @param definition Whitelist to check.
* @return pointer to matching method to invoke. never returns null.
* @throws IllegalArgumentException if no matching whitelisted method was found.
*/
static MethodHandle lookupMethod(Class<?> receiverClass, String name, MethodType type, Definition definition) {
static MethodHandle lookupMethod(Class<?> receiverClass, String name, MethodType type) {
// we don't consider receiver an argument/counting towards arity
type = type.dropParameterTypes(0, 1);
Definition.MethodKey key = new Definition.MethodKey(name, type.parameterCount());
// check whitelist for matching method
for (Class<?> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
RuntimeClass struct = definition.runtimeMap.get(clazz);
RuntimeClass struct = Definition.getRuntimeClass(clazz);
if (struct != null) {
Method method = struct.methods.get(key);
@ -154,7 +154,7 @@ public final class Def {
}
for (final Class<?> iface : clazz.getInterfaces()) {
struct = definition.runtimeMap.get(iface);
struct = Definition.getRuntimeClass(iface);
if (struct != null) {
Method method = struct.methods.get(key);
@ -192,14 +192,13 @@ public final class Def {
* <p>
* @param receiverClass Class of the object to retrieve the field from.
* @param name Name of the field.
* @param definition Whitelist to check.
* @return pointer to matching field. never returns null.
* @throws IllegalArgumentException if no matching whitelisted field was found.
*/
static MethodHandle lookupGetter(Class<?> receiverClass, String name, Definition definition) {
static MethodHandle lookupGetter(Class<?> receiverClass, String name) {
// first try whitelist
for (Class<?> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
RuntimeClass struct = definition.runtimeMap.get(clazz);
RuntimeClass struct = Definition.getRuntimeClass(clazz);
if (struct != null) {
MethodHandle handle = struct.getters.get(name);
@ -209,7 +208,7 @@ public final class Def {
}
for (final Class<?> iface : clazz.getInterfaces()) {
struct = definition.runtimeMap.get(iface);
struct = Definition.getRuntimeClass(iface);
if (struct != null) {
MethodHandle handle = struct.getters.get(name);
@ -263,14 +262,13 @@ public final class Def {
* <p>
* @param receiverClass Class of the object to retrieve the field from.
* @param name Name of the field.
* @param definition Whitelist to check.
* @return pointer to matching field. never returns null.
* @throws IllegalArgumentException if no matching whitelisted field was found.
*/
static MethodHandle lookupSetter(Class<?> receiverClass, String name, Definition definition) {
static MethodHandle lookupSetter(Class<?> receiverClass, String name) {
// first try whitelist
for (Class<?> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
RuntimeClass struct = definition.runtimeMap.get(clazz);
RuntimeClass struct = Definition.getRuntimeClass(clazz);
if (struct != null) {
MethodHandle handle = struct.setters.get(name);
@ -280,7 +278,7 @@ public final class Def {
}
for (final Class<?> iface : clazz.getInterfaces()) {
struct = definition.runtimeMap.get(iface);
struct = Definition.getRuntimeClass(iface);
if (struct != null) {
MethodHandle handle = struct.setters.get(name);
@ -971,6 +969,10 @@ public final class Def {
// Conversion methods for Def to primitive types.
public static boolean DefToboolean(final Object value) {
return (boolean)value;
}
public static byte DefTobyteImplicit(final Object value) {
return (byte)value;
}
@ -1051,79 +1053,6 @@ public final class Def {
}
}
public static Byte DefToByteImplicit(final Object value) {
return (Byte)value;
}
public static Short DefToShortImplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Byte) {
return ((Byte)value).shortValue();
} else {
return (Short)value;
}
}
public static Character DefToCharacterImplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Byte) {
return (char)(byte)value;
} else {
return (Character)value;
}
}
public static Integer DefToIntegerImplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Byte || value instanceof Short) {
return ((Number)value).intValue();
} else if (value instanceof Character) {
return (int)(char)value;
} else {
return (Integer)value;
}
}
public static Long DefToLongImplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Byte || value instanceof Short || value instanceof Integer) {
return ((Number)value).longValue();
} else if (value instanceof Character) {
return (long)(char)value;
} else {
return (Long)value;
}
}
public static Float DefToFloatImplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
return ((Number)value).floatValue();
} else if (value instanceof Character) {
return (float)(char)value;
} else {
return (Float)value;
}
}
public static Double DefToDoubleImplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Byte || value instanceof Short ||
value instanceof Integer || value instanceof Long || value instanceof Float) {
return ((Number)value).doubleValue();
} else if (value instanceof Character) {
return (double)(char)value;
} else {
return (Double)value;
}
}
public static byte DefTobyteExplicit(final Object value) {
if (value instanceof Character) {
return (byte)(char)value;
@ -1179,74 +1108,4 @@ public final class Def {
return ((Number)value).doubleValue();
}
}
public static Byte DefToByteExplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Character) {
return (byte)(char)value;
} else {
return ((Number)value).byteValue();
}
}
public static Short DefToShortExplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Character) {
return (short)(char)value;
} else {
return ((Number)value).shortValue();
}
}
public static Character DefToCharacterExplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Character) {
return ((Character)value);
} else {
return (char)((Number)value).intValue();
}
}
public static Integer DefToIntegerExplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Character) {
return (int)(char)value;
} else {
return ((Number)value).intValue();
}
}
public static Long DefToLongExplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Character) {
return (long)(char)value;
} else {
return ((Number)value).longValue();
}
}
public static Float DefToFloatExplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Character) {
return (float)(char)value;
} else {
return ((Number)value).floatValue();
}
}
public static Double DefToDoubleExplicit(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Character) {
return (double)(char)value;
} else {
return ((Number)value).doubleValue();
}
}
}

View File

@ -94,11 +94,11 @@ public final class DefBootstrap {
private static MethodHandle lookup(int flavor, Class<?> clazz, String name, MethodType type) {
switch(flavor) {
case METHOD_CALL:
return Def.lookupMethod(clazz, name, type, Definition.INSTANCE);
return Def.lookupMethod(clazz, name, type);
case LOAD:
return Def.lookupGetter(clazz, name, Definition.INSTANCE);
return Def.lookupGetter(clazz, name);
case STORE:
return Def.lookupSetter(clazz, name, Definition.INSTANCE);
return Def.lookupSetter(clazz, name);
case ARRAY_LOAD:
return Def.lookupArrayLoad(clazz);
case ARRAY_STORE:

View File

@ -21,7 +21,6 @@ package org.elasticsearch.painless;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Transform;
import org.elasticsearch.painless.Definition.Type;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
@ -34,10 +33,7 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import static org.elasticsearch.painless.WriterConstants.ADDEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.ADDEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.ADDWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.ADDWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.CHAR_TO_STRING;
import static org.elasticsearch.painless.WriterConstants.DEF_ADD_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_AND_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_DIV_CALL;
@ -47,21 +43,27 @@ import static org.elasticsearch.painless.WriterConstants.DEF_OR_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_REM_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_RSH_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_SUB_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_BOOLEAN;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_BYTE_EXPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_BYTE_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_CHAR_EXPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_CHAR_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_DOUBLE_EXPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_DOUBLE_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_FLOAT_EXPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_FLOAT_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_INT_EXPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_INT_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_LONG_EXPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_LONG_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_SHORT_EXPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_TO_SHORT_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_USH_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
import static org.elasticsearch.painless.WriterConstants.DEF_XOR_CALL;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_INT;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_LONG;
import static org.elasticsearch.painless.WriterConstants.INDY_STRING_CONCAT_BOOTSTRAP_HANDLE;
import static org.elasticsearch.painless.WriterConstants.MAX_INDY_STRING_CONCAT_ARGS;
import static org.elasticsearch.painless.WriterConstants.MULEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.MULEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.MULWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.MULWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.PAINLESS_ERROR_TYPE;
import static org.elasticsearch.painless.WriterConstants.REMWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.REMWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_BOOLEAN;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_CHAR;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_DOUBLE;
@ -73,29 +75,9 @@ import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_ST
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_CONSTRUCTOR;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_TOSTRING;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_TYPE;
import static org.elasticsearch.painless.WriterConstants.STRING_TO_CHAR;
import static org.elasticsearch.painless.WriterConstants.STRING_TYPE;
import static org.elasticsearch.painless.WriterConstants.SUBEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.SUBEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.SUBWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.SUBWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOBYTEEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.TOBYTEEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOBYTEWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOBYTEWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOCHAREXACT_INT;
import static org.elasticsearch.painless.WriterConstants.TOCHAREXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOCHARWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOCHARWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOFLOATWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOINTEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOINTWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOINTWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOLONGWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOLONGWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOSHORTEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.TOSHORTEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOSHORTWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOSHORTWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.UTILITY_TYPE;
/**
* Extension of {@link GeneratorAdapter} with some utility methods.
@ -132,49 +114,84 @@ public final class MethodWriter extends GeneratorAdapter {
visitVarInsn(Opcodes.ILOAD, slot);
push(0);
ifICmp(GeneratorAdapter.GT, end);
throwException(PAINLESS_ERROR_TYPE,
"The maximum number of statements that can be executed in a loop has been reached.");
throwException(PAINLESS_ERROR_TYPE, "The maximum number of statements that can be executed in a loop has been reached.");
mark(end);
}
}
public void writeCast(final Cast cast) {
if (cast instanceof Transform) {
final Transform transform = (Transform)cast;
if (transform.upcast != null) {
checkCast(transform.upcast.type);
}
if (java.lang.reflect.Modifier.isStatic(transform.method.reflect.getModifiers())) {
invokeStatic(transform.method.owner.type, transform.method.method);
} else if (java.lang.reflect.Modifier.isInterface(transform.method.owner.clazz.getModifiers())) {
invokeInterface(transform.method.owner.type, transform.method.method);
} else {
invokeVirtual(transform.method.owner.type, transform.method.method);
}
if (transform.downcast != null) {
checkCast(transform.downcast.type);
}
} else if (cast != null) {
if (cast != null) {
final Type from = cast.from;
final Type to = cast.to;
if (from.equals(to)) {
return;
}
if (from.sort.numeric && from.sort.primitive && to.sort.numeric && to.sort.primitive) {
cast(from.type, to.type);
} else {
if (!to.clazz.isAssignableFrom(from.clazz)) {
checkCast(to.type);
if (from.sort == Sort.CHAR && to.sort == Sort.STRING) {
invokeStatic(UTILITY_TYPE, CHAR_TO_STRING);
} else if (from.sort == Sort.STRING && to.sort == Sort.CHAR) {
invokeStatic(UTILITY_TYPE, STRING_TO_CHAR);
} else if (cast.unboxFrom) {
if (from.sort == Sort.DEF) {
if (cast.explicit) {
if (to.sort == Sort.BOOL) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN);
else if (to.sort == Sort.BYTE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT);
else if (to.sort == Sort.SHORT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT);
else if (to.sort == Sort.CHAR) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT);
else if (to.sort == Sort.INT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT);
else if (to.sort == Sort.LONG) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT);
else if (to.sort == Sort.FLOAT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT);
else if (to.sort == Sort.DOUBLE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT);
else throw new IllegalStateException("Illegal tree structure.");
} else {
if (to.sort == Sort.BOOL) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN);
else if (to.sort == Sort.BYTE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT);
else if (to.sort == Sort.SHORT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT);
else if (to.sort == Sort.CHAR) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT);
else if (to.sort == Sort.INT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT);
else if (to.sort == Sort.LONG) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT);
else if (to.sort == Sort.FLOAT) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT);
else if (to.sort == Sort.DOUBLE) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT);
else throw new IllegalStateException("Illegal tree structure.");
}
} else {
unbox(from.type);
writeCast(from, to);
}
} else if (cast.unboxTo) {
writeCast(from, to);
unbox(to.type);
} else if (cast.boxFrom) {
box(from.type);
writeCast(from, to);
} else if (cast.boxTo) {
writeCast(from, to);
box(to.type);
} else {
writeCast(from, to);
}
}
}
private void writeCast(final Type from, final Type to) {
if (from.equals(to)) {
return;
}
if (from.sort.numeric && from.sort.primitive && to.sort.numeric && to.sort.primitive) {
cast(from.type, to.type);
} else {
if (!to.clazz.isAssignableFrom(from.clazz)) {
checkCast(to.type);
}
}
}
/**
* Proxy the box method to use valueOf instead to ensure that the modern boxing methods are used.
*/
@Override
public void box(org.objectweb.asm.Type type) {
valueOf(type);
}
public void writeBranch(final Label tru, final Label fals) {
if (tru != null) {
visitJumpInsn(Opcodes.IFNE, tru);
@ -236,231 +253,51 @@ public final class MethodWriter extends GeneratorAdapter {
}
}
public void writeBinaryInstruction(final CompilerSettings settings, final Definition definition,
final String location,
final Type type, final Operation operation) {
public void writeBinaryInstruction(final String location, final Type type, final Operation operation) {
final Sort sort = type.sort;
boolean exact = !settings.getNumericOverflow() &&
((sort == Sort.INT || sort == Sort.LONG) &&
(operation == Operation.MUL || operation == Operation.DIV ||
operation == Operation.ADD || operation == Operation.SUB) ||
(sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.MUL || operation == Operation.DIV || operation == Operation.REM ||
operation == Operation.ADD || operation == Operation.SUB));
if (exact) {
switch (sort) {
case INT:
switch (operation) {
case MUL: invokeStatic(definition.mathType.type, MULEXACT_INT); break;
case DIV: invokeStatic(definition.utilityType.type, DIVWOOVERLOW_INT); break;
case ADD: invokeStatic(definition.mathType.type, ADDEXACT_INT); break;
case SUB: invokeStatic(definition.mathType.type, SUBEXACT_INT); break;
}
if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.LSH || operation == Operation.USH ||
operation == Operation.RSH || operation == Operation.BWAND ||
operation == Operation.XOR || operation == Operation.BWOR)) {
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
break;
case LONG:
switch (operation) {
case MUL: invokeStatic(definition.mathType.type, MULEXACT_LONG); break;
case DIV: invokeStatic(definition.utilityType.type, DIVWOOVERLOW_LONG); break;
case ADD: invokeStatic(definition.mathType.type, ADDEXACT_LONG); break;
case SUB: invokeStatic(definition.mathType.type, SUBEXACT_LONG); break;
}
break;
case FLOAT:
switch (operation) {
case MUL: invokeStatic(definition.utilityType.type, MULWOOVERLOW_FLOAT); break;
case DIV: invokeStatic(definition.utilityType.type, DIVWOOVERLOW_FLOAT); break;
case REM: invokeStatic(definition.utilityType.type, REMWOOVERLOW_FLOAT); break;
case ADD: invokeStatic(definition.utilityType.type, ADDWOOVERLOW_FLOAT); break;
case SUB: invokeStatic(definition.utilityType.type, SUBWOOVERLOW_FLOAT); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
break;
case DOUBLE:
switch (operation) {
case MUL: invokeStatic(definition.utilityType.type, MULWOOVERLOW_DOUBLE); break;
case DIV: invokeStatic(definition.utilityType.type, DIVWOOVERLOW_DOUBLE); break;
case REM: invokeStatic(definition.utilityType.type, REMWOOVERLOW_DOUBLE); break;
case ADD: invokeStatic(definition.utilityType.type, ADDWOOVERLOW_DOUBLE); break;
case SUB: invokeStatic(definition.utilityType.type, SUBWOOVERLOW_DOUBLE); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
break;
if (sort == Sort.DEF) {
switch (operation) {
case MUL: invokeStatic(DEF_UTIL_TYPE, DEF_MUL_CALL); break;
case DIV: invokeStatic(DEF_UTIL_TYPE, DEF_DIV_CALL); break;
case REM: invokeStatic(DEF_UTIL_TYPE, DEF_REM_CALL); break;
case ADD: invokeStatic(DEF_UTIL_TYPE, DEF_ADD_CALL); break;
case SUB: invokeStatic(DEF_UTIL_TYPE, DEF_SUB_CALL); break;
case LSH: invokeStatic(DEF_UTIL_TYPE, DEF_LSH_CALL); break;
case USH: invokeStatic(DEF_UTIL_TYPE, DEF_RSH_CALL); break;
case RSH: invokeStatic(DEF_UTIL_TYPE, DEF_USH_CALL); break;
case BWAND: invokeStatic(DEF_UTIL_TYPE, DEF_AND_CALL); break;
case XOR: invokeStatic(DEF_UTIL_TYPE, DEF_XOR_CALL); break;
case BWOR: invokeStatic(DEF_UTIL_TYPE, DEF_OR_CALL); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
} else {
if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.LSH || operation == Operation.USH ||
operation == Operation.RSH || operation == Operation.BWAND ||
operation == Operation.XOR || operation == Operation.BWOR)) {
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
if (sort == Sort.DEF) {
switch (operation) {
case MUL: invokeStatic(definition.defobjType.type, DEF_MUL_CALL); break;
case DIV: invokeStatic(definition.defobjType.type, DEF_DIV_CALL); break;
case REM: invokeStatic(definition.defobjType.type, DEF_REM_CALL); break;
case ADD: invokeStatic(definition.defobjType.type, DEF_ADD_CALL); break;
case SUB: invokeStatic(definition.defobjType.type, DEF_SUB_CALL); break;
case LSH: invokeStatic(definition.defobjType.type, DEF_LSH_CALL); break;
case USH: invokeStatic(definition.defobjType.type, DEF_RSH_CALL); break;
case RSH: invokeStatic(definition.defobjType.type, DEF_USH_CALL); break;
case BWAND: invokeStatic(definition.defobjType.type, DEF_AND_CALL); break;
case XOR: invokeStatic(definition.defobjType.type, DEF_XOR_CALL); break;
case BWOR: invokeStatic(definition.defobjType.type, DEF_OR_CALL); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
} else {
switch (operation) {
case MUL: math(GeneratorAdapter.MUL, type.type); break;
case DIV: math(GeneratorAdapter.DIV, type.type); break;
case REM: math(GeneratorAdapter.REM, type.type); break;
case ADD: math(GeneratorAdapter.ADD, type.type); break;
case SUB: math(GeneratorAdapter.SUB, type.type); break;
case LSH: math(GeneratorAdapter.SHL, type.type); break;
case USH: math(GeneratorAdapter.USHR, type.type); break;
case RSH: math(GeneratorAdapter.SHR, type.type); break;
case BWAND: math(GeneratorAdapter.AND, type.type); break;
case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
switch (operation) {
case MUL: math(GeneratorAdapter.MUL, type.type); break;
case DIV: math(GeneratorAdapter.DIV, type.type); break;
case REM: math(GeneratorAdapter.REM, type.type); break;
case ADD: math(GeneratorAdapter.ADD, type.type); break;
case SUB: math(GeneratorAdapter.SUB, type.type); break;
case LSH: math(GeneratorAdapter.SHL, type.type); break;
case USH: math(GeneratorAdapter.USHR, type.type); break;
case RSH: math(GeneratorAdapter.SHR, type.type); break;
case BWAND: math(GeneratorAdapter.AND, type.type); break;
case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
}
}
/**
* Called for any compound assignment (including increment/decrement instructions).
* We have to be stricter than writeBinary and do overflow checks against the original type's size
* instead of the promoted type's size, since the result will be implicitly cast back.
*
* @return This will be true if an instruction is written, false otherwise.
*/
public boolean writeExactInstruction(
final Definition definition, final Sort fsort, final Sort tsort) {
if (fsort == Sort.DOUBLE) {
if (tsort == Sort.FLOAT) {
invokeStatic(definition.utilityType.type, TOFLOATWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.FLOAT_OBJ) {
invokeStatic(definition.utilityType.type, TOFLOATWOOVERFLOW_DOUBLE);
checkCast(definition.floatobjType.type);
} else if (tsort == Sort.LONG) {
invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.LONG_OBJ) {
invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_DOUBLE);
checkCast(definition.longobjType.type);
} else if (tsort == Sort.INT) {
invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.INT_OBJ) {
invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_DOUBLE);
checkCast(definition.intobjType.type);
} else if (tsort == Sort.CHAR) {
invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_DOUBLE);
checkCast(definition.charobjType.type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_DOUBLE);
checkCast(definition.shortobjType.type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_DOUBLE);
checkCast(definition.byteobjType.type);
} else {
return false;
}
} else if (fsort == Sort.FLOAT) {
if (tsort == Sort.LONG) {
invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_FLOAT);
} else if (tsort == Sort.LONG_OBJ) {
invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_FLOAT);
checkCast(definition.longobjType.type);
} else if (tsort == Sort.INT) {
invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_FLOAT);
} else if (tsort == Sort.INT_OBJ) {
invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_FLOAT);
checkCast(definition.intobjType.type);
} else if (tsort == Sort.CHAR) {
invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_FLOAT);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_FLOAT);
checkCast(definition.charobjType.type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_FLOAT);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_FLOAT);
checkCast(definition.shortobjType.type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_FLOAT);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_FLOAT);
checkCast(definition.byteobjType.type);
} else {
return false;
}
} else if (fsort == Sort.LONG) {
if (tsort == Sort.INT) {
invokeStatic(definition.mathType.type, TOINTEXACT_LONG);
} else if (tsort == Sort.INT_OBJ) {
invokeStatic(definition.mathType.type, TOINTEXACT_LONG);
checkCast(definition.intobjType.type);
} else if (tsort == Sort.CHAR) {
invokeStatic(definition.utilityType.type, TOCHAREXACT_LONG);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.utilityType.type, TOCHAREXACT_LONG);
checkCast(definition.charobjType.type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.utilityType.type, TOSHORTEXACT_LONG);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.utilityType.type, TOSHORTEXACT_LONG);
checkCast(definition.shortobjType.type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.utilityType.type, TOBYTEEXACT_LONG);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.utilityType.type, TOBYTEEXACT_LONG);
checkCast(definition.byteobjType.type);
} else {
return false;
}
} else if (fsort == Sort.INT) {
if (tsort == Sort.CHAR) {
invokeStatic(definition.utilityType.type, TOCHAREXACT_INT);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.utilityType.type, TOCHAREXACT_INT);
checkCast(definition.charobjType.type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.utilityType.type, TOSHORTEXACT_INT);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.utilityType.type, TOSHORTEXACT_INT);
checkCast(definition.shortobjType.type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.utilityType.type, TOBYTEEXACT_INT);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.utilityType.type, TOBYTEEXACT_INT);
checkCast(definition.byteobjType.type);
} else {
return false;
}
} else {
return false;
}
return true;
}
public void writeDup(final int size, final int xsize) {
if (size == 1) {
if (xsize == 2) {

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptEngineRegistry;
import org.elasticsearch.script.ScriptMode;
@ -29,6 +30,11 @@ import org.elasticsearch.script.ScriptModule;
*/
public final class PainlessPlugin extends Plugin {
// force to pare our definition at startup (not on the user's first script)
static {
Definition.VOID_TYPE.hashCode();
}
@Override
public String name() {
return "lang-painless";

View File

@ -38,9 +38,7 @@ import java.security.AccessController;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -117,13 +115,7 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
// Use custom settings specified by params.
compilerSettings = new CompilerSettings();
Map<String, String> copy = new HashMap<>(params);
String value = copy.remove(CompilerSettings.NUMERIC_OVERFLOW);
if (value != null) {
compilerSettings.setNumericOverflow(Boolean.parseBoolean(value));
}
value = copy.remove(CompilerSettings.MAX_LOOP_COUNTER);
String value = copy.remove(CompilerSettings.MAX_LOOP_COUNTER);
if (value != null) {
compilerSettings.setMaxLoopCounter(Integer.parseInt(value));
@ -212,7 +204,7 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
* Action taken when the engine is closed.
*/
@Override
public void close() throws IOException {
public void close() {
// Nothing to do.
}
}

View File

@ -25,442 +25,10 @@ package org.elasticsearch.painless;
*/
public class Utility {
public static boolean NumberToboolean(final Number value) {
return value.longValue() != 0;
}
public static char NumberTochar(final Number value) {
return (char)value.intValue();
}
public static Boolean NumberToBoolean(final Number value) {
return value.longValue() != 0;
}
public static Byte NumberToByte(final Number value) {
return value == null ? null : value.byteValue();
}
public static Short NumberToShort(final Number value) {
return value == null ? null : value.shortValue();
}
public static Character NumberToCharacter(final Number value) {
return value == null ? null : (char)value.intValue();
}
public static Integer NumberToInteger(final Number value) {
return value == null ? null : value.intValue();
}
public static Long NumberToLong(final Number value) {
return value == null ? null : value.longValue();
}
public static Float NumberToFloat(final Number value) {
return value == null ? null : value.floatValue();
}
public static Double NumberToDouble(final Number value) {
return value == null ? null : value.doubleValue();
}
public static byte booleanTobyte(final boolean value) {
return (byte)(value ? 1 : 0);
}
public static short booleanToshort(final boolean value) {
return (short)(value ? 1 : 0);
}
public static char booleanTochar(final boolean value) {
return (char)(value ? 1 : 0);
}
public static int booleanToint(final boolean value) {
return value ? 1 : 0;
}
public static long booleanTolong(final boolean value) {
return value ? 1 : 0;
}
public static float booleanTofloat(final boolean value) {
return value ? 1 : 0;
}
public static double booleanTodouble(final boolean value) {
return value ? 1 : 0;
}
public static Integer booleanToInteger(final boolean value) {
return value ? 1 : 0;
}
public static byte BooleanTobyte(final Boolean value) {
return (byte)(value ? 1 : 0);
}
public static short BooleanToshort(final Boolean value) {
return (short)(value ? 1 : 0);
}
public static char BooleanTochar(final Boolean value) {
return (char)(value ? 1 : 0);
}
public static int BooleanToint(final Boolean value) {
return value ? 1 : 0;
}
public static long BooleanTolong(final Boolean value) {
return value ? 1 : 0;
}
public static float BooleanTofloat(final Boolean value) {
return value ? 1 : 0;
}
public static double BooleanTodouble(final Boolean value) {
return value ? 1 : 0;
}
public static Byte BooleanToByte(final Boolean value) {
return value == null ? null : (byte)(value ? 1 : 0);
}
public static Short BooleanToShort(final Boolean value) {
return value == null ? null : (short)(value ? 1 : 0);
}
public static Character BooleanToCharacter(final Boolean value) {
return value == null ? null : (char)(value ? 1 : 0);
}
public static Integer BooleanToInteger(final Boolean value) {
return value == null ? null : value ? 1 : 0;
}
public static Long BooleanToLong(final Boolean value) {
return value == null ? null : value ? 1L : 0L;
}
public static Float BooleanToFloat(final Boolean value) {
return value == null ? null : value ? 1F : 0F;
}
public static Double BooleanToDouble(final Boolean value) {
return value == null ? null : value ? 1D : 0D;
}
public static boolean byteToboolean(final byte value) {
return value != 0;
}
public static Short byteToShort(final byte value) {
return (short)value;
}
public static Character byteToCharacter(final byte value) {
return (char)value;
}
public static Integer byteToInteger(final byte value) {
return (int)value;
}
public static Long byteToLong(final byte value) {
return (long)value;
}
public static Float byteToFloat(final byte value) {
return (float)value;
}
public static Double byteToDouble(final byte value) {
return (double)value;
}
public static boolean ByteToboolean(final Byte value) {
return value != 0;
}
public static char ByteTochar(final Byte value) {
return (char)value.byteValue();
}
public static boolean shortToboolean(final short value) {
return value != 0;
}
public static Byte shortToByte(final short value) {
return (byte)value;
}
public static Character shortToCharacter(final short value) {
return (char)value;
}
public static Integer shortToInteger(final short value) {
return (int)value;
}
public static Long shortToLong(final short value) {
return (long)value;
}
public static Float shortToFloat(final short value) {
return (float)value;
}
public static Double shortToDouble(final short value) {
return (double)value;
}
public static boolean ShortToboolean(final Short value) {
return value != 0;
}
public static char ShortTochar(final Short value) {
return (char)value.shortValue();
}
public static boolean charToboolean(final char value) {
return value != 0;
}
public static Byte charToByte(final char value) {
return (byte)value;
}
public static Short charToShort(final char value) {
return (short)value;
}
public static Integer charToInteger(final char value) {
return (int)value;
}
public static Long charToLong(final char value) {
return (long)value;
}
public static Float charToFloat(final char value) {
return (float)value;
}
public static Double charToDouble(final char value) {
return (double)value;
}
public static String charToString(final char value) {
return String.valueOf(value);
}
public static boolean CharacterToboolean(final Character value) {
return value != 0;
}
public static byte CharacterTobyte(final Character value) {
return (byte)value.charValue();
}
public static short CharacterToshort(final Character value) {
return (short)value.charValue();
}
public static int CharacterToint(final Character value) {
return value;
}
public static long CharacterTolong(final Character value) {
return value;
}
public static float CharacterTofloat(final Character value) {
return value;
}
public static double CharacterTodouble(final Character value) {
return value;
}
public static Boolean CharacterToBoolean(final Character value) {
return value == null ? null : value != 0;
}
public static Byte CharacterToByte(final Character value) {
return value == null ? null : (byte)value.charValue();
}
public static Short CharacterToShort(final Character value) {
return value == null ? null : (short)value.charValue();
}
public static Integer CharacterToInteger(final Character value) {
return value == null ? null : (int)value;
}
public static Long CharacterToLong(final Character value) {
return value == null ? null : (long)value;
}
public static Float CharacterToFloat(final Character value) {
return value == null ? null : (float)value;
}
public static Double CharacterToDouble(final Character value) {
return value == null ? null : (double)value;
}
public static String CharacterToString(final Character value) {
return value == null ? null : value.toString();
}
public static boolean intToboolean(final int value) {
return value != 0;
}
public static Byte intToByte(final int value) {
return (byte)value;
}
public static Short intToShort(final int value) {
return (short)value;
}
public static Character intToCharacter(final int value) {
return (char)value;
}
public static Long intToLong(final int value) {
return (long)value;
}
public static Float intToFloat(final int value) {
return (float)value;
}
public static Double intToDouble(final int value) {
return (double)value;
}
public static boolean IntegerToboolean(final Integer value) {
return value != 0;
}
public static char IntegerTochar(final Integer value) {
return (char)value.intValue();
}
public static boolean longToboolean(final long value) {
return value != 0;
}
public static Byte longToByte(final long value) {
return (byte)value;
}
public static Short longToShort(final long value) {
return (short)value;
}
public static Character longToCharacter(final long value) {
return (char)value;
}
public static Integer longToInteger(final long value) {
return (int)value;
}
public static Float longToFloat(final long value) {
return (float)value;
}
public static Double longToDouble(final long value) {
return (double)value;
}
public static boolean LongToboolean(final Long value) {
return value != 0;
}
public static char LongTochar(final Long value) {
return (char)value.longValue();
}
public static boolean floatToboolean(final float value) {
return value != 0;
}
public static Byte floatToByte(final float value) {
return (byte)value;
}
public static Short floatToShort(final float value) {
return (short)value;
}
public static Character floatToCharacter(final float value) {
return (char)value;
}
public static Integer floatToInteger(final float value) {
return (int)value;
}
public static Long floatToLong(final float value) {
return (long)value;
}
public static Double floatToDouble(final float value) {
return (double)value;
}
public static boolean FloatToboolean(final Float value) {
return value != 0;
}
public static char FloatTochar(final Float value) {
return (char)value.floatValue();
}
public static boolean doubleToboolean(final double value) {
return value != 0;
}
public static Byte doubleToByte(final double value) {
return (byte)value;
}
public static Short doubleToShort(final double value) {
return (short)value;
}
public static Character doubleToCharacter(final double value) {
return (char)value;
}
public static Integer doubleToInteger(final double value) {
return (int)value;
}
public static Long doubleToLong(final double value) {
return (long)value;
}
public static Float doubleToFloat(final double value) {
return (float)value;
}
public static boolean DoubleToboolean(final Double value) {
return value != 0;
}
public static char DoubleTochar(final Double value) {
return (char)value.doubleValue();
}
public static char StringTochar(final String value) {
if (value.length() != 1) {
throw new ClassCastException("Cannot cast [String] with length greater than one to [char].");
@ -469,359 +37,6 @@ public class Utility {
return value.charAt(0);
}
public static Character StringToCharacter(final String value) {
if (value == null) {
return null;
}
if (value.length() != 1) {
throw new ClassCastException("Cannot cast [String] with length greater than one to [Character].");
}
return value.charAt(0);
}
// although divide by zero is guaranteed, the special overflow case is not caught.
// its not needed for remainder because it is not possible there.
// see https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17.2
/**
* Integer divide without overflow
* @throws ArithmeticException on overflow or divide-by-zero
*/
public static int divideWithoutOverflow(int x, int y) {
if (x == Integer.MIN_VALUE && y == -1) {
throw new ArithmeticException("integer overflow");
}
return x / y;
}
/**
* Long divide without overflow
* @throws ArithmeticException on overflow or divide-by-zero
*/
public static long divideWithoutOverflow(long x, long y) {
if (x == Long.MIN_VALUE && y == -1L) {
throw new ArithmeticException("long overflow");
}
return x / y;
}
// byte, short, and char are promoted to int for normal operations,
// so the JDK exact methods are typically used, and the result has a wider range.
// but compound assignments and increment/decrement operators (e.g. byte b = Byte.MAX_VALUE; b++;)
// implicitly cast back to the original type: so these need to be checked against the original range.
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteExact(int value) {
byte s = (byte) value;
if (s != value) {
throw new ArithmeticException("byte overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteExact(long value) {
byte s = (byte) value;
if (s != value) {
throw new ArithmeticException("byte overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteWithoutOverflow(float value) {
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
throw new ArithmeticException("byte overflow");
}
return (byte)value;
}
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteWithoutOverflow(double value) {
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
throw new ArithmeticException("byte overflow");
}
return (byte)value;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortExact(int value) {
short s = (short) value;
if (s != value) {
throw new ArithmeticException("short overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortExact(long value) {
short s = (short) value;
if (s != value) {
throw new ArithmeticException("short overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortWithoutOverflow(float value) {
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
throw new ArithmeticException("short overflow");
}
return (short)value;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortExact(double value) {
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
throw new ArithmeticException("short overflow");
}
return (short)value;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharExact(int value) {
char s = (char) value;
if (s != value) {
throw new ArithmeticException("char overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharExact(long value) {
char s = (char) value;
if (s != value) {
throw new ArithmeticException("char overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharWithoutOverflow(float value) {
if (value < Character.MIN_VALUE || value > Character.MAX_VALUE) {
throw new ArithmeticException("char overflow");
}
return (char)value;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharWithoutOverflow(double value) {
if (value < Character.MIN_VALUE || value > Character.MAX_VALUE) {
throw new ArithmeticException("char overflow");
}
return (char)value;
}
/**
* Like {@link Math#toIntExact(long)} but for int range.
*/
public static int toIntWithoutOverflow(float value) {
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new ArithmeticException("int overflow");
}
return (int)value;
}
/**
* Like {@link Math#toIntExact(long)} but for int range.
*/
public static int toIntWithoutOverflow(double value) {
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new ArithmeticException("int overflow");
}
return (int)value;
}
/**
* Like {@link Math#toIntExact(long)} but for long range.
*/
public static long toLongWithoutOverflow(float value) {
if (value < Long.MIN_VALUE || value > Long.MAX_VALUE) {
throw new ArithmeticException("long overflow");
}
return (long)value;
}
/**
* Like {@link Math#toIntExact(long)} but for long range.
*/
public static float toLongWithoutOverflow(double value) {
if (value < Long.MIN_VALUE || value > Long.MAX_VALUE) {
throw new ArithmeticException("long overflow");
}
return (long)value;
}
/**
* Like {@link Math#toIntExact(long)} but for float range.
*/
public static float toFloatWithoutOverflow(double value) {
if (value < Float.MIN_VALUE || value > Float.MAX_VALUE) {
throw new ArithmeticException("float overflow");
}
return (float)value;
}
/**
* Checks for overflow, result is infinite but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static float checkInfFloat(float x, float y, float z) {
if (Float.isInfinite(z)) {
if (Float.isFinite(x) && Float.isFinite(y)) {
throw new ArithmeticException("float overflow");
}
}
return z;
}
/**
* Checks for NaN, result is NaN but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static float checkNaNFloat(float x, float y, float z) {
if (Float.isNaN(z)) {
if (Float.isFinite(x) && Float.isFinite(y)) {
throw new ArithmeticException("NaN");
}
}
return z;
}
/**
* Checks for NaN, result is infinite but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static double checkInfDouble(double x, double y, double z) {
if (Double.isInfinite(z)) {
if (Double.isFinite(x) && Double.isFinite(y)) {
throw new ArithmeticException("double overflow");
}
}
return z;
}
/**
* Checks for NaN, result is NaN but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static double checkNaNDouble(double x, double y, double z) {
if (Double.isNaN(z)) {
if (Double.isFinite(x) && Double.isFinite(y)) {
throw new ArithmeticException("NaN");
}
}
return z;
}
/**
* Adds two floats but throws {@code ArithmeticException}
* if the result overflows.
*/
public static float addWithoutOverflow(float x, float y) {
return checkInfFloat(x, y, x + y);
}
/**
* Adds two doubles but throws {@code ArithmeticException}
* if the result overflows.
*/
public static double addWithoutOverflow(double x, double y) {
return checkInfDouble(x, y, x + y);
}
/**
* Subtracts two floats but throws {@code ArithmeticException}
* if the result overflows.
*/
public static float subtractWithoutOverflow(float x, float y) {
return checkInfFloat(x, y, x - y);
}
/**
* Subtracts two doubles but throws {@code ArithmeticException}
* if the result overflows.
*/
public static double subtractWithoutOverflow(double x, double y) {
return checkInfDouble(x, y , x - y);
}
/**
* Multiplies two floats but throws {@code ArithmeticException}
* if the result overflows.
*/
public static float multiplyWithoutOverflow(float x, float y) {
return checkInfFloat(x, y, x * y);
}
/**
* Multiplies two doubles but throws {@code ArithmeticException}
* if the result overflows.
*/
public static double multiplyWithoutOverflow(double x, double y) {
return checkInfDouble(x, y, x * y);
}
/**
* Divides two floats but throws {@code ArithmeticException}
* if the result overflows, or would create NaN from finite
* inputs ({@code x == 0, y == 0})
*/
public static float divideWithoutOverflow(float x, float y) {
return checkNaNFloat(x, y, checkInfFloat(x, y, x / y));
}
/**
* Divides two doubles but throws {@code ArithmeticException}
* if the result overflows, or would create NaN from finite
* inputs ({@code x == 0, y == 0})
*/
public static double divideWithoutOverflow(double x, double y) {
return checkNaNDouble(x, y, checkInfDouble(x, y, x / y));
}
/**
* Takes remainder two floats but throws {@code ArithmeticException}
* if the result would create NaN from finite inputs ({@code y == 0})
*/
public static float remainderWithoutOverflow(float x, float y) {
return checkNaNFloat(x, y, x % y);
}
/**
* Divides two doubles but throws {@code ArithmeticException}
* if the result would create NaN from finite inputs ({@code y == 0})
*/
public static double remainderWithoutOverflow(double x, double y) {
return checkNaNDouble(x, y, x % y);
}
public static boolean checkEquals(final Object left, final Object right) {
if (left != null) {
return left.equals(right);

View File

@ -86,14 +86,12 @@ public final class Variables {
}
}
private final Definition definition;
final Reserved reserved;
private final Deque<Integer> scopes = new ArrayDeque<>();
private final Deque<Variable> variables = new ArrayDeque<>();
public Variables(final CompilerSettings settings, final Definition definition, final Reserved reserved) {
this.definition = definition;
public Variables(final CompilerSettings settings, final Reserved reserved) {
this.reserved = reserved;
incrementScope();
@ -101,35 +99,35 @@ public final class Variables {
// Method variables.
// This reference. Internal use only.
addVariable("[" + Reserved.THIS + "]" , definition.execType.name, Reserved.THIS , true, true);
addVariable("[" + Reserved.THIS + "]" , "Executable", Reserved.THIS , true, true);
// Input map of variables passed to the script. TODO: Rename to 'params' since that will be its use.
addVariable("[" + Reserved.PARAMS + "]", definition.smapType.name, Reserved.PARAMS, true, true);
addVariable("[" + Reserved.PARAMS + "]", "Map", Reserved.PARAMS, true, true);
// Scorer parameter passed to the script. Internal use only.
addVariable("[" + Reserved.SCORER + "]", definition.defType.name , Reserved.SCORER, true, true);
addVariable("[" + Reserved.SCORER + "]", "def", Reserved.SCORER, true, true);
// Doc parameter passed to the script. TODO: Currently working as a Map<String,Def>, we can do better?
addVariable("[" + Reserved.DOC + "]" , definition.smapType.name, Reserved.DOC , true, true);
// Doc parameter passed to the script. TODO: Currently working as a Map, we can do better?
addVariable("[" + Reserved.DOC + "]" , "Map", Reserved.DOC , true, true);
// Aggregation _value parameter passed to the script.
addVariable("[" + Reserved.VALUE + "]" , definition.defType.name , Reserved.VALUE , true, true);
addVariable("[" + Reserved.VALUE + "]" , "def", Reserved.VALUE , true, true);
// Shortcut variables.
// Document's score as a read-only double.
if (reserved.score) {
addVariable("[" + Reserved.SCORE + "]", definition.doubleType.name, Reserved.SCORE, true, true);
addVariable("[" + Reserved.SCORE + "]", "double", Reserved.SCORE, true, true);
}
// The ctx map set by executable scripts as a read-only map.
if (reserved.ctx) {
addVariable("[" + Reserved.CTX + "]", definition.smapType.name, Reserved.CTX, true, true);
addVariable("[" + Reserved.CTX + "]", "Map", Reserved.CTX, true, true);
}
// Loop counter to catch infinite loops. Internal use only.
if (reserved.loop && settings.getMaxLoopCounter() > 0) {
addVariable("[" + Reserved.LOOP + "]", definition.intType.name, Reserved.LOOP, true, true);
addVariable("[" + Reserved.LOOP + "]", "int", Reserved.LOOP, true, true);
}
}
@ -182,7 +180,7 @@ public final class Variables {
final Type type;
try {
type = definition.getType(typestr);
type = Definition.getType(typestr);
} catch (final IllegalArgumentException exception) {
throw new IllegalArgumentException("Error " + location + ": Not a type [" + typestr + "].");
}
@ -190,7 +188,7 @@ public final class Variables {
boolean legal = !name.contains("<");
try {
definition.getType(name);
Definition.getType(name);
legal = false;
} catch (final IllegalArgumentException exception) {
// Do nothing.

View File

@ -38,15 +38,14 @@ import static org.elasticsearch.painless.WriterConstants.MAP_TYPE;
*/
final class Writer {
static byte[] write(final CompilerSettings settings, final Definition definition,
static byte[] write(final CompilerSettings settings,
String name, final String source, final Variables variables, final SSource root) {
final Writer writer = new Writer(settings, definition, name, source, variables, root);
final Writer writer = new Writer(settings, name, source, variables, root);
return writer.getBytes();
}
private final CompilerSettings settings;
private final Definition definition;
private final String scriptName;
private final String source;
private final Variables variables;
@ -55,10 +54,9 @@ final class Writer {
private final ClassWriter writer;
private final MethodWriter adapter;
private Writer(final CompilerSettings settings, final Definition definition,
private Writer(final CompilerSettings settings,
String name, final String source, final Variables variables, final SSource root) {
this.settings = settings;
this.definition = definition;
this.scriptName = name;
this.source = source;
this.variables = variables;
@ -177,7 +175,7 @@ final class Writer {
adapter.visitVarInsn(Opcodes.ISTORE, loop.slot);
}
root.write(settings, definition, adapter);
root.write(adapter);
adapter.endMethod();
}

View File

@ -27,7 +27,6 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Map;
@ -56,6 +55,10 @@ public final class WriterConstants {
public final static Type MAP_TYPE = Type.getType(Map.class);
public final static Method MAP_GET = getAsmMethod(Object.class, "get", Object.class);
public final static Type UTILITY_TYPE = Type.getType(Utility.class);
public final static Method STRING_TO_CHAR = getAsmMethod(char.class, "StringTochar", String.class);
public final static Method CHAR_TO_STRING = getAsmMethod(String.class, "charToString", char.class);
/** dynamic callsite bootstrap signature */
public final static MethodType DEF_BOOTSTRAP_TYPE =
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class);
@ -63,19 +66,35 @@ public final class WriterConstants {
new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(DefBootstrap.class),
"bootstrap", DEF_BOOTSTRAP_TYPE.toMethodDescriptorString());
public final static Method DEF_NOT_CALL = getAsmMethod(Object.class, "not", Object.class);
public final static Method DEF_NEG_CALL = getAsmMethod(Object.class, "neg", Object.class);
public final static Method DEF_MUL_CALL = getAsmMethod(Object.class, "mul", Object.class, Object.class);
public final static Method DEF_DIV_CALL = getAsmMethod(Object.class, "div", Object.class, Object.class);
public final static Method DEF_REM_CALL = getAsmMethod(Object.class, "rem", Object.class, Object.class);
public final static Method DEF_ADD_CALL = getAsmMethod(Object.class, "add", Object.class, Object.class);
public final static Method DEF_SUB_CALL = getAsmMethod(Object.class, "sub", Object.class, Object.class);
public final static Method DEF_LSH_CALL = getAsmMethod(Object.class, "lsh", Object.class, int.class);
public final static Method DEF_RSH_CALL = getAsmMethod(Object.class, "rsh", Object.class, int.class);
public final static Method DEF_USH_CALL = getAsmMethod(Object.class, "ush", Object.class, int.class);
public final static Method DEF_AND_CALL = getAsmMethod(Object.class, "and", Object.class, Object.class);
public final static Method DEF_XOR_CALL = getAsmMethod(Object.class, "xor", Object.class, Object.class);
public final static Method DEF_OR_CALL = getAsmMethod(Object.class, "or" , Object.class, Object.class);
public final static Type DEF_UTIL_TYPE = Type.getType(Def.class);
public final static Method DEF_TO_BOOLEAN = getAsmMethod(boolean.class, "DefToboolean" , Object.class);
public final static Method DEF_TO_BYTE_IMPLICIT = getAsmMethod(byte.class , "DefTobyteImplicit" , Object.class);
public final static Method DEF_TO_SHORT_IMPLICIT = getAsmMethod(short.class , "DefToshortImplicit" , Object.class);
public final static Method DEF_TO_CHAR_IMPLICIT = getAsmMethod(char.class , "DefTocharImplicit" , Object.class);
public final static Method DEF_TO_INT_IMPLICIT = getAsmMethod(int.class , "DefTointImplicit" , Object.class);
public final static Method DEF_TO_LONG_IMPLICIT = getAsmMethod(long.class , "DefTolongImplicit" , Object.class);
public final static Method DEF_TO_FLOAT_IMPLICIT = getAsmMethod(float.class , "DefTofloatImplicit" , Object.class);
public final static Method DEF_TO_DOUBLE_IMPLICIT = getAsmMethod(double.class , "DefTodoubleImplicit", Object.class);
public final static Method DEF_TO_BYTE_EXPLICIT = getAsmMethod(byte.class , "DefTobyteExplicit" , Object.class);
public final static Method DEF_TO_SHORT_EXPLICIT = getAsmMethod(short.class , "DefToshortExplicit" , Object.class);
public final static Method DEF_TO_CHAR_EXPLICIT = getAsmMethod(char.class , "DefTocharExplicit" , Object.class);
public final static Method DEF_TO_INT_EXPLICIT = getAsmMethod(int.class , "DefTointExplicit" , Object.class);
public final static Method DEF_TO_LONG_EXPLICIT = getAsmMethod(long.class , "DefTolongExplicit" , Object.class);
public final static Method DEF_TO_FLOAT_EXPLICIT = getAsmMethod(float.class , "DefTofloatExplicit" , Object.class);
public final static Method DEF_TO_DOUBLE_EXPLICIT = getAsmMethod(double.class , "DefTodoubleExplicit", Object.class);
public final static Method DEF_NOT_CALL = getAsmMethod(Object.class , "not", Object.class);
public final static Method DEF_NEG_CALL = getAsmMethod(Object.class , "neg", Object.class);
public final static Method DEF_MUL_CALL = getAsmMethod(Object.class , "mul", Object.class, Object.class);
public final static Method DEF_DIV_CALL = getAsmMethod(Object.class , "div", Object.class, Object.class);
public final static Method DEF_REM_CALL = getAsmMethod(Object.class , "rem", Object.class, Object.class);
public final static Method DEF_ADD_CALL = getAsmMethod(Object.class , "add", Object.class, Object.class);
public final static Method DEF_SUB_CALL = getAsmMethod(Object.class , "sub", Object.class, Object.class);
public final static Method DEF_LSH_CALL = getAsmMethod(Object.class , "lsh", Object.class, int.class);
public final static Method DEF_RSH_CALL = getAsmMethod(Object.class , "rsh", Object.class, int.class);
public final static Method DEF_USH_CALL = getAsmMethod(Object.class , "ush", Object.class, int.class);
public final static Method DEF_AND_CALL = getAsmMethod(Object.class , "and", Object.class, Object.class);
public final static Method DEF_XOR_CALL = getAsmMethod(Object.class , "xor", Object.class, Object.class);
public final static Method DEF_OR_CALL = getAsmMethod(Object.class , "or" , Object.class, Object.class);
public final static Method DEF_EQ_CALL = getAsmMethod(boolean.class, "eq" , Object.class, Object.class);
public final static Method DEF_LT_CALL = getAsmMethod(boolean.class, "lt" , Object.class, Object.class);
public final static Method DEF_LTE_CALL = getAsmMethod(boolean.class, "lte", Object.class, Object.class);
@ -116,59 +135,7 @@ public final class WriterConstants {
public final static Method STRINGBUILDER_APPEND_OBJECT = getAsmMethod(StringBuilder.class, "append", Object.class);
public final static Method STRINGBUILDER_TOSTRING = getAsmMethod(String.class, "toString");
public final static Method TOINTEXACT_LONG = getAsmMethod(int.class, "toIntExact", long.class);
public final static Method NEGATEEXACT_INT = getAsmMethod(int.class, "negateExact", int.class);
public final static Method NEGATEEXACT_LONG = getAsmMethod(long.class, "negateExact", long.class);
public final static Method MULEXACT_INT = getAsmMethod(int.class, "multiplyExact", int.class, int.class);
public final static Method MULEXACT_LONG = getAsmMethod(long.class, "multiplyExact", long.class, long.class);
public final static Method ADDEXACT_INT = getAsmMethod(int.class, "addExact", int.class, int.class);
public final static Method ADDEXACT_LONG = getAsmMethod(long.class, "addExact", long.class, long.class);
public final static Method SUBEXACT_INT = getAsmMethod(int.class, "subtractExact", int.class, int.class);
public final static Method SUBEXACT_LONG = getAsmMethod(long.class, "subtractExact", long.class, long.class);
public final static Method CHECKEQUALS =
getAsmMethod(boolean.class, "checkEquals", Object.class, Object.class);
public final static Method TOBYTEEXACT_INT = getAsmMethod(byte.class, "toByteExact", int.class);
public final static Method TOBYTEEXACT_LONG = getAsmMethod(byte.class, "toByteExact", long.class);
public final static Method TOBYTEWOOVERFLOW_FLOAT = getAsmMethod(byte.class, "toByteWithoutOverflow", float.class);
public final static Method TOBYTEWOOVERFLOW_DOUBLE = getAsmMethod(byte.class, "toByteWithoutOverflow", double.class);
public final static Method TOSHORTEXACT_INT = getAsmMethod(short.class, "toShortExact", int.class);
public final static Method TOSHORTEXACT_LONG = getAsmMethod(short.class, "toShortExact", long.class);
public final static Method TOSHORTWOOVERFLOW_FLOAT = getAsmMethod(short.class, "toShortWithoutOverflow", float.class);
public final static Method TOSHORTWOOVERFLOW_DOUBLE = getAsmMethod(short.class, "toShortWihtoutOverflow", double.class);
public final static Method TOCHAREXACT_INT = getAsmMethod(char.class, "toCharExact", int.class);
public final static Method TOCHAREXACT_LONG = getAsmMethod(char.class, "toCharExact", long.class);
public final static Method TOCHARWOOVERFLOW_FLOAT = getAsmMethod(char.class, "toCharWithoutOverflow", float.class);
public final static Method TOCHARWOOVERFLOW_DOUBLE = getAsmMethod(char.class, "toCharWithoutOverflow", double.class);
public final static Method TOINTWOOVERFLOW_FLOAT = getAsmMethod(int.class, "toIntWithoutOverflow", float.class);
public final static Method TOINTWOOVERFLOW_DOUBLE = getAsmMethod(int.class, "toIntWithoutOverflow", double.class);
public final static Method TOLONGWOOVERFLOW_FLOAT = getAsmMethod(long.class, "toLongWithoutOverflow", float.class);
public final static Method TOLONGWOOVERFLOW_DOUBLE = getAsmMethod(long.class, "toLongWithoutOverflow", double.class);
public final static Method TOFLOATWOOVERFLOW_DOUBLE = getAsmMethod(float.class , "toFloatWihtoutOverflow", double.class);
public final static Method MULWOOVERLOW_FLOAT =
getAsmMethod(float.class, "multiplyWithoutOverflow", float.class, float.class);
public final static Method MULWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "multiplyWithoutOverflow", double.class, double.class);
public final static Method DIVWOOVERLOW_INT =
getAsmMethod(int.class, "divideWithoutOverflow", int.class, int.class);
public final static Method DIVWOOVERLOW_LONG =
getAsmMethod(long.class, "divideWithoutOverflow", long.class, long.class);
public final static Method DIVWOOVERLOW_FLOAT =
getAsmMethod(float.class, "divideWithoutOverflow", float.class, float.class);
public final static Method DIVWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "divideWithoutOverflow", double.class, double.class);
public final static Method REMWOOVERLOW_FLOAT =
getAsmMethod(float.class, "remainderWithoutOverflow", float.class, float.class);
public final static Method REMWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "remainderWithoutOverflow", double.class, double.class);
public final static Method ADDWOOVERLOW_FLOAT =
getAsmMethod(float.class, "addWithoutOverflow", float.class, float.class);
public final static Method ADDWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "addWithoutOverflow", double.class, double.class);
public final static Method SUBWOOVERLOW_FLOAT =
getAsmMethod(float.class, "subtractWithoutOverflow", float.class, float.class);
public final static Method SUBWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "subtractWithoutOverflow", double.class, double.class);
public final static Method CHECKEQUALS = getAsmMethod(boolean.class, "checkEquals", Object.class, Object.class);
private static Method getAsmMethod(final Class<?> rtype, final String name, final Class<?>... ptypes) {
return new Method(name, MethodType.methodType(rtype, ptypes).toMethodDescriptorString());

View File

@ -22,6 +22,7 @@ package org.elasticsearch.painless.antlr;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables.Reserved;
import org.elasticsearch.painless.antlr.PainlessParser.AfterthoughtContext;
@ -121,15 +122,17 @@ import java.util.List;
*/
public final class Walker extends PainlessParserBaseVisitor<ANode> {
public static SSource buildPainlessTree(final String source, final Reserved reserved) {
return new Walker(source, reserved).source;
public static SSource buildPainlessTree(String source, Reserved reserved, CompilerSettings settings) {
return new Walker(source, reserved, settings).source;
}
private final Reserved reserved;
private final SSource source;
private final CompilerSettings settings;
private Walker(final String source, final Reserved reserved) {
private Walker(String source, Reserved reserved, CompilerSettings settings) {
this.reserved = reserved;
this.settings = settings;
this.source = (SSource)visit(buildAntlrTree(source));
}
@ -181,7 +184,7 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
reserved.usesLoop();
return new SWhile(line(ctx), location(ctx), condition, block);
return new SWhile(line(ctx), location(ctx), condition, block, settings.getMaxLoopCounter());
}
@Override
@ -191,7 +194,7 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
reserved.usesLoop();
return new SDo(line(ctx), location(ctx), block, condition);
return new SDo(line(ctx), location(ctx), block, condition, settings.getMaxLoopCounter());
}
@Override
@ -203,7 +206,7 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
reserved.usesLoop();
return new SFor(line(ctx), location(ctx), intializer, condition, afterthought, block);
return new SFor(line(ctx), location(ctx), intializer, condition, afterthought, block, settings.getMaxLoopCounter());
}
@Override

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.AnalyzerCaster;
@ -67,6 +65,12 @@ public abstract class AExpression extends ANode {
*/
protected boolean explicit = false;
/**
* Set to true if a cast is allowed to boxed/unboxed. This is used
* for method arguments because casting may be required.
*/
protected boolean internal = false;
/**
* Set to the value of the constant this expression node represents if
* and only if the node represents a constant. If this is not null
@ -101,27 +105,27 @@ public abstract class AExpression extends ANode {
/**
* Checks for errors and collects data for the writing phase.
*/
abstract void analyze(final CompilerSettings settings, final Definition definition, final Variables variables);
abstract void analyze(Variables variables);
/**
* Writes ASM based on the data collected during the analysis phase.
*/
abstract void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter);
abstract void write(MethodWriter adapter);
/**
* Inserts {@link ECast} nodes into the tree for implicit casts. Also replaces
* nodes with the constant variable set to a non-null value with {@link EConstant}.
* @return The new child node for the parent node calling this method.
*/
AExpression cast(final CompilerSettings settings, final Definition definition, final Variables variables) {
final Cast cast = AnalyzerCaster.getLegalCast(definition, location, actual, expected, explicit);
AExpression cast(Variables variables) {
final Cast cast = AnalyzerCaster.getLegalCast(location, actual, expected, explicit, internal);
if (cast == null) {
if (constant == null || this instanceof EConstant) {
return this;
} else {
final EConstant econstant = new EConstant(line, location, constant);
econstant.analyze(settings, definition, variables);
econstant.analyze(variables);
if (!expected.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure."));
@ -142,7 +146,7 @@ public abstract class AExpression extends ANode {
constant = AnalyzerCaster.constCast(location, constant, cast);
final EConstant econstant = new EConstant(line, location, constant);
econstant.analyze(settings, definition, variables);
econstant.analyze(variables);
if (!expected.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure."));
@ -156,7 +160,7 @@ public abstract class AExpression extends ANode {
return ecast;
} else {
final EConstant econstant = new EConstant(line, location, constant);
econstant.analyze(settings, definition, variables);
econstant.analyze(variables);
if (!actual.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure."));

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -75,7 +73,7 @@ public abstract class ALink extends ANode {
*/
String string = null;
ALink(final int line, final String location, final int size) {
ALink(int line, String location, int size) {
super(line, location);
this.size = size;
@ -87,27 +85,27 @@ public abstract class ALink extends ANode {
* def or a shortcut is used. Otherwise, returns itself. This will be
* updated into the {@link EChain} node's list of links.
*/
abstract ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables);
abstract ALink analyze(Variables variables);
/**
* Write values before a load/store occurs such as an array index.
*/
abstract void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter);
abstract void write(MethodWriter adapter);
/**
* Write a load for the specific link type.
*/
abstract void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter);
abstract void load(MethodWriter adapter);
/**
* Write a store for the specific link type.
*/
abstract void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter);
abstract void store(MethodWriter adapter);
/**
* Used to copy link data from one to another during analysis in the case of replacement.
*/
final ALink copy(final ALink link) {
final ALink copy(ALink link) {
load = link.load;
store = link.store;
statik = link.statik;

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter;
@ -109,17 +107,17 @@ public abstract class AStatement extends ANode {
*/
Label brake = null;
AStatement(final int line, final String location) {
AStatement(int line, String location) {
super(line, location);
}
/**
* Checks for errors and collects data for the writing phase.
*/
abstract void analyze(final CompilerSettings settings, final Definition definition, final Variables variables);
abstract void analyze(Variables variables);
/**
* Writes ASM based on the data collected during the analysis phase.
*/
abstract void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter);
abstract void write(MethodWriter adapter);
}

View File

@ -20,7 +20,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type;
@ -39,7 +38,7 @@ public final class EBinary extends AExpression {
boolean cat = false;
public EBinary(final int line, final String location, final Operation operation, final AExpression left, final AExpression right) {
public EBinary(int line, String location, Operation operation, AExpression left, AExpression right) {
super(line, location);
this.operation = operation;
@ -48,39 +47,39 @@ public final class EBinary extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (operation == Operation.MUL) {
analyzeMul(settings, definition, variables);
analyzeMul(variables);
} else if (operation == Operation.DIV) {
analyzeDiv(settings, definition, variables);
analyzeDiv(variables);
} else if (operation == Operation.REM) {
analyzeRem(settings, definition, variables);
analyzeRem(variables);
} else if (operation == Operation.ADD) {
analyzeAdd(settings, definition, variables);
analyzeAdd(variables);
} else if (operation == Operation.SUB) {
analyzeSub(settings, definition, variables);
analyzeSub(variables);
} else if (operation == Operation.LSH) {
analyzeLSH(settings, definition, variables);
analyzeLSH(variables);
} else if (operation == Operation.RSH) {
analyzeRSH(settings, definition, variables);
analyzeRSH(variables);
} else if (operation == Operation.USH) {
analyzeUSH(settings, definition, variables);
analyzeUSH(variables);
} else if (operation == Operation.BWAND) {
analyzeBWAnd(settings, definition, variables);
analyzeBWAnd(variables);
} else if (operation == Operation.XOR) {
analyzeXor(settings, definition, variables);
analyzeXor(variables);
} else if (operation == Operation.BWOR) {
analyzeBWOr(settings, definition, variables);
analyzeBWOr(variables);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
}
private void analyzeMul(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeMul(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply multiply [*] to types " +
@ -90,25 +89,20 @@ public final class EBinary extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant * (int)right.constant :
Math.multiplyExact((int)left.constant, (int)right.constant);
constant = (int)left.constant * (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant * (long)right.constant :
Math.multiplyExact((long)left.constant, (long)right.constant);
constant = (long)left.constant * (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant * (float)right.constant :
org.elasticsearch.painless.Utility.multiplyWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant * (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant * (double)right.constant :
org.elasticsearch.painless.Utility.multiplyWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant * (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -117,11 +111,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeDiv(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeDiv(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply divide [/] to types " +
@ -131,25 +125,20 @@ public final class EBinary extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant / (int)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((int)left.constant, (int)right.constant);
constant = (int)left.constant / (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant / (long)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((long)left.constant, (long)right.constant);
constant = (long)left.constant / (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant / (float)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant / (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant / (double)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant / (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -158,11 +147,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeRem(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeRem(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply remainder [%] to types " +
@ -172,11 +161,10 @@ public final class EBinary extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
@ -184,11 +172,9 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant % (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant % (float)right.constant :
org.elasticsearch.painless.Utility.remainderWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant % (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant % (double)right.constant :
org.elasticsearch.painless.Utility.remainderWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant % (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -197,11 +183,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeAdd(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeAdd(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteAdd(definition, left.actual, right.actual);
final Type promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
if (promote == null) {
throw new ClassCastException(error("Cannot apply add [+] to types " +
@ -227,24 +213,18 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant + (int)right.constant :
Math.addExact((int)left.constant, (int)right.constant);
constant = (int)left.constant + (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant + (long)right.constant :
Math.addExact((long)left.constant, (long)right.constant);
constant = (long)left.constant + (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant + (float)right.constant :
org.elasticsearch.painless.Utility.addWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant + (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant + (double)right.constant :
org.elasticsearch.painless.Utility.addWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant + (double)right.constant;
} else if (sort == Sort.STRING) {
constant = "" + left.constant + right.constant;
} else {
@ -255,11 +235,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeSub(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeSub(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply subtract [-] to types " +
@ -269,25 +249,20 @@ public final class EBinary extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant - (int)right.constant :
Math.subtractExact((int)left.constant, (int)right.constant);
constant = (int)left.constant - (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant - (long)right.constant :
Math.subtractExact((long)left.constant, (long)right.constant);
constant = (long)left.constant - (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant - (float)right.constant :
org.elasticsearch.painless.Utility.subtractWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant - (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant - (double)right.constant :
org.elasticsearch.painless.Utility.subtractWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant - (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -296,11 +271,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeLSH(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeLSH(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, false, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
if (promote == null) {
throw new ClassCastException(error("Cannot apply left shift [<<] to types " +
@ -308,11 +283,11 @@ public final class EBinary extends AExpression {
}
left.expected = promote;
right.expected = definition.intType;
right.expected = Definition.INT_TYPE;
right.explicit = true;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -329,11 +304,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeRSH(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeRSH(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, false, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
if (promote == null) {
throw new ClassCastException(error("Cannot apply right shift [>>] to types " +
@ -341,11 +316,11 @@ public final class EBinary extends AExpression {
}
left.expected = promote;
right.expected = definition.intType;
right.expected = Definition.INT_TYPE;
right.explicit = true;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -362,11 +337,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeUSH(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeUSH(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, false, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
if (promote == null) {
throw new ClassCastException(error("Cannot apply unsigned shift [>>>] to types " +
@ -374,11 +349,11 @@ public final class EBinary extends AExpression {
}
left.expected = promote;
right.expected = definition.intType;
right.expected = Definition.INT_TYPE;
right.explicit = true;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -395,11 +370,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeBWAnd(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeBWAnd(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, false, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
if (promote == null) {
throw new ClassCastException(error("Cannot apply and [&] to types " +
@ -409,8 +384,8 @@ public final class EBinary extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -427,11 +402,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeXor(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeXor(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteXor(definition, left.actual, right.actual);
final Type promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
if (promote == null) {
throw new ClassCastException(error("Cannot apply xor [^] to types " +
@ -441,8 +416,8 @@ public final class EBinary extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -461,11 +436,11 @@ public final class EBinary extends AExpression {
actual = promote;
}
private void analyzeBWOr(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeBWOr(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, false, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
if (promote == null) {
throw new ClassCastException(error("Cannot apply or [|] to types " +
@ -475,8 +450,8 @@ public final class EBinary extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -494,19 +469,19 @@ public final class EBinary extends AExpression {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
if (actual.sort == Sort.STRING && operation == Operation.ADD) {
if (!cat) {
adapter.writeNewStrings();
}
left.write(settings, definition, adapter);
left.write(adapter);
if (!(left instanceof EBinary) || ((EBinary)left).operation != Operation.ADD || left.actual.sort != Sort.STRING) {
adapter.writeAppendStrings(left.actual);
}
right.write(settings, definition, adapter);
right.write(adapter);
if (!(right instanceof EBinary) || ((EBinary)right).operation != Operation.ADD || right.actual.sort != Sort.STRING) {
adapter.writeAppendStrings(right.actual);
@ -516,10 +491,10 @@ public final class EBinary extends AExpression {
adapter.writeToStrings();
}
} else {
left.write(settings, definition, adapter);
right.write(settings, definition, adapter);
left.write(adapter);
right.write(adapter);
adapter.writeBinaryInstruction(settings, definition, location, actual, operation);
adapter.writeBinaryInstruction(location, actual, operation);
}
adapter.writeBranch(tru, fals);

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables;
@ -35,7 +34,7 @@ public final class EBool extends AExpression {
AExpression left;
AExpression right;
public EBool(final int line, final String location, final Operation operation, final AExpression left, final AExpression right) {
public EBool(int line, String location, Operation operation, AExpression left, AExpression right) {
super(line, location);
this.operation = operation;
@ -44,14 +43,14 @@ public final class EBool extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.expected = definition.booleanType;
left.analyze(settings, definition, variables);
left = left.cast(settings, definition, variables);
void analyze(Variables variables) {
left.expected = Definition.BOOLEAN_TYPE;
left.analyze(variables);
left = left.cast(variables);
right.expected = definition.booleanType;
right.analyze(settings, definition, variables);
right = right.cast(settings, definition, variables);
right.expected = Definition.BOOLEAN_TYPE;
right.analyze(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
if (operation == Operation.AND) {
@ -63,11 +62,11 @@ public final class EBool extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
if (tru != null || fals != null) {
if (operation == Operation.AND) {
final Label localfals = fals == null ? new Label() : fals;
@ -76,8 +75,8 @@ public final class EBool extends AExpression {
right.tru = tru;
right.fals = fals;
left.write(settings, definition, adapter);
right.write(settings, definition, adapter);
left.write(adapter);
right.write(adapter);
if (fals == null) {
adapter.mark(localfals);
@ -89,8 +88,8 @@ public final class EBool extends AExpression {
right.tru = tru;
right.fals = fals;
left.write(settings, definition, adapter);
right.write(settings, definition, adapter);
left.write(adapter);
right.write(adapter);
if (tru == null) {
adapter.mark(localtru);
@ -106,8 +105,8 @@ public final class EBool extends AExpression {
left.fals = localfals;
right.fals = localfals;
left.write(settings, definition, adapter);
right.write(settings, definition, adapter);
left.write(adapter);
right.write(adapter);
adapter.push(true);
adapter.goTo(end);
@ -122,8 +121,8 @@ public final class EBool extends AExpression {
left.tru = localtru;
right.fals = localfals;
left.write(settings, definition, adapter);
right.write(settings, definition, adapter);
left.write(adapter);
right.write(adapter);
adapter.mark(localtru);
adapter.push(true);

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -29,19 +28,19 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class EBoolean extends AExpression {
public EBoolean(final int line, final String location, final boolean constant) {
public EBoolean(int line, String location, boolean constant) {
super(line, location);
this.constant = constant;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
actual = definition.booleanType;
void analyze(Variables variables) {
actual = Definition.BOOLEAN_TYPE;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
throw new IllegalArgumentException(error("Illegal tree structure."));
}
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -36,7 +34,7 @@ final class ECast extends AExpression {
Cast cast = null;
ECast(final int line, final String location, final AExpression child, final Cast cast) {
ECast(int line, String location, AExpression child, Cast cast) {
super(line, location);
this.type = null;
@ -46,13 +44,13 @@ final class ECast extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
throw new IllegalStateException(error("Illegal tree structure."));
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
child.write(settings, definition, adapter);
void write(MethodWriter adapter) {
child.write(adapter);
adapter.writeCast(cast);
adapter.writeBranch(tru, fals);
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Sort;
@ -44,12 +43,11 @@ public final class EChain extends AExpression {
boolean cat = false;
Type promote = null;
boolean exact = false;
Cast there = null;
Cast back = null;
public EChain(final int line, final String location, final List<ALink> links,
final boolean pre, final boolean post, final Operation operation, final AExpression expression) {
public EChain(int line, String location, List<ALink> links,
boolean pre, boolean post, Operation operation, AExpression expression) {
super(line, location);
this.links = links;
@ -60,20 +58,20 @@ public final class EChain extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
analyzeLinks(settings, definition, variables);
void analyze(Variables variables) {
analyzeLinks(variables);
analyzeIncrDecr();
if (operation != null) {
analyzeCompound(settings, definition, variables);
analyzeCompound(variables);
} else if (expression != null) {
analyzeWrite(settings, definition, variables);
analyzeWrite(variables);
} else {
analyzeRead();
}
}
private void analyzeLinks(final CompilerSettings settings, final Definition definition, final Variables variables) {
private void analyzeLinks(Variables variables) {
ALink previous = null;
int index = 0;
@ -93,7 +91,7 @@ public final class EChain extends AExpression {
current.store = expression != null || pre || post;
}
final ALink analyzed = current.analyze(settings, definition, variables);
final ALink analyzed = current.analyze(variables);
if (analyzed == null) {
links.remove(index);
@ -154,33 +152,33 @@ public final class EChain extends AExpression {
}
}
private void analyzeCompound(final CompilerSettings settings, final Definition definition, final Variables variables) {
private void analyzeCompound(Variables variables) {
final ALink last = links.get(links.size() - 1);
expression.analyze(settings, definition, variables);
expression.analyze(variables);
if (operation == Operation.MUL) {
promote = AnalyzerCaster.promoteNumeric(definition, last.after, expression.actual, true, true);
promote = AnalyzerCaster.promoteNumeric(last.after, expression.actual, true);
} else if (operation == Operation.DIV) {
promote = AnalyzerCaster.promoteNumeric(definition, last.after, expression.actual, true, true);
promote = AnalyzerCaster.promoteNumeric(last.after, expression.actual, true);
} else if (operation == Operation.REM) {
promote = AnalyzerCaster.promoteNumeric(definition, last.after, expression.actual, true, true);
promote = AnalyzerCaster.promoteNumeric(last.after, expression.actual, true);
} else if (operation == Operation.ADD) {
promote = AnalyzerCaster.promoteAdd(definition, last.after, expression.actual);
promote = AnalyzerCaster.promoteAdd(last.after, expression.actual);
} else if (operation == Operation.SUB) {
promote = AnalyzerCaster.promoteNumeric(definition, last.after, expression.actual, true, true);
promote = AnalyzerCaster.promoteNumeric(last.after, expression.actual, true);
} else if (operation == Operation.LSH) {
promote = AnalyzerCaster.promoteNumeric(definition, last.after, false, true);
promote = AnalyzerCaster.promoteNumeric(last.after, false);
} else if (operation == Operation.RSH) {
promote = AnalyzerCaster.promoteNumeric(definition, last.after, false, true);
promote = AnalyzerCaster.promoteNumeric(last.after, false);
} else if (operation == Operation.USH) {
promote = AnalyzerCaster.promoteNumeric(definition, last.after, false, true);
promote = AnalyzerCaster.promoteNumeric(last.after, false);
} else if (operation == Operation.BWAND) {
promote = AnalyzerCaster.promoteXor(definition, last.after, expression.actual);
promote = AnalyzerCaster.promoteXor(last.after, expression.actual);
} else if (operation == Operation.XOR) {
promote = AnalyzerCaster.promoteXor(definition, last.after, expression.actual);
promote = AnalyzerCaster.promoteXor(last.after, expression.actual);
} else if (operation == Operation.BWOR) {
promote = AnalyzerCaster.promoteXor(definition, last.after, expression.actual);
promote = AnalyzerCaster.promoteXor(last.after, expression.actual);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -200,42 +198,39 @@ public final class EChain extends AExpression {
expression.expected = expression.actual;
} else if (operation == Operation.LSH || operation == Operation.RSH || operation == Operation.USH) {
expression.expected = definition.intType;
expression.expected = Definition.INT_TYPE;
expression.explicit = true;
} else {
expression.expected = promote;
}
expression = expression.cast(settings, definition, variables);
expression = expression.cast(variables);
exact = !settings.getNumericOverflow() &&
(operation == Operation.MUL || operation == Operation.DIV || operation == Operation.REM ||
operation == Operation.ADD || operation == Operation.SUB);
there = AnalyzerCaster.getLegalCast(definition, location, last.after, promote, false);
back = AnalyzerCaster.getLegalCast(definition, location, promote, last.after, true);
there = AnalyzerCaster.getLegalCast(location, last.after, promote, false, false);
back = AnalyzerCaster.getLegalCast(location, promote, last.after, true, false);
this.statement = true;
this.actual = read ? last.after : definition.voidType;
this.actual = read ? last.after : Definition.VOID_TYPE;
}
private void analyzeWrite(final CompilerSettings settings, final Definition definition, final Variables variables) {
private void analyzeWrite(Variables variables) {
final ALink last = links.get(links.size() - 1);
// If the store node is a DEF node, we remove the cast to DEF from the expression
// and promote the real type to it:
if (last instanceof IDefLink) {
expression.analyze(settings, definition, variables);
expression.analyze(variables);
last.after = expression.expected = expression.actual;
} else {
// otherwise we adapt the type of the expression to the store type
expression.expected = last.after;
expression.analyze(settings, definition, variables);
expression.analyze(variables);
}
expression = expression.cast(settings, definition, variables);
expression = expression.cast(variables);
this.statement = true;
this.actual = read ? last.after : definition.voidType;
this.actual = read ? last.after : Definition.VOID_TYPE;
}
private void analyzeRead() {
@ -252,7 +247,7 @@ public final class EChain extends AExpression {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
if (cat) {
adapter.writeNewStrings();
}
@ -260,15 +255,15 @@ public final class EChain extends AExpression {
final ALink last = links.get(links.size() - 1);
for (final ALink link : links) {
link.write(settings, definition, adapter);
link.write(adapter);
if (link == last && link.store) {
if (cat) {
adapter.writeDup(link.size, 1);
link.load(settings, definition, adapter);
link.load(adapter);
adapter.writeAppendStrings(link.after);
expression.write(settings, definition, adapter);
expression.write(adapter);
if (!(expression instanceof EBinary) ||
((EBinary)expression).operation != Operation.ADD || expression.actual.sort != Sort.STRING) {
@ -282,39 +277,37 @@ public final class EChain extends AExpression {
adapter.writeDup(link.after.sort.size, link.size);
}
link.store(settings, definition, adapter);
link.store(adapter);
} else if (operation != null) {
adapter.writeDup(link.size, 0);
link.load(settings, definition, adapter);
link.load(adapter);
if (link.load && post) {
adapter.writeDup(link.after.sort.size, link.size);
}
adapter.writeCast(there);
expression.write(settings, definition, adapter);
adapter.writeBinaryInstruction(settings, definition, location, promote, operation);
expression.write(adapter);
adapter.writeBinaryInstruction(location, promote, operation);
if (!exact || !adapter.writeExactInstruction(definition, promote.sort, link.after.sort)) {
adapter.writeCast(back);
}
adapter.writeCast(back);
if (link.load && !post) {
adapter.writeDup(link.after.sort.size, link.size);
}
link.store(settings, definition, adapter);
link.store(adapter);
} else {
expression.write(settings, definition, adapter);
expression.write(adapter);
if (link.load) {
adapter.writeDup(link.after.sort.size, link.size);
}
link.store(settings, definition, adapter);
link.store(adapter);
}
} else {
link.load(settings, definition, adapter);
link.load(adapter);
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type;
@ -35,6 +34,8 @@ import static org.elasticsearch.painless.WriterConstants.DEF_GTE_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_GT_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_LTE_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_LT_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
import static org.elasticsearch.painless.WriterConstants.UTILITY_TYPE;
/**
* Represents a comparison expression.
@ -45,7 +46,7 @@ public final class EComp extends AExpression {
AExpression left;
AExpression right;
public EComp(final int line, final String location, final Operation operation, final AExpression left, final AExpression right) {
public EComp(int line, String location, Operation operation, AExpression left, AExpression right) {
super(line, location);
this.operation = operation;
@ -54,33 +55,33 @@ public final class EComp extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (operation == Operation.EQ) {
analyzeEq(settings, definition, variables);
analyzeEq(variables);
} else if (operation == Operation.EQR) {
analyzeEqR(settings, definition, variables);
analyzeEqR(variables);
} else if (operation == Operation.NE) {
analyzeNE(settings, definition, variables);
analyzeNE(variables);
} else if (operation == Operation.NER) {
analyzeNER(settings, definition, variables);
analyzeNER(variables);
} else if (operation == Operation.GTE) {
analyzeGTE(settings, definition, variables);
analyzeGTE(variables);
} else if (operation == Operation.GT) {
analyzeGT(settings, definition, variables);
analyzeGT(variables);
} else if (operation == Operation.LTE) {
analyzeLTE(settings, definition, variables);
analyzeLTE(variables);
} else if (operation == Operation.LT) {
analyzeLT(settings, definition, variables);
analyzeLT(variables);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
}
private void analyzeEq(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeEq(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteEquality(definition, left.actual, right.actual);
final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
throw new ClassCastException(error("Cannot apply equals [==] to types " +
@ -90,8 +91,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants."));
@ -119,14 +120,14 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
private void analyzeEqR(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeEqR(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteReference(definition, left.actual, right.actual);
final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
throw new ClassCastException(error("Cannot apply reference equals [===] to types " +
@ -136,8 +137,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants."));
@ -161,14 +162,14 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
private void analyzeNE(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeNE(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteEquality(definition, left.actual, right.actual);
final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
throw new ClassCastException(error("Cannot apply not equals [!=] to types " +
@ -178,8 +179,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants."));
@ -207,14 +208,14 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
private void analyzeNER(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeNER(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteReference(definition, left.actual, right.actual);
final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
throw new ClassCastException(error("Cannot apply reference not equals [!==] to types " +
@ -224,8 +225,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants."));
@ -249,14 +250,14 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
private void analyzeGTE(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeGTE(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply greater than or equals [>=] to types " +
@ -266,8 +267,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -285,14 +286,14 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
private void analyzeGT(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeGT(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply greater than [>] to types " +
@ -302,8 +303,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -321,14 +322,14 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
private void analyzeLTE(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeLTE(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply less than or equals [<=] to types " +
@ -338,8 +339,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -357,14 +358,14 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
private void analyzeLT(final CompilerSettings settings, final Definition definition, final Variables variables) {
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
private void analyzeLT(Variables variables) {
left.analyze(variables);
right.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, left.actual, right.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply less than [>=] to types " +
@ -374,8 +375,8 @@ public final class EComp extends AExpression {
left.expected = promote;
right.expected = promote;
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
final Sort sort = promote.sort;
@ -393,19 +394,19 @@ public final class EComp extends AExpression {
}
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
final boolean branch = tru != null || fals != null;
final org.objectweb.asm.Type rtype = right.actual.type;
final Sort rsort = right.actual.sort;
left.write(settings, definition, adapter);
left.write(adapter);
if (!right.isNull) {
right.write(settings, definition, adapter);
right.write(adapter);
}
final Label jump = tru != null ? tru : fals != null ? fals : new Label();
@ -455,34 +456,37 @@ public final class EComp extends AExpression {
if (eq) {
if (right.isNull) {
adapter.ifNull(jump);
} else if (!left.isNull && operation == Operation.EQ) {
adapter.invokeStatic(definition.defobjType.type, DEF_EQ_CALL);
} else if (!left.isNull && (operation == Operation.EQ || operation == Operation.NE)) {
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
writejump = false;
} else {
adapter.ifCmp(rtype, MethodWriter.EQ, jump);
}
} else if (ne) {
if (right.isNull) {
adapter.ifNonNull(jump);
} else if (!left.isNull && operation == Operation.NE) {
adapter.invokeStatic(definition.defobjType.type, DEF_EQ_CALL);
} else if (!left.isNull && (operation == Operation.EQ || operation == Operation.NE)) {
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
adapter.ifZCmp(MethodWriter.EQ, jump);
} else {
adapter.ifCmp(rtype, MethodWriter.NE, jump);
}
} else if (lt) {
adapter.invokeStatic(definition.defobjType.type, DEF_LT_CALL);
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_LT_CALL);
writejump = false;
} else if (lte) {
adapter.invokeStatic(definition.defobjType.type, DEF_LTE_CALL);
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_LTE_CALL);
writejump = false;
} else if (gt) {
adapter.invokeStatic(definition.defobjType.type, DEF_GT_CALL);
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_GT_CALL);
writejump = false;
} else if (gte) {
adapter.invokeStatic(definition.defobjType.type, DEF_GTE_CALL);
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_GTE_CALL);
writejump = false;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
writejump = left.isNull || ne || operation == Operation.EQR;
if (branch && !writejump) {
adapter.ifZCmp(MethodWriter.NE, jump);
}
@ -492,8 +496,8 @@ public final class EComp extends AExpression {
if (eq) {
if (right.isNull) {
adapter.ifNull(jump);
} else if (operation == Operation.EQ) {
adapter.invokeStatic(definition.utilityType.type, CHECKEQUALS);
} else if (operation == Operation.EQ || operation == Operation.NE) {
adapter.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
if (branch) {
adapter.ifZCmp(MethodWriter.NE, jump);
@ -506,8 +510,8 @@ public final class EComp extends AExpression {
} else if (ne) {
if (right.isNull) {
adapter.ifNonNull(jump);
} else if (operation == Operation.NE) {
adapter.invokeStatic(definition.utilityType.type, CHECKEQUALS);
} else if (operation == Operation.EQ || operation == Operation.NE) {
adapter.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
adapter.ifZCmp(MethodWriter.EQ, jump);
} else {
adapter.ifCmp(rtype, MethodWriter.NE, jump);

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.AnalyzerCaster;
@ -36,8 +35,7 @@ public final class EConditional extends AExpression {
AExpression left;
AExpression right;
public EConditional(final int line, final String location,
final AExpression condition, final AExpression left, final AExpression right) {
public EConditional(int line, String location, AExpression condition, AExpression left, AExpression right) {
super(line, location);
this.condition = condition;
@ -46,10 +44,10 @@ public final class EConditional extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
condition.expected = definition.booleanType;
condition.analyze(settings, definition, variables);
condition = condition.cast(settings, definition, variables);
void analyze(Variables variables) {
condition.expected = Definition.BOOLEAN_TYPE;
condition.analyze(variables);
condition = condition.cast(variables);
if (condition.constant != null) {
throw new IllegalArgumentException(error("Extraneous conditional statement."));
@ -57,27 +55,29 @@ public final class EConditional extends AExpression {
left.expected = expected;
left.explicit = explicit;
left.internal = internal;
right.expected = expected;
right.explicit = explicit;
right.internal = internal;
actual = expected;
left.analyze(settings, definition, variables);
right.analyze(settings, definition, variables);
left.analyze(variables);
right.analyze(variables);
if (expected == null) {
final Type promote = AnalyzerCaster.promoteConditional(definition, left.actual, right.actual, left.constant, right.constant);
final Type promote = AnalyzerCaster.promoteConditional(left.actual, right.actual, left.constant, right.constant);
left.expected = promote;
right.expected = promote;
actual = promote;
}
left = left.cast(settings, definition, variables);
right = right.cast(settings, definition, variables);
left = left.cast(variables);
right = right.cast(variables);
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
final Label localfals = new Label();
final Label end = new Label();
@ -85,11 +85,11 @@ public final class EConditional extends AExpression {
left.tru = right.tru = tru;
left.fals = right.fals = fals;
condition.write(settings, definition, adapter);
left.write(settings, definition, adapter);
condition.write(adapter);
left.write(adapter);
adapter.goTo(end);
adapter.mark(localfals);
right.write(settings, definition, adapter);
right.write(adapter);
adapter.mark(end);
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
@ -31,39 +30,39 @@ import org.elasticsearch.painless.MethodWriter;
*/
final class EConstant extends AExpression {
EConstant(final int line, final String location, final Object constant) {
EConstant(int line, String location, Object constant) {
super(line, location);
this.constant = constant;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (constant instanceof String) {
actual = definition.stringType;
actual = Definition.STRING_TYPE;
} else if (constant instanceof Double) {
actual = definition.doubleType;
actual = Definition.DOUBLE_TYPE;
} else if (constant instanceof Float) {
actual = definition.floatType;
actual = Definition.FLOAT_TYPE;
} else if (constant instanceof Long) {
actual = definition.longType;
actual = Definition.LONG_TYPE;
} else if (constant instanceof Integer) {
actual = definition.intType;
actual = Definition.INT_TYPE;
} else if (constant instanceof Character) {
actual = definition.charType;
actual = Definition.CHAR_TYPE;
} else if (constant instanceof Short) {
actual = definition.shortType;
actual = Definition.SHORT_TYPE;
} else if (constant instanceof Byte) {
actual = definition.byteType;
actual = Definition.BYTE_TYPE;
} else if (constant instanceof Boolean) {
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
final Sort sort = actual.sort;
switch (sort) {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -31,25 +30,25 @@ public final class EDecimal extends AExpression {
final String value;
public EDecimal(final int line, final String location, final String value) {
public EDecimal(int line, String location, String value) {
super(line, location);
this.value = value;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (value.endsWith("f") || value.endsWith("F")) {
try {
constant = Float.parseFloat(value.substring(0, value.length() - 1));
actual = definition.floatType;
actual = Definition.FLOAT_TYPE;
} catch (final NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid float constant [" + value + "]."));
}
} else {
try {
constant = Double.parseDouble(value);
actual = definition.doubleType;
actual = Definition.DOUBLE_TYPE;
} catch (final NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid double constant [" + value + "]."));
}
@ -57,7 +56,7 @@ public final class EDecimal extends AExpression {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
throw new IllegalArgumentException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -32,7 +31,7 @@ public final class EExplicit extends AExpression {
final String type;
AExpression child;
public EExplicit(final int line, final String location, final String type, final AExpression child) {
public EExplicit(int line, String location, String type, AExpression child) {
super(line, location);
this.type = type;
@ -40,28 +39,29 @@ public final class EExplicit extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
try {
actual = definition.getType(this.type);
actual = Definition.getType(this.type);
} catch (final IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
}
child.expected = actual;
child.explicit = true;
child.analyze(settings, definition, variables);
child = child.cast(settings, definition, variables);
child.analyze(variables);
child = child.cast(variables);
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
throw new IllegalArgumentException(error("Illegal tree structure."));
}
AExpression cast(final CompilerSettings settings, final Definition definition, final Variables variables) {
AExpression cast(Variables variables) {
child.expected = expected;
child.explicit = explicit;
child.internal = internal;
return child.cast(settings, definition, variables);
return child.cast(variables);
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Opcodes;
@ -30,12 +29,12 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class ENull extends AExpression {
public ENull(final int line, final String location) {
public ENull(int line, String location) {
super(line, location);
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
isNull = true;
if (expected != null) {
@ -45,12 +44,12 @@ public final class ENull extends AExpression {
actual = expected;
} else {
actual = definition.objectType;
actual = Definition.OBJECT_TYPE;
}
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
adapter.visitInsn(Opcodes.ACONST_NULL);
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
@ -33,7 +32,7 @@ public final class ENumeric extends AExpression {
final String value;
int radix;
public ENumeric(final int line, final String location, final String value, final int radix) {
public ENumeric(int line, String location, String value, int radix) {
super(line, location);
this.value = value;
@ -41,7 +40,7 @@ public final class ENumeric extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (value.endsWith("d") || value.endsWith("D")) {
if (radix != 10) {
throw new IllegalStateException(error("Invalid tree structure."));
@ -49,7 +48,7 @@ public final class ENumeric extends AExpression {
try {
constant = Double.parseDouble(value.substring(0, value.length() - 1));
actual = definition.doubleType;
actual = Definition.DOUBLE_TYPE;
} catch (final NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid double constant [" + value + "]."));
}
@ -60,14 +59,14 @@ public final class ENumeric extends AExpression {
try {
constant = Float.parseFloat(value.substring(0, value.length() - 1));
actual = definition.floatType;
actual = Definition.FLOAT_TYPE;
} catch (final NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid float constant [" + value + "]."));
}
} else if (value.endsWith("l") || value.endsWith("L")) {
try {
constant = Long.parseLong(value.substring(0, value.length() - 1), radix);
actual = definition.longType;
actual = Definition.LONG_TYPE;
} catch (final NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid long constant [" + value + "]."));
}
@ -78,16 +77,16 @@ public final class ENumeric extends AExpression {
if (sort == Sort.BYTE && integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) {
constant = (byte)integer;
actual = definition.byteType;
actual = Definition.BYTE_TYPE;
} else if (sort == Sort.CHAR && integer >= Character.MIN_VALUE && integer <= Character.MAX_VALUE) {
constant = (char)integer;
actual = definition.charType;
actual = Definition.CHAR_TYPE;
} else if (sort == Sort.SHORT && integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) {
constant = (short)integer;
actual = definition.shortType;
actual = Definition.SHORT_TYPE;
} else {
constant = integer;
actual = definition.intType;
actual = Definition.INT_TYPE;
}
} catch (final NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid int constant [" + value + "]."));
@ -96,7 +95,7 @@ public final class ENumeric extends AExpression {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
throw new IllegalArgumentException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type;
@ -31,8 +30,7 @@ import org.elasticsearch.painless.MethodWriter;
import static org.elasticsearch.painless.WriterConstants.DEF_NEG_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_NOT_CALL;
import static org.elasticsearch.painless.WriterConstants.NEGATEEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.NEGATEEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
/**
* Represents a unary math expression.
@ -42,7 +40,7 @@ public final class EUnary extends AExpression {
Operation operation;
AExpression child;
public EUnary(final int line, final String location, final Operation operation, final AExpression child) {
public EUnary(int line, String location, Operation operation, AExpression child) {
super(line, location);
this.operation = operation;
@ -50,43 +48,43 @@ public final class EUnary extends AExpression {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (operation == Operation.NOT) {
analyzeNot(settings, definition, variables);
analyzeNot(variables);
} else if (operation == Operation.BWNOT) {
analyzeBWNot(settings, definition, variables);
analyzeBWNot(variables);
} else if (operation == Operation.ADD) {
analyzerAdd(settings, definition, variables);
analyzerAdd(variables);
} else if (operation == Operation.SUB) {
analyzerSub(settings, definition, variables);
analyzerSub(variables);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
}
void analyzeNot(final CompilerSettings settings, final Definition definition, final Variables variables) {
child.expected = definition.booleanType;
child.analyze(settings, definition, variables);
child = child.cast(settings, definition, variables);
void analyzeNot(Variables variables) {
child.expected = Definition.BOOLEAN_TYPE;
child.analyze(variables);
child = child.cast(variables);
if (child.constant != null) {
constant = !(boolean)child.constant;
}
actual = definition.booleanType;
actual = Definition.BOOLEAN_TYPE;
}
void analyzeBWNot(final CompilerSettings settings, final Definition definition, final Variables variables) {
child.analyze(settings, definition, variables);
void analyzeBWNot(Variables variables) {
child.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, child.actual, false, true);
final Type promote = AnalyzerCaster.promoteNumeric(child.actual, false);
if (promote == null) {
throw new ClassCastException(error("Cannot apply not [~] to type [" + child.actual.name + "]."));
}
child.expected = promote;
child = child.cast(settings, definition, variables);
child = child.cast(variables);
if (child.constant != null) {
final Sort sort = promote.sort;
@ -103,17 +101,17 @@ public final class EUnary extends AExpression {
actual = promote;
}
void analyzerAdd(final CompilerSettings settings, final Definition definition, final Variables variables) {
child.analyze(settings, definition, variables);
void analyzerAdd(Variables variables) {
child.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, child.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply positive [+] to type [" + child.actual.name + "]."));
}
child.expected = promote;
child = child.cast(settings, definition, variables);
child = child.cast(variables);
if (child.constant != null) {
final Sort sort = promote.sort;
@ -134,27 +132,25 @@ public final class EUnary extends AExpression {
actual = promote;
}
void analyzerSub(final CompilerSettings settings, final Definition definition, final Variables variables) {
child.analyze(settings, definition, variables);
void analyzerSub(Variables variables) {
child.analyze(variables);
final Type promote = AnalyzerCaster.promoteNumeric(definition, child.actual, true, true);
final Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
if (promote == null) {
throw new ClassCastException(error("Cannot apply negative [-] to type [" + child.actual.name + "]."));
}
child.expected = promote;
child = child.cast(settings, definition, variables);
child = child.cast(variables);
if (child.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? -(int)child.constant : Math.negateExact((int)child.constant);
constant = -(int)child.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? -(long)child.constant : Math.negateExact((long)child.constant);
constant = -(long)child.constant;
} else if (sort == Sort.FLOAT) {
constant = -(float)child.constant;
} else if (sort == Sort.DOUBLE) {
@ -168,14 +164,14 @@ public final class EUnary extends AExpression {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
if (operation == Operation.NOT) {
if (tru == null && fals == null) {
final Label localfals = new Label();
final Label end = new Label();
child.fals = localfals;
child.write(settings, definition, adapter);
child.write(adapter);
adapter.push(false);
adapter.goTo(end);
@ -185,17 +181,17 @@ public final class EUnary extends AExpression {
} else {
child.tru = fals;
child.fals = tru;
child.write(settings, definition, adapter);
child.write(adapter);
}
} else {
final org.objectweb.asm.Type type = actual.type;
final Sort sort = actual.sort;
child.write(settings, definition, adapter);
child.write(adapter);
if (operation == Operation.BWNOT) {
if (sort == Sort.DEF) {
adapter.invokeStatic(definition.defobjType.type, DEF_NOT_CALL);
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_NOT_CALL);
} else {
if (sort == Sort.INT) {
adapter.push(-1);
@ -209,19 +205,9 @@ public final class EUnary extends AExpression {
}
} else if (operation == Operation.SUB) {
if (sort == Sort.DEF) {
adapter.invokeStatic(definition.defobjType.type, DEF_NEG_CALL);
adapter.invokeStatic(DEF_UTIL_TYPE, DEF_NEG_CALL);
} else {
if (settings.getNumericOverflow()) {
adapter.math(MethodWriter.NEG, type);
} else {
if (sort == Sort.INT) {
adapter.invokeStatic(definition.mathType.type, NEGATEEXACT_INT);
} else if (sort == Sort.LONG) {
adapter.invokeStatic(definition.mathType.type, NEGATEEXACT_LONG);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
}
adapter.math(MethodWriter.NEG, type);
}
} else if (operation != Operation.ADD) {
throw new IllegalStateException(error("Illegal tree structure."));

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -31,14 +30,14 @@ public final class LArrayLength extends ALink {
final String value;
LArrayLength(final int line, final String location, final String value) {
LArrayLength(int line, String location, String value) {
super(line, location, -1);
this.value = value;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if ("length".equals(value)) {
if (!load) {
throw new IllegalArgumentException(error("Must read array field [length]."));
@ -46,7 +45,7 @@ public final class LArrayLength extends ALink {
throw new IllegalArgumentException(error("Cannot write to read-only array field [length]."));
}
after = definition.intType;
after = Definition.INT_TYPE;
} else {
throw new IllegalArgumentException(error("Illegal field access [" + value + "]."));
}
@ -55,17 +54,17 @@ public final class LArrayLength extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
adapter.arrayLength();
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
throw new IllegalStateException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
@ -35,14 +34,14 @@ public final class LBrace extends ALink {
AExpression index;
public LBrace(final int line, final String location, final AExpression index) {
public LBrace(int line, String location, AExpression index) {
super(line, location, 2);
this.index = index;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if (before == null) {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -50,36 +49,36 @@ public final class LBrace extends ALink {
final Sort sort = before.sort;
if (sort == Sort.ARRAY) {
index.expected = definition.intType;
index.analyze(settings, definition, variables);
index = index.cast(settings, definition, variables);
index.expected = Definition.INT_TYPE;
index.analyze(variables);
index = index.cast(variables);
after = definition.getType(before.struct, before.dimensions - 1);
after = Definition.getType(before.struct, before.dimensions - 1);
return this;
} else if (sort == Sort.DEF) {
return new LDefArray(line, location, index).copy(this).analyze(settings, definition, variables);
return new LDefArray(line, location, index).copy(this).analyze(variables);
} else if (Map.class.isAssignableFrom(before.clazz)) {
return new LMapShortcut(line, location, index).copy(this).analyze(settings, definition, variables);
return new LMapShortcut(line, location, index).copy(this).analyze(variables);
} else if (List.class.isAssignableFrom(before.clazz)) {
return new LListShortcut(line, location, index).copy(this).analyze(settings, definition, variables);
return new LListShortcut(line, location, index).copy(this).analyze(variables);
}
throw new IllegalArgumentException(error("Illegal array access on type [" + before.name + "]."));
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
index.write(settings, definition, adapter);
void write(MethodWriter adapter) {
index.write(adapter);
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
adapter.arrayLoad(after.type);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
adapter.arrayStore(after.type);
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Struct;
@ -38,7 +37,7 @@ public final class LCall extends ALink {
Method method = null;
public LCall(final int line, final String location, final String name, final List<AExpression> arguments) {
public LCall(int line, String location, String name, List<AExpression> arguments) {
super(line, location, -1);
this.name = name;
@ -46,7 +45,7 @@ public final class LCall extends ALink {
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if (before == null) {
throw new IllegalStateException(error("Illegal tree structure."));
} else if (before.sort == Definition.Sort.ARRAY) {
@ -64,8 +63,9 @@ public final class LCall extends ALink {
final AExpression expression = arguments.get(argument);
expression.expected = method.arguments.get(argument);
expression.analyze(settings, definition, variables);
arguments.set(argument, expression.cast(settings, definition, variables));
expression.internal = true;
expression.analyze(variables);
arguments.set(argument, expression.cast(variables));
}
statement = true;
@ -76,7 +76,7 @@ public final class LCall extends ALink {
final ALink link = new LDefCall(line, location, name, arguments);
link.copy(this);
return link.analyze(settings, definition, variables);
return link.analyze(variables);
}
throw new IllegalArgumentException(error("Unknown call [" + name + "] with [" + arguments.size() +
@ -84,14 +84,14 @@ public final class LCall extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
for (final AExpression argument : arguments) {
argument.write(settings, definition, adapter);
argument.write(adapter);
}
if (java.lang.reflect.Modifier.isStatic(method.reflect.getModifiers())) {
@ -108,7 +108,7 @@ public final class LCall extends ALink {
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
throw new IllegalStateException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.AnalyzerCaster;
@ -35,14 +34,14 @@ public final class LCast extends ALink {
Cast cast = null;
public LCast(final int line, final String location, final String type) {
public LCast(int line, String location, String type) {
super(line, location, -1);
this.type = type;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if (before == null) {
throw new IllegalStateException(error("Illegal tree structure."));
} else if (store) {
@ -50,28 +49,28 @@ public final class LCast extends ALink {
}
try {
after = definition.getType(type);
after = Definition.getType(type);
} catch (final IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + type + "]."));
}
cast = AnalyzerCaster.getLegalCast(definition, location, before, after, true);
cast = AnalyzerCaster.getLegalCast(location, before, after, true, false);
return cast != null ? this : null;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
adapter.writeCast(cast);
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
// Do nothing.
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
throw new IllegalStateException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables;
@ -35,37 +34,37 @@ final class LDefArray extends ALink implements IDefLink {
AExpression index;
LDefArray(final int line, final String location, final AExpression index) {
LDefArray(int line, String location, AExpression index) {
super(line, location, 2);
this.index = index;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
index.analyze(settings, definition, variables);
ALink analyze(Variables variables) {
index.analyze(variables);
index.expected = index.actual;
index = index.cast(settings, definition, variables);
index = index.cast(variables);
after = definition.defType;
after = Definition.DEF_TYPE;
return this;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
index.write(settings, definition, adapter);
void write(MethodWriter adapter) {
index.write(adapter);
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(after.type, definition.defType.type, index.actual.type);
void load(MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type);
adapter.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_LOAD);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(definition.voidType.type, definition.defType.type,
void store(MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type,
index.actual.type, after.type);
adapter.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_STORE);
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables;
@ -37,7 +36,7 @@ final class LDefCall extends ALink implements IDefLink {
final String name;
final List<AExpression> arguments;
LDefCall(final int line, final String location, final String name, final List<AExpression> arguments) {
LDefCall(int line, String location, String name, List<AExpression> arguments) {
super(line, location, -1);
this.name = name;
@ -45,39 +44,40 @@ final class LDefCall extends ALink implements IDefLink {
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
for (int argument = 0; argument < arguments.size(); ++argument) {
final AExpression expression = arguments.get(argument);
expression.analyze(settings, definition, variables);
expression.internal = true;
expression.analyze(variables);
expression.expected = expression.actual;
arguments.set(argument, expression.cast(settings, definition, variables));
arguments.set(argument, expression.cast(variables));
}
statement = true;
after = definition.defType;
after = Definition.DEF_TYPE;
return this;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
final StringBuilder signature = new StringBuilder();
signature.append('(');
// first parameter is the receiver, we never know its type: always Object
signature.append(definition.defType.type.getDescriptor());
signature.append(Definition.DEF_TYPE.type.getDescriptor());
// TODO: remove our explicit conversions and feed more type information for return value,
// it can avoid some unnecessary boxing etc.
for (final AExpression argument : arguments) {
signature.append(argument.actual.type.getDescriptor());
argument.write(settings, definition, adapter);
argument.write(adapter);
}
signature.append(')');
@ -88,7 +88,7 @@ final class LDefCall extends ALink implements IDefLink {
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
throw new IllegalStateException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables;
@ -35,7 +34,7 @@ final class LDefField extends ALink implements IDefLink {
final String value;
LDefField(final int line, final String location, final String value) {
LDefField(int line, String location, String value) {
super(line, location, 1);
this.value = value;
@ -43,26 +42,26 @@ final class LDefField extends ALink implements IDefLink {
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
after = definition.defType;
ALink analyze(Variables variables) {
after = Definition.DEF_TYPE;
return this;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(after.type, definition.defType.type);
void load(MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type);
adapter.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.LOAD);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(definition.voidType.type, definition.defType.type, after.type);
void store(MethodWriter adapter) {
final String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type);
adapter.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.STORE);
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Field;
import org.elasticsearch.painless.Definition.Sort;
@ -39,14 +38,14 @@ public final class LField extends ALink {
Field field;
public LField(final int line, final String location, final String value) {
public LField(int line, String location, String value) {
super(line, location, 1);
this.value = value;
}
@Override
ALink analyze(CompilerSettings settings, Definition definition, Variables variables) {
ALink analyze(Variables variables) {
if (before == null) {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -54,9 +53,9 @@ public final class LField extends ALink {
final Sort sort = before.sort;
if (sort == Sort.ARRAY) {
return new LArrayLength(line, location, value).copy(this).analyze(settings, definition, variables);
return new LArrayLength(line, location, value).copy(this).analyze(variables);
} else if (sort == Sort.DEF) {
return new LDefField(line, location, value).copy(this).analyze(settings, definition, variables);
return new LDefField(line, location, value).copy(this).analyze(variables);
}
final Struct struct = before.struct;
@ -80,17 +79,17 @@ public final class LField extends ALink {
Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
if (shortcut) {
return new LShortcut(line, location, value).copy(this).analyze(settings, definition, variables);
return new LShortcut(line, location, value).copy(this).analyze(variables);
} else {
final EConstant index = new EConstant(line, location, value);
index.analyze(settings, definition, variables);
index.analyze(variables);
if (Map.class.isAssignableFrom(before.clazz)) {
return new LMapShortcut(line, location, index).copy(this).analyze(settings, definition, variables);
return new LMapShortcut(line, location, index).copy(this).analyze(variables);
}
if (List.class.isAssignableFrom(before.clazz)) {
return new LListShortcut(line, location, index).copy(this).analyze(settings, definition, variables);
return new LListShortcut(line, location, index).copy(this).analyze(variables);
}
}
}
@ -99,29 +98,21 @@ public final class LField extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isStatic(field.reflect.getModifiers())) {
adapter.getStatic(field.owner.type, field.reflect.getName(), field.type.type);
if (!field.generic.clazz.equals(field.type.clazz)) {
adapter.checkCast(field.generic.type);
}
} else {
adapter.getField(field.owner.type, field.reflect.getName(), field.type.type);
if (!field.generic.clazz.equals(field.type.clazz)) {
adapter.checkCast(field.generic.type);
}
}
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isStatic(field.reflect.getModifiers())) {
adapter.putStatic(field.owner.type, field.reflect.getName(), field.type.type);
} else {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort;
@ -35,14 +34,14 @@ final class LListShortcut extends ALink {
Method getter;
Method setter;
LListShortcut(final int line, final String location, final AExpression index) {
LListShortcut(int line, String location, AExpression index) {
super(line, location, 2);
this.index = index;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
getter = before.struct.methods.get(new Definition.MethodKey("get", 1));
setter = before.struct.methods.get(new Definition.MethodKey("set", 2));
@ -61,9 +60,9 @@ final class LListShortcut extends ALink {
}
if ((load || store) && (!load || getter != null) && (!store || setter != null)) {
index.expected = definition.intType;
index.analyze(settings, definition, variables);
index = index.cast(settings, definition, variables);
index.expected = Definition.INT_TYPE;
index.analyze(variables);
index = index.cast(variables);
after = setter != null ? setter.arguments.get(1) : getter.rtn;
} else {
@ -74,12 +73,12 @@ final class LListShortcut extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
index.write(settings, definition, adapter);
void write(MethodWriter adapter) {
index.write(adapter);
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
adapter.invokeInterface(getter.owner.type, getter.method);
} else {
@ -92,7 +91,7 @@ final class LListShortcut extends ALink {
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
adapter.invokeInterface(setter.owner.type, setter.method);
} else {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort;
@ -35,14 +34,14 @@ final class LMapShortcut extends ALink {
Method getter;
Method setter;
LMapShortcut(final int line, final String location, final AExpression index) {
LMapShortcut(int line, String location, AExpression index) {
super(line, location, 2);
this.index = index;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
getter = before.struct.methods.get(new Definition.MethodKey("get", 1));
setter = before.struct.methods.get(new Definition.MethodKey("put", 2));
@ -61,8 +60,8 @@ final class LMapShortcut extends ALink {
if ((load || store) && (!load || getter != null) && (!store || setter != null)) {
index.expected = setter != null ? setter.arguments.get(0) : getter.arguments.get(0);
index.analyze(settings, definition, variables);
index = index.cast(settings, definition, variables);
index.analyze(variables);
index = index.cast(variables);
after = setter != null ? setter.arguments.get(1) : getter.rtn;
} else {
@ -73,12 +72,12 @@ final class LMapShortcut extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
index.write(settings, definition, adapter);
void write(MethodWriter adapter) {
index.write(adapter);
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
adapter.invokeInterface(getter.owner.type, getter.method);
} else {
@ -91,7 +90,7 @@ final class LMapShortcut extends ALink {
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
adapter.invokeInterface(setter.owner.type, setter.method);
} else {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables;
@ -35,7 +34,7 @@ public final class LNewArray extends ALink {
final String type;
final List<AExpression> arguments;
public LNewArray(final int line, final String location, final String type, final List<AExpression> arguments) {
public LNewArray(int line, String location, String type, List<AExpression> arguments) {
super(line, location, -1);
this.type = type;
@ -43,7 +42,7 @@ public final class LNewArray extends ALink {
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if (before != null) {
throw new IllegalStateException(error("Illegal tree structure."));
} else if (store) {
@ -55,7 +54,7 @@ public final class LNewArray extends ALink {
final Type type;
try {
type = definition.getType(this.type);
type = Definition.getType(this.type);
} catch (final IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
}
@ -63,36 +62,36 @@ public final class LNewArray extends ALink {
for (int argument = 0; argument < arguments.size(); ++argument) {
final AExpression expression = arguments.get(argument);
expression.expected = definition.intType;
expression.analyze(settings, definition, variables);
arguments.set(argument, expression.cast(settings, definition, variables));
expression.expected = Definition.INT_TYPE;
expression.analyze(variables);
arguments.set(argument, expression.cast(variables));
}
after = definition.getType(type.struct, arguments.size());
after = Definition.getType(type.struct, arguments.size());
return this;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
for (final AExpression argument : arguments) {
argument.write(settings, definition, adapter);
argument.write(adapter);
}
if (arguments.size() > 1) {
adapter.visitMultiANewArrayInsn(after.type.getDescriptor(), after.type.getDimensions());
} else {
adapter.newArray(definition.getType(after.struct, 0).type);
adapter.newArray(Definition.getType(after.struct, 0).type);
}
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
throw new IllegalStateException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Constructor;
import org.elasticsearch.painless.Definition.Struct;
@ -39,7 +38,7 @@ public final class LNewObj extends ALink {
Constructor constructor;
public LNewObj(final int line, final String location, final String type, final List<AExpression> arguments) {
public LNewObj(int line, String location, String type, List<AExpression> arguments) {
super(line, location, -1);
this.type = type;
@ -47,7 +46,7 @@ public final class LNewObj extends ALink {
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if (before != null) {
throw new IllegalStateException(error("Illegal tree structure"));
} else if (store) {
@ -57,7 +56,7 @@ public final class LNewObj extends ALink {
final Type type;
try {
type = definition.getType(this.type);
type = Definition.getType(this.type);
} catch (final IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
}
@ -78,8 +77,9 @@ public final class LNewObj extends ALink {
final AExpression expression = arguments.get(argument);
expression.expected = types[argument];
expression.analyze(settings, definition, variables);
arguments.set(argument, expression.cast(settings, definition, variables));
expression.internal = true;
expression.analyze(variables);
arguments.set(argument, expression.cast(variables));
}
statement = true;
@ -92,27 +92,27 @@ public final class LNewObj extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
adapter.newInstance(after.type);
if (load) {
adapter.dup();
}
for (final AExpression argument : arguments) {
argument.write(settings, definition, adapter);
for (AExpression argument : arguments) {
argument.write(adapter);
}
adapter.invokeConstructor(constructor.owner.type, constructor.method);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
throw new IllegalStateException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort;
@ -37,14 +36,14 @@ final class LShortcut extends ALink {
Method getter = null;
Method setter = null;
LShortcut(final int line, final String location, final String value) {
LShortcut(int line, String location, String value) {
super(line, location, 1);
this.value = value;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
final Struct struct = before.struct;
getter = struct.methods.get(new Definition.MethodKey("get" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0));
@ -74,12 +73,12 @@ final class LShortcut extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
adapter.invokeInterface(getter.owner.type, getter.method);
} else {
@ -92,7 +91,7 @@ final class LShortcut extends ALink {
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
adapter.invokeInterface(setter.owner.type, setter.method);
} else {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -29,14 +28,14 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class LString extends ALink {
public LString(final int line, final String location, final String string) {
public LString(int line, String location, String string) {
super(line, location, -1);
this.string = string;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if (before != null) {
throw new IllegalStateException("Illegal tree structure.");
} else if (store) {
@ -45,23 +44,23 @@ public final class LString extends ALink {
throw new IllegalArgumentException(error("Must read String constant [" + string + "]."));
}
after = definition.stringType;
after = Definition.STRING_TYPE;
return this;
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
adapter.push(string);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
throw new IllegalStateException(error("Illegal tree structure."));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables;
@ -36,14 +35,14 @@ public final class LVariable extends ALink {
int slot;
public LVariable(final int line, final String location, final String name) {
public LVariable(int line, String location, String name) {
super(line, location, 0);
this.name = name;
}
@Override
ALink analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
ALink analyze(Variables variables) {
if (before != null) {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -51,7 +50,7 @@ public final class LVariable extends ALink {
Type type = null;
try {
type = definition.getType(name);
type = Definition.getType(name);
} catch (final IllegalArgumentException exception) {
// Do nothing.
}
@ -74,17 +73,17 @@ public final class LVariable extends ALink {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
// Do nothing.
}
@Override
void load(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void load(MethodWriter adapter) {
adapter.visitVarInsn(after.type.getOpcode(Opcodes.ILOAD), slot);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void store(MethodWriter adapter) {
adapter.visitVarInsn(after.type.getOpcode(Opcodes.ISTORE), slot);
}
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -34,17 +32,17 @@ public final class SBlock extends AStatement {
final List<AStatement> statements;
public SBlock(final int line, final String location, final List<AStatement> statements) {
public SBlock(int line, String location, List<AStatement> statements) {
super(line, location);
this.statements = Collections.unmodifiableList(statements);
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
final AStatement last = statements.get(statements.size() - 1);
for (final AStatement statement : statements) {
for (AStatement statement : statements) {
if (allEscape) {
throw new IllegalArgumentException(error("Unreachable statement."));
}
@ -53,7 +51,7 @@ public final class SBlock extends AStatement {
statement.lastSource = lastSource && statement == last;
statement.lastLoop = (beginLoop || lastLoop) && statement == last;
statement.analyze(settings, definition, variables);
statement.analyze(variables);
methodEscape = statement.methodEscape;
loopEscape = statement.loopEscape;
@ -65,11 +63,11 @@ public final class SBlock extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
for (final AStatement statement : statements) {
void write(MethodWriter adapter) {
for (AStatement statement : statements) {
statement.continu = continu;
statement.brake = brake;
statement.write(settings, definition, adapter);
statement.write(adapter);
}
}
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -29,12 +27,12 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class SBreak extends AStatement {
public SBreak(final int line, final String location) {
public SBreak(int line, String location) {
super(line, location);
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (!inLoop) {
throw new IllegalArgumentException(error("Break statement outside of a loop."));
}
@ -46,7 +44,7 @@ public final class SBreak extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
adapter.goTo(brake);
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -29,12 +27,12 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class SContinue extends AStatement {
public SContinue(final int line, final String location) {
public SContinue(int line, String location) {
super(line, location);
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
if (!inLoop) {
throw new IllegalArgumentException(error("Continue statement outside of a loop."));
}
@ -49,7 +47,7 @@ public final class SContinue extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
adapter.goTo(continu);
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -34,25 +32,25 @@ public final class SDeclBlock extends AStatement {
final List<SDeclaration> declarations;
public SDeclBlock(final int line, final String location, final List<SDeclaration> declarations) {
public SDeclBlock(int line, String location, List<SDeclaration> declarations) {
super(line, location);
this.declarations = Collections.unmodifiableList(declarations);
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
for (final SDeclaration declaration : declarations) {
declaration.analyze(settings, definition, variables);
declaration.analyze(variables);
}
statementCount = declarations.size();
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
for (final SDeclaration declaration : declarations) {
declaration.write(settings, definition, adapter);
declaration.write(adapter);
}
}
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable;
@ -38,7 +36,7 @@ public final class SDeclaration extends AStatement {
Variable variable;
public SDeclaration(final int line, final String location, final String type, final String name, final AExpression expression) {
public SDeclaration(int line, String location, String type, String name, AExpression expression) {
super(line, location);
this.type = type;
@ -47,18 +45,18 @@ public final class SDeclaration extends AStatement {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
variable = variables.addVariable(location, type, name, false, false);
if (expression != null) {
expression.expected = variable.type;
expression.analyze(settings, definition, variables);
expression = expression.cast(settings, definition, variables);
expression.analyze(variables);
expression = expression.cast(variables);
}
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
final org.objectweb.asm.Type type = variable.type.type;
final Sort sort = variable.type.sort;
@ -66,7 +64,7 @@ public final class SDeclaration extends AStatement {
final boolean initialize = expression == null;
if (!initialize) {
expression.write(settings, definition, adapter);
expression.write(adapter);
}
switch (sort) {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
@ -32,30 +31,32 @@ public final class SDo extends AStatement {
final AStatement block;
AExpression condition;
final int maxLoopCounter;
public SDo(final int line, final String location, final AStatement block, final AExpression condition) {
public SDo(int line, String location, AStatement block, AExpression condition, int maxLoopCounter) {
super(line, location);
this.condition = condition;
this.block = block;
this.maxLoopCounter = maxLoopCounter;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
variables.incrementScope();
block.beginLoop = true;
block.inLoop = true;
block.analyze(settings, definition, variables);
block.analyze(variables);
if (block.loopEscape && !block.anyContinue) {
throw new IllegalArgumentException(error("Extraneous do while loop."));
}
condition.expected = definition.booleanType;
condition.analyze(settings, definition, variables);
condition = condition.cast(settings, definition, variables);
condition.expected = Definition.BOOLEAN_TYPE;
condition.analyze(variables);
condition = condition.cast(variables);
if (condition.constant != null) {
final boolean continuous = (boolean)condition.constant;
@ -72,7 +73,7 @@ public final class SDo extends AStatement {
statementCount = 1;
if (settings.getMaxLoopCounter() > 0) {
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
@ -80,7 +81,7 @@ public final class SDo extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
final Label start = new Label();
final Label begin = new Label();
@ -90,12 +91,12 @@ public final class SDo extends AStatement {
block.continu = begin;
block.brake = end;
block.write(settings, definition, adapter);
block.write(adapter);
adapter.mark(begin);
condition.fals = end;
condition.write(settings, definition, adapter);
condition.write(adapter);
adapter.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount));

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
@ -32,16 +31,16 @@ public final class SExpression extends AStatement {
AExpression expression;
public SExpression(final int line, final String location, final AExpression expression) {
public SExpression(int line, String location, AExpression expression) {
super(line, location);
this.expression = expression;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
expression.read = lastSource;
expression.analyze(settings, definition, variables);
expression.analyze(variables);
if (!lastSource && !expression.statement) {
throw new IllegalArgumentException(error("Not a statement."));
@ -49,8 +48,9 @@ public final class SExpression extends AStatement {
final boolean rtn = lastSource && expression.actual.sort != Sort.VOID;
expression.expected = rtn ? definition.objectType : expression.actual;
expression = expression.cast(settings, definition, variables);
expression.expected = rtn ? Definition.OBJECT_TYPE : expression.actual;
expression.internal = rtn;
expression = expression.cast(variables);
methodEscape = rtn;
loopEscape = rtn;
@ -59,9 +59,9 @@ public final class SExpression extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
expression.write(settings, definition, adapter);
expression.write(adapter);
if (methodEscape) {
adapter.returnValue();

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
@ -34,31 +33,33 @@ public final class SFor extends AStatement {
AExpression condition;
AExpression afterthought;
final AStatement block;
final int maxLoopCounter;
public SFor(final int line, final String location,
final ANode initializer, final AExpression condition, final AExpression afterthought, final AStatement block) {
public SFor(int line, String location,
ANode initializer, AExpression condition, AExpression afterthought, AStatement block, int maxLoopCounter) {
super(line, location);
this.initializer = initializer;
this.condition = condition;
this.afterthought = afterthought;
this.block = block;
this.maxLoopCounter = maxLoopCounter;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
variables.incrementScope();
boolean continuous = false;
if (initializer != null) {
if (initializer instanceof SDeclBlock) {
((SDeclBlock)initializer).analyze(settings, definition, variables);
((SDeclBlock)initializer).analyze(variables);
} else if (initializer instanceof AExpression) {
final AExpression initializer = (AExpression)this.initializer;
initializer.read = false;
initializer.analyze(settings, definition, variables);
initializer.analyze(variables);
if (!initializer.statement) {
throw new IllegalArgumentException(initializer.error("Not a statement."));
@ -70,9 +71,9 @@ public final class SFor extends AStatement {
if (condition != null) {
condition.expected = definition.booleanType;
condition.analyze(settings, definition, variables);
condition = condition.cast(settings, definition, variables);
condition.expected = Definition.BOOLEAN_TYPE;
condition.analyze(variables);
condition = condition.cast(variables);
if (condition.constant != null) {
continuous = (boolean)condition.constant;
@ -91,7 +92,7 @@ public final class SFor extends AStatement {
if (afterthought != null) {
afterthought.read = false;
afterthought.analyze(settings, definition, variables);
afterthought.analyze(variables);
if (!afterthought.statement) {
throw new IllegalArgumentException(afterthought.error("Not a statement."));
@ -104,7 +105,7 @@ public final class SFor extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block.analyze(settings, definition, variables);
block.analyze(variables);
if (block.loopEscape && !block.anyContinue) {
throw new IllegalArgumentException(error("Extraneous for loop."));
@ -120,7 +121,7 @@ public final class SFor extends AStatement {
statementCount = 1;
if (settings.getMaxLoopCounter() > 0) {
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
@ -128,18 +129,18 @@ public final class SFor extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
final Label start = new Label();
final Label begin = afterthought == null ? start : new Label();
final Label end = new Label();
if (initializer instanceof SDeclBlock) {
((SDeclBlock)initializer).write(settings, definition, adapter);
((SDeclBlock)initializer).write(adapter);
} else if (initializer instanceof AExpression) {
AExpression initializer = (AExpression)this.initializer;
initializer.write(settings, definition, adapter);
initializer.write(adapter);
adapter.writePop(initializer.expected.sort.size);
}
@ -147,7 +148,7 @@ public final class SFor extends AStatement {
if (condition != null) {
condition.fals = end;
condition.write(settings, definition, adapter);
condition.write(adapter);
}
boolean allEscape = false;
@ -162,14 +163,14 @@ public final class SFor extends AStatement {
}
adapter.writeLoopCounter(loopCounterSlot, statementCount);
block.write(settings, definition, adapter);
block.write(adapter);
} else {
adapter.writeLoopCounter(loopCounterSlot, 1);
}
if (afterthought != null) {
adapter.mark(begin);
afterthought.write(settings, definition, adapter);
afterthought.write(adapter);
}
if (afterthought != null || !allEscape) {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
@ -34,8 +33,7 @@ public final class SIfElse extends AStatement {
final AStatement ifblock;
final AStatement elseblock;
public SIfElse(final int line, final String location,
final AExpression condition, final AStatement ifblock, final AStatement elseblock) {
public SIfElse(int line, String location, AExpression condition, AStatement ifblock, AStatement elseblock) {
super(line, location);
this.condition = condition;
@ -44,10 +42,10 @@ public final class SIfElse extends AStatement {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
condition.expected = definition.booleanType;
condition.analyze(settings, definition, variables);
condition = condition.cast(settings, definition, variables);
void analyze(Variables variables) {
condition.expected = Definition.BOOLEAN_TYPE;
condition.analyze(variables);
condition = condition.cast(variables);
if (condition.constant != null) {
throw new IllegalArgumentException(error("Extraneous if statement."));
@ -58,7 +56,7 @@ public final class SIfElse extends AStatement {
ifblock.lastLoop = lastLoop;
variables.incrementScope();
ifblock.analyze(settings, definition, variables);
ifblock.analyze(variables);
variables.decrementScope();
anyContinue = ifblock.anyContinue;
@ -71,7 +69,7 @@ public final class SIfElse extends AStatement {
elseblock.lastLoop = lastLoop;
variables.incrementScope();
elseblock.analyze(settings, definition, variables);
elseblock.analyze(variables);
variables.decrementScope();
methodEscape = ifblock.methodEscape && elseblock.methodEscape;
@ -84,17 +82,17 @@ public final class SIfElse extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
final Label end = new Label();
final Label fals = elseblock != null ? new Label() : end;
condition.fals = fals;
condition.write(settings, definition, adapter);
condition.write(adapter);
ifblock.continu = continu;
ifblock.brake = brake;
ifblock.write(settings, definition, adapter);
ifblock.write(adapter);
if (elseblock != null) {
if (!ifblock.allEscape) {
@ -105,7 +103,7 @@ public final class SIfElse extends AStatement {
elseblock.continu = continu;
elseblock.brake = brake;
elseblock.write(settings, definition, adapter);
elseblock.write(adapter);
}
adapter.mark(end);

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -31,17 +30,18 @@ public final class SReturn extends AStatement {
AExpression expression;
public SReturn(final int line, final String location, final AExpression expression) {
public SReturn(int line, String location, AExpression expression) {
super(line, location);
this.expression = expression;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
expression.expected = definition.objectType;
expression.analyze(settings, definition, variables);
expression = expression.cast(settings, definition, variables);
void analyze(Variables variables) {
expression.expected = Definition.OBJECT_TYPE;
expression.internal = true;
expression.analyze(variables);
expression = expression.cast(variables);
methodEscape = true;
loopEscape = true;
@ -51,9 +51,9 @@ public final class SReturn extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
expression.write(settings, definition, adapter);
expression.write(adapter);
adapter.returnValue();
}
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Opcodes;
import org.elasticsearch.painless.MethodWriter;
@ -35,14 +33,14 @@ public final class SSource extends AStatement {
final List<AStatement> statements;
public SSource(final int line, final String location, final List<AStatement> statements) {
public SSource(int line, String location, List<AStatement> statements) {
super(line, location);
this.statements = Collections.unmodifiableList(statements);
}
@Override
public void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
public void analyze(Variables variables) {
variables.incrementScope();
final AStatement last = statements.get(statements.size() - 1);
@ -53,7 +51,7 @@ public final class SSource extends AStatement {
}
statement.lastSource = statement == last;
statement.analyze(settings, definition, variables);
statement.analyze(variables);
methodEscape = statement.methodEscape;
allEscape = statement.allEscape;
@ -63,9 +61,9 @@ public final class SSource extends AStatement {
}
@Override
public void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
public void write(MethodWriter adapter) {
for (final AStatement statement : statements) {
statement.write(settings, definition, adapter);
statement.write(adapter);
}
if (!methodEscape) {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -31,17 +30,17 @@ public final class SThrow extends AStatement {
AExpression expression;
public SThrow(final int line, final String location, final AExpression expression) {
public SThrow(int line, String location, AExpression expression) {
super(line, location);
this.expression = expression;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
expression.expected = definition.exceptionType;
expression.analyze(settings, definition, variables);
expression = expression.cast(settings, definition, variables);
void analyze(Variables variables) {
expression.expected = Definition.EXCEPTION_TYPE;
expression.analyze(variables);
expression = expression.cast(variables);
methodEscape = true;
loopEscape = true;
@ -50,9 +49,9 @@ public final class SThrow extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
expression.write(settings, definition, adapter);
expression.write(adapter);
adapter.throwException();
}
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable;
import org.objectweb.asm.Label;
@ -42,7 +40,7 @@ public final class STrap extends AStatement {
Label end;
Label exception;
public STrap(final int line, final String location, final String type, final String name, final AStatement block) {
public STrap(int line, String location, String type, String name, AStatement block) {
super(line, location);
this.type = type;
@ -51,7 +49,7 @@ public final class STrap extends AStatement {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
variable = variables.addVariable(location, type, name, true, false);
if (!Exception.class.isAssignableFrom(variable.type.clazz)) {
@ -63,7 +61,7 @@ public final class STrap extends AStatement {
block.inLoop = inLoop;
block.lastLoop = lastLoop;
block.analyze(settings, definition, variables);
block.analyze(variables);
methodEscape = block.methodEscape;
loopEscape = block.loopEscape;
@ -75,7 +73,7 @@ public final class STrap extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
final Label jump = new Label();
@ -85,7 +83,7 @@ public final class STrap extends AStatement {
if (block != null) {
block.continu = continu;
block.brake = brake;
block.write(settings, definition, adapter);
block.write(adapter);
}
adapter.visitTryCatchBlock(begin, end, jump, variable.type.type.getInternalName());

View File

@ -19,8 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter;
@ -36,7 +34,7 @@ public final class STry extends AStatement {
final AStatement block;
final List<STrap> traps;
public STry(final int line, final String location, final AStatement block, final List<STrap> traps) {
public STry(int line, String location, AStatement block, List<STrap> traps) {
super(line, location);
this.block = block;
@ -44,13 +42,13 @@ public final class STry extends AStatement {
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
block.lastSource = lastSource;
block.inLoop = inLoop;
block.lastLoop = lastLoop;
variables.incrementScope();
block.analyze(settings, definition, variables);
block.analyze(variables);
variables.decrementScope();
methodEscape = block.methodEscape;
@ -67,7 +65,7 @@ public final class STry extends AStatement {
trap.lastLoop = lastLoop;
variables.incrementScope();
trap.analyze(settings, definition, variables);
trap.analyze(variables);
variables.decrementScope();
methodEscape &= trap.methodEscape;
@ -83,7 +81,7 @@ public final class STry extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
final Label begin = new Label();
final Label end = new Label();
@ -93,7 +91,7 @@ public final class STry extends AStatement {
block.continu = continu;
block.brake = brake;
block.write(settings, definition, adapter);
block.write(adapter);
if (!block.allEscape) {
adapter.goTo(exception);
@ -105,7 +103,7 @@ public final class STry extends AStatement {
trap.begin = begin;
trap.end = end;
trap.exception = traps.size() > 1 ? exception : null;
trap.write(settings, definition, adapter);
trap.write(adapter);
}
if (!block.allEscape || traps.size() > 1) {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
@ -32,21 +31,23 @@ public final class SWhile extends AStatement {
AExpression condition;
final AStatement block;
final int maxLoopCounter;
public SWhile(final int line, final String location, final AExpression condition, final AStatement block) {
public SWhile(int line, String location, AExpression condition, AStatement block, int maxLoopCounter) {
super(line, location);
this.condition = condition;
this.block = block;
this.maxLoopCounter = maxLoopCounter;
}
@Override
void analyze(final CompilerSettings settings, final Definition definition, final Variables variables) {
void analyze(Variables variables) {
variables.incrementScope();
condition.expected = definition.booleanType;
condition.analyze(settings, definition, variables);
condition = condition.cast(settings, definition, variables);
condition.expected = Definition.BOOLEAN_TYPE;
condition.analyze(variables);
condition = condition.cast(variables);
boolean continuous = false;
@ -68,7 +69,7 @@ public final class SWhile extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block.analyze(settings, definition, variables);
block.analyze(variables);
if (block.loopEscape && !block.anyContinue) {
throw new IllegalArgumentException(error("Extranous while loop."));
@ -84,7 +85,7 @@ public final class SWhile extends AStatement {
statementCount = 1;
if (settings.getMaxLoopCounter() > 0) {
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
@ -92,7 +93,7 @@ public final class SWhile extends AStatement {
}
@Override
void write(final CompilerSettings settings, final Definition definition, final MethodWriter adapter) {
void write(MethodWriter adapter) {
writeDebugInfo(adapter);
final Label begin = new Label();
final Label end = new Label();
@ -100,14 +101,14 @@ public final class SWhile extends AStatement {
adapter.mark(begin);
condition.fals = end;
condition.write(settings, definition, adapter);
condition.write(adapter);
if (block != null) {
adapter.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount));
block.continu = begin;
block.brake = end;
block.write(settings, definition, adapter);
block.write(adapter);
} else {
adapter.writeLoopCounter(loopCounterSlot, 1);
}

View File

@ -22,6 +22,7 @@
* <p>
* The following are the types of nodes:
* A* (abstract) - These are the abstract nodes that are the superclasses for the other types.
* I* (interface) -- Thse are marker interfaces to denote a property of the node.
* S* (statement) - These are nodes that represent a statement in Painless. These are the highest level nodes.
* E* (expression) - These are nodess that represent an expression in Painless. These are the middle level nodes.
* L* (link) - These are nodes that respresent a piece of a variable/method chain. The are the lowest level nodes.

View File

@ -0,0 +1,375 @@
#
# Licensed to Elasticsearch under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# Painless definition file. This defines the hierarchy of classes,
# what methods and fields they have, etc.
#
# primitive types
class void -> void {
}
class boolean -> boolean {
}
class byte -> byte {
}
class short -> short {
}
class char -> char {
}
class int -> int {
}
class long -> long {
}
class float -> float {
}
class double -> double {
}
# basic JDK classes
class Object -> java.lang.Object {
boolean equals(Object)
int hashCode()
String toString()
}
class def -> java.lang.Object {
boolean equals(Object)
int hashCode()
String toString()
}
class Void -> java.lang.Void extends Object {
}
class Boolean -> java.lang.Boolean extends Object {
Boolean TRUE
Boolean FALSE
int compare(boolean,boolean)
boolean parseBoolean(String)
Boolean valueOf(boolean)
boolean booleanValue()
int compareTo(Boolean)
}
class Byte -> java.lang.Byte extends Number,Object {
byte MIN_VALUE
byte MAX_VALUE
int compare(byte,byte)
int compareTo(Byte)
byte parseByte(String)
Byte valueOf(byte)
}
class Short -> java.lang.Short extends Number,Object {
short MIN_VALUE
short MAX_VALUE
int compare(short,short)
int compareTo(Short)
short parseShort(String)
Short valueOf(short)
}
class Character -> java.lang.Character extends Object {
char MIN_VALUE
char MAX_VALUE
int charCount(int)
char charValue()
int compare(char,char)
int compareTo(Character)
int digit(int,int)
char forDigit(int,int)
String getName(int)
int getNumericValue(int)
boolean isAlphabetic(int)
boolean isDefined(int)
boolean isDigit(int)
boolean isIdeographic(int)
boolean isLetter(int)
boolean isLetterOrDigit(int)
boolean isLowerCase(int)
boolean isMirrored(int)
boolean isSpaceChar(int)
boolean isTitleCase(int)
boolean isUpperCase(int)
boolean isWhitespace(int)
Character valueOf(char)
}
class Integer -> java.lang.Integer extends Number,Object {
int MIN_VALUE
int MAX_VALUE
int compare(int,int)
int compareTo(Integer)
int min(int,int)
int max(int,int)
int parseInt(String)
int signum(int)
String toHexString(int)
Integer valueOf(int)
}
class Long -> java.lang.Long extends Number,Object {
long MIN_VALUE
long MAX_VALUE
int compare(long,long)
int compareTo(Long)
long min(long,long)
long max(long,long)
long parseLong(String)
int signum(long)
String toHexString(long)
Long valueOf(long)
}
class Float -> java.lang.Float extends Number,Object {
float MIN_VALUE
float MAX_VALUE
int compare(float,float)
int compareTo(Float)
float min(float,float)
float max(float,float)
float parseFloat(String)
String toHexString(float)
Float valueOf(float)
}
class Double -> java.lang.Double extends Number,Object {
double MIN_VALUE
double MAX_VALUE
int compare(double,double)
int compareTo(Double)
double min(double,double)
double max(double,double)
double parseDouble(String)
String toHexString(double)
Double valueOf(double)
}
class Number -> java.lang.Number extends Object {
byte byteValue()
short shortValue()
int intValue()
long longValue()
float floatValue()
double doubleValue()
}
class CharSequence -> java.lang.CharSequence extends Object {
char charAt(int)
int length()
}
class String -> java.lang.String extends CharSequence,Object {
String <init>()
int codePointAt(int)
int compareTo(String)
String concat(String)
boolean endsWith(String)
int indexOf(String)
int indexOf(String,int)
boolean isEmpty()
String replace(CharSequence,CharSequence)
boolean startsWith(String)
String substring(int,int)
char[] toCharArray()
String trim()
}
class Math -> java.lang.Math {
double E
double PI
double abs(double)
double acos(double)
double asin(double)
double atan(double)
double atan2(double,double)
double cbrt(double)
double ceil(double)
double cos(double)
double cosh(double)
double exp(double)
double expm1(double)
double floor(double)
double hypot(double,double)
double log(double)
double log10(double)
double log1p(double)
double max(double,double)
double min(double,double)
double pow(double,double)
double random()
double rint(double)
long round(double)
double sin(double)
double sinh(double)
double sqrt(double)
double tan(double)
double tanh(double)
double toDegrees(double)
double toRadians(double)
}
class Iterator -> java.util.Iterator extends Object {
boolean hasNext()
def next()
void remove()
}
class Collection -> java.util.Collection extends Object {
boolean add(def)
void clear()
boolean contains(def)
boolean isEmpty()
Iterator iterator()
boolean remove(def)
int size()
}
class List -> java.util.List extends Collection,Object {
def set(int,def)
def get(int)
def remove(int)
int getLength/size()
}
class ArrayList -> java.util.ArrayList extends List,Collection,Object {
ArrayList <init>()
}
class Set -> java.util.Set extends Collection,Object {
}
class HashSet -> java.util.HashSet extends Set,Collection,Object {
HashSet <init>()
}
class Map -> java.util.Map extends Object {
def put(def,def)
def get(def)
def remove(def)
boolean isEmpty()
int size()
boolean containsKey(def)
Set keySet()
Collection values()
}
class HashMap -> java.util.HashMap extends Map,Object {
HashMap <init>()
}
class Exception -> java.lang.Exception extends Object {
String getMessage()
}
class ArithmeticException -> java.lang.ArithmeticException extends Exception,Object {
ArithmeticException <init>()
}
class IllegalArgumentException -> java.lang.IllegalArgumentException extends Exception,Object {
IllegalArgumentException <init>()
}
class IllegalStateException -> java.lang.IllegalStateException extends Exception,Object {
IllegalStateException <init>()
}
class NumberFormatException -> java.lang.NumberFormatException extends Exception,Object {
NumberFormatException <init>()
}
# ES Scripting API
class GeoPoint -> org.elasticsearch.common.geo.GeoPoint extends Object {
double getLat()
double getLon()
}
class Strings -> org.elasticsearch.index.fielddata.ScriptDocValues$Strings extends List,Collection,Object {
String getValue()
List getValues()
}
class Longs -> org.elasticsearch.index.fielddata.ScriptDocValues$Longs extends List,Collection,Object {
long getValue()
List getValues()
}
class Doubles -> org.elasticsearch.index.fielddata.ScriptDocValues$Doubles extends List,Collection,Object {
double getValue()
List getValues()
}
class GeoPoints -> org.elasticsearch.index.fielddata.ScriptDocValues$GeoPoints extends List,Collection,Object {
GeoPoint getValue()
List getValues()
double getLat()
double getLon()
double[] getLats()
double[] getLons()
# geo distance functions... so many...
double factorDistance(double,double)
double factorDistanceWithDefault(double,double,double)
double factorDistance02(double,double)
double factorDistance13(double,double)
double arcDistance(double,double)
double arcDistanceWithDefault(double,double,double)
double arcDistanceInKm(double,double)
double arcDistanceInKmWithDefault(double,double,double)
double arcDistanceInMiles(double,double)
double arcDistanceInMilesWithDefault(double,double,double)
double distance(double,double)
double distanceWithDefault(double,double,double)
double distanceInKm(double,double)
double distanceInKmWithDefault(double,double,double)
double distanceInMiles(double,double)
double distanceInMilesWithDefault(double,double,double)
double geohashDistance(String)
double geohashDistanceInKm(String)
double geohashDistanceInMiles(String)
}
# for testing.
# currently FeatureTest exposes overloaded constructor, field load store, and overloaded static methods
class FeatureTest -> org.elasticsearch.painless.FeatureTest extends Object {
FeatureTest <init>()
FeatureTest <init>(int,int)
int getX()
int getY()
void setX(int)
void setY(int)
boolean overloadedStatic()
boolean overloadedStatic(boolean)
}
# currently needed internally
class Executable -> org.elasticsearch.painless.Executable {
}

View File

@ -24,10 +24,8 @@ public class BasicAPITests extends ScriptTestCase {
public void testListIterator() {
assertEquals(3, exec("List x = new ArrayList(); x.add(2); x.add(3); x.add(-2); Iterator y = x.iterator(); " +
"int total = 0; while (y.hasNext()) total += y.next(); return total;"));
assertEquals(3, exec("List<Object> x = new ArrayList(); x.add(2); x.add(3); x.add(-2); Iterator<Object> y = x.iterator(); " +
"int total = 0; while (y.hasNext()) total += (int)y.next(); return total;"));
assertEquals("abc", exec("List<String> x = new ArrayList(); x.add(\"a\"); x.add(\"b\"); x.add(\"c\"); " +
"Iterator<String> y = x.iterator(); String total = \"\"; while (y.hasNext()) total += y.next(); return total;"));
assertEquals("abc", exec("List x = new ArrayList(); x.add(\"a\"); x.add(\"b\"); x.add(\"c\"); " +
"Iterator y = x.iterator(); String total = \"\"; while (y.hasNext()) total += y.next(); return total;"));
assertEquals(3, exec("def x = new ArrayList(); x.add(2); x.add(3); x.add(-2); def y = x.iterator(); " +
"def total = 0; while (y.hasNext()) total += y.next(); return total;"));
}
@ -35,10 +33,8 @@ public class BasicAPITests extends ScriptTestCase {
public void testSetIterator() {
assertEquals(3, exec("Set x = new HashSet(); x.add(2); x.add(3); x.add(-2); Iterator y = x.iterator(); " +
"int total = 0; while (y.hasNext()) total += y.next(); return total;"));
assertEquals(3, exec("Set<Object> x = new HashSet(); x.add(2); x.add(3); x.add(-2); Iterator<Object> y = x.iterator(); " +
"int total = 0; while (y.hasNext()) total += (int)y.next(); return total;"));
assertEquals("abc", exec("Set<String> x = new HashSet(); x.add(\"a\"); x.add(\"b\"); x.add(\"c\"); " +
"Iterator<String> y = x.iterator(); String total = \"\"; while (y.hasNext()) total += y.next(); return total;"));
assertEquals("abc", exec("Set x = new HashSet(); x.add(\"a\"); x.add(\"b\"); x.add(\"c\"); " +
"Iterator y = x.iterator(); String total = \"\"; while (y.hasNext()) total += y.next(); return total;"));
assertEquals(3, exec("def x = new HashSet(); x.add(2); x.add(3); x.add(-2); def y = x.iterator(); " +
"def total = 0; while (y.hasNext()) total += (int)y.next(); return total;"));
}
@ -78,12 +74,20 @@ public class BasicAPITests extends ScriptTestCase {
assertEquals(1, exec("def x = new ArrayList(); x.add(5); return x.length"));
assertEquals(5, exec("def x = new ArrayList(); x.add(5); return x[0]"));
assertEquals(1, exec("List x = new ArrayList(); x.add('Hallo'); return x.length"));
assertEquals(1, exec("List<String> x = new ArrayList<String>(); x.add('Hallo'); return x.length"));
assertEquals(1, exec("List<Object> x = new ArrayList<Object>(); x.add('Hallo'); return x.length"));
}
public void testDefAssignments() {
assertEquals(2, exec("int x; def y = 2.0; x = (int)y;"));
}
public void testInternalBoxing() {
assertBytecodeExists("def x = true", "INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;");
assertBytecodeExists("def x = (byte)1", "INVOKESTATIC java/lang/Byte.valueOf (B)Ljava/lang/Byte;");
assertBytecodeExists("def x = (short)1", "INVOKESTATIC java/lang/Short.valueOf (S)Ljava/lang/Short;");
assertBytecodeExists("def x = (char)1", "INVOKESTATIC java/lang/Character.valueOf (C)Ljava/lang/Character;");
assertBytecodeExists("def x = 1", "INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;");
assertBytecodeExists("def x = 1L", "INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;");
assertBytecodeExists("def x = 1F", "INVOKESTATIC java/lang/Float.valueOf (F)Ljava/lang/Float;");
assertBytecodeExists("def x = 1D", "INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;");
}
}

View File

@ -96,15 +96,15 @@ public class BasicExpressionTests extends ScriptTestCase {
}
/**
* Test boxed objects in various places
* Test boxed def objects in various places
*/
public void testBoxing() {
// return
assertEquals(4, exec("return params.get(\"x\");", Collections.singletonMap("x", 4)));
// assignment
assertEquals(4, exec("int y = (Integer)params.get(\"x\"); return y;", Collections.singletonMap("x", 4)));
assertEquals(4, exec("int y = params.get(\"x\"); return y;", Collections.singletonMap("x", 4)));
// comparison
assertEquals(true, exec("return 5 > (Integer)params.get(\"x\");", Collections.singletonMap("x", 4)));
assertEquals(true, exec("return 5 > params.get(\"x\");", Collections.singletonMap("x", 4)));
}
public void testBool() {

View File

@ -135,7 +135,7 @@ public class BasicStatementTests extends ScriptTestCase {
assertEquals(2.0, exec("double a = 2; return a;"));
assertEquals(false, exec("boolean a = false; return a;"));
assertEquals("string", exec("String a = \"string\"; return a;"));
assertEquals(HashMap.class, exec("Map<String,Object> a = new HashMap<String,Object>(); return a;").getClass());
assertEquals(HashMap.class, exec("Map a = new HashMap(); return a;").getClass());
assertEquals(byte[].class, exec("byte[] a = new byte[1]; return a;").getClass());
assertEquals(short[].class, exec("short[] a = new short[1]; return a;").getClass());
@ -146,7 +146,7 @@ public class BasicStatementTests extends ScriptTestCase {
assertEquals(double[].class, exec("double[] a = new double[1]; return a;").getClass());
assertEquals(boolean[].class, exec("boolean[] a = new boolean[1]; return a;").getClass());
assertEquals(String[].class, exec("String[] a = new String[1]; return a;").getClass());
assertEquals(Map[].class, exec("Map<String,Object>[] a = new Map<String,Object>[1]; return a;").getClass());
assertEquals(Map[].class, exec("Map[] a = new Map[1]; return a;").getClass());
assertEquals(byte[][].class, exec("byte[][] a = new byte[1][2]; return a;").getClass());
assertEquals(short[][][].class, exec("short[][][] a = new short[1][2][3]; return a;").getClass());
@ -157,7 +157,7 @@ public class BasicStatementTests extends ScriptTestCase {
assertEquals(double[][][][].class, exec("double[][][][] a = new double[1][2][3][4]; return a;").getClass());
assertEquals(boolean[][][][][].class, exec("boolean[][][][][] a = new boolean[1][2][3][4][5]; return a;").getClass());
assertEquals(String[][].class, exec("String[][] a = new String[1][2]; return a;").getClass());
assertEquals(Map[][][].class, exec("Map<String,Object>[][][] a = new Map<String,Object>[1][2][3]; return a;").getClass());
assertEquals(Map[][][].class, exec("Map[][][] a = new Map[1][2][3]; return a;").getClass());
}
public void testContinueStatement() {
@ -174,6 +174,6 @@ public class BasicStatementTests extends ScriptTestCase {
assertEquals(5, exec("int x = 5; return x;"));
assertEquals(4, exec("int[] x = new int[2]; x[1] = 4; return x[1];"));
assertEquals(5, ((short[])exec("short[] s = new short[3]; s[1] = 5; return s;"))[1]);
assertEquals(10, ((Map)exec("Map<String, Object> s = new HashMap< String , Object >(); s.put(\"x\", 10); return s;")).get("x"));
assertEquals(10, ((Map)exec("Map s = new HashMap(); s.put(\"x\", 10); return s;")).get("x"));
}
}

View File

@ -230,18 +230,18 @@ public class CompoundAssignmentTests extends ScriptTestCase {
assertEquals(false, exec("boolean x = true; x &= false; return x;"));
assertEquals(false, exec("boolean x = false; x &= true; return x;"));
assertEquals(false, exec("boolean x = false; x &= false; return x;"));
assertEquals(true, exec("Boolean x = true; x &= true; return x;"));
assertEquals(false, exec("Boolean x = true; x &= false; return x;"));
assertEquals(false, exec("Boolean x = false; x &= true; return x;"));
assertEquals(false, exec("Boolean x = false; x &= false; return x;"));
assertEquals(true, exec("def x = true; x &= true; return x;"));
assertEquals(false, exec("def x = true; x &= false; return x;"));
assertEquals(false, exec("def x = false; x &= true; return x;"));
assertEquals(false, exec("def x = false; x &= false; return x;"));
assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] &= true; return x[0];"));
assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] &= false; return x[0];"));
assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] &= true; return x[0];"));
assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] &= false; return x[0];"));
assertEquals(true, exec("Boolean[] x = new Boolean[1]; x[0] = true; x[0] &= true; return x[0];"));
assertEquals(false, exec("Boolean[] x = new Boolean[1]; x[0] = true; x[0] &= false; return x[0];"));
assertEquals(false, exec("Boolean[] x = new Boolean[1]; x[0] = false; x[0] &= true; return x[0];"));
assertEquals(false, exec("Boolean[] x = new Boolean[1]; x[0] = false; x[0] &= false; return x[0];"));
assertEquals(true, exec("def[] x = new def[1]; x[0] = true; x[0] &= true; return x[0];"));
assertEquals(false, exec("def[] x = new def[1]; x[0] = true; x[0] &= false; return x[0];"));
assertEquals(false, exec("def[] x = new def[1]; x[0] = false; x[0] &= true; return x[0];"));
assertEquals(false, exec("def[] x = new def[1]; x[0] = false; x[0] &= false; return x[0];"));
// byte
assertEquals((byte) (13 & 14), exec("byte x = 13; x &= 14; return x;"));
@ -261,18 +261,18 @@ public class CompoundAssignmentTests extends ScriptTestCase {
assertEquals(true, exec("boolean x = true; x |= false; return x;"));
assertEquals(true, exec("boolean x = false; x |= true; return x;"));
assertEquals(false, exec("boolean x = false; x |= false; return x;"));
assertEquals(true, exec("Boolean x = true; x |= true; return x;"));
assertEquals(true, exec("Boolean x = true; x |= false; return x;"));
assertEquals(true, exec("Boolean x = false; x |= true; return x;"));
assertEquals(false, exec("Boolean x = false; x |= false; return x;"));
assertEquals(true, exec("def x = true; x |= true; return x;"));
assertEquals(true, exec("def x = true; x |= false; return x;"));
assertEquals(true, exec("def x = false; x |= true; return x;"));
assertEquals(false, exec("def x = false; x |= false; return x;"));
assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] |= true; return x[0];"));
assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] |= false; return x[0];"));
assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] |= true; return x[0];"));
assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] |= false; return x[0];"));
assertEquals(true, exec("Boolean[] x = new Boolean[1]; x[0] = true; x[0] |= true; return x[0];"));
assertEquals(true, exec("Boolean[] x = new Boolean[1]; x[0] = true; x[0] |= false; return x[0];"));
assertEquals(true, exec("Boolean[] x = new Boolean[1]; x[0] = false; x[0] |= true; return x[0];"));
assertEquals(false, exec("Boolean[] x = new Boolean[1]; x[0] = false; x[0] |= false; return x[0];"));
assertEquals(true, exec("def[] x = new def[1]; x[0] = true; x[0] |= true; return x[0];"));
assertEquals(true, exec("def[] x = new def[1]; x[0] = true; x[0] |= false; return x[0];"));
assertEquals(true, exec("def[] x = new def[1]; x[0] = false; x[0] |= true; return x[0];"));
assertEquals(false, exec("def[] x = new def[1]; x[0] = false; x[0] |= false; return x[0];"));
// byte
assertEquals((byte) (13 | 14), exec("byte x = 13; x |= 14; return x;"));
@ -292,18 +292,18 @@ public class CompoundAssignmentTests extends ScriptTestCase {
assertEquals(true, exec("boolean x = true; x ^= false; return x;"));
assertEquals(true, exec("boolean x = false; x ^= true; return x;"));
assertEquals(false, exec("boolean x = false; x ^= false; return x;"));
assertEquals(false, exec("Boolean x = true; x ^= true; return x;"));
assertEquals(true, exec("Boolean x = true; x ^= false; return x;"));
assertEquals(true, exec("Boolean x = false; x ^= true; return x;"));
assertEquals(false, exec("Boolean x = false; x ^= false; return x;"));
assertEquals(false, exec("def x = true; x ^= true; return x;"));
assertEquals(true, exec("def x = true; x ^= false; return x;"));
assertEquals(true, exec("def x = false; x ^= true; return x;"));
assertEquals(false, exec("def x = false; x ^= false; return x;"));
assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] ^= true; return x[0];"));
assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] ^= false; return x[0];"));
assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] ^= true; return x[0];"));
assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] ^= false; return x[0];"));
assertEquals(false, exec("Boolean[] x = new Boolean[1]; x[0] = true; x[0] ^= true; return x[0];"));
assertEquals(true, exec("Boolean[] x = new Boolean[1]; x[0] = true; x[0] ^= false; return x[0];"));
assertEquals(true, exec("Boolean[] x = new Boolean[1]; x[0] = false; x[0] ^= true; return x[0];"));
assertEquals(false, exec("Boolean[] x = new Boolean[1]; x[0] = false; x[0] ^= false; return x[0];"));
assertEquals(false, exec("def[] x = new def[1]; x[0] = true; x[0] ^= true; return x[0];"));
assertEquals(true, exec("def[] x = new def[1]; x[0] = true; x[0] ^= false; return x[0];"));
assertEquals(true, exec("def[] x = new def[1]; x[0] = false; x[0] ^= true; return x[0];"));
assertEquals(false, exec("def[] x = new def[1]; x[0] = false; x[0] ^= false; return x[0];"));
// byte
assertEquals((byte) (13 ^ 14), exec("byte x = 13; x ^= 14; return x;"));

View File

@ -65,10 +65,8 @@ public class ConditionalTests extends ScriptTestCase {
public void testPromotion() {
assertEquals(false, exec("boolean x = false; boolean y = true; return (x ? 2 : 4.0F) == (y ? 2 : 4.0F);"));
assertEquals(false, exec("boolean x = false; boolean y = true; return (x ? 2 : 4.0F) == (y ? new Long(2) : new Float(4.0F));"));
assertEquals(false, exec("boolean x = false; boolean y = true; " +
"return (x ? new HashMap() : new ArrayList()) == (y ? new Long(2) : new Float(4.0F));"));
assertEquals(false, exec("boolean x = false; boolean y = true; return (x ? 2 : 4.0F) == (y ? new HashMap() : new ArrayList());"));
"return (x ? new HashMap() : new ArrayList()) == (y ? new HashMap() : new ArrayList());"));
}
public void testIncompatibleAssignment() {

View File

@ -22,10 +22,10 @@ package org.elasticsearch.painless;
public class DefOperationTests extends ScriptTestCase {
public void testIllegalCast() {
Exception exception = expectThrows(ClassCastException.class, () -> exec("def x = 1.0; int y = x; return y;"));
assertTrue(exception.getMessage().contains("java.lang.Double cannot be cast to java.lang.Integer"));
assertTrue(exception.getMessage().contains("cannot be cast"));
exception = expectThrows(ClassCastException.class, () -> exec("def x = (short)1; byte y = x; return y;"));
assertTrue(exception.getMessage().contains("java.lang.Short cannot be cast to java.lang.Byte"));
assertTrue(exception.getMessage().contains("cannot be cast"));
}
public void testNot() {
@ -103,13 +103,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(4D, exec("def x = (float)2; def y = (double)2; return x * y"));
assertEquals(4D, exec("def x = (double)2; def y = (double)2; return x * y"));
assertEquals(4, exec("def x = (Byte)2; def y = (byte)2; return x * y"));
assertEquals(4, exec("def x = (Short)2; def y = (short)2; return x * y"));
assertEquals(4, exec("def x = (Character)2; def y = (char)2; return x * y"));
assertEquals(4, exec("def x = (Integer)2; def y = (int)2; return x * y"));
assertEquals(4L, exec("def x = (Long)2; def y = (long)2; return x * y"));
assertEquals(4F, exec("def x = (Float)2; def y = (float)2; return x * y"));
assertEquals(4D, exec("def x = (Double)2; def y = (double)2; return x * y"));
assertEquals(4, exec("def x = (byte)2; def y = (byte)2; return x * y"));
assertEquals(4, exec("def x = (short)2; def y = (short)2; return x * y"));
assertEquals(4, exec("def x = (char)2; def y = (char)2; return x * y"));
assertEquals(4, exec("def x = (int)2; def y = (int)2; return x * y"));
assertEquals(4L, exec("def x = (long)2; def y = (long)2; return x * y"));
assertEquals(4F, exec("def x = (float)2; def y = (float)2; return x * y"));
assertEquals(4D, exec("def x = (double)2; def y = (double)2; return x * y"));
}
public void testDiv() {
@ -169,13 +169,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(1D, exec("def x = (float)2; def y = (double)2; return x / y"));
assertEquals(1D, exec("def x = (double)2; def y = (double)2; return x / y"));
assertEquals(1, exec("def x = (Byte)2; def y = (byte)2; return x / y"));
assertEquals(1, exec("def x = (Short)2; def y = (short)2; return x / y"));
assertEquals(1, exec("def x = (Character)2; def y = (char)2; return x / y"));
assertEquals(1, exec("def x = (Integer)2; def y = (int)2; return x / y"));
assertEquals(1L, exec("def x = (Long)2; def y = (long)2; return x / y"));
assertEquals(1F, exec("def x = (Float)2; def y = (float)2; return x / y"));
assertEquals(1D, exec("def x = (Double)2; def y = (double)2; return x / y"));
assertEquals(1, exec("def x = (byte)2; def y = (byte)2; return x / y"));
assertEquals(1, exec("def x = (short)2; def y = (short)2; return x / y"));
assertEquals(1, exec("def x = (char)2; def y = (char)2; return x / y"));
assertEquals(1, exec("def x = (int)2; def y = (int)2; return x / y"));
assertEquals(1L, exec("def x = (long)2; def y = (long)2; return x / y"));
assertEquals(1F, exec("def x = (float)2; def y = (float)2; return x / y"));
assertEquals(1D, exec("def x = (double)2; def y = (double)2; return x / y"));
}
public void testRem() {
@ -235,13 +235,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(0D, exec("def x = (float)2; def y = (double)2; return x % y"));
assertEquals(0D, exec("def x = (double)2; def y = (double)2; return x % y"));
assertEquals(0, exec("def x = (Byte)2; def y = (byte)2; return x % y"));
assertEquals(0, exec("def x = (Short)2; def y = (short)2; return x % y"));
assertEquals(0, exec("def x = (Character)2; def y = (char)2; return x % y"));
assertEquals(0, exec("def x = (Integer)2; def y = (int)2; return x % y"));
assertEquals(0L, exec("def x = (Long)2; def y = (long)2; return x % y"));
assertEquals(0F, exec("def x = (Float)2; def y = (float)2; return x % y"));
assertEquals(0D, exec("def x = (Double)2; def y = (double)2; return x % y"));
assertEquals(0, exec("def x = (byte)2; def y = (byte)2; return x % y"));
assertEquals(0, exec("def x = (short)2; def y = (short)2; return x % y"));
assertEquals(0, exec("def x = (char)2; def y = (char)2; return x % y"));
assertEquals(0, exec("def x = (int)2; def y = (int)2; return x % y"));
assertEquals(0L, exec("def x = (long)2; def y = (long)2; return x % y"));
assertEquals(0F, exec("def x = (float)2; def y = (float)2; return x % y"));
assertEquals(0D, exec("def x = (double)2; def y = (double)2; return x % y"));
}
public void testAdd() {
@ -301,13 +301,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(2D, exec("def x = (float)1; def y = (double)1; return x + y"));
assertEquals(2D, exec("def x = (double)1; def y = (double)1; return x + y"));
assertEquals(2, exec("def x = (Byte)1; def y = (byte)1; return x + y"));
assertEquals(2, exec("def x = (Short)1; def y = (short)1; return x + y"));
assertEquals(2, exec("def x = (Character)1; def y = (char)1; return x + y"));
assertEquals(2, exec("def x = (Integer)1; def y = (int)1; return x + y"));
assertEquals(2L, exec("def x = (Long)1; def y = (long)1; return x + y"));
assertEquals(2F, exec("def x = (Float)1; def y = (float)1; return x + y"));
assertEquals(2D, exec("def x = (Double)1; def y = (double)1; return x + y"));
assertEquals(2, exec("def x = (byte)1; def y = (byte)1; return x + y"));
assertEquals(2, exec("def x = (short)1; def y = (short)1; return x + y"));
assertEquals(2, exec("def x = (char)1; def y = (char)1; return x + y"));
assertEquals(2, exec("def x = (int)1; def y = (int)1; return x + y"));
assertEquals(2L, exec("def x = (long)1; def y = (long)1; return x + y"));
assertEquals(2F, exec("def x = (float)1; def y = (float)1; return x + y"));
assertEquals(2D, exec("def x = (double)1; def y = (double)1; return x + y"));
}
public void testSub() {
@ -367,13 +367,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(0D, exec("def x = (float)1; def y = (double)1; return x - y"));
assertEquals(0D, exec("def x = (double)1; def y = (double)1; return x - y"));
assertEquals(0, exec("def x = (Byte)1; def y = (byte)1; return x - y"));
assertEquals(0, exec("def x = (Short)1; def y = (short)1; return x - y"));
assertEquals(0, exec("def x = (Character)1; def y = (char)1; return x - y"));
assertEquals(0, exec("def x = (Integer)1; def y = (int)1; return x - y"));
assertEquals(0L, exec("def x = (Long)1; def y = (long)1; return x - y"));
assertEquals(0F, exec("def x = (Float)1; def y = (float)1; return x - y"));
assertEquals(0D, exec("def x = (Double)1; def y = (double)1; return x - y"));
assertEquals(0, exec("def x = (byte)1; def y = (byte)1; return x - y"));
assertEquals(0, exec("def x = (short)1; def y = (short)1; return x - y"));
assertEquals(0, exec("def x = (char)1; def y = (char)1; return x - y"));
assertEquals(0, exec("def x = (int)1; def y = (int)1; return x - y"));
assertEquals(0L, exec("def x = (long)1; def y = (long)1; return x - y"));
assertEquals(0F, exec("def x = (float)1; def y = (float)1; return x - y"));
assertEquals(0D, exec("def x = (double)1; def y = (double)1; return x - y"));
}
public void testLsh() {
@ -433,13 +433,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(2L, exec("def x = (float)1; def y = (double)1; return x << y"));
assertEquals(2L, exec("def x = (double)1; def y = (double)1; return x << y"));
assertEquals(2, exec("def x = (Byte)1; def y = (byte)1; return x << y"));
assertEquals(2, exec("def x = (Short)1; def y = (short)1; return x << y"));
assertEquals(2, exec("def x = (Character)1; def y = (char)1; return x << y"));
assertEquals(2, exec("def x = (Integer)1; def y = (int)1; return x << y"));
assertEquals(2L, exec("def x = (Long)1; def y = (long)1; return x << y"));
assertEquals(2L, exec("def x = (Float)1; def y = (float)1; return x << y"));
assertEquals(2L, exec("def x = (Double)1; def y = (double)1; return x << y"));
assertEquals(2, exec("def x = (byte)1; def y = (byte)1; return x << y"));
assertEquals(2, exec("def x = (short)1; def y = (short)1; return x << y"));
assertEquals(2, exec("def x = (char)1; def y = (char)1; return x << y"));
assertEquals(2, exec("def x = (int)1; def y = (int)1; return x << y"));
assertEquals(2L, exec("def x = (long)1; def y = (long)1; return x << y"));
assertEquals(2L, exec("def x = (float)1; def y = (float)1; return x << y"));
assertEquals(2L, exec("def x = (double)1; def y = (double)1; return x << y"));
}
public void testRsh() {
@ -499,13 +499,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(2L, exec("def x = (float)4; def y = (double)1; return x >> y"));
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >> y"));
assertEquals(2, exec("def x = (Byte)4; def y = (byte)1; return x >> y"));
assertEquals(2, exec("def x = (Short)4; def y = (short)1; return x >> y"));
assertEquals(2, exec("def x = (Character)4; def y = (char)1; return x >> y"));
assertEquals(2, exec("def x = (Integer)4; def y = (int)1; return x >> y"));
assertEquals(2L, exec("def x = (Long)4; def y = (long)1; return x >> y"));
assertEquals(2L, exec("def x = (Float)4; def y = (float)1; return x >> y"));
assertEquals(2L, exec("def x = (Double)4; def y = (double)1; return x >> y"));
assertEquals(2, exec("def x = (byte)4; def y = (byte)1; return x >> y"));
assertEquals(2, exec("def x = (short)4; def y = (short)1; return x >> y"));
assertEquals(2, exec("def x = (char)4; def y = (char)1; return x >> y"));
assertEquals(2, exec("def x = (int)4; def y = (int)1; return x >> y"));
assertEquals(2L, exec("def x = (long)4; def y = (long)1; return x >> y"));
assertEquals(2L, exec("def x = (float)4; def y = (float)1; return x >> y"));
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >> y"));
}
public void testUsh() {
@ -565,13 +565,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(2L, exec("def x = (float)4; def y = (double)1; return x >>> y"));
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >>> y"));
assertEquals(2, exec("def x = (Byte)4; def y = (byte)1; return x >>> y"));
assertEquals(2, exec("def x = (Short)4; def y = (short)1; return x >>> y"));
assertEquals(2, exec("def x = (Character)4; def y = (char)1; return x >>> y"));
assertEquals(2, exec("def x = (Integer)4; def y = (int)1; return x >>> y"));
assertEquals(2L, exec("def x = (Long)4; def y = (long)1; return x >>> y"));
assertEquals(2L, exec("def x = (Float)4; def y = (float)1; return x >>> y"));
assertEquals(2L, exec("def x = (Double)4; def y = (double)1; return x >>> y"));
assertEquals(2, exec("def x = (byte)4; def y = (byte)1; return x >>> y"));
assertEquals(2, exec("def x = (short)4; def y = (short)1; return x >>> y"));
assertEquals(2, exec("def x = (char)4; def y = (char)1; return x >>> y"));
assertEquals(2, exec("def x = (int)4; def y = (int)1; return x >>> y"));
assertEquals(2L, exec("def x = (long)4; def y = (long)1; return x >>> y"));
assertEquals(2L, exec("def x = (float)4; def y = (float)1; return x >>> y"));
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >>> y"));
}
public void testAnd() {
@ -631,13 +631,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(0L, exec("def x = (float)4; def y = (double)1; return x & y"));
assertEquals(0L, exec("def x = (double)4; def y = (double)1; return x & y"));
assertEquals(0, exec("def x = (Byte)4; def y = (byte)1; return x & y"));
assertEquals(0, exec("def x = (Short)4; def y = (short)1; return x & y"));
assertEquals(0, exec("def x = (Character)4; def y = (char)1; return x & y"));
assertEquals(0, exec("def x = (Integer)4; def y = (int)1; return x & y"));
assertEquals(0L, exec("def x = (Long)4; def y = (long)1; return x & y"));
assertEquals(0L, exec("def x = (Float)4; def y = (float)1; return x & y"));
assertEquals(0L, exec("def x = (Double)4; def y = (double)1; return x & y"));
assertEquals(0, exec("def x = (byte)4; def y = (byte)1; return x & y"));
assertEquals(0, exec("def x = (short)4; def y = (short)1; return x & y"));
assertEquals(0, exec("def x = (char)4; def y = (char)1; return x & y"));
assertEquals(0, exec("def x = (int)4; def y = (int)1; return x & y"));
assertEquals(0L, exec("def x = (long)4; def y = (long)1; return x & y"));
assertEquals(0L, exec("def x = (float)4; def y = (float)1; return x & y"));
assertEquals(0L, exec("def x = (double)4; def y = (double)1; return x & y"));
}
public void testXor() {
@ -697,13 +697,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(5L, exec("def x = (float)4; def y = (double)1; return x ^ y"));
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x ^ y"));
assertEquals(5, exec("def x = (Byte)4; def y = (byte)1; return x ^ y"));
assertEquals(5, exec("def x = (Short)4; def y = (short)1; return x ^ y"));
assertEquals(5, exec("def x = (Character)4; def y = (char)1; return x ^ y"));
assertEquals(5, exec("def x = (Integer)4; def y = (int)1; return x ^ y"));
assertEquals(5L, exec("def x = (Long)4; def y = (long)1; return x ^ y"));
assertEquals(5L, exec("def x = (Float)4; def y = (float)1; return x ^ y"));
assertEquals(5L, exec("def x = (Double)4; def y = (double)1; return x ^ y"));
assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x ^ y"));
assertEquals(5, exec("def x = (short)4; def y = (short)1; return x ^ y"));
assertEquals(5, exec("def x = (char)4; def y = (char)1; return x ^ y"));
assertEquals(5, exec("def x = (int)4; def y = (int)1; return x ^ y"));
assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x ^ y"));
assertEquals(5L, exec("def x = (float)4; def y = (float)1; return x ^ y"));
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x ^ y"));
}
public void testOr() {
@ -763,13 +763,13 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(5L, exec("def x = (float)4; def y = (double)1; return x | y"));
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x | y"));
assertEquals(5, exec("def x = (Byte)4; def y = (byte)1; return x | y"));
assertEquals(5, exec("def x = (Short)4; def y = (short)1; return x | y"));
assertEquals(5, exec("def x = (Character)4; def y = (char)1; return x | y"));
assertEquals(5, exec("def x = (Integer)4; def y = (int)1; return x | y"));
assertEquals(5L, exec("def x = (Long)4; def y = (long)1; return x | y"));
assertEquals(5L, exec("def x = (Float)4; def y = (float)1; return x | y"));
assertEquals(5L, exec("def x = (Double)4; def y = (double)1; return x | y"));
assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x | y"));
assertEquals(5, exec("def x = (short)4; def y = (short)1; return x | y"));
assertEquals(5, exec("def x = (char)4; def y = (char)1; return x | y"));
assertEquals(5, exec("def x = (int)4; def y = (int)1; return x | y"));
assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x | y"));
assertEquals(5L, exec("def x = (float)4; def y = (float)1; return x | y"));
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x | y"));
}
public void testEq() {

View File

@ -94,17 +94,8 @@ public class EqualsTests extends ScriptTestCase {
}
public void testEquals() {
assertEquals(true, exec("return new Long(3) == new Long(3);"));
assertEquals(false, exec("return new Long(3) === new Long(3);"));
assertEquals(true, exec("Integer x = new Integer(3); Object y = x; return x == y;"));
assertEquals(true, exec("Integer x = new Integer(3); Object y = x; return x === y;"));
assertEquals(true, exec("Integer x = new Integer(3); Object y = new Integer(3); return x == y;"));
assertEquals(false, exec("Integer x = new Integer(3); Object y = new Integer(3); return x === y;"));
assertEquals(true, exec("Integer x = new Integer(3); int y = 3; return x == y;"));
assertEquals(true, exec("Integer x = new Integer(3); short y = 3; return x == y;"));
assertEquals(true, exec("Integer x = new Integer(3); Short y = (short)3; return x == y;"));
assertEquals(false, exec("Integer x = new Integer(3); int y = 3; return x === y;"));
assertEquals(false, exec("Integer x = new Integer(3); double y = 3; return x === y;"));
assertEquals(true, exec("return 3 == 3;"));
assertEquals(false, exec("int x = 4; int y = 5; x == y"));
assertEquals(true, exec("int[] x = new int[1]; Object y = x; return x == y;"));
assertEquals(true, exec("int[] x = new int[1]; Object y = x; return x === y;"));
assertEquals(false, exec("int[] x = new int[1]; Object y = new int[1]; return x == y;"));
@ -114,14 +105,8 @@ public class EqualsTests extends ScriptTestCase {
}
public void testNotEquals() {
assertEquals(false, exec("return new Long(3) != new Long(3);"));
assertEquals(true, exec("return new Long(3) !== new Long(3);"));
assertEquals(false, exec("Integer x = new Integer(3); Object y = x; return x != y;"));
assertEquals(false, exec("Integer x = new Integer(3); Object y = x; return x !== y;"));
assertEquals(false, exec("Integer x = new Integer(3); Object y = new Integer(3); return x != y;"));
assertEquals(true, exec("Integer x = new Integer(3); Object y = new Integer(3); return x !== y;"));
assertEquals(true, exec("Integer x = new Integer(3); int y = 3; return x !== y;"));
assertEquals(true, exec("Integer x = new Integer(3); double y = 3; return x !== y;"));
assertEquals(false, exec("return 3 != 3;"));
assertEquals(true, exec("int x = 4; int y = 5; x != y"));
assertEquals(false, exec("int[] x = new int[1]; Object y = x; return x != y;"));
assertEquals(false, exec("int[] x = new int[1]; Object y = x; return x !== y;"));
assertEquals(true, exec("int[] x = new int[1]; Object y = new int[1]; return x != y;"));
@ -131,54 +116,36 @@ public class EqualsTests extends ScriptTestCase {
}
public void testBranchEquals() {
assertEquals(0, exec("Character a = (char)'a'; Character b = (char)'b'; if (a == b) return 1; else return 0;"));
assertEquals(1, exec("Character a = (char)'a'; Character b = (char)'a'; if (a == b) return 1; else return 0;"));
assertEquals(0, exec("Integer a = new Integer(1); Integer b = 1; if (a === b) return 1; else return 0;"));
assertEquals(0, exec("Character a = (char)'a'; Character b = new Character((char)'a'); if (a === b) return 1; else return 0;"));
assertEquals(1, exec("Character a = (char)'a'; Object b = a; if (a === b) return 1; else return 0;"));
assertEquals(1, exec("Integer a = 1; Number b = a; Number c = a; if (c === b) return 1; else return 0;"));
assertEquals(0, exec("Integer a = 1; Character b = (char)'a'; if (a === (Object)b) return 1; else return 0;"));
assertEquals(0, exec("def a = (char)'a'; def b = (char)'b'; if (a == b) return 1; else return 0;"));
assertEquals(1, exec("def a = (char)'a'; def b = (char)'a'; if (a == b) return 1; else return 0;"));
assertEquals(1, exec("def a = 1; def b = 1; if (a === b) return 1; else return 0;"));
assertEquals(1, exec("def a = (char)'a'; def b = (char)'a'; if (a === b) return 1; else return 0;"));
assertEquals(1, exec("def a = (char)'a'; Object b = a; if (a === b) return 1; else return 0;"));
assertEquals(1, exec("def a = 1; Number b = a; Number c = a; if (c === b) return 1; else return 0;"));
assertEquals(0, exec("def a = 1; Object b = new HashMap(); if (a === (Object)b) return 1; else return 0;"));
}
public void testBranchNotEquals() {
assertEquals(1, exec("Character a = (char)'a'; Character b = (char)'b'; if (a != b) return 1; else return 0;"));
assertEquals(0, exec("Character a = (char)'a'; Character b = (char)'a'; if (a != b) return 1; else return 0;"));
assertEquals(1, exec("Integer a = new Integer(1); Integer b = 1; if (a !== b) return 1; else return 0;"));
assertEquals(1, exec("Character a = (char)'a'; Character b = new Character((char)'a'); if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("Character a = (char)'a'; Object b = a; if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("Integer a = 1; Number b = a; Number c = a; if (c !== b) return 1; else return 0;"));
assertEquals(1, exec("Integer a = 1; Character b = (char)'a'; if (a !== (Object)b) return 1; else return 0;"));
assertEquals(1, exec("def a = (char)'a'; def b = (char)'b'; if (a != b) return 1; else return 0;"));
assertEquals(0, exec("def a = (char)'a'; def b = (char)'a'; if (a != b) return 1; else return 0;"));
assertEquals(0, exec("def a = 1; def b = 1; if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("def a = (char)'a'; def b = (char)'a'; if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("def a = (char)'a'; Object b = a; if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("def a = 1; Number b = a; Number c = a; if (c !== b) return 1; else return 0;"));
assertEquals(1, exec("def a = 1; Object b = new HashMap(); if (a !== (Object)b) return 1; else return 0;"));
}
public void testRightHandNull() {
assertEquals(false, exec("Character a = (char)'a'; return a == null;"));
assertEquals(false, exec("Character a = (char)'a'; return a === null;"));
assertEquals(true, exec("Character a = (char)'a'; return a != null;"));
assertEquals(true, exec("Character a = (char)'a'; return a !== null;"));
assertEquals(true, exec("Character a = null; return a == null;"));
assertEquals(false, exec("Character a = null; return a != null;"));
assertEquals(false, exec("Character a = (char)'a'; Character b = null; return a == b;"));
assertEquals(true, exec("Character a = null; Character b = null; return a === b;"));
assertEquals(true, exec("Character a = (char)'a'; Character b = null; return a != b;"));
assertEquals(false, exec("Character a = null; Character b = null; return a !== b;"));
assertEquals(false, exec("Integer x = null; double y = 2.0; return x == y;"));
assertEquals(true, exec("Integer x = null; Short y = null; return x == y;"));
assertEquals(false, exec("HashMap a = new HashMap(); return a == null;"));
assertEquals(false, exec("HashMap a = new HashMap(); return a === null;"));
assertEquals(true, exec("HashMap a = new HashMap(); return a != null;"));
assertEquals(true, exec("HashMap a = new HashMap(); return a !== null;"));
}
public void testLeftHandNull() {
assertEquals(false, exec("Character a = (char)'a'; return null == a;"));
assertEquals(false, exec("Character a = (char)'a'; return null === a;"));
assertEquals(true, exec("Character a = (char)'a'; return null != a;"));
assertEquals(true, exec("Character a = (char)'a'; return null !== a;"));
assertEquals(true, exec("Character a = null; return null == a;"));
assertEquals(false, exec("Character a = null; return null != a;"));
assertEquals(false, exec("Character a = null; Character b = (char)'a'; return a == b;"));
assertEquals(true, exec("Character a = null; Character b = null; return a == b;"));
assertEquals(true, exec("Character a = null; Character b = null; return b === a;"));
assertEquals(true, exec("Character a = null; Character b = (char)'a'; return a != b;"));
assertEquals(false, exec("Character a = null; Character b = null; return b != a;"));
assertEquals(false, exec("Character a = null; Character b = null; return b !== a;"));
assertEquals(false, exec("Integer x = null; double y = 2.0; return y == x;"));
assertEquals(true, exec("Integer x = null; Short y = null; return y == x;"));
assertEquals(false, exec("HashMap a = new HashMap(); return null == a;"));
assertEquals(false, exec("HashMap a = new HashMap(); return null === a;"));
assertEquals(true, exec("HashMap a = new HashMap(); return null != a;"));
assertEquals(true, exec("HashMap a = new HashMap(); return null !== a;"));
}
}

View File

@ -1,293 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests floating point overflow with numeric overflow disabled */
public class FloatOverflowDisabledTests extends ScriptTestCase {
/** wire overflow to false for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "false"));
}
public void testAssignmentAdditionOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x += 3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = -3.4028234663852886E38f; x += -3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x += 1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = -1.7976931348623157E308; x += -1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentSubtractionOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x -= -3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = -3.4028234663852886E38f; x -= 3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x -= -1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = -1.7976931348623157E308; x -= 1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentMultiplicationOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x *= 3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 3.4028234663852886E38f; x *= -3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x *= 1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; x *= -1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentDivisionOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x /= 1.401298464324817E-45f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 3.4028234663852886E38f; x /= -1.401298464324817E-45f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 1.0f; x /= 0.0f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x /= 4.9E-324; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; x /= -4.9E-324; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.0f; x /= 0.0; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddition() throws Exception {
try {
exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x + y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; double y = 1.7976931348623157E308; return x + y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAdditionConst() throws Exception {
try {
exec("return 3.4028234663852886E38f + 3.4028234663852886E38f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.7976931348623157E308 + 1.7976931348623157E308;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtraction() throws Exception {
try {
exec("float x = -3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x - y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = -1.7976931348623157E308; double y = 1.7976931348623157E308; return x - y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractionConst() throws Exception {
try {
exec("return -3.4028234663852886E38f - 3.4028234663852886E38f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return -1.7976931348623157E308 - 1.7976931348623157E308;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplication() throws Exception {
try {
exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x * y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; double y = 1.7976931348623157E308; return x * y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplicationConst() throws Exception {
try {
exec("return 3.4028234663852886E38f * 3.4028234663852886E38f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.7976931348623157E308 * 1.7976931348623157E308;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivision() throws Exception {
try {
exec("float x = 3.4028234663852886E38f; float y = 1.401298464324817E-45f; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 1.0f; float y = 0.0f; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; double y = 4.9E-324; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.0; double y = 0.0; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivisionConst() throws Exception {
try {
exec("return 3.4028234663852886E38f / 1.401298464324817E-45f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.0f / 0.0f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.7976931348623157E308 / 4.9E-324;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.0 / 0.0;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivisionNaN() throws Exception {
// float division, constant division, and assignment
try {
exec("float x = 0f; float y = 0f; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 0f / 0f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 0f; x /= 0f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double division, constant division, and assignment
try {
exec("double x = 0.0; double y = 0.0; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 0.0 / 0.0;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 0.0; x /= 0.0; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testRemainderNaN() throws Exception {
// float division, constant division, and assignment
try {
exec("float x = 1f; float y = 0f; return x % y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1f % 0f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 1f; x %= 0f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double division, constant division, and assignment
try {
exec("double x = 1.0; double y = 0.0; return x % y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.0 % 0.0;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.0; x %= 0.0; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
}

View File

@ -19,17 +19,8 @@
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests floating point overflow with numeric overflow enabled */
public class FloatOverflowEnabledTests extends ScriptTestCase {
/** wire overflow to true for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "true"));
}
/** Tests floating point overflow cases */
public class FloatOverflowTests extends ScriptTestCase {
public void testAssignmentAdditionOverflow() {
// float

View File

@ -1,444 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests integer overflow with numeric overflow disabled */
public class IntegerOverflowDisabledTests extends ScriptTestCase {
/** wire overflow to true for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "false"));
}
public void testAssignmentAdditionOverflow() {
// byte
try {
exec("byte x = 0; x += 128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x += -129; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = 0; x += 32768; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x += -32769; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 0; x += 65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("char x = 0; x += -65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 1; x += 2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = -2; x += -2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 1; x += 9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -2; x += -9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentSubtractionOverflow() {
// byte
try {
exec("byte x = 0; x -= -128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x -= 129; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = 0; x -= -32768; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x -= 32769; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 0; x -= -65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("char x = 0; x -= 65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 1; x -= -2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = -2; x -= 2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 1; x -= -9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -2; x -= 9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentMultiplicationOverflow() {
// byte
try {
exec("byte x = 2; x *= 128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 2; x *= -128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 2; x *= 65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("char x = 2; x *= -65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 2; x *= 2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = 2; x *= -2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 2; x *= 9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 2; x *= -9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentDivisionOverflow() {
// byte
try {
exec("byte x = (byte) -128; x /= -1; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = (short) -32768; x /= -1; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
// cannot happen for char: unsigned
// int
try {
exec("int x = -2147483647 - 1; x /= -1; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = -9223372036854775807L - 1L; x /=-1L; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testIncrementOverFlow() throws Exception {
// byte
try {
exec("byte x = 127; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 127; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = (byte) -128; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = (byte) -128; x--; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = 32767; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("short x = 32767; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("short x = (short) -32768; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("short x = (short) -32768; x--; return x;");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 65535; ++x; return x;");
} catch (ArithmeticException expected) {}
try {
exec("char x = 65535; x++; return x;");
} catch (ArithmeticException expected) {}
try {
exec("char x = (char) 0; --x; return x;");
} catch (ArithmeticException expected) {}
try {
exec("char x = (char) 0; x--; return x;");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 2147483647; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = 2147483647; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = (int) -2147483648L; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = (int) -2147483648L; x--; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 9223372036854775807L; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 9223372036854775807L; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775807L - 1L; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775807L - 1L; x--; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddition() throws Exception {
try {
exec("int x = 2147483647; int y = 2147483647; return x + y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x + y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testAdditionConst() throws Exception {
try {
exec("return 2147483647 + 2147483647;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return 9223372036854775807L + 9223372036854775807L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testSubtraction() throws Exception {
try {
exec("int x = -10; int y = 2147483647; return x - y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -10L; long y = 9223372036854775807L; return x - y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractionConst() throws Exception {
try {
exec("return -10 - 2147483647;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return -10L - 9223372036854775807L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplication() throws Exception {
try {
exec("int x = 2147483647; int y = 2147483647; return x * y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x * y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplicationConst() throws Exception {
try {
exec("return 2147483647 * 2147483647;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return 9223372036854775807L * 9223372036854775807L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testDivision() throws Exception {
try {
exec("int x = -2147483647 - 1; int y = -1; return x / y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775808L; long y = -1L; return x / y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testDivisionConst() throws Exception {
try {
exec("return (-2147483648) / -1;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return (-9223372036854775808L) / -1L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testNegationOverflow() throws Exception {
try {
exec("int x = -2147483648; x = -x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775808L; x = -x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testNegationOverflowConst() throws Exception {
try {
exec("int x = -(-2147483648); return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -(-9223372036854775808L); return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
}

View File

@ -19,17 +19,8 @@
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests integer overflow with numeric overflow enabled */
public class IntegerOverflowEnabledTests extends ScriptTestCase {
/** wire overflow to true for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "true"));
}
/** Tests integer overflow cases */
public class IntegerOverflowTests extends ScriptTestCase {
public void testAssignmentAdditionOverflow() {
// byte

View File

@ -60,6 +60,7 @@ public class NeedsScoreTests extends ESSingleNodeTestCase {
ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "painless", compiled),
lookup, Collections.<String, Object>emptyMap());
assertTrue(ss.needsScores());
service.close();
}
}

View File

@ -35,7 +35,7 @@ public class NoSemiColonTests extends ScriptTestCase {
assertEquals(2.0, exec("double a = 2; return a"));
assertEquals(false, exec("boolean a = false; return a"));
assertEquals("string", exec("String a = \"string\"; return a"));
assertEquals(HashMap.class, exec("Map<String, Object> a = new HashMap<String, Object>(); return a").getClass());
assertEquals(HashMap.class, exec("Map a = new HashMap(); return a").getClass());
assertEquals(byte[].class, exec("byte[] a = new byte[1]; return a").getClass());
assertEquals(short[].class, exec("short[] a = new short[1]; return a").getClass());
@ -46,7 +46,7 @@ public class NoSemiColonTests extends ScriptTestCase {
assertEquals(double[].class, exec("double[] a = new double[1]; return a").getClass());
assertEquals(boolean[].class, exec("boolean[] a = new boolean[1]; return a").getClass());
assertEquals(String[].class, exec("String[] a = new String[1]; return a").getClass());
assertEquals(Map[].class, exec("Map<String,Object>[] a = new Map<String,Object>[1]; return a").getClass());
assertEquals(Map[].class, exec("Map[] a = new Map[1]; return a").getClass());
assertEquals(byte[][].class, exec("byte[][] a = new byte[1][2]; return a").getClass());
assertEquals(short[][][].class, exec("short[][][] a = new short[1][2][3]; return a").getClass());
@ -57,7 +57,7 @@ public class NoSemiColonTests extends ScriptTestCase {
assertEquals(double[][][][].class, exec("double[][][][] a = new double[1][2][3][4]; return a").getClass());
assertEquals(boolean[][][][][].class, exec("boolean[][][][][] a = new boolean[1][2][3][4][5]; return a").getClass());
assertEquals(String[][].class, exec("String[][] a = new String[1][2]; return a").getClass());
assertEquals(Map[][][].class, exec("Map<String,Object>[][][] a = new Map<String,Object>[1][2][3]; return a").getClass());
assertEquals(Map[][][].class, exec("Map[][][] a = new Map[1][2][3]; return a").getClass());
}
public void testExpression() {
@ -73,6 +73,6 @@ public class NoSemiColonTests extends ScriptTestCase {
assertEquals(5, exec("int x = 5; return x"));
assertEquals(4, exec("int[] x = new int[2]; x[1] = 4; return x[1]"));
assertEquals(5, ((short[])exec("short[] s = new short[3]; s[1] = 5; return s"))[1]);
assertEquals(10, ((Map)exec("Map<String,Object> s = new HashMap< String,Object>(); s.put(\"x\", 10); return s")).get("x"));
assertEquals(10, ((Map)exec("Map s = new HashMap(); s.put(\"x\", 10); return s")).get("x"));
}
}

View File

@ -48,7 +48,7 @@ public abstract class ScriptTestCase extends ESTestCase {
/** Compiles and returns the result of {@code script} with access to {@code vars} */
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, Boolean.toString(random().nextBoolean())));
return exec(script, vars, Collections.emptyMap());
}
/** Compiles and returns the result of {@code script} with access to {@code vars} and compile-time parameters */

View File

@ -166,14 +166,14 @@ public class StringTests extends ScriptTestCase {
assertEquals("cc", exec("return (String)(char)\"cc\""));
fail();
} catch (final ClassCastException cce) {
assertTrue(cce.getMessage().contains("Cannot cast from [String] to [char]."));
assertTrue(cce.getMessage().contains("Cannot cast [String] with length greater than one to [char]."));
}
try {
assertEquals("cc", exec("return (String)(char)'cc'"));
fail();
} catch (final ClassCastException cce) {
assertTrue(cce.getMessage().contains("Cannot cast from [String] to [char]."));
assertTrue(cce.getMessage().contains("Cannot cast [String] with length greater than one to [char]."));
}
try {
@ -189,41 +189,5 @@ public class StringTests extends ScriptTestCase {
} catch (final ClassCastException cce) {
assertTrue(cce.getMessage().contains("Cannot cast [String] with length greater than one to [char]."));
}
assertEquals('c', exec("return (Character)\"c\""));
assertEquals('c', exec("return (Character)'c'"));
assertEquals("c", exec("return (String)(Character)\"c\""));
assertEquals("c", exec("return (String)(Character)'c'"));
assertEquals('c', exec("String s = \"c\"; (Character)s"));
assertEquals('c', exec("String s = 'c'; (Character)s"));
try {
assertEquals("cc", exec("return (String)(Character)\"cc\""));
fail();
} catch (final ClassCastException ise) {
assertTrue(ise.getMessage().contains("Cannot cast [String] with length greater than one to [Character]."));
}
try {
assertEquals("cc", exec("return (String)(Character)'cc'"));
fail();
} catch (final ClassCastException ise) {
assertTrue(ise.getMessage().contains("Cannot cast [String] with length greater than one to [Character]."));
}
try {
assertEquals('c', exec("String s = \"cc\"; (Character)s"));
fail();
} catch (final ClassCastException cce) {
assertTrue(cce.getMessage().contains("Cannot cast [String] with length greater than one to [Character]."));
}
try {
assertEquals('c', exec("String s = 'cc'; (Character)s"));
fail();
} catch (final ClassCastException cce) {
assertTrue(cce.getMessage().contains("Cannot cast [String] with length greater than one to [Character]."));
}
}
}

View File

@ -1,250 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless;
import org.elasticsearch.test.ESTestCase;
/**
* Tests utility methods (typically built-ins)
*/
public class UtilityTests extends ESTestCase {
public void testDivideWithoutOverflowInt() {
assertEquals(5 / 2, Utility.divideWithoutOverflow(5, 2));
try {
Utility.divideWithoutOverflow(Integer.MIN_VALUE, -1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5, 0);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivideWithoutOverflowLong() {
assertEquals(5L / 2L, Utility.divideWithoutOverflow(5L, 2L));
try {
Utility.divideWithoutOverflow(Long.MIN_VALUE, -1L);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5L, 0L);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testToByteExact() {
for (int b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
assertEquals((byte)b, Utility.toByteExact(b));
}
try {
Utility.toByteExact(Byte.MIN_VALUE - 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.toByteExact(Byte.MAX_VALUE + 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testToShortExact() {
for (int s = Short.MIN_VALUE; s < Short.MAX_VALUE; s++) {
assertEquals((short)s, Utility.toShortExact(s));
}
try {
Utility.toShortExact(Short.MIN_VALUE - 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.toShortExact(Short.MAX_VALUE + 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testToCharExact() {
for (int c = Character.MIN_VALUE; c < Character.MAX_VALUE; c++) {
assertEquals((char)c, Utility.toCharExact(c));
}
try {
Utility.toCharExact(Character.MIN_VALUE - 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.toCharExact(Character.MAX_VALUE + 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddWithoutOverflowFloat() {
assertEquals(10F, Utility.addWithoutOverflow(5F, 5F), 0F);
assertTrue(Float.isNaN(Utility.addWithoutOverflow(5F, Float.NaN)));
assertTrue(Float.isNaN(Utility.addWithoutOverflow(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY)));
try {
Utility.addWithoutOverflow(Float.MAX_VALUE, Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.addWithoutOverflow(-Float.MAX_VALUE, -Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddWithoutOverflowDouble() {
assertEquals(10D, Utility.addWithoutOverflow(5D, 5D), 0D);
assertTrue(Double.isNaN(Utility.addWithoutOverflow(5D, Double.NaN)));
assertTrue(Double.isNaN(Utility.addWithoutOverflow(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)));
try {
Utility.addWithoutOverflow(Double.MAX_VALUE, Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.addWithoutOverflow(-Double.MAX_VALUE, -Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractWithoutOverflowFloat() {
assertEquals(5F, Utility.subtractWithoutOverflow(10F, 5F), 0F);
assertTrue(Float.isNaN(Utility.subtractWithoutOverflow(5F, Float.NaN)));
assertTrue(Float.isNaN(Utility.subtractWithoutOverflow(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)));
try {
Utility.subtractWithoutOverflow(Float.MAX_VALUE, -Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.subtractWithoutOverflow(-Float.MAX_VALUE, Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractWithoutOverflowDouble() {
assertEquals(5D, Utility.subtractWithoutOverflow(10D, 5D), 0D);
assertTrue(Double.isNaN(Utility.subtractWithoutOverflow(5D, Double.NaN)));
assertTrue(Double.isNaN(Utility.subtractWithoutOverflow(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)));
try {
Utility.subtractWithoutOverflow(Double.MAX_VALUE, -Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.subtractWithoutOverflow(-Double.MAX_VALUE, Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplyWithoutOverflowFloat() {
assertEquals(25F, Utility.multiplyWithoutOverflow(5F, 5F), 0F);
assertTrue(Float.isNaN(Utility.multiplyWithoutOverflow(5F, Float.NaN)));
assertEquals(Float.POSITIVE_INFINITY, Utility.multiplyWithoutOverflow(5F, Float.POSITIVE_INFINITY), 0F);
try {
Utility.multiplyWithoutOverflow(Float.MAX_VALUE, Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplyWithoutOverflowDouble() {
assertEquals(25D, Utility.multiplyWithoutOverflow(5D, 5D), 0D);
assertTrue(Double.isNaN(Utility.multiplyWithoutOverflow(5D, Double.NaN)));
assertEquals(Double.POSITIVE_INFINITY, Utility.multiplyWithoutOverflow(5D, Double.POSITIVE_INFINITY), 0D);
try {
Utility.multiplyWithoutOverflow(Double.MAX_VALUE, Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivideWithoutOverflowFloat() {
assertEquals(5F, Utility.divideWithoutOverflow(25F, 5F), 0F);
assertTrue(Float.isNaN(Utility.divideWithoutOverflow(5F, Float.NaN)));
assertEquals(Float.POSITIVE_INFINITY, Utility.divideWithoutOverflow(Float.POSITIVE_INFINITY, 5F), 0F);
try {
Utility.divideWithoutOverflow(Float.MAX_VALUE, Float.MIN_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(0F, 0F);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5F, 0F);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivideWithoutOverflowDouble() {
assertEquals(5D, Utility.divideWithoutOverflow(25D, 5D), 0D);
assertTrue(Double.isNaN(Utility.divideWithoutOverflow(5D, Double.NaN)));
assertEquals(Double.POSITIVE_INFINITY, Utility.divideWithoutOverflow(Double.POSITIVE_INFINITY, 5D), 0D);
try {
Utility.divideWithoutOverflow(Double.MAX_VALUE, Double.MIN_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(0D, 0D);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5D, 0D);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testRemainderWithoutOverflowFloat() {
assertEquals(1F, Utility.remainderWithoutOverflow(25F, 4F), 0F);
try {
Utility.remainderWithoutOverflow(5F, 0F);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testRemainderWithoutOverflowDouble() {
assertEquals(1D, Utility.remainderWithoutOverflow(25D, 4D), 0D);
try {
Utility.remainderWithoutOverflow(5D, 0D);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
}