From 4fcefd106eb23295592e9cc23a0c5d63a28f9e76 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 17 Apr 2016 15:02:01 -0400 Subject: Code maintenance and changes --- .../java/bjc/dicelang/ast/ArithmeticCollapser.java | 64 ++++++ .../java/bjc/dicelang/ast/DiceASTEvaluator.java | 253 +++++++++------------ .../main/java/bjc/dicelang/ast/DiceASTParser.java | 6 +- .../java/bjc/dicelang/ast/IOperatorCollapser.java | 10 +- 4 files changed, 185 insertions(+), 148 deletions(-) create mode 100644 dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java (limited to 'dice-lang/src/main/java/bjc') 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 valueOp; + + public ArithmeticCollapser(OperatorDiceNode type, + BinaryOperator valueOp) { + this.type = type; + this.valueOp = valueOp; + } + + @Override + public IPair> apply( + IFunctionalList>> nodes) { + IPair> initState = + new Pair<>(0, new Tree<>(type)); + + BinaryOperator>> reducer = + (accumulatedState, currentState) -> { + return reduceStates(accumulatedState, + currentState); + }; + + return nodes.reduceAux(initState, reducer, (state) -> state); + } + + private IPair> reduceStates( + IPair> accumulatedState, + IPair> 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 @@ -29,44 +25,6 @@ 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 valueOp; - - public ArithmeticCollapser(OperatorDiceNode type, - BinaryOperator valueOp) { - this.type = type; - this.valueOp = valueOp; - } - - @Override - public IPair> apply( - IPair> leftNode, - IPair> 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 * @@ -74,9 +32,11 @@ public class DiceASTEvaluator { * The enviroment to evaluate bindings and such against * @return The operations to use when collapsing the AST */ - private static IFunctionalMap buildOperations( - IFunctionalMap> enviroment) { - IFunctionalMap operatorCollapsers = new FunctionalMap<>(); + private static IFunctionalMap + buildOperations( + IFunctionalMap> enviroment) { + IFunctionalMap 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 expression, - IFunctionalMap> enviroment) { - IFunctionalMap collapsers = buildOperations( - enviroment); + public static int evaluateAST(ITree expression, + IFunctionalMap> enviroment) { + IFunctionalMap collapsers = + buildOperations(enviroment); return expression.collapse( (node) -> evaluateLeaf(node, enviroment), collapsers::get, - (pair) -> pair.merge((left, right) -> left)); + (pair) -> pair.getLeft()); } - private static IPair> evaluateLeaf( + private static IPair> evaluateLeaf( IDiceASTNode leafNode, - IFunctionalMap> enviroment) { - AST returnedAST = new AST<>(leafNode); + IFunctionalMap> enviroment) { + ITree 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> 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> parseBinding( - IFunctionalMap> enviroment, - IPair> left, - IPair> 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 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> parseBinding( + IFunctionalMap> enviroment, + IFunctionalList>> 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> nameNode = nodes.getByIndex(0); + IPair> 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> parseCompound( - IPair> leftNode, - IPair> 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 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> parseCompound( + IFunctionalList>> nodes) { + if (nodes.getSize() != 2) { + throw new UnsupportedOperationException( + "Can only form a group from two dice"); + } + + IPair> leftDiceNode = + nodes.getByIndex(0); + IPair> 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> parseGroup( - IPair> leftNode, - IPair> 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> parseGroup( + IFunctionalList>> nodes) { + if (nodes.getSize() != 2) { + throw new UnsupportedOperationException( + "Can only form a group from two dice"); + } + + IPair> numberDiceNode = + nodes.getByIndex(0); + IPair> 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 createFromString( + public static ITree createFromString( IFunctionalList tokens) { - AST rawTokens = TreeConstructor.constructTree(tokens, + ITree 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>> { +public interface IOperatorCollapser extends + Function>>, + IPair>> { // Just an alias } -- cgit v1.2.3