diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2017-02-22 12:36:55 -0500 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2017-02-22 12:36:55 -0500 |
| commit | f4845d197c043aaedfd7dc6ee2a00d5843e54eb3 (patch) | |
| tree | 982df636d5940370e0ed491439ea3e171683f9a1 /dice-lang/src/bjc | |
| parent | fc0a33e00865b6ea66d3e1b8ce785ef02682a23b (diff) | |
Update to allow backflow during step-evals
Diffstat (limited to 'dice-lang/src/bjc')
| -rw-r--r-- | dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java | 44 | ||||
| -rw-r--r-- | dice-lang/src/bjc/dicelang/v2/Errors.java | 5 | ||||
| -rw-r--r-- | dice-lang/src/bjc/dicelang/v2/Evaluator.java | 223 |
3 files changed, 155 insertions, 117 deletions
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java index 07b6b10..aa6d519 100644 --- a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java +++ b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java @@ -15,6 +15,7 @@ import bjc.utils.funcutils.StringUtils; import java.util.Arrays; import java.util.Comparator; import java.util.Deque; +import java.util.Iterator; import java.util.List; import java.util.LinkedList; import java.util.regex.Matcher; @@ -38,6 +39,8 @@ public class DiceLangEngine { private boolean postfixMode; // Should we reverse the token stream private boolean prefixMode; + // Should we do step-by-step evaluation + private boolean stepEval; // Shunter for token postfixing private Shunter shunt; @@ -114,6 +117,7 @@ public class DiceLangEngine { debugMode = true; postfixMode = false; prefixMode = false; + stepEval = true; streamEng = new StreamEngine(this); @@ -394,13 +398,45 @@ public class DiceLangEngine { for(ITree<Node> ast : astForest) { System.out.println("\t\tTree " + treeNo + " in forest:\n\t\t " + ast); - Evaluator.Result res = eval.evaluate(ast); - System.out.printf("\t\tEvaluates to %s", res); + if(stepEval) { + int step = 1; - if(res.type == Evaluator.Result.Type.DICE) { - System.out.println(" (sample roll " + res.diceVal.value() + ")"); + for(Iterator<ITree<Node>> itr = eval.stepDebug(ast); itr.hasNext();){ + ITree<Node> nodeStep = itr.next(); + + System.out.printf("\t\tStep %d: Node is %s", step, nodeStep); + + if(nodeStep.getHead().type == Node.Type.RESULT) { + Evaluator.Result res = nodeStep.getHead().resultVal; + + System.out.printf(" (result is %s", res); + + if(res.type == Evaluator.Result.Type.DICE) { + System.out.printf(" (sample roll %s)", res.diceVal.value()); + } + + if(res.origVal != null) { + System.out.printf(" (original tree is %s)", res.origVal); + } + + System.out.printf(")"); + } + + + System.out.println(); + step += 1; + } + } else { + Evaluator.Result res = eval.evaluate(ast); + System.out.printf("\t\tEvaluates to %s", res); + + if(res.type == Evaluator.Result.Type.DICE) { + System.out.println(" (sample roll " + res.diceVal.value() + ")"); + } } + System.out.println(); + treeNo += 1; } } diff --git a/dice-lang/src/bjc/dicelang/v2/Errors.java b/dice-lang/src/bjc/dicelang/v2/Errors.java index c358214..4ba0aca 100644 --- a/dice-lang/src/bjc/dicelang/v2/Errors.java +++ b/dice-lang/src/bjc/dicelang/v2/Errors.java @@ -53,6 +53,8 @@ public class Errors { EK_EVAL_INVDGROUP, // Incorrect type to other dice operator EK_EVAL_INVDICE, + // Mismatched types to math operator + EK_EVAL_MISMATH, // Parser Error // Group closing where there couldn't be an opener @@ -173,6 +175,9 @@ public class Errors { case EK_EVAL_INVDICE: System.out.printf("\tERROR: Dice operators expect scalar dice, not %s\n", args[0]); break; + case EK_EVAL_MISMATH: + System.out.printf("\tERROR: Math operators expect two operands of the same type\n"); + break; case EK_PARSE_NOCLOSE: System.out.printf("\tERROR: Group closing with no possible group opener\n"); break; diff --git a/dice-lang/src/bjc/dicelang/v2/Evaluator.java b/dice-lang/src/bjc/dicelang/v2/Evaluator.java index ef50364..8658656 100644 --- a/dice-lang/src/bjc/dicelang/v2/Evaluator.java +++ b/dice-lang/src/bjc/dicelang/v2/Evaluator.java @@ -2,7 +2,11 @@ package bjc.dicelang.v2; import bjc.utils.data.ITree; import bjc.utils.data.Tree; +import bjc.utils.data.TransformedIterator; +import bjc.utils.data.TopDownTransformIterator; import bjc.utils.data.TopDownTransformResult; +import java.util.Iterator; +import java.util.function.Consumer; import static bjc.dicelang.v2.Errors.ErrorKey.*; import static bjc.dicelang.v2.Evaluator.Result.Type.*; @@ -18,15 +22,32 @@ public class Evaluator { // These may or may not have values based // off of the result type - public long intVal; - public double floatVal; + public long intVal; + public double floatVal; public DiceBox.DieExpression diceVal; - public String stringVal; + public String stringVal; + + // Original node this + public ITree<Node> origVal; public Result(Type typ) { type = typ; } + public Result(Type typ, ITree<Node> orig) { + this(typ); + + origVal = orig; + } + + public Result(Type typ, Node orig) { + this(typ, new Tree<>(orig)); + } + + public Result(Type typ, Result orig) { + this(typ, new Node(Node.Type.RESULT, orig)); + } + public Result(Type typ, long iVal) { this(typ); @@ -81,7 +102,21 @@ public class Evaluator { } } - private final static Node FAIL = new Node(Node.Type.RESULT, new Result(Result.Type.FAILURE)); + private static Node FAIL() { + return new Node(Node.Type.RESULT, new Result(Result.Type.FAILURE)); + } + + private static Node FAIL(ITree<Node> orig) { + return new Node(Node.Type.RESULT, new Result(Result.Type.FAILURE, orig)); + } + + private static Node FAIL(Node orig) { + return new Node(Node.Type.RESULT, new Result(Result.Type.FAILURE, orig)); + } + + private static Node FAIL(Result res) { + return new Node(Node.Type.RESULT, new Result(Result.Type.FAILURE, new Node(Node.Type.RESULT, res))); + } private DiceLangEngine eng; @@ -90,7 +125,17 @@ public class Evaluator { } public Result evaluate(ITree<Node> comm) { - return comm.topDownTransform(this::pickEvaluationType, this::evaluateNode).getHead().resultVal; + Consumer<Iterator<ITree<Node>>> 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, thunk)).getHead().resultVal; + } + + public Iterator<ITree<Node>> stepDebug(ITree<Node> comm) { + return new TopDownTransformIterator<>(this::pickEvaluationType, this::evaluateNode, comm); } private TopDownTransformResult pickEvaluationType(Node nd) { @@ -100,30 +145,30 @@ public class Evaluator { } } - private ITree<Node> evaluateNode(ITree<Node> ast) { + private ITree<Node> evaluateNode(ITree<Node> ast, Consumer<Iterator<ITree<Node>>> thunk) { switch(ast.getHead().type) { case UNARYOP: System.out.println("\tEVALUATOR ERROR: Unary operator evaluation isn't supported yet"); - return new Tree<>(FAIL); + return new Tree<>(FAIL(ast)); case BINOP: - return evaluateBinaryOp(ast); + return evaluateBinaryOp(ast, thunk); case TOKREF: - return evaluateTokenRef(ast.getHead().tokenVal); + return evaluateTokenRef(ast.getHead().tokenVal, thunk); case ROOT: return ast.getChild(ast.getChildrenCount() - 1); default: Errors.inst.printError(EK_EVAL_INVNODE, ast.getHead().type.toString()); - return new Tree<>(FAIL); + return new Tree<>(FAIL(ast)); } } - private ITree<Node> evaluateBinaryOp(ITree<Node> ast) { + private ITree<Node> evaluateBinaryOp(ITree<Node> ast, Consumer<Iterator<ITree<Node>>> thunk) { Token.Type binOp = ast.getHead().operatorType; if(ast.getChildrenCount() != 2) { Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount())); - return new Tree<>(FAIL); + return new Tree<>(FAIL(ast)); } ITree<Node> left = ast.getChild(0); @@ -135,18 +180,18 @@ public class Evaluator { case MULTIPLY: case DIVIDE: case IDIVIDE: - return evaluateMathBinary(binOp, left.getHead().resultVal, right.getHead().resultVal); + return evaluateMathBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, thunk); case DICEGROUP: case DICECONCAT: case DICELIST: - return evaluateDiceBinary(binOp, left.getHead().resultVal, right.getHead().resultVal); + return evaluateDiceBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, thunk); default: Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString()); - return new Tree<>(FAIL); + return new Tree<>(FAIL(ast)); } } - private ITree<Node> evaluateDiceBinary(Token.Type op, Result left, Result right) { + private ITree<Node> evaluateDiceBinary(Token.Type op, Result left, Result right, Consumer<Iterator<ITree<Node>>> thunk) { Result res = null; switch(op) { @@ -159,7 +204,7 @@ public class Evaluator { res = new Result(DICE, new DiceBox.SimpleDie(left.diceVal.scalar, right.intVal)); } else { Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); - return new Tree<>(FAIL); + return new Tree<>(FAIL(right)); } } else if(left.type == INT) { if(right.type == DICE && !right.diceVal.isList) { @@ -168,19 +213,19 @@ public class Evaluator { res = new Result(DICE, new DiceBox.SimpleDie(left.intVal, right.intVal)); } else { Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); - return new Tree<>(FAIL); + return new Tree<>(FAIL(right)); } } else { Errors.inst.printError(EK_EVAL_INVDGROUP, left.type.toString()); - return new Tree<>(FAIL); + 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); + 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); + return new Tree<>(FAIL(right)); } else { res = new Result(DICE, new DiceBox.CompoundDie(left.diceVal.scalar, right.diceVal.scalar)); @@ -189,10 +234,10 @@ public class Evaluator { case DICELIST: if(left.type != DICE || left.diceVal.isList) { Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString()); - return new Tree<>(FAIL); + 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); + return new Tree<>(FAIL(right)); } else { res = new Result(DICE, new DiceBox.SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); @@ -200,21 +245,33 @@ public class Evaluator { break; default: Errors.inst.printError(EK_EVAL_UNDICE, op.toString()); - return new Tree<>(FAIL); + return new Tree<>(FAIL()); } return new Tree<>(new Node(Node.Type.RESULT, res)); } - private ITree<Node> evaluateMathBinary(Token.Type op, Result left, Result right) { + private ITree<Node> evaluateMathBinary(Token.Type op, Result left, Result right, Consumer<Iterator<ITree<Node>>> thunk) { if(left.type == Result.Type.DICE || right.type == Result.Type.DICE) { System.out.println("\tEVALUATOR ERROR: Math on dice isn't supported yet"); - return new Tree<>(FAIL); + return new Tree<>(FAIL()); } else if(left.type == Result.Type.STRING || right.type == Result.Type.STRING) { - System.out.println("\tERROR: Math operators don't work on strings"); - return new Tree<>(FAIL); + Errors.inst.printError(EK_EVAL_STRINGMATH); + return new Tree<>(FAIL()); } else if(left.type == Result.Type.FAILURE || right.type == Result.Type.FAILURE) { - return new Tree<>(FAIL); + return new Tree<>(FAIL()); + } else if(left.type == Result.Type.INT && right.type != Result.Type.INT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(left.type == Result.Type.FLOAT && right.type != Result.Type.FLOAT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(right.type == Result.Type.INT && left.type != Result.Type.INT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); + } else if(right.type == Result.Type.FLOAT && left.type != Result.Type.FLOAT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); } Result res = null; @@ -222,128 +279,68 @@ public class Evaluator { switch(op) { case ADD: if(left.type == Result.Type.INT) { - if(right.type == Result.Type.INT) { - res = new Result(Result.Type.INT, left.intVal + right.intVal); - } else { - res = new Result(Result.Type.FLOAT, left.intVal + right.floatVal); - } + res = new Result(Result.Type.INT, left.intVal + right.intVal); } else { - if(right.type == Result.Type.INT) { - res = new Result(Result.Type.FLOAT, left.floatVal + right.intVal); - } else { - res = new Result(Result.Type.FLOAT, left.floatVal + right.floatVal); - } + res = new Result(Result.Type.FLOAT, left.floatVal + right.floatVal); } break; case SUBTRACT: if(left.type == Result.Type.INT) { - if(right.type == Result.Type.INT) { - res = new Result(Result.Type.INT, left.intVal - right.intVal); - } else { - res = new Result(Result.Type.FLOAT, left.intVal - right.floatVal); - } + res = new Result(Result.Type.INT, left.intVal - right.intVal); } else { - if(right.type == Result.Type.INT) { - res = new Result(Result.Type.FLOAT, left.floatVal - right.intVal); - } else { - res = new Result(Result.Type.FLOAT, left.floatVal - right.floatVal); - } + res = new Result(Result.Type.FLOAT, left.floatVal - right.floatVal); } break; case MULTIPLY: if(left.type == Result.Type.INT) { - if(right.type == Result.Type.INT) { - res = new Result(Result.Type.INT, left.intVal * right.intVal); - } else { - res = new Result(Result.Type.FLOAT, left.intVal * right.floatVal); - } + res = new Result(Result.Type.INT, left.intVal * right.intVal); } else { - if(right.type == Result.Type.INT) { - res = new Result(Result.Type.FLOAT, left.floatVal * right.intVal); - } else { - res = new Result(Result.Type.FLOAT, left.floatVal * right.floatVal); - } + res = new Result(Result.Type.FLOAT, left.floatVal * right.floatVal); } break; case DIVIDE: if(left.type == Result.Type.INT) { - if(right.type == Result.Type.INT) { - if(right.intVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.FLOAT, left.intVal / right.intVal); - } + if(right.intVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new Result(Result.Type.FAILURE, right); } else { - if(right.floatVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.FLOAT, left.intVal / right.floatVal); - } + res = new Result(Result.Type.FLOAT, left.intVal / right.intVal); } } else { - if(right.type == Result.Type.INT) { - if(right.intVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.FLOAT, left.floatVal / right.intVal); - } + if(right.floatVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new Result(Result.Type.FAILURE, right); } else { - if(right.floatVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.FLOAT, left.floatVal / right.floatVal); - } + res = new Result(Result.Type.FLOAT, left.floatVal / right.floatVal); } } break; case IDIVIDE: if(left.type == Result.Type.INT) { - if(right.type == Result.Type.INT) { - if(right.intVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.INT, (int) (left.intVal / right.intVal)); - } + if(right.intVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new Result(Result.Type.FAILURE, right); } else { - if(right.floatVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.INT, (int) (left.intVal / right.floatVal)); - } + res = new Result(Result.Type.INT, (int) (left.intVal / right.intVal)); } } else { - if(right.type == Result.Type.INT) { - if(right.intVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.INT, (int) (left.floatVal / right.intVal)); - } + if(right.floatVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new Result(Result.Type.FAILURE, right); } else { - if(right.floatVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new Result(Result.Type.FAILURE); - } else { - res = new Result(Result.Type.INT, (int) (left.floatVal / right.floatVal)); - } + res = new Result(Result.Type.INT, (int) (left.floatVal / right.floatVal)); } } break; default: Errors.inst.printError(EK_EVAL_UNMATH, op.toString()); - return new Tree<>(FAIL); + return new Tree<>(FAIL()); } return new Tree<>(new Node(Node.Type.RESULT, res)); } - private ITree<Node> evaluateTokenRef(Token tk) { + private ITree<Node> evaluateTokenRef(Token tk, Consumer<Iterator<ITree<Node>>> thunk) { Result res = null; switch(tk.type) { |
