diff options
| author | bjculkin <bjculkin@WIT-136XG42.wvu-ad.wvu.edu> | 2017-03-01 10:13:41 -0500 |
|---|---|---|
| committer | bjculkin <bjculkin@WIT-136XG42.wvu-ad.wvu.edu> | 2017-03-01 10:13:41 -0500 |
| commit | 36e0911c6ec27707a74f0b90b1052a16374243ea (patch) | |
| tree | 08ca7723b0c0a6a7f3ce1830c59e5211e46168b8 /dice-lang/src/bjc/dicelang/Evaluator.java | |
| parent | 6ed83507953322c35a456d64d89f8f4f9cb0a6a1 (diff) | |
Package reorganization
Diffstat (limited to 'dice-lang/src/bjc/dicelang/Evaluator.java')
| -rw-r--r-- | dice-lang/src/bjc/dicelang/Evaluator.java | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/dice-lang/src/bjc/dicelang/Evaluator.java b/dice-lang/src/bjc/dicelang/Evaluator.java new file mode 100644 index 0000000..7b9bc83 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Evaluator.java @@ -0,0 +1,424 @@ +package bjc.dicelang; + +import bjc.dicelang.dice.CompoundDie; +import bjc.dicelang.dice.MathDie; +import bjc.dicelang.dice.SimpleDie; +import bjc.dicelang.dice.SimpleDieList; +import bjc.utils.data.ITree; +import bjc.utils.data.SingleIterator; +import bjc.utils.data.Tree; +import bjc.utils.data.TopDownTransformIterator; +import bjc.utils.data.TopDownTransformResult; + +import static bjc.dicelang.Errors.ErrorKey.*; +import static bjc.dicelang.EvaluatorResult.Type.*; + +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.function.Consumer; + +public class Evaluator { + private static enum CoerceSteps { + INTEGER, FLOAT; + } + + private static class Context { + public Consumer<Iterator<ITree<Node>>> thunk; + + public boolean isDebug; + } + + private static Node FAIL() { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE)); + } + + private static Node FAIL(ITree<Node> orig) { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); + } + + private static Node FAIL(Node orig) { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); + } + + private static Node FAIL(EvaluatorResult res) { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, new Node(Node.Type.RESULT, res))); + } + + private DiceLangEngine eng; + + public Evaluator(DiceLangEngine en) { + eng = en; + } + + public EvaluatorResult evaluate(ITree<Node> comm) { + Context ctx = new Context(); + + ctx.isDebug = false; + ctx.thunk = (itr) -> { + // Deliberately finish the iterator, but ignore results. It's only for stepwise evaluation + // but we don't know if stepping the iterator causes something to happen + while(itr.hasNext()) itr.next(); + }; + + return comm.topDownTransform(this::pickEvaluationType, + (node) -> this.evaluateNode(node, ctx)).getHead().resultVal; + } + + // @FIXME Something's broken with step evaluation + public Iterator<ITree<Node>> stepDebug(ITree<Node> comm) { + Context ctx = new Context(); + + ctx.isDebug = true; + + return new TopDownTransformIterator<>(this::pickEvaluationType, (node, thnk) -> { + ctx.thunk = thnk; + + return this.evaluateNode(node, ctx); + }, comm); + } + + private TopDownTransformResult pickEvaluationType(Node nd) { + switch(nd.type) { + case UNARYOP: + switch(nd.operatorType) { + case COERCE: + return TopDownTransformResult.RTRANSFORM; + default: + return TopDownTransformResult.PUSHDOWN; + } + default: + return TopDownTransformResult.PUSHDOWN; + } + } + + private ITree<Node> evaluateNode(ITree<Node> ast, Context ctx) { + switch(ast.getHead().type) { + case UNARYOP: + return evaluateUnaryOp(ast, ctx); + case BINOP: + return evaluateBinaryOp(ast, ctx); + case TOKREF: + return evaluateTokenRef(ast.getHead().tokenVal, ctx); + case ROOT: + return ast.getChild(ast.getChildrenCount() - 1); + case RESULT: + return ast; + default: + Errors.inst.printError(EK_EVAL_INVNODE, ast.getHead().type.toString()); + return new Tree<>(FAIL(ast)); + } + } + + private ITree<Node> evaluateUnaryOp(ITree<Node> ast, Context ctx) { + switch(ast.getHead().operatorType) { + case COERCE: + if(ast.getChildrenCount() != 1) { + Errors.inst.printError(EK_EVAL_UNUNARY, Integer.toString(ast.getChildrenCount())); + return new Tree<>(FAIL(ast)); + } + + ITree<Node> toCoerce = ast.getChild(0); + ITree<Node> retVal = new Tree<>(toCoerce.getHead()); + Deque<ITree<Node>> children = new LinkedList<>(); + + CoerceSteps curLevel = CoerceSteps.INTEGER; + + for(int i = 0; i < toCoerce.getChildrenCount(); i++) { + ITree<Node> child = toCoerce.getChild(i); + ITree<Node> nChild = null; + + if(ctx.isDebug) { + Iterator<ITree<Node>> nd = stepDebug(child); + + for(; nd.hasNext(); nChild = nd.next()) { + ctx.thunk.accept(new SingleIterator<>(child)); + } + } else { + nChild = new Tree<>(new Node(Node.Type.RESULT, evaluate(child))); + + if(nChild != null) ctx.thunk.accept(new SingleIterator<>(nChild)); + } + + Node childNode = nChild.getHead(); + EvaluatorResult res = childNode.resultVal; + + if(res.type == FLOAT) curLevel = CoerceSteps.FLOAT; + + children.add(nChild); + } + + for(ITree<Node> child : children) { + Node nd = child.getHead(); + EvaluatorResult res = nd.resultVal; + + switch(res.type) { + case INT: + if(curLevel == CoerceSteps.FLOAT) { + nd.resultVal = new EvaluatorResult(FLOAT, (double)res.intVal); + } + default: + // Do nothing + break; + } + + retVal.addChild(child); + } + + return retVal; + default: + Errors.inst.printError(EK_EVAL_INVUNARY, ast.getHead().operatorType.toString()); + return new Tree<>(FAIL(ast)); + } + } + + private ITree<Node> evaluateBinaryOp(ITree<Node> ast, Context ctx) { + Token.Type binOp = ast.getHead().operatorType; + + if(ast.getChildrenCount() != 2) { + Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()), ast.toString()); + + return new Tree<>(FAIL(ast)); + } + + ITree<Node> left = ast.getChild(0); + ITree<Node> right = ast.getChild(1); + + switch(binOp) { + case ADD: + case SUBTRACT: + case MULTIPLY: + case DIVIDE: + case IDIVIDE: + return evaluateMathBinary(binOp, + left.getHead().resultVal, right.getHead().resultVal, + ctx); + case DICEGROUP: + case DICECONCAT: + case DICELIST: + return evaluateDiceBinary(binOp, + left.getHead().resultVal, right.getHead().resultVal, + ctx); + default: + Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString()); + return new Tree<>(FAIL(ast)); + } + } + + private ITree<Node> evaluateDiceBinary(Token.Type op, + EvaluatorResult left, EvaluatorResult right, Context ctx) { + EvaluatorResult res = null; + + switch(op) { + case DICEGROUP: + if(left.type == DICE && !left.diceVal.isList) { + if(right.type == DICE && !right.diceVal.isList) { + res = new EvaluatorResult(DICE, + new SimpleDie(left.diceVal.scalar, right.diceVal.scalar)); + } else if (right.type == INT) { + res = new EvaluatorResult(DICE, new SimpleDie(left.diceVal.scalar, right.intVal)); + } else { + Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); + return new Tree<>(FAIL(right)); + } + } else if(left.type == INT) { + if(right.type == DICE && !right.diceVal.isList) { + res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.diceVal.scalar)); + } else if (right.type == INT) { + res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.intVal)); + } else { + Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); + return new Tree<>(FAIL(right)); + } + } else { + Errors.inst.printError(EK_EVAL_INVDGROUP, left.type.toString()); + return new Tree<>(FAIL(left)); + } + case DICECONCAT: + if(left.type != DICE || left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString()); + return new Tree<>(FAIL(left)); + } else if(right.type != DICE || right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString()); + return new Tree<>(FAIL(right)); + } else { + res = new EvaluatorResult(DICE, + new CompoundDie(left.diceVal.scalar, right.diceVal.scalar)); + } + break; + case DICELIST: + if(left.type != DICE || left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString()); + return new Tree<>(FAIL(left)); + } else if(right.type != DICE || right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString()); + return new Tree<>(FAIL(right)); + } else { + res = new EvaluatorResult(DICE, + new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); + } + break; + default: + Errors.inst.printError(EK_EVAL_UNDICE, op.toString()); + return new Tree<>(FAIL()); + } + + return new Tree<>(new Node(Node.Type.RESULT, res)); + } + + private ITree<Node> evaluateMathBinary(Token.Type op, + EvaluatorResult left, EvaluatorResult right, Context ctx) { + if(left.type == STRING || right.type == STRING) { + Errors.inst.printError(EK_EVAL_STRINGMATH); + return new Tree<>(FAIL()); + } else if(left.type == FAILURE || right.type == FAILURE) { + return new Tree<>(FAIL()); + } else if(left.type == INT && right.type != INT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(left.type == FLOAT && right.type != FLOAT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(left.type == DICE && right.type != DICE) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(right.type == INT && left.type != INT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); + } else if(right.type == FLOAT && left.type != FLOAT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); + } else if(right.type == DICE && left.type != DICE) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); + } + + EvaluatorResult res = null; + + switch(op) { + case ADD: + if(left.type == INT) { + res = new EvaluatorResult(INT, left.intVal + right.intVal); + } else if(left.type == DICE) { + if(left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); + return new Tree<>(FAIL(left)); + } else if(right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); + return new Tree<>(FAIL(right)); + } + + res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.ADD, + left.diceVal.scalar, right.diceVal.scalar)); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal + right.floatVal); + } + break; + case SUBTRACT: + if(left.type == INT) { + res = new EvaluatorResult(INT, left.intVal - right.intVal); + } else if(left.type == DICE) { + if(left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); + return new Tree<>(FAIL(left)); + } else if(right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); + return new Tree<>(FAIL(right)); + } + + res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.SUBTRACT, + left.diceVal.scalar, right.diceVal.scalar)); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal - right.floatVal); + } + break; + case MULTIPLY: + if(left.type == INT) { + res = new EvaluatorResult(INT, left.intVal * right.intVal); + } else if(left.type == DICE) { + if(left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); + return new Tree<>(FAIL(left)); + } else if(right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); + return new Tree<>(FAIL(right)); + } + + res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.MULTIPLY, + left.diceVal.scalar, right.diceVal.scalar)); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal * right.floatVal); + } + break; + case DIVIDE: + if(left.type == INT) { + if(right.intVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(FLOAT, left.intVal / right.intVal); + } + } else if(left.type == FLOAT) { + if(right.floatVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal / right.floatVal); + } + } else { + Errors.inst.printError(EK_EVAL_DIVDICE); + return new Tree<>(FAIL()); + } + break; + case IDIVIDE: + if(left.type == INT) { + if(right.intVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(INT, (int) (left.intVal / right.intVal)); + } + } else if(left.type == FLOAT) { + if(right.floatVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(INT, (int) (left.floatVal / right.floatVal)); + } + } else { + Errors.inst.printError(EK_EVAL_DIVDICE); + return new Tree<>(FAIL()); + } + break; + default: + Errors.inst.printError(EK_EVAL_UNMATH, op.toString()); + return new Tree<>(FAIL()); + } + + return new Tree<>(new Node(Node.Type.RESULT, res)); + } + + private ITree<Node> evaluateTokenRef(Token tk, Context ctx) { + EvaluatorResult res = null; + + switch(tk.type) { + case INT_LIT: + res = new EvaluatorResult(INT, tk.intValue); + break; + case FLOAT_LIT: + res = new EvaluatorResult(FLOAT, tk.floatValue); + break; + case DICE_LIT: + res = new EvaluatorResult(DICE, tk.diceValue); + break; + case STRING_LIT: + res = new EvaluatorResult(STRING, eng.stringLits.get((int)(tk.intValue))); + break; + default: + Errors.inst.printError(EK_EVAL_UNTOK, tk.type.toString()); + res = new EvaluatorResult(FAILURE); + } + + return new Tree<>(new Node(Node.Type.RESULT, res)); + } +} |
