initial commit

This commit is contained in:
wea_ondara
2022-07-11 21:18:54 +02:00
commit 8bb2265abd
34 changed files with 2488 additions and 0 deletions

View File

@@ -0,0 +1,229 @@
package jef;
import jef.expressions.Expression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
public class DBSet<T extends Serializable> implements Queryable<T> {
private final String table;
public DBSet(String table) {
this.table = table;
}
@Override
public String getTableAlias() {
return String.valueOf((char) ('a' - 1));
}
@Override
public Expression getExpression() {
return new SelectExpression(List.of("*"), new TableExpression(table), "");
}
@Override
public String toString() {
return "SELECT * FROM `" + table + "`";
}
@Override
public Iterator<T> iterator() {
return null;
}
@Override
public Spliterator<T> spliterator() {
return null;
}
@Override
public boolean isParallel() {
return false;
}
@Override
public DBSet<T> sequential() {
return this;
}
@Override
public DBSet<T> parallel() {
return this;
}
@Override
public DBSet<T> unordered() {
return this;
}
@Override
public DBSet<T> onClose(Runnable runnable) {
return this;
}
@Override
public void close() {
}
//stream
// @Override
// public <R extends Serializable> Queryable<R> map(Function<? super T, ? extends R> function) {
// return null;
// }
//
// @Override
// public IntStream mapToInt(ToIntFunction<? super T> toIntFunction) {
// return null;
// }
//
// @Override
// public LongStream mapToLong(ToLongFunction<? super T> toLongFunction) {
// return null;
// }
//
// @Override
// public DoubleStream mapToDouble(ToDoubleFunction<? super T> toDoubleFunction) {
// return null;
// }
//
// @Override
// public <R extends Serializable> Queryable<R> flatMap(Function<? super T, ? extends Stream<? extends R>> function) {
// return null;
// }
//
// @Override
// public IntStream flatMapToInt(Function<? super T, ? extends IntStream> function) {
// return null;
// }
//
// @Override
// public LongStream flatMapToLong(Function<? super T, ? extends LongStream> function) {
// return null;
// }
//
// @Override
// public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> function) {
// return null;
// }
//
// @Override
// public DBSet<T> distinct() {
// return null;
// }
//
// @Override
// public DBSet<T> sorted() {
// return null;
// }
//
// @Override
// public DBSet<T> sorted(Comparator<? super T> comparator) {
// return null;
// }
//
// @Override
// public DBSet<T> peek(Consumer<? super T> consumer) {
// return null;
// }
//
// @Override
// public DBSet<T> limit(long l) {
// return null;
// }
//
// @Override
// public DBSet<T> skip(long l) {
// return null;
// }
//<editor-fold desc="terminating operations">
// @Override
// public void forEach(Consumer<? super T> consumer) {
// }
//
// @Override
// public void forEachOrdered(Consumer<? super T> consumer) {
// }
//
// @Override
// public Object[] toArray() {
// return new Object[0];
// }
//
// @Override
// public <A> A[] toArray(IntFunction<A[]> intFunction) {
// return null;
// }
//
// @Override
// public T reduce(T t, BinaryOperator<T> binaryOperator) {
// return null;
// }
//
// @Override
// public Optional<T> reduce(BinaryOperator<T> binaryOperator) {
// return Optional.empty();
// }
//
// @Override
// public <U> U reduce(U u, BiFunction<U, ? super T, U> biFunction, BinaryOperator<U> binaryOperator) {
// return null;
// }
//
// @Override
// public <R extends Serializable> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> biConsumer, BiConsumer<R, R> biConsumer1) {
// return null;
// }
//
// @Override
// public <R extends Serializable, A> R collect(Collector<? super T, A, R> collector) {
// return null;
// }
//
// @Override
// public Optional<T> min(Comparator<? super T> comparator) {
// return Optional.empty();
// }
//
// @Override
// public Optional<T> max(Comparator<? super T> comparator) {
// return Optional.empty();
// }
//
// @Override
// public long count() {
// return 0;
// }
//
// @Override
// public boolean anyMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return false;
// }
//
// @Override
// public boolean allMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return false;
// }
//
// @Override
// public boolean noneMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return false;
// }
//
// @Override
// public Optional<T> findFirst() {
// return Optional.empty();
// }
//
// @Override
// public Optional<T> findAny() {
// return Optional.empty();
// }
//</editor-fold>
}

View File

@@ -0,0 +1,181 @@
package jef;
import jef.expressions.Expression;
import jef.operations.FilterOp;
import jef.serializable.SerializablePredicate;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Spliterator;
public interface Queryable<T extends Serializable> {
//
String getTableAlias();
Expression getExpression();
String toString();
//stream functions
default Iterator<T> iterator() {
return null;
}
default Spliterator<T> spliterator() {
return null;
}
default boolean isParallel() {
return false;
}
default Queryable<T> sequential() {
return this;
}
default Queryable<T> parallel() {
return this;
}
default Queryable<T> unordered() {
return this;
}
default Queryable<T> onClose(Runnable runnable) {
return this;
}
default void close() {
}
//stream
default Queryable<T> filter(SerializablePredicate<? super T> predicate) {
return new FilterOp<T>(this, predicate);
}
// default <R extends Serializable> Queryable<R> map(Function<? super T, ? extends R> function) {
// return null;
// }
//
// default IntStream mapToInt(ToIntFunction<? super T> toIntFunction) {
// return null;
// }
//
// default LongStream mapToLong(ToLongFunction<? super T> toLongFunction) {
// return null;
// }
//
// default DoubleStream mapToDouble(ToDoubleFunction<? super T> toDoubleFunction) {
// return null;
// }
//
// default <R extends Serializable> Queryable<R> flatMap(Function<? super T, ? extends Stream<? extends R>> function) {
// return null;
// }
//
// default IntStream flatMapToInt(Function<? super T, ? extends IntStream> function) {
// return null;
// }
//
// default LongStream flatMapToLong(Function<? super T, ? extends LongStream> function) {
// return null;
// }
//
// default DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> function) {
// return null;
// }
//
// default Queryable<T> distinct() {
// return null;
// }
//
// default Queryable<T> sorted() {
// return null;
// }
//
// default Queryable<T> sorted(Comparator<? super T> comparator) {
// return null;
// }
//
// default Queryable<T> peek(Consumer<? super T> consumer) {
// return null;
// }
//
// default Queryable<T> limit(long l) {
// return null;
// }
//
// default Queryable<T> skip(long l) {
// return null;
// }
//<editor-fold desc="terminating operations">
// default void forEach(Consumer<? super T> consumer) {
// }
//
// default void forEachOrdered(Consumer<? super T> consumer) {
// }
//
// default Object[] toArray() {
// return new Object[0];
// }
//
// default <A> A[] toArray(IntFunction<A[]> intFunction) {
// return null;
// }
//
// default T reduce(T t, BinaryOperator<T> binaryOperator) {
// return null;
// }
//
// default Optional<T> reduce(BinaryOperator<T> binaryOperator) {
// return Optional.empty();
// }
//
// default <U> U reduce(U u, BiFunction<U, ? super T, U> biFunction, BinaryOperator<U> binaryOperator) {
// return null;
// }
//
// default <R extends Serializable> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> biConsumer, BiConsumer<R, R> biConsumer1) {
// return null;
// }
//
// default <R extends Serializable, A> R collect(Collector<? super T, A, R> collector) {
// return null;
// }
//
// default Optional<T> min(Comparator<? super T> comparator) {
// return Optional.empty();
// }
//
// default Optional<T> max(Comparator<? super T> comparator) {
// return Optional.empty();
// }
//
// default long count() {
// return 0;
// }
//
// default boolean anyMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return false;
// }
//
// default boolean allMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return false;
// }
//
// default boolean noneMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return false;
// }
//
// default Optional<T> findFirst() {
// return Optional.empty();
// }
//
// default Optional<T> findAny() {
// return Optional.empty();
// }
//</editor-fold>
}

