package com.kreative.paint.material.shape;
public abstract class Expression {
public abstract double eval(Bindings bindings);
public abstract Expression optimize();
public static class Value extends Expression {
public final double value;
public Value(double value) {
this.value = value;
}
@Override
public double eval(Bindings bindings) {
return value;
}
@Override
public Expression optimize() {
return this;
}
}
public static class Binding extends Expression {
public final String key;
public Binding(String key) {
this.key = key;
}
@Override
public double eval(Bindings bindings) {
return bindings.get(key);
}
@Override
public Expression optimize() {
return this;
}
}
public static class Unary extends Expression {
public final Function function;
public final Expression argument;
public Unary(Function function, Expression argument) {
this.function = function;
this.argument = argument;
}
@Override
public double eval(Bindings bindings) {
return function.eval(argument.eval(bindings));
}
@Override
public Expression optimize() {
Expression a = argument.optimize();
if (a instanceof Value) {
double v = ((Value)a).value;
v = function.eval(v);
return new Value(v);
} else {
return new Unary(function, a);
}
}
}
public static class Binary extends Expression {
public final Operator operator;
public final Expression left;
public final Expression right;
public Binary(Operator operator, Expression left, Expression right) {
this.operator = operator;
this.left = left;
this.right = right;
}
@Override
public double eval(Bindings bindings) {
return operator.eval(left.eval(bindings), right.eval(bindings));
}
@Override
public Expression optimize() {
Expression l = left.optimize();
Expression r = right.optimize();
if (l instanceof Value && r instanceof Value) {
double lv = ((Value)l).value;
double rv = ((Value)r).value;
double v = operator.eval(lv, rv);
return new Value(v);
} else {
return new Binary(operator, l, r);
}
}
}
public static class Conditional extends Expression {
public final Expression ifexpr;
public final Expression thenexpr;
public final Expression elseexpr;
public Conditional(Expression ifexpr, Expression thenexpr, Expression elseexpr) {
this.ifexpr = ifexpr;
this.thenexpr = thenexpr;
this.elseexpr = elseexpr;
}
@Override
public double eval(Bindings bindings) {
return ((ifexpr.eval(bindings) != 0) ? thenexpr : elseexpr).eval(bindings);
}
@Override
public Expression optimize() {
Expression ie = ifexpr.optimize();
Expression te = thenexpr.optimize();
Expression ee = elseexpr.optimize();
if (ie instanceof Value) {
return (((Value)ie).value != 0) ? te : ee;
} else {
return new Conditional(ie, te, ee);
}
}
}
}