All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
co.streamx.fluent.extree.expression.Interpreter Maven / Gradle / Ivy
package co.streamx.fluent.extree.expression;
import static co.streamx.fluent.extree.function.Functions.add;
import static co.streamx.fluent.extree.function.Functions.and;
import static co.streamx.fluent.extree.function.Functions.bitwiseAnd;
import static co.streamx.fluent.extree.function.Functions.bitwiseNot;
import static co.streamx.fluent.extree.function.Functions.bitwiseOr;
import static co.streamx.fluent.extree.function.Functions.constant;
import static co.streamx.fluent.extree.function.Functions.divide;
import static co.streamx.fluent.extree.function.Functions.equal;
import static co.streamx.fluent.extree.function.Functions.greaterThan;
import static co.streamx.fluent.extree.function.Functions.greaterThanOrEqual;
import static co.streamx.fluent.extree.function.Functions.iif;
import static co.streamx.fluent.extree.function.Functions.instanceOf;
import static co.streamx.fluent.extree.function.Functions.lessThan;
import static co.streamx.fluent.extree.function.Functions.lessThanOrEqual;
import static co.streamx.fluent.extree.function.Functions.modulo;
import static co.streamx.fluent.extree.function.Functions.multiply;
import static co.streamx.fluent.extree.function.Functions.negate;
import static co.streamx.fluent.extree.function.Functions.not;
import static co.streamx.fluent.extree.function.Functions.or;
import static co.streamx.fluent.extree.function.Functions.shiftLeft;
import static co.streamx.fluent.extree.function.Functions.shiftRight;
import static co.streamx.fluent.extree.function.Functions.subtract;
import static co.streamx.fluent.extree.function.Functions.xor;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
*
*/
final class Interpreter implements ExpressionVisitor> {
static final Interpreter Instance = new Interpreter();
private static final Object[] emptyArray = new Object[0];
private Interpreter() {
}
private Function normalize(BiFunction source) {
return pp -> source.apply(pp, pp);
}
private Function normalize(BiPredicate source) {
return pp -> source.test(pp, pp);
}
private Function normalize(Predicate source) {
return pp -> source.test(pp);
}
// https://stackoverflow.com/questions/3473756/java-convert-primitive-class/17836370
private static final Class>[] wrappers = {Integer.class, Double.class, Byte.class, Boolean.class,
Character.class, Void.class, Short.class, Float.class, Long.class};
@SuppressWarnings("unchecked")
private static Class wrap(final Class clazz) {
if (!clazz.isPrimitive())
return clazz;
final String name = clazz.getName();
final int c0 = name.charAt(0);
final int c2 = name.charAt(2);
final int mapper = (c0 + c0 + c0 + 5) & (118 - c2);
return (Class) wrappers[mapper];
}
@SuppressWarnings("unchecked")
@Override
public Function visit(BinaryExpression e) {
final Function first = e.getFirst().accept(this);
final Function second = e.getSecond().accept(this);
switch (e.getExpressionType()) {
case ExpressionType.Add:
return normalize(add((Function) first, (Function) second));
case ExpressionType.BitwiseAnd:
return normalize(bitwiseAnd((Function) first, (Function) second));
case ExpressionType.LogicalAnd:
return normalize(and((Function) first, (Function) second));
case ExpressionType.ArrayIndex:
return t -> Array.get(first.apply(t), (Integer) second.apply(t));
// return new Function() {
// // @Override
// public Object invoke(Object[] t) throws Throwable {
// return Array.get(first.invoke(t), (Integer) second
// .invoke(t));
// }
// };
// case ExpressionType.Coalesce:
// return coalesce((Function, Object[]>) first,
// (Function, Object[]>) second);
case ExpressionType.Conditional:
return iif((Function) e.getOperator().accept(this), first, second);
case ExpressionType.Divide:
return normalize(divide((Function) first, (Function) second));
case ExpressionType.Equal:
return normalize(equal(first, second));
case ExpressionType.ExclusiveOr:
return normalize(xor((Function) first, (Function) second));
case ExpressionType.GreaterThan:
return normalize(
greaterThan((Function) first, (Function) second));
case ExpressionType.GreaterThanOrEqual:
return normalize(greaterThanOrEqual((Function) first,
(Function) second));
case ExpressionType.LeftShift:
return normalize(shiftLeft((Function) first, (Function) second));
case ExpressionType.LessThan:
return normalize(lessThan((Function) first, (Function) second));
case ExpressionType.LessThanOrEqual:
return normalize(
lessThanOrEqual((Function) first, (Function) second));
case ExpressionType.Modulo:
return normalize(modulo((Function) first, (Function) second));
case ExpressionType.Multiply:
return normalize(multiply((Function) first, (Function) second));
case ExpressionType.NotEqual:
return normalize(equal(first, second).negate());
case ExpressionType.BitwiseOr:
return normalize(bitwiseOr((Function) first, (Function) second));
case ExpressionType.LogicalOr:
return normalize(or((Function) first, (Function) second));
// case ExpressionType.Power:
// return power((Function) first,
// (Function) second);
case ExpressionType.RightShift:
return normalize(shiftRight((Function) first, (Function) second));
case ExpressionType.Subtract:
return normalize(subtract((Function) first, (Function) second));
case ExpressionType.InstanceOf:
return normalize(instanceOf(first, (Class>) second.apply(null)));
default:
throw new IllegalArgumentException(ExpressionType.toString(e.getExpressionType()));
}
}
@Override
public Function visit(ConstantExpression e) {
return constant(e.getValue());
}
@Override
public Function visit(NewArrayInitExpression newArrayInitExpression) {
List> args = newArrayInitExpression.getInitializers()
.stream()
.map(i -> (Function) i.accept(this))
.collect(Collectors.toList());
Class> componentType = newArrayInitExpression.getComponentType();
return pp -> {
Object r = Array.newInstance(componentType, args.size());
for (int index = 0; index < args.size(); index++) {
Array.set(r, index, args.get(index).apply(pp));
}
return r;
};
}
@Override
public Function visit(InvocationExpression e) {
InvocableExpression target = e.getTarget();
Function m = target.accept(this);
Function x;
if (target.getExpressionType() == ExpressionType.Lambda) {
x = (Object[] pp) -> {
Function f1 = (Function) m.apply(pp);
return f1.apply(emptyArray);
};
} else {
x = m;
}
int size = e.getArguments().size();
List> ppe = new ArrayList<>(size);
for (Expression p : e.getArguments())
ppe.add(p.accept(this));
Function params = pp -> {
if (target.getExpressionType() == ExpressionType.FieldAccess)
return pp; // field: no arguments, just the instance
Object[] r = new Object[ppe.size()];
int index = 0;
for (Function pe : ppe) {
r[index++] = pe.apply(pp);
}
// for MethodAccess we need both outer and inner scope arguments
return (target.getExpressionType() == ExpressionType.MethodAccess
|| target.getExpressionType() == ExpressionType.Delegate) ? new Object[]{pp, r} : r;
};
return x.compose(params);
}
@Override
public Function visit(LambdaExpression> e) {
Function f = e.getBody().accept(this);
List locals = e.getLocals();
int size = locals.size();
if (size > 0) {
List> ple = new ArrayList<>(size);
for (Expression p : locals)
ple.add(p != null ? p.accept(this) : null);
f = f.compose((Object[] pp) -> {
int originalLength = pp.length;
pp = Arrays.copyOf(pp, originalLength + size);
for (int index = 0; index < size; index++) {
Function le = ple.get(index);
if (le == null)
continue;
pp[index + originalLength] = le.apply(pp);
}
return pp;
});
}
return toClosure(f.compose(visitParameters(e)));
}
private static Function toClosure(Function f) {
return (Function>) (Object[] captured) -> (Object[] p) -> f
.apply(concat(captured, p));
}
private static T[] concat(T[] first,
T[] second) {
if (first == null || first.length == 0)
return second;
if (second == null || second.length == 0)
return first;
T[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
private Function visitParameters(InvocableExpression invocable) {
List parameters = invocable.getParameters();
int size = parameters.size();
List> ppe = new ArrayList<>(size);
for (ParameterExpression p : parameters)
ppe.add(p.accept(this));
Function params = pp -> {
Object[] r = new Object[ppe.size()];
int index = 0;
for (Function pe : ppe) {
r[parameters.get(index++).getIndex()] = pe.apply(pp);
}
return r;
};
return params;
}
@Override
public Function visit(DelegateExpression e) {
final Function f = e.getDelegate().accept(this);
Function params = visitParameters(e);
return t -> {
InvocableExpression l = (InvocableExpression) f.apply((Object[]) t[0]);
Function f1 = (Function) l.accept(this).apply(params.apply((Object[]) t[1]));
return l.getExpressionType() == ExpressionType.Lambda ? f1.apply(emptyArray) : f1;
};
}
@Override
public Function visit(BlockExpression e) {
List> ff = new ArrayList<>();
for (Expression s : e.getExpressions())
ff.add(s.accept(this));
return t -> {
Object result = null;
for (Function f : ff)
result = f.apply(t);
return result;
};
}
@Override
public Function visit(MemberExpression e) {
final Member m = e.getMember();
if (!Modifier.isPublic(m.getModifiers()) && m instanceof AccessibleObject) {
AccessibleObject ao = (AccessibleObject) m;
try {
if (!ao.isAccessible())
ao.setAccessible(true);
} catch (Exception ee) {
// suppress
}
}
Expression ei = e.getInstance();
final Function instance = ei != null ? ei.accept(this) : null;
Function params = visitParameters(e);
Function field = t -> {
try {
return ((Field) m).get(instance == null ? null : instance.apply(t));
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
};
Function method = t -> {
Object inst;
if (instance != null) {
inst = instance.apply((Object[]) t[0]);
} else
inst = null;
try {
Object[] pp = params.apply((Object[]) t[1]);
return ((Method) m).invoke(inst, pp);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new RuntimeException(ex);
}
};
Function ctor = t -> {
try {
return ((Constructor>) m).newInstance(params.apply(t));
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException ex) {
throw new RuntimeException(ex);
}
};
Function member;
if (m instanceof Field)
member = field;
else if (m instanceof Method)
member = method;
else
member = ctor;
return member;// .compose(params);
}
@Override
public Function visit(ParameterExpression e) {
final int index = e.getIndex();
return t -> t[index];
}
@SuppressWarnings("unchecked")
@Override
public Function visit(UnaryExpression e) {
final Function first = e.getFirst().accept(this);
switch (e.getExpressionType()) {
case ExpressionType.ArrayLength:
return t -> Array.getLength(first.apply(t));
case ExpressionType.BitwiseNot:
return (Function) bitwiseNot((Function) first);
case ExpressionType.Convert:
final Class> to = e.getResultType();
if (to.isPrimitive() || Number.class.isAssignableFrom(to))
return t -> {
Object source = first.apply(t);
if (source instanceof Number) {
Number result = (Number) source;
if (to.isPrimitive()) {
if (to == Integer.TYPE)
return result.intValue();
if (to == Long.TYPE)
return result.longValue();
if (to == Float.TYPE)
return result.floatValue();
if (to == Double.TYPE)
return result.doubleValue();
if (to == Byte.TYPE)
return result.byteValue();
if (to == Character.TYPE)
return (char) result.intValue();
if (to == Short.TYPE)
return result.shortValue();
} else if (result != null) {
if (to == BigInteger.class)
return BigInteger.valueOf(result.longValue());
if (to == BigDecimal.class)
return BigDecimal.valueOf(result.doubleValue());
}
}
if (source instanceof Character) {
if (to == Character.TYPE)
return (char) source;
if (to == Integer.TYPE)
return (int) (char) source;
if (to == Long.TYPE)
return (long) (char) source;
if (to == Float.TYPE)
return (float) (char) source;
if (to == Double.TYPE)
return (double) (char) source;
}
return wrap(to).cast(source);
};
return first;
case ExpressionType.IsNull:
return first.andThen(r -> r == null);
case ExpressionType.IsNonNull:
return first.andThen(r -> r != null);
case ExpressionType.LogicalNot:
return normalize(not((Function) first));
case ExpressionType.Negate:
return (Function) negate((Function) first);
// case ExpressionType.UnaryPlus:
// return abs((Function extends Number, Object[]>) first);
default:
throw new IllegalArgumentException(ExpressionType.toString(e.getExpressionType()));
}
}
}