View File

@@ -0,0 +1,229 @@
package jef;
import jef.expressions.Expression;
import jef.serializable.SerializablePredicate;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Spliterator;
public class QueryableProxy<T extends Serializable> implements Queryable<T> {
private final Queryable<T> delegate;
public QueryableProxy(Queryable<T> delegate) {
this.delegate = delegate;
}
@Override
public String getTableAlias() {
return delegate.getTableAlias();
}
@Override
public Expression getExpression() {
return delegate.getExpression();
}
@Override
public Iterator<T> iterator() {
return delegate.iterator();
}
@Override
public Spliterator<T> spliterator() {
return delegate.spliterator();
}
@Override
public boolean isParallel() {
return delegate.isParallel();
}
@Override
public Queryable<T> sequential() {
return delegate.sequential();
}
@Override
public Queryable<T> parallel() {
return delegate.parallel();
}
@Override
public Queryable<T> unordered() {
return delegate.unordered();
}
@Override
public Queryable<T> onClose(Runnable runnable) {
return delegate.onClose(runnable);
}
@Override
public void close() {
delegate.close();
}
//stream
@Override
public Queryable<T> filter(SerializablePredicate<? super T> predicate) {
return delegate.filter(predicate);
}
// @Override
// public <R extends Serializable> Queryable<R> map(Function<? super T, ? extends R> function) {
// return delegate.map(function);
// }
//
// @Override
// public IntStream mapToInt(ToIntFunction<? super T> toIntFunction) {
// return delegate.mapToInt(toIntFunction);
// }
//
// @Override
// public LongStream mapToLong(ToLongFunction<? super T> toLongFunction) {
// return delegate.mapToLong(toLongFunction);
// }
//
// @Override
// public DoubleStream mapToDouble(ToDoubleFunction<? super T> toDoubleFunction) {
// return delegate.mapToDouble(toDoubleFunction);
// }
//
// @Override
// public <R extends Serializable> Queryable<R> flatMap(Function<? super T, ? extends Stream<? extends R>> function) {
// return delegate.flatMap(function);
// }
//
// @Override
// public IntStream flatMapToInt(Function<? super T, ? extends IntStream> function) {
// return delegate.flatMapToInt(function);
// }
//
// @Override
// public LongStream flatMapToLong(Function<? super T, ? extends LongStream> function) {
// return delegate.flatMapToLong(function);
// }
//
// @Override
// public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> function) {
// return delegate.flatMapToDouble(function);
// }
//
// @Override
// public Queryable<T> distinct() {
// return delegate.distinct();
// }
//
// @Override
// public Queryable<T> sorted() {
// return delegate.sorted();
// }
//
// @Override
// public Queryable<T> sorted(Comparator<? super T> comparator) {
// return delegate.sorted(comparator);
// }
//
// @Override
// public Queryable<T> peek(Consumer<? super T> consumer) {
// return delegate.peek(consumer);
// }
//
// @Override
// public Queryable<T> limit(long l) {
// return delegate.limit(l);
// }
//
// @Override
// public Queryable<T> skip(long l) {
// return delegate.skip(l);
// }
//<editor-fold desc="terminating operations">
// @Override
// public void forEach(Consumer<? super T> consumer) {
// delegate.forEach(consumer);
// }
//
// @Override
// public void forEachOrdered(Consumer<? super T> consumer) {
// delegate.forEachOrdered(consumer);
// }
//
// @Override
// public Object[] toArray() {
// return delegate.toArray();
// }
//
// @Override
// public <A> A[] toArray(IntFunction<A[]> intFunction) {
// return delegate.toArray(intFunction);
// }
//
// @Override
// public T reduce(T t, BinaryOperator<T> binaryOperator) {
// return delegate.reduce(t, binaryOperator);
// }
//
// @Override
// public Optional<T> reduce(BinaryOperator<T> binaryOperator) {
// return delegate.reduce(binaryOperator);
// }
//
// @Override
// public <U> U reduce(U u, BiFunction<U, ? super T, U> biFunction, BinaryOperator<U> binaryOperator) {
// return delegate.reduce(u, biFunction, binaryOperator);
// }
//
// @Override
// public <R extends Serializable> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> biConsumer, BiConsumer<R, R> biConsumer1) {
// return delegate.collect(supplier, biConsumer, biConsumer1);
// }
//
// @Override
// public <R extends Serializable, A> R collect(Collector<? super T, A, R> collector) {
// return delegate.collect(collector);
// }
//
// @Override
// public Optional<T> min(Comparator<? super T> comparator) {
// return delegate.min(comparator);
// }
//
// @Override
// public Optional<T> max(Comparator<? super T> comparator) {
// return delegate.max(comparator);
// }
//
// @Override
// public long count() {
// return delegate.count();
// }
//
// @Override
// public boolean anyMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return delegate.anyMatch(SerializablePredicate);
// }
//
// @Override
// public boolean allMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return delegate.allMatch(SerializablePredicate);
// }
//
// @Override
// public boolean noneMatch(SerializablePredicate<? super T> SerializablePredicate) {
// return delegate.noneMatch(SerializablePredicate);
// }
//
// @Override
// public Optional<T> findFirst() {
// return delegate.findFirst();
// }
//
// @Override
// public Optional<T> findAny() {
// return delegate.findAny();
// }
//</editor-fold>
}

View File

