summaryrefslogtreecommitdiff
path: root/base/src/bjc/dicelang/eval
diff options
context:
space:
mode:
authorstudent <student@69.161.224.78>2018-02-12 17:17:37 -0500
committerstudent <student@69.161.224.78>2018-02-12 17:17:37 -0500
commite1480c4e706d4902f9865f6119e71e30b4173153 (patch)
tree01377a2021af9409f02b7bd43dba8072b216948d /base/src/bjc/dicelang/eval
parent26b0cf727656b4d5984f04d73566661644c78fdd (diff)
Refactor EvaluatorResult
Diffstat (limited to 'base/src/bjc/dicelang/eval')
-rw-r--r--base/src/bjc/dicelang/eval/DiceEvaluatorResult.java32
-rw-r--r--base/src/bjc/dicelang/eval/Evaluator.java602
-rw-r--r--base/src/bjc/dicelang/eval/EvaluatorResult.java82
-rw-r--r--base/src/bjc/dicelang/eval/FailureEvaluatorResult.java55
-rw-r--r--base/src/bjc/dicelang/eval/FloatEvaluatorResult.java43
-rw-r--r--base/src/bjc/dicelang/eval/StringEvaluatorResult.java44
6 files changed, 858 insertions, 0 deletions
diff --git a/base/src/bjc/dicelang/eval/DiceEvaluatorResult.java b/base/src/bjc/dicelang/eval/DiceEvaluatorResult.java
new file mode 100644
index 0000000..8e50333
--- /dev/null
+++ b/base/src/bjc/dicelang/eval/DiceEvaluatorResult.java
@@ -0,0 +1,32 @@
+package bjc.dicelang.eval;
+
+import bjc.dicelang.dice.DiceExpression;
+import bjc.dicelang.dice.Die;
+import bjc.dicelang.dice.DieList;
+import bjc.dicelang.dice.ListDiceExpression;
+import bjc.dicelang.dice.ScalarDiceExpression;
+
+public class DiceEvaluatorResult extends EvaluatorResult {
+ /**
+ * The dice value of the result.
+ */
+ public DiceExpression diceVal;
+
+ public DiceEvaluatorResult(DiceExpression expr) {
+ super(Type.DICE);
+
+ diceVal = expr;
+ }
+
+ public DiceEvaluatorResult(Die die) {
+ this(new ScalarDiceExpression(die));
+ }
+
+ public DiceEvaluatorResult(DieList list) {
+ this(new ListDiceExpression(list));
+ }
+
+ public boolean isList() {
+ return diceVal.isList();
+ }
+}
diff --git a/base/src/bjc/dicelang/eval/Evaluator.java b/base/src/bjc/dicelang/eval/Evaluator.java
new file mode 100644
index 0000000..4cc2a1e
--- /dev/null
+++ b/base/src/bjc/dicelang/eval/Evaluator.java
@@ -0,0 +1,602 @@
+package bjc.dicelang.eval;
+
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.function.Consumer;
+
+import bjc.dicelang.DiceLangEngine;
+import bjc.dicelang.DiceToken;
+import bjc.dicelang.Errors;
+import bjc.dicelang.FloatToken;
+import bjc.dicelang.Node;
+import bjc.dicelang.Token;
+import bjc.dicelang.dice.CompoundDie;
+import bjc.dicelang.dice.Die;
+import bjc.dicelang.dice.MathDie;
+import bjc.dicelang.dice.ScalarDiceExpression;
+import bjc.dicelang.dice.ScalarDie;
+import bjc.dicelang.dice.SimpleDie;
+import bjc.dicelang.dice.SimpleDieList;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.SingleIterator;
+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.eval.EvaluatorResult.Type.*;
+
+/*
+ * @TODO 10/09/17 Ben Culkin :EvaluatorSplit
+ *
+ * Type/sanity checking should be moved into a seperate stage, not part of
+ * evaluation.
+ */
+/**
+ * Evaluate DiceLang ASTs
+ *
+ * @author EVE
+ *
+ */
+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. */
+ }
+ }
+
+ /* The engine we are connected to. */
+ private final DiceLangEngine eng;
+
+ /**
+ * Create a new evaluator.
+ *
+ * @param en
+ * The engine.
+ */
+ public Evaluator(final DiceLangEngine en) {
+ eng = en;
+ }
+
+ /**
+ * Evaluate a AST.
+ *
+ * @param comm
+ * The AST to evaluate.
+ *
+ * @return The result of the tree.
+ */
+ public EvaluatorResult evaluate(final ITree<Node> comm) {
+ final 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 has side effects.
+ */
+ while (itr.hasNext()) {
+ itr.next();
+ }
+ };
+
+ /* The result. */
+ final ITree<Node> res = comm.topDownTransform(this::pickEvaluationType, node -> this.evaluateNode(node, ctx));
+
+ return res.getHead().resultVal;
+ }
+
+ /*
+ * @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();
+
+ ctx.isDebug = true;
+
+ return new TopDownTransformIterator<>(this::pickEvaluationType, (node, thnk) -> {
+ ctx.thunk = thnk;
+
+ return this.evaluateNode(node, ctx);
+ }, comm);
+ }
+
+ /* Pick the way to evaluate a node. */
+ private TopDownTransformResult pickEvaluationType(final Node nd) {
+ switch (nd.type) {
+ case UNARYOP:
+ switch (nd.operatorType) {
+ case COERCE:
+ /* Coerce does special things to the tree. */
+ return TopDownTransformResult.RTRANSFORM;
+ default:
+ return TopDownTransformResult.PUSHDOWN;
+ }
+
+ default:
+ return TopDownTransformResult.PUSHDOWN;
+ }
+ }
+
+ /* Evaluate a node. */
+ private ITree<Node> evaluateNode(final ITree<Node> ast, final 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<>(Node.FAIL(ast));
+ }
+ }
+
+ /* 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<>(Node.FAIL(ast));
+ }
+
+ switch (ast.getHead().operatorType) {
+ /*
+ * @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));
+ }
+
+ if (nChild == null) {
+ Errors.inst.printError(EK_EVAL_INVNODE);
+ return new Tree<>(Node.FAIL(ast));
+ }
+
+ final Node childNode = nChild.getHead();
+ final EvaluatorResult res = childNode.resultVal;
+
+ /* Move up to coercing to a float. */
+ if (res.type == FLOAT) {
+ curLevel = CoerceSteps.DOUBLE;
+ }
+
+ children.add(nChild);
+ }
+
+ for (final ITree<Node> child : children) {
+ final Node nd = child.getHead();
+ final EvaluatorResult res = nd.resultVal;
+
+ switch (res.type) {
+ case INT:
+ /* Coerce ints to doubles if we need to. */
+ if (curLevel == CoerceSteps.DOUBLE) {
+ nd.resultVal = new FloatEvaluatorResult((double) res.intVal);
+ }
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ retVal.addChild(child);
+ }
+
+ return retVal;
+ case DICESCALAR:
+ final EvaluatorResult opr = ast.getChild(0).getHead().resultVal;
+
+ if (opr.type != INT) {
+ Errors.inst.printError(EK_EVAL_INVDCREATE, opr.type.toString());
+ }
+
+ final EvaluatorResult sres = new DiceEvaluatorResult(new ScalarDie(opr.intVal));
+ return new Tree<>(new Node(Node.Type.RESULT, sres));
+ case DICEFUDGE:
+ final EvaluatorResult oprn = ast.getChild(0).getHead().resultVal;
+
+ if (oprn.type != INT) {
+ Errors.inst.printError(EK_EVAL_INVDCREATE, oprn.type.toString());
+ }
+
+ final EvaluatorResult fres = new DiceEvaluatorResult(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<>(Node.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());
+
+ return new Tree<>(Node.FAIL(ast));
+ }
+
+ 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, leftRes, rightRes, ctx);
+ case DICEGROUP:
+ case DICECONCAT:
+ case DICELIST:
+ return evaluateDiceBinary(binOp, leftRes, rightRes, ctx);
+ case STRCAT:
+ case STRREP:
+ return evaluateStringBinary(binOp, leftRes, rightRes, ctx);
+ default:
+ Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString());
+ return new Tree<>(Node.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) {
+ if (left.type != STRING) {
+ Errors.inst.printError(EK_EVAL_INVSTRING, left.type.toString());
+ return new Tree<>(Node.FAIL(left));
+ }
+
+ final String strang = ((StringEvaluatorResult) left).stringVal;
+
+ switch (op) {
+ case STRCAT:
+ if (right.type != STRING) {
+ Errors.inst.printError(EK_EVAL_UNSTRING, right.type.toString());
+ return new Tree<>(Node.FAIL(right));
+ }
+
+ final String strung = ((StringEvaluatorResult) right).stringVal;
+ final EvaluatorResult cres = new StringEvaluatorResult(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());
+ return new Tree<>(Node.FAIL(right));
+ }
+
+ String res = strang;
+ final long count = right.intVal;
+
+ for (long i = 1; i < count; i++) {
+ res += strang;
+ }
+
+ return new Tree<>(new Node(Node.Type.RESULT, new StringEvaluatorResult(res)));
+ default:
+ Errors.inst.printError(EK_EVAL_UNSTRING, op.toString());
+ return new Tree<>(Node.FAIL());
+ }
+ }
+
+ /* Evaluate dice binary operators. */
+ private static ITree<Node> evaluateDiceBinary(final Token.Type op, 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.
+ *
+ * ADDENDA: Replace the .diceVal.isList() with .isList()
+ */
+ case DICEGROUP:
+ if (left.type == DICE && !((DiceEvaluatorResult) left).diceVal.isList()) {
+ Die lhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) left).diceVal).scalar;
+
+ if (right.type == DICE && !((DiceEvaluatorResult) right).diceVal.isList()) {
+ Die rhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) right).diceVal).scalar;
+
+ Die simple = new SimpleDie(lhs, rhs);
+
+ res = new DiceEvaluatorResult(simple);
+ } else if (right.type == INT) {
+ res = new DiceEvaluatorResult(new SimpleDie(lhs, right.intVal));
+ } else {
+ Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString());
+ return new Tree<>(Node.FAIL(right));
+ }
+ } else if (left.type == INT) {
+ if (right.type == DICE && !((DiceEvaluatorResult) right).diceVal.isList()) {
+ Die rhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) right).diceVal).scalar;
+
+ res = new DiceEvaluatorResult(new SimpleDie(left.intVal, rhs));
+ } else if (right.type == INT) {
+ res = new DiceEvaluatorResult(new SimpleDie(left.intVal, right.intVal));
+ } else {
+ Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString());
+ return new Tree<>(Node.FAIL(right));
+ }
+ } else {
+ Errors.inst.printError(EK_EVAL_INVDGROUP, left.type.toString());
+ return new Tree<>(Node.FAIL(left));
+ }
+
+ case DICECONCAT:
+ if (left.type != DICE || ((DiceEvaluatorResult) left).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString());
+ return new Tree<>(Node.FAIL(left));
+ } else if (right.type != DICE || ((DiceEvaluatorResult) right).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString());
+ return new Tree<>(Node.FAIL(right));
+ } else {
+ Die lhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) left).diceVal).scalar;
+ Die rhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) right).diceVal).scalar;
+
+ res = new DiceEvaluatorResult(new CompoundDie(lhs, rhs));
+ }
+
+ break;
+
+ case DICELIST:
+ if (left.type != DICE || ((DiceEvaluatorResult) left).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString());
+ return new Tree<>(Node.FAIL(left));
+ } else if (right.type != DICE || ((DiceEvaluatorResult) right).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString());
+ return new Tree<>(Node.FAIL(right));
+ } else {
+ Die lhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) left).diceVal).scalar;
+ Die rhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) right).diceVal).scalar;
+
+ res = new DiceEvaluatorResult(new SimpleDieList(lhs, rhs));
+ }
+
+ break;
+
+ default:
+ Errors.inst.printError(EK_EVAL_UNDICE, op.toString());
+ return new Tree<>(Node.FAIL());
+ }
+
+ 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) {
+ if (left.type == STRING || right.type == STRING) {
+ Errors.inst.printError(EK_EVAL_STRINGMATH);
+ return new Tree<>(Node.FAIL());
+ } else if (left.type == FAILURE || right.type == FAILURE) {
+ return new Tree<>(Node.FAIL());
+ } else if (left.type == INT && right.type != INT) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(Node.FAIL(right));
+ } else if (left.type == FLOAT && right.type != FLOAT) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(Node.FAIL(right));
+ } else if (left.type == DICE && right.type != DICE) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(Node.FAIL(right));
+ } else if (right.type == INT && left.type != INT) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(Node.FAIL(left));
+ } else if (right.type == FLOAT && left.type != FLOAT) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(Node.FAIL(left));
+ } else if (right.type == DICE && left.type != DICE) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(Node.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 (((DiceEvaluatorResult) left).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.toString());
+ return new Tree<>(Node.FAIL(left));
+ } else if (((DiceEvaluatorResult) right).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.toString());
+ return new Tree<>(Node.FAIL(right));
+ }
+
+ Die lhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) left).diceVal).scalar;
+ Die rhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) right).diceVal).scalar;
+
+ res = new DiceEvaluatorResult(new MathDie(MathDie.MathOp.ADD, lhs, rhs));
+ } else {
+ res = new FloatEvaluatorResult(
+ ((FloatEvaluatorResult) left).floatVal + ((FloatEvaluatorResult) right).floatVal);
+ }
+
+ break;
+
+ case SUBTRACT:
+ if (left.type == INT) {
+ res = new EvaluatorResult(INT, left.intVal - right.intVal);
+ } else if (left.type == DICE) {
+ if (((DiceEvaluatorResult) left).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.toString());
+ return new Tree<>(Node.FAIL(left));
+ } else if (((DiceEvaluatorResult) right).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.toString());
+ return new Tree<>(Node.FAIL(right));
+ }
+
+ Die lhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) left).diceVal).scalar;
+ Die rhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) right).diceVal).scalar;
+
+ res = new DiceEvaluatorResult(new MathDie(MathDie.MathOp.SUBTRACT, lhs, rhs));
+ } else {
+ res = new FloatEvaluatorResult(
+ ((FloatEvaluatorResult) left).floatVal - ((FloatEvaluatorResult) right).floatVal);
+ }
+
+ break;
+
+ case MULTIPLY:
+ if (left.type == INT) {
+ res = new EvaluatorResult(INT, left.intVal * right.intVal);
+ } else if (left.type == DICE) {
+ if (((DiceEvaluatorResult) left).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.toString());
+ return new Tree<>(Node.FAIL(left));
+ } else if (((DiceEvaluatorResult) right).diceVal.isList()) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.toString());
+ return new Tree<>(Node.FAIL(right));
+ }
+
+ Die lhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) left).diceVal).scalar;
+ Die rhs = ((ScalarDiceExpression) ((DiceEvaluatorResult) right).diceVal).scalar;
+
+ res = new DiceEvaluatorResult(new MathDie(MathDie.MathOp.MULTIPLY, lhs, rhs));
+ } else {
+ res = new FloatEvaluatorResult(
+ ((FloatEvaluatorResult) left).floatVal * ((FloatEvaluatorResult) right).floatVal);
+ }
+
+ break;
+
+ case DIVIDE:
+ if (left.type == INT) {
+ if (right.intVal == 0) {
+ Errors.inst.printError(EK_EVAL_DIVZERO);
+ res = new FailureEvaluatorResult(right);
+ } else {
+ res = new EvaluatorResult(FLOAT, left.intVal / right.intVal);
+ }
+ } else if (left.type == FLOAT) {
+ if (((FloatEvaluatorResult) right).floatVal == 0) {
+ Errors.inst.printError(EK_EVAL_DIVZERO);
+ res = new FailureEvaluatorResult(right);
+ } else {
+ res = new FloatEvaluatorResult(
+ ((FloatEvaluatorResult) left).floatVal / ((FloatEvaluatorResult) right).floatVal);
+ }
+ } else {
+ Errors.inst.printError(EK_EVAL_DIVDICE);
+ return new Tree<>(Node.FAIL());
+ }
+
+ break;
+
+ case IDIVIDE:
+ if (left.type == INT) {
+ if (right.intVal == 0) {
+ Errors.inst.printError(EK_EVAL_DIVZERO);
+ res = new FailureEvaluatorResult(right);
+ } else {
+ res = new EvaluatorResult(INT, (int) (left.intVal / right.intVal));
+ }
+ } else if (left.type == FLOAT) {
+ if (((FloatEvaluatorResult) right).floatVal == 0) {
+ Errors.inst.printError(EK_EVAL_DIVZERO);
+ res = new FailureEvaluatorResult(right);
+ } else {
+ res = new EvaluatorResult(INT,
+ (int) (((FloatEvaluatorResult) left).floatVal / ((FloatEvaluatorResult) right).floatVal));
+ }
+ } else {
+ Errors.inst.printError(EK_EVAL_DIVDICE);
+ return new Tree<>(Node.FAIL());
+ }
+
+ break;
+
+ default:
+ Errors.inst.printError(EK_EVAL_UNMATH, op.toString());
+ return new Tree<>(Node.FAIL());
+ }
+
+ 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;
+
+ switch (tk.type) {
+ case INT_LIT:
+ res = new EvaluatorResult(INT, tk.intValue);
+ break;
+ case FLOAT_LIT:
+ res = new FloatEvaluatorResult(((FloatToken) tk).floatValue);
+ break;
+ case DICE_LIT:
+ res = new DiceEvaluatorResult(((DiceToken) tk).diceValue);
+ break;
+ case STRING_LIT:
+ res = new StringEvaluatorResult(eng.getStringLiteral((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));
+ }
+}
diff --git a/base/src/bjc/dicelang/eval/EvaluatorResult.java b/base/src/bjc/dicelang/eval/EvaluatorResult.java
new file mode 100644
index 0000000..3ac0202
--- /dev/null
+++ b/base/src/bjc/dicelang/eval/EvaluatorResult.java
@@ -0,0 +1,82 @@
+package bjc.dicelang.eval;
+
+/*
+ * @TODO 10/09/17 Ben Culkin :EvalResultReorg
+ *
+ * Again, split it into separate classes based off of the type.
+ */
+/**
+ * The result from the evaluator.
+ *
+ * @author EVE
+ *
+ */
+public class EvaluatorResult {
+ /**
+ * The type of the result.
+ *
+ * @author EVE
+ *
+ */
+ public static enum Type {
+ /**
+ * The type of a failure.
+ */
+ FAILURE,
+ /**
+ * The type of an integer.
+ */
+ INT,
+ /**
+ * The type of a float.
+ */
+ FLOAT,
+ /**
+ * The type of a dice.
+ */
+ DICE,
+ /**
+ * The type of a string.
+ */
+ STRING
+ }
+
+ /**
+ * The type of the result.
+ */
+ public final EvaluatorResult.Type type;
+
+ // These may or may not have values based
+ // off of the result type
+ /**
+ * The integer value of the result.
+ */
+ public long intVal;
+
+ /**
+ * Create a new result.
+ *
+ * @param typ
+ * The type of the result.
+ */
+ protected EvaluatorResult(final EvaluatorResult.Type typ) {
+ type = typ;
+ }
+
+ /**
+ * Create a new result.
+ *
+ * @param typ
+ * @param iVal
+ */
+ public EvaluatorResult(final EvaluatorResult.Type typ, final long iVal) {
+ this(typ);
+
+ intVal = iVal;
+ }
+
+ @Override
+ public String toString() {
+ return type.toString();
+ }
+}
diff --git a/base/src/bjc/dicelang/eval/FailureEvaluatorResult.java b/base/src/bjc/dicelang/eval/FailureEvaluatorResult.java
new file mode 100644
index 0000000..3b641db
--- /dev/null
+++ b/base/src/bjc/dicelang/eval/FailureEvaluatorResult.java
@@ -0,0 +1,55 @@
+package bjc.dicelang.eval;
+
+import bjc.dicelang.Node;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+
+public class FailureEvaluatorResult extends EvaluatorResult {
+ /**
+ * Original node data
+ */
+ public ITree<Node> origVal;
+
+ public FailureEvaluatorResult() {
+ super(Type.FAILURE);
+ }
+
+ public FailureEvaluatorResult(final ITree<Node> orig) {
+ super(Type.FAILURE);
+
+ origVal = orig;
+ }
+
+ public FailureEvaluatorResult(final Node orig) {
+ this(new Tree<>(orig));
+ }
+
+ public FailureEvaluatorResult(EvaluatorResult right) {
+ this(new Node(Node.Type.RESULT, right));
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((origVal == null) ? 0 : origVal.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FailureEvaluatorResult other = (FailureEvaluatorResult) obj;
+ if (origVal == null) {
+ if (other.origVal != null)
+ return false;
+ } else if (!origVal.equals(other.origVal))
+ return false;
+ return true;
+ }
+}
diff --git a/base/src/bjc/dicelang/eval/FloatEvaluatorResult.java b/base/src/bjc/dicelang/eval/FloatEvaluatorResult.java
new file mode 100644
index 0000000..7fbbcdc
--- /dev/null
+++ b/base/src/bjc/dicelang/eval/FloatEvaluatorResult.java
@@ -0,0 +1,43 @@
+package bjc.dicelang.eval;
+
+public class FloatEvaluatorResult extends EvaluatorResult {
+ /**
+ * The float value of the result.
+ */
+ public double floatVal;
+
+ public FloatEvaluatorResult(double val) {
+ super(Type.FLOAT);
+
+ floatVal = val;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(" + floatVal + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(floatVal);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FloatEvaluatorResult other = (FloatEvaluatorResult) obj;
+ if (Double.doubleToLongBits(floatVal) != Double.doubleToLongBits(other.floatVal))
+ return false;
+ return true;
+ }
+}
diff --git a/base/src/bjc/dicelang/eval/StringEvaluatorResult.java b/base/src/bjc/dicelang/eval/StringEvaluatorResult.java
new file mode 100644
index 0000000..870fd01
--- /dev/null
+++ b/base/src/bjc/dicelang/eval/StringEvaluatorResult.java
@@ -0,0 +1,44 @@
+package bjc.dicelang.eval;
+
+public class StringEvaluatorResult extends EvaluatorResult {
+ /**
+ * The string value of the result.
+ */
+ public String stringVal;
+
+ public StringEvaluatorResult(String strang) {
+ super(Type.STRING);
+
+ stringVal = strang;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(" + stringVal + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((stringVal == null) ? 0 : stringVal.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StringEvaluatorResult other = (StringEvaluatorResult) obj;
+ if (stringVal == null) {
+ if (other.stringVal != null)
+ return false;
+ } else if (!stringVal.equals(other.stringVal))
+ return false;
+ return true;
+ }
+}