mirror of
https://github.com/cincheo/jsweet.git
synced 2025-12-15 15:29:22 +00:00
171 lines
4.8 KiB
Java
171 lines
4.8 KiB
Java
package source.api;
|
|
|
|
import static jsweet.util.Lang.$export;
|
|
|
|
import java.util.Deque;
|
|
import java.util.LinkedList;
|
|
import java.util.Stack;
|
|
import java.util.function.BinaryOperator;
|
|
import java.util.function.UnaryOperator;
|
|
|
|
public class ExpressionBuilderTest2 {
|
|
|
|
public static class ExpressionBuilder<T> {
|
|
|
|
private final int defaultLevel;
|
|
private final BinaryOperator<T>[] operations;
|
|
private String[] operationStrings;
|
|
|
|
private final Stack<UnaryOperator<T>> unary = new Stack<>();
|
|
private final ExpressionBuilder<T> parent;
|
|
private final Stack<Integer> levelHistory;
|
|
private final Deque<T>[] elements;
|
|
private int currentLevel;
|
|
private boolean operationDeclared;
|
|
|
|
// public ExpressionBuilder(int defaultLevel, BinaryOperator<T>...
|
|
// precedence) {
|
|
// this(null, defaultLevel, precedence);
|
|
// }
|
|
|
|
private ExpressionBuilder(ExpressionBuilder<T> parent, int defaultLevel, BinaryOperator<T>... precedence) {
|
|
this.operations = precedence;
|
|
this.parent = parent;
|
|
this.defaultLevel = defaultLevel;
|
|
this.levelHistory = new Stack<>();
|
|
this.currentLevel = 0;
|
|
this.operationDeclared = true;
|
|
this.elements = new LinkedList[operations.length];
|
|
for (int i = 0; i < elements.length; ++i) {
|
|
this.elements[i] = new LinkedList<>();
|
|
}
|
|
}
|
|
|
|
public ExpressionBuilder<T> add(T element) {
|
|
if (element == null) {
|
|
throw new NullPointerException();
|
|
}
|
|
if (!operationDeclared) {
|
|
if (defaultLevel < 0) {
|
|
throw new IllegalArgumentException("two elements in row");
|
|
} else {
|
|
insertOperation(defaultLevel);
|
|
}
|
|
}
|
|
while (!unary.isEmpty()) {
|
|
element = unary.pop().apply(element);
|
|
}
|
|
elements[currentLevel].addLast(element);
|
|
operationDeclared = false;
|
|
|
|
return this;
|
|
}
|
|
|
|
private T evaluate(int level) {
|
|
Deque<T> q = elements[level];
|
|
BinaryOperator<T> op = operations[level];
|
|
T result = q.pollFirst();
|
|
while (!q.isEmpty()) {
|
|
result = op.apply(result, q.pollFirst());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private void insertOperation(int i) {
|
|
while (currentLevel > i) {
|
|
T result = evaluate(currentLevel);
|
|
currentLevel = levelHistory.pop();
|
|
elements[currentLevel].addLast(result);
|
|
}
|
|
if (i > currentLevel) {
|
|
elements[i].addLast(elements[currentLevel].pollLast());
|
|
levelHistory.add(currentLevel);
|
|
}
|
|
currentLevel = i;
|
|
operationDeclared = true;
|
|
}
|
|
|
|
public ExpressionBuilder<T> operation(UnaryOperator<T> op) {
|
|
unary.add(op);
|
|
return this;
|
|
}
|
|
|
|
public ExpressionBuilder<T> operation(int number) {
|
|
if (operationDeclared) {
|
|
throw new IllegalStateException("cannot insert two operations in row");
|
|
}
|
|
if (number < 0 || number >= operations.length) {
|
|
throw new ArrayIndexOutOfBoundsException("unknown operation number");
|
|
}
|
|
insertOperation(number);
|
|
return this;
|
|
}
|
|
|
|
public ExpressionBuilder<T> push() {
|
|
return new ExpressionBuilder<>(this, defaultLevel, operations);
|
|
}
|
|
|
|
public ExpressionBuilder<T> pop() {
|
|
if (parent == null) {
|
|
throw new IllegalStateException("non-matched brackets detected");
|
|
} else {
|
|
parent.add(build());
|
|
return parent;
|
|
}
|
|
}
|
|
|
|
public T build() {
|
|
while (true) {
|
|
T result = evaluate(currentLevel);
|
|
if (levelHistory.isEmpty()) {
|
|
return result;
|
|
}
|
|
currentLevel = levelHistory.pop();
|
|
elements[currentLevel].addLast(result);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class Function {
|
|
|
|
final String name;
|
|
final UnaryOperator<Double> func;
|
|
|
|
private Function(String name, UnaryOperator<Double> func) {
|
|
this.name = name;
|
|
this.func = func;
|
|
}
|
|
|
|
public UnaryOperator<Double> getFunc() {
|
|
return func;
|
|
}
|
|
}
|
|
|
|
public static Function[] functions = { new Function("sin", Math::sin), new Function("cos", Math::cos), new Function("tg", Math::tan),
|
|
new Function("ctg", x -> 1 / Math.tan(x)), new Function("exp", Math::exp), new Function("sqrt", Math::sqrt), new Function("ln", Math::log),
|
|
new Function("abs", Math::abs) };
|
|
|
|
public static void main(String[] args) {
|
|
$export("result2", testCalc());
|
|
}
|
|
|
|
public static int testCalc() {
|
|
ExpressionBuilder<Double> builder;
|
|
builder = new ExpressionBuilder<>(null, -1, (a, b) -> a + b, // 0
|
|
(a, b) -> a - b, // 1
|
|
(a, b) -> a * b, // 2
|
|
(a, b) -> a / b, // 3
|
|
(a, b) -> Math.pow(a, b) // 4
|
|
);
|
|
|
|
// equation is "1-8*9+(5^(1+(2/2))*2^2)+abs(0-cos(0))"
|
|
Double r1 = builder.add(1.).operation(1).add((double) 8f).operation(2).add(9.0).operation(0).push()
|
|
.add(5.000000000000000000000000000000000000000000000000000000000000).operation(4).push().add((double) 1.000f).operation(0).push().add(+2.0)
|
|
.operation(3).add(2.).pop().pop().operation(2).add((double) (int) (float) 2).operation(4).add((double) 2).pop().operation(0)
|
|
.operation(functions[functions.length - 1].func).push().add(-0.0).operation(1).operation(functions[1].getFunc()).add(+0.0).pop().build();
|
|
|
|
// result is 30
|
|
return ((int) (double) r1);
|
|
}
|
|
}
|