@@ -0,0 +1,22 @@
package jef.asm;
public class AsmParseException extends Exception {
public AsmParseException() {
}
public AsmParseException(String message) {
super(message);
}
public AsmParseException(String message, Throwable cause) {
super(message, cause);
}
public AsmParseException(Throwable cause) {
super(cause);
}
public AsmParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -0,0 +1,32 @@
package jef.asm;
import jef.expressions.Expression;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import java.util.function.Consumer;
class FilterClassVisitor extends ClassVisitor {
private final int api;
private final String lambdaname;
private final Consumer<Expression> queryConsumer;
private final Object[] args;
protected FilterClassVisitor(int api, String lambdaname, Object[] args, Consumer<Expression> queryConsumer) {
super(api);
this.api = api;
this.lambdaname = lambdaname;
this.args = args;
this.queryConsumer = queryConsumer;
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
if (!name.equals(lambdaname)) {
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
System.out.println("found method name: " + name);
return new FilterMethodVisitor(api, descriptor, args, queryConsumer);
}
}

View File

@@ -0,0 +1,445 @@
package jef.asm;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.FieldExpression;
import jef.expressions.ParameterExpression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import jef.expressions.WhereExpression;
import lombok.ToString;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class FilterMethodVisitor extends MethodVisitor {
private Stack<Expression> varStack = new Stack<>();
private final String[] parameterClasses;
private final Object[] args;
private final Consumer<Expression> exprConsumer;
private Expression prediacteExpr;
protected FilterMethodVisitor(int api, String descriptor, Object[] args, Consumer<Expression> exprConsumer) {
super(api);
this.args = args;
this.exprConsumer = exprConsumer;
//parameters
var types = Type.getMethodType(descriptor).getArgumentTypes();
parameterClasses = new String[types.length];
for (int i = 0; i < types.length; i++) {
parameterClasses[i] = types[i].getClassName();
}
}
@Override
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
System.out.println("local var: " + name);
super.visitLocalVariable(name, descriptor, signature, start, end, index);
debugExpr();
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
System.out.println("field insn: " + ops.getOrDefault(opcode, "" + opcode) + ", " + owner + ", " + name + ", " + descriptor);
if (opcode == Opcodes.GETFIELD) {
var v = varStack.pop();
if (v instanceof ParameterExpression) {
// if (((Expression.ParameterExpression) v).isInput()) {
// varStack.push(new Expression.ConstantExpression(name));
// } else {
System.out.println("womp womp " + v);
throw new RuntimeException("field insn: unsupported GETFIELD op");
// }
} else if (v instanceof ConstantExpression) {
varStack.push(new FieldExpression(name));
} else {
throw new RuntimeException("field insn: unsupported GETFIELD op");
}
} else {
throw new RuntimeException("field insn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode));
}
super.visitFieldInsn(opcode, owner, name, descriptor);
debugExpr();
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
System.out.println("method insn: " + ops.getOrDefault(opcode, "" + opcode) + ", " + owner + ", " + name + ", " + descriptor);
if (opcode == Opcodes.INVOKESTATIC) {
//ignore boxed primitive types
var boxedPrimitiveClasses = Set.of("java/lang/Boolean", "java/lang/Integer", "java/lang/Long", "java/lang/Float", "java/lang/Double");
if (boxedPrimitiveClasses.contains(owner)) {
//do nothing
} else {
//do something
throw new RuntimeException("method insn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode));
}
} else if (opcode == Opcodes.INVOKEINTERFACE) {
try {
if (name.equals("contains")
&& owner.startsWith("java/util/")
&& Collection.class.isAssignableFrom(Class.forName(owner.replace("/", ".")))) {
var element = varStack.pop();
var collection = varStack.pop();
// System.out.println("element: " + element);
// System.out.println("collection: " + collection);
varStack.push(new BinaryExpression(element, collection, BinaryExpression.Operator.IN));
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("method insn: ", e);
}
} else {
throw new RuntimeException("method insn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode));
}
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
debugExpr();
}
@Override
public void visitVarInsn(int opcode, int varIndex) {
System.out.println("var insn: " + ops.getOrDefault(opcode, "" + opcode) + ", " + varIndex);
if (opcode == Opcodes.ALOAD) {
if (varIndex == parameterClasses.length - 1) {
varStack.push(new ConstantExpression("predicate param"));
} else {
varStack.push(new ParameterExpression(varIndex, args[varIndex], varIndex == parameterClasses.length - 1));
}
} else {
throw new RuntimeException("var insn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode));
}
super.visitVarInsn(opcode, varIndex);
debugExpr();
}
@Override
public void visitInsn(int opcode) {
System.out.println("insn: " + ops.getOrDefault(opcode, "" + opcode));
if (opcode == Opcodes.ICONST_1) {
varStack.push(ConstantExpression.I1);
} else if (opcode == Opcodes.ICONST_0) {
varStack.push(ConstantExpression.I0);
} else if (opcode == Opcodes.IRETURN) {
//collapse conditions
for (int i = condStack.size() - 1; i >= 0; i--) {
condStack.get(i).e1 = varStack.pop();
varStack = condStack.get(i).varStack;
evalCond(condStack.get(i));
}
// condStack.clear();
prediacteExpr = varStack.pop();
} else {
throw new RuntimeException("insn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode));
}
// if (!mpgotoconds.isEmpty()) {
// var e1 = varStack.pop();
// for (int i = mpgotoconds.size() - 1; i >= 0; i--) {
// var cond = mpgotoconds.get(i);
// cond.e1 = e1;
//// for (int j = 0; j < condStack.size() && condStack.get(j) != cond; j++) {
//// condStack.get(j).e1 = e1;
//// }
// condStack.remove(cond);
// varStack = cond.varStack;
// evalCond(cond);
// }
// mpgotoconds = new ArrayList<>();
// }
super.visitInsn(opcode);
debugExpr();
}
@ToString
class Cond {
final int opcode;
final Label condTarget;
Label gotoTarget;
final Stack<Expression> varStack;
Expression e1;
Expression e2;
public Cond(int opcode, Label condTarget, Stack<Expression> varStack) {
this.opcode = opcode;
this.condTarget = condTarget;
this.varStack = varStack;
}
}
private LinkedList<Cond> condStack = new LinkedList<>();
@Override
public void visitJumpInsn(int opcode, Label label) {
System.out.println("jump insn: " + ops.getOrDefault(opcode, "" + opcode) + ", " + label);
switch (opcode) {
case Opcodes.IFEQ:
case Opcodes.IFNE:
case Opcodes.IF_ICMPNE:
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLT:
handleLextLabel();
condStack.add(new Cond(opcode, label, varStack));
varStack = new Stack<>();
System.out.println("jump new stack");
break;
case Opcodes.GOTO:
handleLextLabel();
System.out.println("goto new stack");
condStack.getLast().gotoTarget = label;
condStack.getLast().e1 = varStack.pop();
varStack = new Stack<>();
break;
default: {
throw new RuntimeException("jump insn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode));
}
}
// int IFEQ = 153; // visitJumpInsn
// int IFNE = 154; // -
// int IFLT = 155; // -
// int IFGE = 156; // -
// int IFGT = 157; // -
// int IFLE = 158; // -
// int IF_ICMPEQ = 159; // -
// int IF_ICMPNE = 160; // -
// int IF_ICMPLT = 161; // -
// int IF_ICMPGE = 162; // -
// int IF_ICMPGT = 163; // -
// int IF_ICMPLE = 164; // -
// int IF_ACMPEQ = 165; // -
// int IF_ACMPNE = 166; // -
// int GOTO = 167; // -
// int JSR = 168; // -
// int RET = 169; // visitVarInsn
super.visitJumpInsn(opcode, label);
debugExpr();
}
List<Cond> nextLabelConds = new ArrayList<>();
private void handleLextLabel() {
if (!nextLabelConds.isEmpty()) {
var e1 = varStack.peek();
for (int i = 0; i < nextLabelConds.size(); i++) {
// for (int i = nextLabelConds.size() - 1; i >= 0; i--) {
var cond = nextLabelConds.get(i);
cond.e2 = e1;
// for (int j = 0; j < condStack.size() && condStack.get(j) != cond; j++) {
// condStack.get(j).e1 = e1;
// }
// condStack.remove(cond);
// varStack = cond.varStack;
// evalCond(cond);
}
nextLabelConds = new ArrayList<>();
}
}
@Override
public void visitLabel(Label label) {
System.out.println("label: " + label);
handleLextLabel();
// System.out.println("------>");
// System.out.println("condstack: " + condStack);
List<Cond> conds = condStack.stream().filter(e -> e.gotoTarget != null && e.gotoTarget.equals(label)).toList();
nextLabelConds = condStack.stream().filter(e -> e.gotoTarget == null && e.condTarget.equals(label)).toList();
// List<Cond> conds = condStack.stream().filter(e -> e.gotoTarget != null
// ? e.gotoTarget.equals(label)
// : e.condTarget.equals(label)//bad
// ).toList();
if (!conds.isEmpty()) {
Expression e2 = varStack.pop();
for (int i = conds.size() - 1; i >= 0; i--) {
var cond = conds.get(i);
// System.out.println("condstack pop " + cond);
cond.e2 = e2;
//also set e2 for all outer conds
// for (int j = 0; j < condStack.size() && condStack.get(j) != cond; j++) {
// condStack.get(j).e2 = e2;
// }
condStack.remove(cond);
varStack = cond.varStack;
evalCond(cond);
}
}
// System.out.println("<------");
super.visitLabel(label);
debugExpr();
}
Label collapseAfterNextInstruction = null;
private void evalCond(Cond cond) {
var right = varStack.pop();
// System.out.println("left: " + left);
// System.out.println("cond.e1: " + cond.e1);
// System.out.println("cond.e2: " + cond.e2);
boolean wrapInTernary = cond.e1 != ConstantExpression.I1 || cond.e2 != ConstantExpression.I0;
// boolean wrapInTernary = true;
Expression expr;
// 153, "IFEQ",
// 154, "IFNE",
// 155, "IFLT",
// 156, "IFGE",
// 157, "IFGT",
// 158, "IFLE",
switch (cond.opcode) {
case Opcodes.IFEQ:
expr = right;
// expr = new Expression.TernaryExpression(right, cond.e1, cond.e2);
break;
case Opcodes.IFNE:
expr = right;
// expr = new Expression.TernaryExpression(right, cond.e1, cond.e2);
// if (expr instanceof Expression.TernaryExpression texpr
// && texpr.getWhenFalse() == Expression.ConstantExpression.I0) {
// expr = new Expression.BinaryExpression(texpr.getCond(), texpr.getWhenTrue(), "AND");
// }
// wrapInTernary = false;
expr = new UnaryExpression(expr, UnaryExpression.Operator.NOT);
break;
default: {
var left = varStack.pop();
switch (cond.opcode) {
case Opcodes.IF_ICMPEQ:
expr = new BinaryExpression(left, right, BinaryExpression.Operator.NE);
break;
case Opcodes.IF_ICMPNE:
expr = new BinaryExpression(left, right, BinaryExpression.Operator.EQ);
break;
case Opcodes.IF_ICMPLT:
expr = new BinaryExpression(left, right, BinaryExpression.Operator.GE);
break;
case Opcodes.IF_ICMPGE:
expr = new BinaryExpression(left, right, BinaryExpression.Operator.LT);
break;
case Opcodes.IF_ICMPGT:
expr = new BinaryExpression(left, right, BinaryExpression.Operator.LE);
break;
case Opcodes.IF_ICMPLE:
expr = new BinaryExpression(left, right, BinaryExpression.Operator.GT);
break;
default:
throw new RuntimeException("jump insn: unsupported opcode " + ops.getOrDefault(cond.opcode, "" + cond.opcode));
}
}
}
if (wrapInTernary) {
expr = new TernaryExpression(expr, cond.e1, cond.e2);
}
varStack.push(expr);
debugExpr();
}
@Override
public void visitAttribute(Attribute attribute) {
System.out.println("attr: " + attribute);
super.visitAttribute(attribute);
debugExpr();
}
@Override
public void visitLdcInsn(Object value) {
System.out.println("ldc: " + value);
super.visitLdcInsn(value);
debugExpr();
}
@Override
public void visitEnd() {
System.out.println("end");
super.visitEnd();
exprConsumer.accept(prediacteExpr);
}
@Override
public void visitIntInsn(int opcode, int operand) {
System.out.println("intinsn: " + ops.getOrDefault(opcode, "" + opcode) + ", " + operand);
switch (opcode) {
case Opcodes.SIPUSH:
varStack.push(new ConstantExpression(operand));
break;
default:
throw new RuntimeException("intinsn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode));
}
super.visitIntInsn(opcode, operand);
debugExpr();
}
private Map<Integer, String> ops = createOpsMap(
3, "ICONST_0",
4, "ICONST_1",
17, "SIPUSH",
25, "ALOAD",
//jmp
153, "IFEQ",
154, "IFNE",
155, "IFLT",
156, "IFGE",
157, "IFGT",
158, "IFLE",
159, "IF_ICMPEQ",
160, "IF_ICMPNE",
161, "IF_ICMPLT",
162, "IF_ICMPGE",
163, "IF_ICMPGT",
164, "IF_ICMPLE",
165, "IF_ACMPEQ",
166, "IF_ACMPNE",
167, "GOTO",
168, "JSR",
169, "RET",
172, "IRETURN",
//field
180, "GETFIELD",
181, "PUTFIELD",
182, "INVOKEVIRTUAL",
183, "INVOKESPECIAL",
184, "INVOKESTATIC",
185, "INVOKEINTERFACE",
186, "INVOKEDYNAMIC"
);
private static Map<Integer, String> createOpsMap(Object... o) {
return IntStream.range(0, o.length / 2).boxed().collect(Collectors.toMap(i -> (int) o[i * 2], i -> (String) o[i * 2 + 1]));
}
private void debugExpr() {
if (!varStack.isEmpty()) {
System.out.println("-------------------> " + new WhereExpression(new SelectExpression(List.of("*"), new TableExpression("dummy"), ""), varStack.peek()));
}
}
}

View File

@@ -0,0 +1,60 @@
package jef.asm;
import jef.expressions.Expression;
import jef.serializable.SerializablePredicate;
import lombok.Getter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import java.io.InputStream;
import java.lang.invoke.SerializedLambda;
import java.util.stream.IntStream;
@Getter
public class PredicateParser {
private final SerializablePredicate<?> predicate;
public PredicateParser(SerializablePredicate<?> predicate) {
this.predicate = predicate;
}
public Expression parse() throws AsmParseException {
try {
return parseExpression();
} catch (Exception e) {
throw new AsmParseException("PredicateParser: failed to parse expression", e);
}
}
private Expression parseExpression() throws Exception {
var cls = predicate.getClass();
var loader = cls.getClassLoader();
InputStream is;
// System.out.println(cls);
// System.out.println(cls.getName());
if (cls.getName().contains("$$Lambda$")) {
// System.out.println(cls.getName().split("\\$\\$")[0].replace(".", "/") + ".class");
is = loader.getResourceAsStream(cls.getName().split("\\$\\$")[0].replace(".", "/") + ".class");
} else {
// System.out.println(cls.getName().replace(".", "/") + ".class");
is = loader.getResourceAsStream(cls.getName().replace(".", "/") + ".class");
}
var x = cls.getDeclaredMethod("writeReplace");
// System.out.println(x);
x.setAccessible(true);
var serlambda = (SerializedLambda) x.invoke(predicate);
Object[] args = IntStream.range(0, serlambda.getCapturedArgCount()).mapToObj(serlambda::getCapturedArg).toArray();
// System.out.println(serlambda);
var lambdaname = serlambda.getImplMethodName();
// System.out.println(lambdaname);
var expr = new Expression[1];
var cr = new ClassReader(is);
var visiter = new FilterClassVisitor(Opcodes.ASM9, lambdaname, args, e -> expr[0] = e);
cr.accept(visiter, 0);
return expr[0];
}
}

View File

@@ -0,0 +1,33 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public class AndExpression implements Expression {
private final List<Expression> exprs;
public AndExpression(Expression... exprs) {
this.exprs = List.of(exprs);
}
@Override
public Type getType() {
return Type.AND;
}
@Override
public String toString() {
return exprs.stream().map(e -> {
if (e instanceof OrExpression) {
return "(" + e + ")";
} else {
return e.toString();
}
}).collect(Collectors.joining(" AND "));
}
}

View File

@@ -0,0 +1,60 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Map;
@Getter
@AllArgsConstructor
public class BinaryExpression implements Expression {
private final Expression left;
private final Expression right;
private final Operator operator;
@Override
public Type getType() {
return Type.BINARY;
}
@Override
public String toString() {
return left + " " + operator + " " + right;
}
@AllArgsConstructor
public enum Operator {
EQ("="),
NE("<>"),
LT("<"),
LE("<="),
GT(">"),
GE(">="),
// OR("OR"),
// AND("AND"),
IN("IN"),
;
private final String string;
@Override
public String toString() {
return string;
}
private static final Map<Operator, Operator> INVERSION = Map.of(
EQ, NE,
NE, EQ,
LT, GE,
GE, LT,
LE, GT,
GT, LE);
public Operator invert() {
return INVERSION.get(this);
}
public boolean isInvertible() {
return INVERSION.containsKey(this);
}
}
}

View File

@@ -0,0 +1,23 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class ConstantExpression implements Expression {
public static final jef.expressions.ConstantExpression I0 = new jef.expressions.ConstantExpression(0);
public static final jef.expressions.ConstantExpression I1 = new jef.expressions.ConstantExpression(1);
protected final Object value;
@Override
public Type getType() {
return Type.CONSTANT;
}
@Override
public String toString() {
return value.toString();
}
}

View File

@@ -0,0 +1,19 @@
package jef.expressions;
public interface Expression {
Type getType();
public enum Type {
AND,
BINARY,
CONSTANT,
FIELD,
OR,
PARAMETER,
SELECT,
TABLE,
TERNARY,
UNARY,
WHERE,
}
}

View File

@@ -0,0 +1,23 @@
package jef.expressions;
import lombok.Getter;
@Getter
public class FieldExpression extends ConstantExpression implements Expression {
private final String name;
public FieldExpression(String name) {
super(name);
this.name = name;
}
@Override
public Type getType() {
return Type.FIELD;
}
@Override
public String toString() {
return name;
}
}

View File

@@ -0,0 +1,27 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public class OrExpression implements Expression {
private final List<Expression> exprs;
public OrExpression(Expression... exprs) {
this.exprs = List.of(exprs);
}
@Override
public Type getType() {
return Type.OR;
}
@Override
public String toString() {
return exprs.stream().map(Expression::toString).collect(Collectors.joining(" OR "));
}
}

View File

@@ -0,0 +1,35 @@
package jef.expressions;
import lombok.Getter;
import java.util.Collection;
import java.util.stream.Collectors;
@Getter
public class ParameterExpression extends ConstantExpression implements Expression {
private final int index;
private final boolean isInput;
public ParameterExpression(int index, Object value, boolean isInput) {
super(value);
this.index = index;
this.isInput = isInput;
}
@Override
public Type getType() {
return Type.PARAMETER;
}
@Override
public String toString() {
if (isInput) {
return "param #" + index;
} else if (this.value == null) {
return "null";
} else if (this.value instanceof Collection) {
return "(" + ((Collection) this.value).stream().map(Object::toString).collect(Collectors.joining(",")) + ")";
}
return value.toString();
}
}

View File

@@ -0,0 +1,27 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public class SelectExpression implements Expression {
private final List<String> fields;
private final Expression from;
private final String fromAlias;
@Override
public Type getType() {
return Type.SELECT;
}
@Override
public String toString() {
return "SELECT " + fields.stream().map(e -> e.equals("*") ? e : "`" + e + "`").collect(Collectors.joining(", ")) + " FROM "
+ (!(from instanceof TableExpression) ? "(" + from + ")" : from)
+ ((fromAlias == null || fromAlias.isBlank()) ? "" : " " + fromAlias);
}
}

View File

@@ -0,0 +1,28 @@
package jef.expressions;
import lombok.Getter;
@Getter
public class TableExpression extends ConstantExpression {
private final String name;
public TableExpression(String name) {
super(name);
this.name = name;
}
@Override
public Type getType() {
return Type.TABLE;
}
@Override
public String getValue() {
return (String) super.getValue();
}
@Override
public String toString() {
return "`" + super.toString() + "`";
}
}

View File

@@ -0,0 +1,24 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class TernaryExpression implements Expression {
private final Expression cond;
private final Expression whenTrue;
private final Expression whenFalse;
@Override
public Type getType() {
return Type.TERNARY;
}
@Override
public String toString() {
return cond
+ " ? " + (!(whenTrue instanceof ConstantExpression) ? "(" + whenTrue + ")" : whenTrue)
+ " : " + (!(whenFalse instanceof ConstantExpression) ? "(" + whenFalse + ")" : whenFalse);
}
}

View File

@@ -0,0 +1,35 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class UnaryExpression implements Expression {
private final Expression expr;
private final Operator operator;
@Override
public Type getType() {
return Type.UNARY;
}
@Override
public String toString() {
return operator + " (" + expr + ")";
}
@AllArgsConstructor
public enum Operator {
NOT("NOT"),
// NEG("-"),
// POS("+"),
;
private final String string;
@Override
public String toString() {
return string;
}
}
}

View File

@@ -0,0 +1,21 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class WhereExpression implements Expression {
private Expression queryable;
private Expression where;
@Override
public Type getType() {
return Type.WHERE;
}
@Override
public String toString() {
return queryable + " WHERE " + where;
}
}

View File

@@ -0,0 +1,89 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.FieldExpression;
import jef.expressions.OrExpression;
import jef.expressions.ParameterExpression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import jef.expressions.WhereExpression;
import java.util.ArrayList;
public abstract class ExpressionModifier {
public Expression modify(Expression expr) {
return switch (expr.getType()) {
case AND -> modifyAnd((AndExpression) expr);
case BINARY -> modifyBinary((BinaryExpression) expr);
case CONSTANT -> modifyConstant((ConstantExpression) expr);
case FIELD -> modifyField((FieldExpression) expr);
case OR -> modifyOr((OrExpression) expr);
case PARAMETER -> modifyParameter((ParameterExpression) expr);
case SELECT -> modifySelect((SelectExpression) expr);
case TABLE -> modifyTable((TableExpression) expr);
case TERNARY -> modifyTernary((TernaryExpression) expr);
case UNARY -> modifyUnary((UnaryExpression) expr);
case WHERE -> modifyWhere((WhereExpression) expr);
default -> throw new IllegalStateException();
};
}
public Expression modifyAnd(AndExpression expr) {
var exprs = new ArrayList<Expression>(expr.getExprs().size());
for (Expression e : expr.getExprs()) {
exprs.add(modify(e));
}
return new AndExpression(exprs);
}
public Expression modifyBinary(BinaryExpression expr) {
return new BinaryExpression(modify(expr.getLeft()), modify(expr.getRight()), expr.getOperator());
}
public Expression modifyConstant(ConstantExpression expr) {
return expr;
}
public Expression modifyField(FieldExpression expr) {
return expr;
}
public Expression modifyOr(OrExpression expr) {
var exprs = new ArrayList<Expression>(expr.getExprs().size());
for (Expression e : expr.getExprs()) {
exprs.add(modify(e));
}
return new OrExpression(exprs);
}
public Expression modifyParameter(ParameterExpression expr) {
return expr;
}
public Expression modifySelect(SelectExpression expr) {
return new SelectExpression(expr.getFields(), modify(expr.getFrom()), expr.getFromAlias());
}
public Expression modifyTable(TableExpression expr) {
return expr;
}
public Expression modifyTernary(TernaryExpression expr) {
return new TernaryExpression(modify(expr.getCond()), modify(expr.getWhenTrue()), modify(expr.getWhenFalse()));
}
public Expression modifyUnary(UnaryExpression expr) {
return new UnaryExpression(modify(expr.getExpr()), expr.getOperator());
}
public Expression modifyWhere(WhereExpression expr) {
return new WhereExpression(modify(expr.getQueryable()), modify(expr.getWhere()));
}
}

View File

@@ -0,0 +1,102 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.OrExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import java.util.ArrayList;
public class ExpressionOptimizer extends ExpressionModifier {
@Override
public Expression modifyAnd(AndExpression expr) {
var ands = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ands
for (Expression e : expr.getExprs()) {
if (e.getType() == Expression.Type.AND) {
ands.addAll(((AndExpression) e).getExprs());
} else {
ands.add(e);
}
}
ands.replaceAll(this::modify);
// x && false -> false
for (Expression e : ands) {
if (e == ConstantExpression.I0) {
return ConstantExpression.I0;
}
}
while (ands.remove(ConstantExpression.I1)) ;
return new AndExpression(ands);
}
@Override
public Expression modifyOr(OrExpression expr) {
var ors = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ors
for (Expression e : expr.getExprs()) {
if (e.getType() == Expression.Type.OR) {
ors.addAll(((OrExpression) e).getExprs());
} else {
ors.add(e);
}
}
ors.replaceAll(this::modify);
// x || true -> true
for (Expression e : ors) {
if (e == ConstantExpression.I1) {
return ConstantExpression.I1;
}
}
while (ors.remove(ConstantExpression.I0)) ;
return new OrExpression(ors);
}
@Override
public Expression modifyTernary(TernaryExpression expr) {
if (expr.getWhenFalse() == ConstantExpression.I1 && expr.getWhenFalse() == ConstantExpression.I0) {
//x ? 1 : 0 -> x
return modify(expr.getCond());
} else if (expr.getWhenFalse() == ConstantExpression.I0 && expr.getWhenFalse() == ConstantExpression.I1) {
//x ? 0 : 1 -> !x
return modify(new UnaryExpression(expr.getCond(), UnaryExpression.Operator.NOT));
} else if (expr.getWhenFalse() == ConstantExpression.I0) {
//x ? y : 0 -> x && y
return modify(new AndExpression(expr.getCond(), expr.getWhenTrue()));
} else if (expr.getWhenFalse() == ConstantExpression.I1) {
//x ? y : 1 -> !x or y
return modify(new OrExpression(new UnaryExpression(expr.getCond(), UnaryExpression.Operator.NOT), expr.getWhenTrue()));
} else if (expr.getWhenTrue() instanceof TernaryExpression t && expr.getWhenFalse() == t.getWhenFalse()) {
// x ? (y ? z : u) : u -> (x && y) ? z : u
return new TernaryExpression(new AndExpression(expr.getCond(), t.getCond()), t.getWhenTrue(), t.getWhenFalse());
} else {
return super.modifyTernary(expr);
}
}
@Override
public Expression modifyUnary(UnaryExpression expr) {
if (expr.getExpr() instanceof UnaryExpression u
&& expr.getOperator() == u.getOperator()
&& expr.getOperator() == UnaryExpression.Operator.NOT) {
//!!x -> x
return modify(u.getExpr());
} else if (expr.getExpr() instanceof BinaryExpression b
&& expr.getOperator() == UnaryExpression.Operator.NOT
&& b.getOperator().isInvertible()) {
//!(a < b) -> a >= b
return new BinaryExpression(b.getLeft(), b.getRight(), b.getOperator().invert());
} else {
return super.modifyUnary(expr);
}
}
}

View File

@@ -0,0 +1,108 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.OrExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import java.util.ArrayList;
public class ExpressionOptimizerBottomUp extends ExpressionModifier {
@Override
public Expression modifyAnd(AndExpression expr) {
var andsOpt = expr.getExprs().stream().map(this::modify).toList();
var ands = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ands
for (Expression e : andsOpt) {
if (e.getType() == Expression.Type.AND) {
ands.addAll(((AndExpression) e).getExprs());
} else {
ands.add(e);
}
}
ands.replaceAll(this::modify);
// x && false -> false
for (Expression e : ands) {
if (e == ConstantExpression.I0) {
return ConstantExpression.I0;
}
}
while (ands.remove(ConstantExpression.I1)) ;
return new AndExpression(ands);
}
@Override
public Expression modifyOr(OrExpression expr) {
var orsOpt = expr.getExprs().stream().map(this::modify).toList();
var ors = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ors
for (Expression e : orsOpt) {
if (e.getType() == Expression.Type.OR) {
ors.addAll(((OrExpression) e).getExprs());
} else {
ors.add(e);
}
}
ors.replaceAll(this::modify);
// x || true -> true
for (Expression e : ors) {
if (e == ConstantExpression.I1) {
return ConstantExpression.I1;
}
}
while (ors.remove(ConstantExpression.I0)) ;
return new OrExpression(ors);
}
@Override
public Expression modifyTernary(TernaryExpression expr) {
var cond = modify(expr.getCond());
var whenTrue = modify(expr.getWhenTrue());
var whenFalse = modify(expr.getWhenFalse());
if (whenTrue == ConstantExpression.I1 && whenFalse == ConstantExpression.I0) {
//x ? 1 : 0 -> x
return cond;
} else if (whenTrue == ConstantExpression.I0 && whenFalse == ConstantExpression.I1) {
//x ? 0 : 1 -> !x
return modify(new UnaryExpression(cond, UnaryExpression.Operator.NOT));
} else if (whenFalse == ConstantExpression.I0) {
//x ? y : 0 -> x && y
return modify(new AndExpression(cond, whenTrue));
} else if (whenFalse == ConstantExpression.I1) {
//x ? y : 1 -> !x or y
return modify(new OrExpression(new UnaryExpression(cond, UnaryExpression.Operator.NOT), whenTrue));
} else if (whenTrue instanceof TernaryExpression t && whenFalse == t.getWhenFalse()) {
// x ? (y ? z : u) : u -> (x && y) ? z : u
return new TernaryExpression(new AndExpression(cond, t.getCond()), t.getWhenTrue(), t.getWhenFalse());
} else {
return super.modifyTernary(expr);
}
}
@Override
public Expression modifyUnary(UnaryExpression expr) {
var inner = modify(expr.getExpr());
if (inner instanceof UnaryExpression u
&& expr.getOperator() == u.getOperator()
&& expr.getOperator() == UnaryExpression.Operator.NOT) {
//!!x -> x
return modify(u.getExpr());
} else if (inner instanceof BinaryExpression b
&& expr.getOperator() == UnaryExpression.Operator.NOT
&& b.getOperator().isInvertible()) {
//!(a < b) -> a >= b
return new BinaryExpression(b.getLeft(), b.getRight(), b.getOperator().invert());
} else {
return super.modifyUnary(expr);
}
}
}

View File

@@ -0,0 +1,19 @@
package jef.expressions.modifier;
import jef.expressions.Expression;
import jef.expressions.FieldExpression;
public class TableAliasInjector extends ExpressionModifier {
private final String tableAlias;
private final String prefix;
public TableAliasInjector(String tableAlias) {
this.tableAlias = tableAlias;
this.prefix = (tableAlias == null || tableAlias.isBlank()) ? "" : tableAlias + ".";
}
@Override
public Expression modifyField(FieldExpression expr) {
return new FieldExpression(prefix + expr.getName());
}
}

View File

@@ -0,0 +1,20 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.OrExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import java.util.ArrayList;
public class TernaryRewriter extends ExpressionModifier {
@Override
public Expression modifyTernary(TernaryExpression expr) {
return new OrExpression(new AndExpression(expr.getCond(), expr.getWhenTrue()),
new AndExpression(new UnaryExpression(expr.getCond(), UnaryExpression.Operator.NOT), expr.getWhenFalse()));
// return new OrExpression(new AndExpression(expr.getCond(), expr.getWhenTrue()), expr.getWhenFalse());
}
}

View File

@@ -0,0 +1,128 @@
package jef.expressions.visitors;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.FieldExpression;
import jef.expressions.OrExpression;
import jef.expressions.ParameterExpression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import jef.expressions.WhereExpression;
import java.util.Collection;
import java.util.stream.Collectors;
public class DebugExpressionVisitor extends ExpressionVisitor {
private int indent = 0;
@Override
public void visitAnd(AndExpression expr) {
for (int i = 0; i < expr.getExprs().size(); i++) {
indent++;
visit(expr.getExprs().get(i));
indent--;
if (i + 1 < expr.getExprs().size())
System.out.println(i() + "AND");
}
}
@Override
public void visitBinary(BinaryExpression expr) {
indent++;
visit(expr.getLeft());
indent--;
System.out.println(i() + expr.getOperator());
indent++;
visit(expr.getRight());
indent--;
}
@Override
public void visitConstant(ConstantExpression expr) {
System.out.println(i() + expr.getValue());
}
@Override
public void visitField(FieldExpression expr) {
System.out.println(i() + expr.getName());
}
@Override
public void visitOr(OrExpression expr) {
for (int i = 0; i < expr.getExprs().size(); i++) {
indent++;
visit(expr.getExprs().get(i));
indent--;
if (i + 1 < expr.getExprs().size())
System.out.println(i() + "OR");
}
}
@Override
public void visitParameter(ParameterExpression expr) {
if (expr.getValue() instanceof Collection c) {
System.out.println(i() + c.stream().map(String::valueOf).collect(Collectors.joining(",")));
} else {
System.out.println(i() + expr.getValue());
}
}
@Override
public void visitSelect(SelectExpression expr) {
var table = expr.getFrom() instanceof TableExpression;
var tableName = table ? ((TableExpression) expr.getFrom()).getName() : null;
var tableAlias = (expr.getFromAlias() == null || expr.getFromAlias().isBlank()) ? "" : " " + expr.getFromAlias();
System.out.println(i() + "SELECT " + expr.getFields().stream().collect(Collectors.joining(", "))
+ " FROM" + (!table ? " (" : tableName + " " + tableAlias));
if (!table) {
indent++;
visit(expr.getFrom());
indent--;
System.out.println(i() + ")" + tableAlias);
}
}
@Override
public void visitTable(TableExpression expr) {
System.out.println(i() + expr.getValue());
}
@Override
public void visitTernary(TernaryExpression expr) {
indent++;
visit(expr.getCond());
indent--;
System.out.println(i() + "?");
indent++;
visit(expr.getWhenTrue());
indent--;
System.out.println(i() + ":");
indent++;
visit(expr.getWhenFalse());
indent--;
}
@Override
public void visitUnary(UnaryExpression expr) {
System.out.println(i() + expr.getOperator());
indent++;
visit(expr.getExpr());
indent--;
}
@Override
public void visitWhere(WhereExpression expr) {
visit(expr.getQueryable());
System.out.println(i() + "WHERE");
indent++;
visit(expr.getWhere());
indent--;
}
private String i() {
return " ".repeat(indent);
}
}

View File

@@ -0,0 +1,81 @@
package jef.expressions.visitors;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.FieldExpression;
import jef.expressions.OrExpression;
import jef.expressions.ParameterExpression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import jef.expressions.WhereExpression;
public abstract class ExpressionVisitor {
public void visit(Expression expr) {
switch (expr.getType()) {
case AND -> visitAnd((AndExpression) expr);
case BINARY -> visitBinary((BinaryExpression) expr);
case CONSTANT -> visitConstant((ConstantExpression) expr);
case FIELD -> visitField((FieldExpression) expr);
case OR -> visitOr((OrExpression) expr);
case PARAMETER -> visitParameter((ParameterExpression) expr);
case SELECT -> visitSelect((SelectExpression) expr);
case TABLE -> visitTable((TableExpression) expr);
case TERNARY -> visitTernary((TernaryExpression) expr);
case UNARY -> visitUnary((UnaryExpression) expr);
case WHERE -> visitWhere((WhereExpression) expr);
default -> throw new IllegalStateException();
}
}
public void visitAnd(AndExpression expr) {
for (Expression e : expr.getExprs()) {
visit(e);
}
}
public void visitBinary(BinaryExpression expr) {
visit(expr.getLeft());
visit(expr.getRight());
}
public void visitConstant(ConstantExpression expr) {
}
public void visitField(FieldExpression expr) {
}
public void visitOr(OrExpression expr) {
for (Expression e : expr.getExprs()) {
visit(e);
}
}
public void visitParameter(ParameterExpression expr) {
}
public void visitSelect(SelectExpression expr) {
visit(expr.getFrom());
}
public void visitTable(TableExpression expr) {
}
public void visitTernary(TernaryExpression expr) {
visit(expr.getCond());
visit(expr.getWhenTrue());
visit(expr.getWhenFalse());
}
public void visitUnary(UnaryExpression expr) {
visit(expr.getExpr());
}
public void visitWhere(WhereExpression expr) {
visit(expr.getQueryable());
visit(expr.getWhere());
}
}

View File

@@ -0,0 +1,58 @@
package jef.operations;
import jef.Queryable;
import jef.asm.AsmParseException;
import jef.asm.PredicateParser;
import jef.expressions.Expression;
import jef.expressions.SelectExpression;
import jef.expressions.WhereExpression;
import jef.expressions.modifier.ExpressionOptimizer;
import jef.expressions.modifier.ExpressionOptimizerBottomUp;
import jef.expressions.modifier.TableAliasInjector;
import jef.expressions.modifier.TernaryRewriter;
import jef.serializable.SerializablePredicate;
import java.io.Serializable;
import java.util.List;
import java.util.function.Predicate;
public class FilterOp<T extends Serializable> implements Queryable<T>, Operation<T> {
private final Queryable<T> queryable;
private final Predicate<? super T> predicate;
private final Expression predicateExpr;
public FilterOp(Queryable<T> queryable, SerializablePredicate<? super T> predicate) {
this.queryable = queryable;
this.predicate = predicate;
var parser = new PredicateParser(predicate);
Expression expr;
try {
expr = parser.parse();
} catch (AsmParseException e) {
throw new RuntimeException(e);
}
System.out.println(expr);
expr = new TernaryRewriter().modify(expr);
System.out.println(expr);
expr = new ExpressionOptimizer().modify(expr);
// expr = new ExpressionOptimizerBottomUp().modify(expr);
expr = new TableAliasInjector(getTableAlias()).modify(expr);
this.predicateExpr = expr;
}
@Override
public String getTableAlias() {
return String.valueOf((char) (queryable.getTableAlias().charAt(0) + (char) 1));
}
@Override
public Expression getExpression() {
return new WhereExpression(new SelectExpression(List.of("*"), queryable.getExpression(), getTableAlias()), predicateExpr);
}
@Override
public String toString() {
return getExpression().toString();
}
}

View File

@@ -0,0 +1,9 @@
package jef.operations;
import jef.Queryable;
import java.io.Serializable;
public interface Operation<T extends Serializable> extends Queryable<T> {
}

View File

@@ -0,0 +1,7 @@
package jef.serializable;
import java.io.Serializable;
import java.util.function.Function;
public interface SerializableFunction<T, R> extends Function<T, R>, Serializable {
}

View File

@@ -0,0 +1,7 @@
package jef.serializable;
import java.io.Serializable;
import java.util.function.Predicate;
public interface SerializablePredicate<T> extends Predicate<T>, Serializable {
}