diff options
| author | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-09 16:02:10 -0300 |
|---|---|---|
| committer | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-09 16:02:10 -0300 |
| commit | f028ea6dc555fc5192a96b00b8e96e90dbf6de55 (patch) | |
| tree | 4b2a28ecbeb30095b50e6e9e8ac8b98fa8ddc79e /dice-lang/src/bjc/dicelang/Evaluator.java | |
| parent | be4675f9512060aa85b1e0a4f223208b51b55812 (diff) | |
TODO tagging
Diffstat (limited to 'dice-lang/src/bjc/dicelang/Evaluator.java')
| -rw-r--r-- | dice-lang/src/bjc/dicelang/Evaluator.java | 172 |
1 files changed, 90 insertions, 82 deletions
diff --git a/dice-lang/src/bjc/dicelang/Evaluator.java b/dice-lang/src/bjc/dicelang/Evaluator.java index 0a583c8..10f7651 100644 --- a/dice-lang/src/bjc/dicelang/Evaluator.java +++ b/dice-lang/src/bjc/dicelang/Evaluator.java @@ -1,28 +1,5 @@ package bjc.dicelang; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_DIVDICE; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_DIVZERO; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVBIN; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVDCREATE; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVDGROUP; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVDICE; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVNODE; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVSTRING; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVUNARY; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_MISMATH; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_STRINGMATH; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNBIN; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNDICE; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNMATH; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNSTRING; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNTOK; -import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNUNARY; -import static bjc.dicelang.EvaluatorResult.Type.DICE; -import static bjc.dicelang.EvaluatorResult.Type.FAILURE; -import static bjc.dicelang.EvaluatorResult.Type.FLOAT; -import static bjc.dicelang.EvaluatorResult.Type.INT; -import static bjc.dicelang.EvaluatorResult.Type.STRING; - import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; @@ -40,6 +17,18 @@ import bjc.utils.data.TopDownTransformIterator; import bjc.utils.data.TopDownTransformResult; import bjc.utils.data.Tree; +import static bjc.dicelang.Errors.ErrorKey.*; +import static bjc.dicelang.EvaluatorResult.Type.DICE; +import static bjc.dicelang.EvaluatorResult.Type.FAILURE; +import static bjc.dicelang.EvaluatorResult.Type.FLOAT; +import static bjc.dicelang.EvaluatorResult.Type.INT; +import static bjc.dicelang.EvaluatorResult.Type.STRING; + + +/* @TODO 10/09/17 Ben Culkin :EvaluatorSplit + * Type/sanity checking should be moved into a seperate stage, not part of + * evaluation. + */ /** * Evaluate DiceLang ASTs * @@ -47,19 +36,26 @@ import bjc.utils.data.Tree; * */ public class Evaluator { + /* The steps of type coercion. */ private static enum CoerceSteps { INTEGER, DOUBLE; } + /* The context during iteration. */ private static class Context { public Consumer<Iterator<ITree<Node>>> thunk; public boolean isDebug; public Context() { + /* Empty block. */ } } + /* @TODO 10/09/17 Ben Culkin :NodeFAIL + * These methods should be moved to Node. + */ + /* Create a failing node. */ private static Node FAIL() { return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE)); } @@ -68,7 +64,6 @@ public class Evaluator { return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); } - @SuppressWarnings("unused") private static Node FAIL(final Node orig) { return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); } @@ -78,6 +73,7 @@ public class Evaluator { return new Node(Node.Type.RESULT, eres); } + /* The engine we are connected to. */ private final DiceLangEngine eng; /** @@ -103,25 +99,26 @@ public class Evaluator { 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. - * + * if stepping the iterator has side effects. */ while (itr.hasNext()) { itr.next(); } }; - final ITree<Node> res = comm.topDownTransform(this::pickEvaluationType, - node -> this.evaluateNode(node, ctx)); + /* The result. */ + final ITree<Node> res = comm.topDownTransform( + this::pickEvaluationType, + node -> this.evaluateNode(node, ctx)); return res.getHead().resultVal; } - // FIXME Something's broken with step evaluation - @SuppressWarnings("javadoc") + /* @NOTE + * This is broken until stepwise top-down transforms are fixed. */ public Iterator<ITree<Node>> stepDebug(final ITree<Node> comm) { final Context ctx = new Context(); @@ -140,8 +137,8 @@ public class Evaluator { case UNARYOP: switch (nd.operatorType) { case COERCE: + /* Coerce does special things to the tree. */ return TopDownTransformResult.RTRANSFORM; - default: return TopDownTransformResult.PUSHDOWN; } @@ -156,19 +153,14 @@ public class Evaluator { 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)); @@ -177,31 +169,45 @@ public class Evaluator { /* Evaluate a unary operator. */ private ITree<Node> evaluateUnaryOp(final ITree<Node> ast, final Context ctx) { + /* Unary operators only take one operand. */ if (ast.getChildrenCount() != 1) { Errors.inst.printError(EK_EVAL_UNUNARY, Integer.toString(ast.getChildrenCount())); return new Tree<>(FAIL(ast)); } switch (ast.getHead().operatorType) { - /* @TODO move coercing to its own class */ + /* + * @TODO 10/09/17 Ben Culkin :CoerceRefactor :EvaluatorSplit + * Coercing should be moved to its own class, or at the + * very least its own method. When the evaluator splits, + * this node type'll be handled exclusively by the + * type-checker. + * + * Coerce also needs to be able to coerce things to + * dice and ratios (whenever they get added). + */ case COERCE: final ITree<Node> toCoerce = ast.getChild(0); final ITree<Node> retVal = new Tree<>(toCoerce.getHead()); final Deque<ITree<Node>> children = new LinkedList<>(); + /* The current type we are coercing to. */ CoerceSteps curLevel = CoerceSteps.INTEGER; for (int i = 0; i < toCoerce.getChildrenCount(); i++) { final ITree<Node> child = toCoerce.getChild(i); ITree<Node> nChild = null; + /* Tell our thunk we processed a node. */ if (ctx.isDebug) { + /* Evaluate each step of the child. */ final Iterator<ITree<Node>> nd = stepDebug(child); for (; nd.hasNext(); nChild = nd.next()) { ctx.thunk.accept(new SingleIterator<>(child)); } } else { + /* Evaluate the child. */ nChild = new Tree<>(new Node(Node.Type.RESULT, evaluate(child))); ctx.thunk.accept(new SingleIterator<>(nChild)); @@ -215,6 +221,7 @@ public class Evaluator { final Node childNode = nChild.getHead(); final EvaluatorResult res = childNode.resultVal; + /* Move up to coercing to a float. */ if (res.type == FLOAT) { curLevel = CoerceSteps.DOUBLE; } @@ -228,14 +235,12 @@ public class Evaluator { switch (res.type) { case INT: + /* Coerce ints to doubles if we need to. */ if (curLevel == CoerceSteps.DOUBLE) { nd.resultVal = new EvaluatorResult(FLOAT, (double) res.intVal); } - default: - /* - * Do nothing - */ + /* Do nothing */ break; } @@ -243,7 +248,6 @@ public class Evaluator { } return retVal; - case DICESCALAR: final EvaluatorResult opr = ast.getChild(0).getHead().resultVal; @@ -251,9 +255,8 @@ public class Evaluator { Errors.inst.printError(EK_EVAL_INVDCREATE, opr.type.toString()); } - return new Tree<>(new Node(Node.Type.RESULT, - new EvaluatorResult(DICE, new ScalarDie(opr.intVal)))); - + final EvaluatorResult sres = new EvaluatorResult(DICE, new ScalarDie(opr.intVal)); + return new Tree<>(new Node(Node.Type.RESULT, sres)); case DICEFUDGE: final EvaluatorResult oprn = ast.getChild(0).getHead().resultVal; @@ -261,57 +264,56 @@ public class Evaluator { Errors.inst.printError(EK_EVAL_INVDCREATE, oprn.type.toString()); } - return new Tree<>(new Node(Node.Type.RESULT, - new EvaluatorResult(DICE, new FudgeDie(oprn.intVal)))); - + final EvaluatorResult fres = new EvaluatorResult(DICE, new ScalarDie(oprn.intVal)); + return new Tree<>(new Node(Node.Type.RESULT, fres)); default: Errors.inst.printError(EK_EVAL_INVUNARY, ast.getHead().operatorType.toString()); return new Tree<>(FAIL(ast)); } } + /* Evaluate a binary operator. */ private static ITree<Node> evaluateBinaryOp(final ITree<Node> ast, final Context ctx) { final Token.Type binOp = ast.getHead().operatorType; + /* Binary operators always have two children. */ if (ast.getChildrenCount() != 2) { Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()), - ast.toString()); + ast.toString()); return new Tree<>(FAIL(ast)); } - final ITree<Node> left = ast.getChild(0); + final ITree<Node> left = ast.getChild(0); final ITree<Node> right = ast.getChild(1); + final EvaluatorResult leftRes = left.getHead().resultVal; + final EvaluatorResult rightRes = right.getHead().resultVal; + switch (binOp) { case ADD: case SUBTRACT: case MULTIPLY: case DIVIDE: case IDIVIDE: - return evaluateMathBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, - ctx); - + return evaluateMathBinary(binOp, leftRes, rightRes, ctx); case DICEGROUP: case DICECONCAT: case DICELIST: - return evaluateDiceBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, - ctx); - + return evaluateDiceBinary(binOp, leftRes, rightRes, ctx); case STRCAT: case STRREP: - return evaluateStringBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, - ctx); - + return evaluateStringBinary(binOp, leftRes, rightRes, ctx); default: Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString()); return new Tree<>(FAIL(ast)); } } + /* Evaluate a binary operator on strings. */ private static ITree<Node> evaluateStringBinary(final Token.Type op, - final EvaluatorResult left, - final EvaluatorResult right, final Context ctx) { + final EvaluatorResult left, + final EvaluatorResult right, final Context ctx) { if (left.type != STRING) { Errors.inst.printError(EK_EVAL_INVSTRING, left.type.toString()); return new Tree<>(FAIL(left)); @@ -327,9 +329,9 @@ public class Evaluator { } final String strung = right.stringVal; - return new Tree<>(new Node(Node.Type.RESULT, new EvaluatorResult(STRING, - strang + strung))); + final EvaluatorResult cres = new EvaluatorResult(STRING, strang + strung); + return new Tree<>(new Node(Node.Type.RESULT, cres)); case STRREP: if (right.type != INT) { Errors.inst.printError(EK_EVAL_INVSTRING, right.type.toString()); @@ -344,27 +346,35 @@ public class Evaluator { } return new Tree<>(new Node(Node.Type.RESULT, new EvaluatorResult(STRING, res))); - default: Errors.inst.printError(EK_EVAL_UNSTRING, op.toString()); return new Tree<>(FAIL()); } } + /* Evaluate dice binary operators. */ private static ITree<Node> evaluateDiceBinary(final Token.Type op, - final EvaluatorResult left, - final EvaluatorResult right, final Context ctx) { + final EvaluatorResult left, + final EvaluatorResult right, final Context ctx) { EvaluatorResult res = null; switch (op) { + /* + * @TODO 10/09/17 Ben Culkin :DiceSimplify + * Figure out some way to simplify this sort of + * thing. + */ 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)); + Die simple = new SimpleDie( + left.diceVal.scalar, + right.diceVal.scalar); + + res = new EvaluatorResult(DICE, simple); } else if (right.type == INT) { res = new EvaluatorResult(DICE, - new SimpleDie(left.diceVal.scalar, right.intVal)); + new SimpleDie(left.diceVal.scalar, right.intVal)); } else { Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); return new Tree<>(FAIL(right)); @@ -372,7 +382,7 @@ public class Evaluator { } else if (left.type == INT) { if (right.type == DICE && !right.diceVal.isList) { res = new EvaluatorResult(DICE, - new SimpleDie(left.intVal, right.diceVal.scalar)); + new SimpleDie(left.intVal, right.diceVal.scalar)); } else if (right.type == INT) { res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.intVal)); } else { @@ -393,7 +403,7 @@ public class Evaluator { return new Tree<>(FAIL(right)); } else { res = new EvaluatorResult(DICE, - new CompoundDie(left.diceVal.scalar, right.diceVal.scalar)); + new CompoundDie(left.diceVal.scalar, right.diceVal.scalar)); } break; @@ -407,7 +417,7 @@ public class Evaluator { return new Tree<>(FAIL(right)); } else { res = new EvaluatorResult(DICE, - new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); + new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); } break; @@ -420,9 +430,10 @@ public class Evaluator { return new Tree<>(new Node(Node.Type.RESULT, res)); } + /* Evaluate a binary math operator. */ private static ITree<Node> evaluateMathBinary(final Token.Type op, - final EvaluatorResult left, - final EvaluatorResult right, final Context ctx) { + final EvaluatorResult left, + final EvaluatorResult right, final Context ctx) { if (left.type == STRING || right.type == STRING) { Errors.inst.printError(EK_EVAL_STRINGMATH); return new Tree<>(FAIL()); @@ -464,7 +475,7 @@ public class Evaluator { } res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.ADD, left.diceVal.scalar, - right.diceVal.scalar)); + right.diceVal.scalar)); } else { res = new EvaluatorResult(FLOAT, left.floatVal + right.floatVal); } @@ -484,7 +495,7 @@ public class Evaluator { } res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.SUBTRACT, - left.diceVal.scalar, right.diceVal.scalar)); + left.diceVal.scalar, right.diceVal.scalar)); } else { res = new EvaluatorResult(FLOAT, left.floatVal - right.floatVal); } @@ -504,7 +515,7 @@ public class Evaluator { } res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.MULTIPLY, - left.diceVal.scalar, right.diceVal.scalar)); + left.diceVal.scalar, right.diceVal.scalar)); } else { res = new EvaluatorResult(FLOAT, left.floatVal * right.floatVal); } @@ -563,6 +574,7 @@ public class Evaluator { return new Tree<>(new Node(Node.Type.RESULT, res)); } + /* Evaluate a token reference. */ private ITree<Node> evaluateTokenRef(final Token tk, final Context ctx) { EvaluatorResult res = null; @@ -570,19 +582,15 @@ public class Evaluator { 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.getStringLiteral((int) tk.intValue)); break; - default: Errors.inst.printError(EK_EVAL_UNTOK, tk.type.toString()); res = new EvaluatorResult(FAILURE); |
