summaryrefslogtreecommitdiff
path: root/dice-lang/src/bjc/dicelang/Evaluator.java
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2017-10-09 16:02:10 -0300
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2017-10-09 16:02:10 -0300
commitf028ea6dc555fc5192a96b00b8e96e90dbf6de55 (patch)
tree4b2a28ecbeb30095b50e6e9e8ac8b98fa8ddc79e /dice-lang/src/bjc/dicelang/Evaluator.java
parentbe4675f9512060aa85b1e0a4f223208b51b55812 (diff)
TODO tagging
Diffstat (limited to 'dice-lang/src/bjc/dicelang/Evaluator.java')
-rw-r--r--dice-lang/src/bjc/dicelang/Evaluator.java172
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);