summaryrefslogtreecommitdiff
path: root/dice-lang/src/main/java/bjc
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2016-04-17 15:02:01 -0400
committerbculkin2442 <bjculkin@mix.wvu.edu>2016-04-17 15:02:01 -0400
commit4fcefd106eb23295592e9cc23a0c5d63a28f9e76 (patch)
treee262854fc899c1bba65a4029bd9a500291f77e9e /dice-lang/src/main/java/bjc
parent9a5aac3995cd92afbab0a4b29d42e61078ea0bb0 (diff)
Code maintenance and changes
Diffstat (limited to 'dice-lang/src/main/java/bjc')
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java64
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java253
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java6
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java10
4 files changed, 185 insertions, 148 deletions
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java
new file mode 100644
index 0000000..5ad0a0f
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java
@@ -0,0 +1,64 @@
+package bjc.dicelang.ast;
+
+import java.util.function.BinaryOperator;
+
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+import bjc.dicelang.ast.nodes.OperatorDiceNode;
+import bjc.utils.data.IPair;
+import bjc.utils.data.Pair;
+import bjc.utils.funcdata.IFunctionalList;
+import bjc.utils.funcdata.ITree;
+import bjc.utils.funcdata.Tree;
+
+/**
+ * Responsible for collapsing arithmetic operators
+ *
+ * @author ben
+ *
+ */
+final class ArithmeticCollapser
+ implements IOperatorCollapser {
+ private OperatorDiceNode type;
+
+ private BinaryOperator<Integer> valueOp;
+
+ public ArithmeticCollapser(OperatorDiceNode type,
+ BinaryOperator<Integer> valueOp) {
+ this.type = type;
+ this.valueOp = valueOp;
+ }
+
+ @Override
+ public IPair<Integer, ITree<IDiceASTNode>> apply(
+ IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
+ IPair<Integer, ITree<IDiceASTNode>> initState =
+ new Pair<>(0, new Tree<>(type));
+
+ BinaryOperator<IPair<Integer, ITree<IDiceASTNode>>> reducer =
+ (accumulatedState, currentState) -> {
+ return reduceStates(accumulatedState,
+ currentState);
+ };
+
+ return nodes.reduceAux(initState, reducer, (state) -> state);
+ }
+
+ private IPair<Integer, ITree<IDiceASTNode>> reduceStates(
+ IPair<Integer, ITree<IDiceASTNode>> accumulatedState,
+ IPair<Integer, ITree<IDiceASTNode>> currentState) {
+ return accumulatedState
+ .bind((accumulatedValue, accumulatedTree) -> {
+ return currentState
+ .bind((currentValue, currentTree) -> {
+ accumulatedTree.addChild(currentTree);
+
+ Integer combinedValue =
+ valueOp.apply(accumulatedValue,
+ currentValue);
+
+ return new Pair<>(combinedValue,
+ accumulatedTree);
+ });
+ });
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java
index 454850c..e934b9f 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java
@@ -1,9 +1,6 @@
package bjc.dicelang.ast;
-import java.util.function.BinaryOperator;
-
import bjc.dicelang.ComplexDice;
-
import bjc.dicelang.ast.nodes.DiceASTType;
import bjc.dicelang.ast.nodes.DiceLiteralNode;
import bjc.dicelang.ast.nodes.DiceLiteralType;
@@ -12,15 +9,14 @@ import bjc.dicelang.ast.nodes.ILiteralDiceNode;
import bjc.dicelang.ast.nodes.IntegerLiteralNode;
import bjc.dicelang.ast.nodes.OperatorDiceNode;
import bjc.dicelang.ast.nodes.VariableDiceNode;
-
-import bjc.utils.data.GenHolder;
import bjc.utils.data.IPair;
+import bjc.utils.data.LazyPair;
import bjc.utils.data.Pair;
-import bjc.utils.data.lazy.LazyPair;
import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IFunctionalList;
import bjc.utils.funcdata.IFunctionalMap;
-import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod;
-import bjc.utils.parserutils.AST;
+import bjc.utils.funcdata.ITree;
+import bjc.utils.funcdata.Tree;
/**
* Evaluate a dice AST to an integer value
@@ -30,53 +26,17 @@ import bjc.utils.parserutils.AST;
*/
public class DiceASTEvaluator {
/**
- * Responsible for collapsing arithmetic operators
- *
- * @author ben
- *
- */
- private static final class ArithmeticCollapser
- implements IOperatorCollapser {
- private OperatorDiceNode type;
-
- private BinaryOperator<Integer> valueOp;
-
- public ArithmeticCollapser(OperatorDiceNode type,
- BinaryOperator<Integer> valueOp) {
- this.type = type;
- this.valueOp = valueOp;
- }
-
- @Override
- public IPair<Integer, AST<IDiceASTNode>> apply(
- IPair<Integer, AST<IDiceASTNode>> leftNode,
- IPair<Integer, AST<IDiceASTNode>> rightNode) {
- return leftNode.bind((leftValue, leftAST) -> {
- return rightNode.bind((rightValue, rightAST) -> {
- if (type == OperatorDiceNode.DIVIDE
- && rightValue == 0) {
- throw new ArithmeticException(
- "Attempted to divide by zero. The AST of the problem expression is "
- + rightAST);
- }
-
- return new Pair<>(valueOp.apply(leftValue, rightValue),
- new AST<>(type, leftAST, rightAST));
- });
- });
- }
- }
-
- /**
* Build the map of operations to use when collapsing the AST
*
* @param enviroment
* The enviroment to evaluate bindings and such against
* @return The operations to use when collapsing the AST
*/
- private static IFunctionalMap<IDiceASTNode, IOperatorCollapser> buildOperations(
- IFunctionalMap<String, AST<IDiceASTNode>> enviroment) {
- IFunctionalMap<IDiceASTNode, IOperatorCollapser> operatorCollapsers = new FunctionalMap<>();
+ private static IFunctionalMap<IDiceASTNode, IOperatorCollapser>
+ buildOperations(
+ IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) {
+ IFunctionalMap<IDiceASTNode, IOperatorCollapser> operatorCollapsers =
+ new FunctionalMap<>();
operatorCollapsers.put(OperatorDiceNode.ADD,
new ArithmeticCollapser(OperatorDiceNode.ADD,
@@ -94,8 +54,8 @@ public class DiceASTEvaluator {
new ArithmeticCollapser(OperatorDiceNode.DIVIDE,
(left, right) -> left / right));
- operatorCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
- return parseBinding(enviroment, left, right);
+ operatorCollapsers.put(OperatorDiceNode.ASSIGN, (nodes) -> {
+ return parseBinding(enviroment, nodes);
});
operatorCollapsers.put(OperatorDiceNode.COMPOUND,
@@ -116,38 +76,30 @@ public class DiceASTEvaluator {
* The enviroment to look up variables in
* @return The integer value of the expression
*/
- public static int evaluateAST(AST<IDiceASTNode> expression,
- IFunctionalMap<String, AST<IDiceASTNode>> enviroment) {
- IFunctionalMap<IDiceASTNode, IOperatorCollapser> collapsers = buildOperations(
- enviroment);
+ public static int evaluateAST(ITree<IDiceASTNode> expression,
+ IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) {
+ IFunctionalMap<IDiceASTNode, IOperatorCollapser> collapsers =
+ buildOperations(enviroment);
return expression.collapse(
(node) -> evaluateLeaf(node, enviroment), collapsers::get,
- (pair) -> pair.merge((left, right) -> left));
+ (pair) -> pair.getLeft());
}
- private static IPair<Integer, AST<IDiceASTNode>> evaluateLeaf(
+ private static IPair<Integer, ITree<IDiceASTNode>> evaluateLeaf(
IDiceASTNode leafNode,
- IFunctionalMap<String, AST<IDiceASTNode>> enviroment) {
- AST<IDiceASTNode> returnedAST = new AST<>(leafNode);
+ IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) {
+ ITree<IDiceASTNode> returnedAST = new Tree<>(leafNode);
switch (leafNode.getType()) {
case LITERAL:
-
return new Pair<>(evaluateLiteral(leafNode), returnedAST);
+
case VARIABLE:
return new LazyPair<>(() -> {
- String variableName = ((VariableDiceNode) leafNode)
- .getVariable();
-
- if (enviroment.containsKey(variableName)) {
- return evaluateAST(enviroment.get(variableName),
- enviroment);
- }
-
- // Value to allow for assignments
- return 0;
+ return bindLiteralValue(leafNode, enviroment);
}, () -> returnedAST);
+
case OPERATOR:
default:
throw new UnsupportedOperationException(
@@ -155,9 +107,21 @@ public class DiceASTEvaluator {
}
}
+ private static Integer bindLiteralValue(IDiceASTNode leafNode,
+ IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) {
+ String variableName = ((VariableDiceNode) leafNode).getVariable();
+
+ if (enviroment.containsKey(variableName)) {
+ return evaluateAST(enviroment.get(variableName), enviroment);
+ }
+
+ // Value to allow for assignments
+ return 0;
+ }
+
private static int evaluateLiteral(IDiceASTNode leafNode) {
- DiceLiteralType literalType = ((ILiteralDiceNode) leafNode)
- .getLiteralType();
+ DiceLiteralType literalType =
+ ((ILiteralDiceNode) leafNode).getLiteralType();
switch (literalType) {
case DICE:
@@ -171,88 +135,95 @@ public class DiceASTEvaluator {
}
}
- private static IPair<Integer, AST<IDiceASTNode>> parseBinding(
- IFunctionalMap<String, AST<IDiceASTNode>> enviroment,
- IPair<Integer, AST<IDiceASTNode>> left,
- IPair<Integer, AST<IDiceASTNode>> right) {
- return left.bind((leftValue, leftAST) -> {
- return right.bind((rightValue, rightAST) -> {
- String variableName = leftAST.applyToHead((node) -> {
- if (node.getType() != DiceASTType.VARIABLE) {
- throw new UnsupportedOperationException(
- "Attempted to assign to '" + node
- + "' which is not a variable");
- }
-
- return ((VariableDiceNode) node).getVariable();
- });
-
- GenHolder<Boolean> selfReference = new GenHolder<>(false);
-
- DiceASTReferenceChecker refChecker = new DiceASTReferenceChecker(
- selfReference, variableName);
-
- rightAST.traverse(TreeLinearizationMethod.PREORDER,
- refChecker);
-
- // Ignore meta-variable
- if (selfReference.unwrap((bool) -> bool)
- && !variableName.equals("last")) {
- throw new UnsupportedOperationException(
- "Variable '" + variableName
- + "' references itself. Problematic definition: \n\t"
- + rightAST);
- }
+ private static IPair<Integer, ITree<IDiceASTNode>> parseBinding(
+ IFunctionalMap<String, ITree<IDiceASTNode>> enviroment,
+ IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
+ if (nodes.getSize() != 2) {
+ throw new UnsupportedOperationException(
+ "Can only bind nodes with two children. Problem children are "
+ + nodes);
+ }
- if (!variableName.equals("last")) {
- enviroment.put(variableName, rightAST);
- } else {
- // Do nothing, last is an auto-handled meta-variable
+ IPair<Integer, ITree<IDiceASTNode>> nameNode = nodes.getByIndex(0);
+ IPair<Integer, ITree<IDiceASTNode>> valueNode =
+ nodes.getByIndex(1);
+
+ return nameNode.bindRight((nameTree) -> {
+ return valueNode.bind((valueValue, valueTree) -> {
+ if (containsSimpleVariable(nameTree)) {
+ String varName = nameTree.transformHead((nameNod) -> {
+ return ((VariableDiceNode) nameNod).getVariable();
+ });
+
+ enviroment.put(varName, valueTree);
+
+ return new Pair<>(valueValue, nameTree);
}
- return new Pair<>(rightValue, new AST<>(
- OperatorDiceNode.ASSIGN, leftAST, rightAST));
+ throw new IllegalStateException(
+ "Statement that shouldn't be hit was hit.");
});
});
}
- private static IPair<Integer, AST<IDiceASTNode>> parseCompound(
- IPair<Integer, AST<IDiceASTNode>> leftNode,
- IPair<Integer, AST<IDiceASTNode>> rightNode) {
- return leftNode.bind((leftValue, leftAST) -> {
- return rightNode.bind((rightValue, rightAST) -> {
- int compoundValue = Integer
- .parseInt(Integer.toString(leftValue)
- + Integer.toString(rightValue));
-
- return new Pair<>(compoundValue, new AST<>(
- OperatorDiceNode.COMPOUND, leftAST, rightAST));
+ private static boolean
+ containsSimpleVariable(ITree<IDiceASTNode> nameTree) {
+ return nameTree.transformHead((nameNod) -> {
+ if (nameNod.getType() != DiceASTType.VARIABLE) {
+ throw new UnsupportedOperationException(
+ "Assigning to complex variables isn't supported. Problem node is "
+ + nameNod);
+ }
+
+ return true;
+ });
+ }
+
+ private static IPair<Integer, ITree<IDiceASTNode>> parseCompound(
+ IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
+ if (nodes.getSize() != 2) {
+ throw new UnsupportedOperationException(
+ "Can only form a group from two dice");
+ }
+
+ IPair<Integer, ITree<IDiceASTNode>> leftDiceNode =
+ nodes.getByIndex(0);
+ IPair<Integer, ITree<IDiceASTNode>> rightDiceNode =
+ nodes.getByIndex(1);
+
+ return leftDiceNode.bind((leftDiceValue, leftDiceTree) -> {
+ return rightDiceNode.bind((rightDiceValue, rightDiceTree) -> {
+ Integer result =
+ Integer.parseInt(Integer.toString(leftDiceValue)
+ + Integer.toString(rightDiceValue));
+
+ return new Pair<>(result,
+ new Tree<>(OperatorDiceNode.GROUP, leftDiceTree,
+ rightDiceTree));
});
});
}
- private static IPair<Integer, AST<IDiceASTNode>> parseGroup(
- IPair<Integer, AST<IDiceASTNode>> leftNode,
- IPair<Integer, AST<IDiceASTNode>> rightNode) {
- return leftNode.bind((leftValue, leftAST) -> {
- return rightNode.bind((rightValue, rightAST) -> {
- if (leftValue < 0) {
- throw new UnsupportedOperationException(
- "Can't attempt to roll a negative number of dice."
- + " The problematic AST is "
- + leftAST);
- } else if (rightValue < 1) {
- throw new UnsupportedOperationException(
- "Can't roll dice with less than one side."
- + " The problematic AST is "
- + rightAST);
- }
+ private static IPair<Integer, ITree<IDiceASTNode>> parseGroup(
+ IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
+ if (nodes.getSize() != 2) {
+ throw new UnsupportedOperationException(
+ "Can only form a group from two dice");
+ }
+
+ IPair<Integer, ITree<IDiceASTNode>> numberDiceNode =
+ nodes.getByIndex(0);
+ IPair<Integer, ITree<IDiceASTNode>> diceTypeNode =
+ nodes.getByIndex(1);
- int rolledValue = new ComplexDice(leftValue, rightValue)
- .roll();
+ return numberDiceNode.bind((numberDiceValue, numberDiceTree) -> {
+ return diceTypeNode.bind((diceTypeValue, diceTypeTree) -> {
+ ComplexDice cDice =
+ new ComplexDice(numberDiceValue, diceTypeValue);
- return new Pair<>(rolledValue, new AST<>(
- OperatorDiceNode.GROUP, leftAST, rightAST));
+ return new Pair<>(cDice.roll(),
+ new Tree<>(OperatorDiceNode.GROUP, numberDiceTree,
+ diceTypeTree));
});
});
}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
index f6500e3..95495bd 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
@@ -11,7 +11,7 @@ import bjc.dicelang.ast.nodes.IntegerLiteralNode;
import bjc.dicelang.ast.nodes.OperatorDiceNode;
import bjc.dicelang.ast.nodes.VariableDiceNode;
import bjc.utils.funcdata.IFunctionalList;
-import bjc.utils.parserutils.AST;
+import bjc.utils.funcdata.ITree;
import bjc.utils.parserutils.TreeConstructor;
/**
@@ -28,9 +28,9 @@ public class DiceASTParser {
* The list of tokens to convert
* @return An AST built from the tokens
*/
- public static AST<IDiceASTNode> createFromString(
+ public static ITree<IDiceASTNode> createFromString(
IFunctionalList<String> tokens) {
- AST<String> rawTokens = TreeConstructor.constructTree(tokens,
+ ITree<String> rawTokens = TreeConstructor.constructTree(tokens,
(token) -> {
return isOperatorNode(token);
}, (operator) -> false, null);
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
index ed818d4..10df77b 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
@@ -1,10 +1,11 @@
package bjc.dicelang.ast;
-import java.util.function.BinaryOperator;
+import java.util.function.Function;
import bjc.dicelang.ast.nodes.IDiceASTNode;
import bjc.utils.data.IPair;
-import bjc.utils.parserutils.AST;
+import bjc.utils.funcdata.IFunctionalList;
+import bjc.utils.funcdata.ITree;
/**
* Alias for operator collapsers. Because 68-char types are too long
@@ -12,7 +13,8 @@ import bjc.utils.parserutils.AST;
* @author ben
*
*/
-public interface IOperatorCollapser
- extends BinaryOperator<IPair<Integer, AST<IDiceASTNode>>> {
+public interface IOperatorCollapser extends
+ Function<IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>>,
+ IPair<Integer, ITree<IDiceASTNode>>> {
// Just an alias
}