Merge pull request #18463 from rmuir/whitelist_cleanup
painless: steps at definition cleanup
This commit is contained in:
commit
a2ff002e2b
|
@ -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;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
@ -182,7 +199,7 @@ public final class MethodWriter extends GeneratorAdapter {
|
|||
visitJumpInsn(Opcodes.IFEQ, fals);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void writeNewStrings() {
|
||||
if (INDY_STRING_CONCAT_BOOTSTRAP_HANDLE != null) {
|
||||
// Java 9+: we just push our argument collector onto deque
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
@ -117,7 +115,7 @@ final class Writer {
|
|||
// if we truncated, make it obvious
|
||||
if (limit != source.length()) {
|
||||
fileName.append(" ...");
|
||||
}
|
||||
}
|
||||
fileName.append(" @ <inline script>");
|
||||
} else {
|
||||
// its a named script, just use the name
|
||||
|
@ -177,7 +175,7 @@ final class Writer {
|
|||
adapter.visitVarInsn(Opcodes.ISTORE, loop.slot);
|
||||
}
|
||||
|
||||
root.write(settings, definition, adapter);
|
||||
root.write(adapter);
|
||||
adapter.endMethod();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -39,7 +38,7 @@ public final class WriterConstants {
|
|||
|
||||
public final static String BASE_CLASS_NAME = Executable.class.getName();
|
||||
public final static Type BASE_CLASS_TYPE = Type.getType(Executable.class);
|
||||
|
||||
|
||||
public final static String CLASS_NAME = BASE_CLASS_NAME + "$Script";
|
||||
public final static Type CLASS_TYPE = Type.getObjectType(CLASS_NAME.replace('.', '/'));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -99,9 +118,9 @@ public final class WriterConstants {
|
|||
}
|
||||
INDY_STRING_CONCAT_BOOTSTRAP_HANDLE = bs;
|
||||
}
|
||||
|
||||
|
||||
public final static int MAX_INDY_STRING_CONCAT_ARGS = 200;
|
||||
|
||||
|
||||
public final static Type STRING_TYPE = Type.getType(String.class);
|
||||
public final static Type STRINGBUILDER_TYPE = Type.getType(StringBuilder.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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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."));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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."));
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,22 +76,22 @@ 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() +
|
||||
throw new IllegalArgumentException(error("Unknown call [" + name + "] with [" + arguments.size() +
|
||||
"] arguments on type [" + struct.name + "]."));
|
||||
}
|
||||
|
||||
@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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -34,7 +34,7 @@ public class ArrayTests extends ScriptTestCase {
|
|||
assertArrayLength(10, new Integer[10]);
|
||||
assertArrayLength(11, new String[11][2]);
|
||||
}
|
||||
|
||||
|
||||
private void assertArrayLength(int length, Object array) throws Throwable {
|
||||
assertEquals(length, (int) Def.arrayLengthGetter(array.getClass()).invoke(array));
|
||||
}
|
||||
|
@ -43,36 +43,36 @@ public class ArrayTests extends ScriptTestCase {
|
|||
assertEquals(5, exec("def x = new int[5]; return x.length"));
|
||||
assertEquals(5, exec("def x = new int[4]; x[0] = 5; return x[0];"));
|
||||
}
|
||||
|
||||
|
||||
public void testArrayLoadStoreString() {
|
||||
assertEquals(5, exec("def x = new String[5]; return x.length"));
|
||||
assertEquals("foobar", exec("def x = new String[4]; x[0] = 'foobar'; return x[0];"));
|
||||
}
|
||||
|
||||
|
||||
public void testArrayLoadStoreDef() {
|
||||
assertEquals(5, exec("def x = new def[5]; return x.length"));
|
||||
assertEquals(5, exec("def x = new def[4]; x[0] = 5; return x[0];"));
|
||||
}
|
||||
|
||||
|
||||
public void testArrayCompoundInt() {
|
||||
assertEquals(6, exec("int[] x = new int[5]; x[0] = 5; x[0]++; return x[0];"));
|
||||
}
|
||||
|
||||
|
||||
public void testArrayCompoundDef() {
|
||||
assertEquals(6, exec("def x = new int[5]; x[0] = 5; x[0]++; return x[0];"));
|
||||
}
|
||||
|
||||
|
||||
public void testJacksCrazyExpression1() {
|
||||
assertEquals(1, exec("int x; def[] y = new def[1]; x = y[0] = 1; return x;"));
|
||||
}
|
||||
|
||||
|
||||
public void testJacksCrazyExpression2() {
|
||||
assertEquals(1, exec("int x; def y = new def[1]; x = y[0] = 1; return x;"));
|
||||
}
|
||||
|
||||
|
||||
public void testForLoop() {
|
||||
assertEquals(999*1000/2, exec("def a = new int[1000]; for (int x = 0; x < a.length; x++) { a[x] = x; } "+
|
||||
"int total = 0; for (int x = 0; x < a.length; x++) { total += a[x]; } return total;"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;"));
|
||||
}
|
||||
|
@ -49,41 +45,49 @@ public class BasicAPITests extends ScriptTestCase {
|
|||
assertEquals(3, exec("Map x = new HashMap(); x.put(2, 2); x.put(3, 3); x.put(-2, -2); Iterator y = x.values().iterator(); " +
|
||||
"int total = 0; while (y.hasNext()) total += (int)y.next(); return total;"));
|
||||
}
|
||||
|
||||
|
||||
/** Test loads and stores with a map */
|
||||
public void testMapLoadStore() {
|
||||
assertEquals(5, exec("def x = new HashMap(); x.abc = 5; return x.abc;"));
|
||||
assertEquals(5, exec("def x = new HashMap(); x['abc'] = 5; return x['abc'];"));
|
||||
}
|
||||
|
||||
|
||||
/** Test loads and stores with a list */
|
||||
public void testListLoadStore() {
|
||||
assertEquals(5, exec("def x = new ArrayList(); x.add(3); x.0 = 5; return x.0;"));
|
||||
assertEquals(5, exec("def x = new ArrayList(); x.add(3); x[0] = 5; return x[0];"));
|
||||
}
|
||||
|
||||
|
||||
/** Test shortcut for getters with isXXXX */
|
||||
public void testListEmpty() {
|
||||
assertEquals(true, exec("def x = new ArrayList(); return x.empty;"));
|
||||
assertEquals(true, exec("def x = new HashMap(); return x.empty;"));
|
||||
}
|
||||
|
||||
|
||||
/** Test list method invocation */
|
||||
public void testListGet() {
|
||||
assertEquals(5, exec("def x = new ArrayList(); x.add(5); return x.get(0);"));
|
||||
assertEquals(5, exec("def x = new ArrayList(); x.add(5); def index = 0; return x.get(index);"));
|
||||
}
|
||||
|
||||
|
||||
public void testListAsArray() {
|
||||
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;");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;"));
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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) {}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -70,13 +70,13 @@ public class StringTests extends ScriptTestCase {
|
|||
public void testAppendMultiple() {
|
||||
assertEquals("cat" + true + "abc" + null, exec("String s = \"cat\"; return s + true + 'abc' + null;"));
|
||||
}
|
||||
|
||||
|
||||
public void testAppendMany() {
|
||||
for (int i = MAX_INDY_STRING_CONCAT_ARGS - 5; i < MAX_INDY_STRING_CONCAT_ARGS + 5; i++) {
|
||||
doTestAppendMany(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doTestAppendMany(int count) {
|
||||
StringBuilder script = new StringBuilder("String s = \"cat\"; return s");
|
||||
StringBuilder result = new StringBuilder("cat");
|
||||
|
@ -90,11 +90,11 @@ public class StringTests extends ScriptTestCase {
|
|||
Debugger.toString(s).contains(String.format(Locale.ROOT, "LDC \"%03d\"", count/2)));
|
||||
assertEquals(result.toString(), exec(s));
|
||||
}
|
||||
|
||||
|
||||
public void testNestedConcats() {
|
||||
assertEquals("foo1010foo", exec("String s = 'foo'; String x = '10'; return s + Integer.parseInt(x + x) + s;"));
|
||||
}
|
||||
|
||||
|
||||
public void testStringAPI() {
|
||||
assertEquals("", exec("return new String();"));
|
||||
assertEquals('x', exec("String s = \"x\"; return s.charAt(0);"));
|
||||
|
@ -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]."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue