diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-04-04 10:08:00 -0400 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-04-04 10:08:00 -0400 |
| commit | 66b3ea905d077577a32ed82983b0cd9e8ee10bea (patch) | |
| tree | e1038a380c0714d4dda986514b365b9e474d3c15 /dice-lang/src/main/java/bjc/dicelang | |
| parent | b296ecf265120a0cac9cc5c558bdc60c6a27fff2 (diff) | |
Work on optimizations
Diffstat (limited to 'dice-lang/src/main/java/bjc/dicelang')
13 files changed, 350 insertions, 213 deletions
diff --git a/dice-lang/src/main/java/bjc/dicelang/ComplexDice.java b/dice-lang/src/main/java/bjc/dicelang/ComplexDice.java index 054c73b..9fa324b 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ComplexDice.java +++ b/dice-lang/src/main/java/bjc/dicelang/ComplexDice.java @@ -15,7 +15,7 @@ public class ComplexDice implements IDiceExpression { * The string to parse the dice from * @return A dice group parsed from the string */ - public static ComplexDice fromString(String dice) { + public static IDiceExpression fromString(String dice) { /* * Split it on the dice type marker */ @@ -116,4 +116,18 @@ public class ComplexDice implements IDiceExpression { + die.toString() + "]"; } } + + @Override + public boolean canOptimize() { + if (nDice.canOptimize() && die.canOptimize()) { + return die.optimize() == 1; + } + + return false; + } + + @Override + public int optimize() { + return nDice.optimize(); + } }
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/CompoundDice.java b/dice-lang/src/main/java/bjc/dicelang/CompoundDice.java index dcde650..6f7319a 100644 --- a/dice-lang/src/main/java/bjc/dicelang/CompoundDice.java +++ b/dice-lang/src/main/java/bjc/dicelang/CompoundDice.java @@ -77,4 +77,14 @@ public class CompoundDice implements IDiceExpression { public String toString() { return "compound[l=" + l.toString() + ", r=" + r.toString() + "]"; } -} + + @Override + public int optimize() { + return Integer.parseInt(l.optimize() + "" + r.optimize()); + } + + @Override + public boolean canOptimize() { + return l.canOptimize() && r.canOptimize(); + } +}
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/DiceExpressionBuilder.java b/dice-lang/src/main/java/bjc/dicelang/DiceExpressionBuilder.java index b3cc37a..42368e3 100644 --- a/dice-lang/src/main/java/bjc/dicelang/DiceExpressionBuilder.java +++ b/dice-lang/src/main/java/bjc/dicelang/DiceExpressionBuilder.java @@ -15,16 +15,6 @@ public class DiceExpressionBuilder { private IDiceExpression baking; /** - * Build a dice expresssion from a seed dice - * - * @param firstDice - * The dice to use as a seed - */ - public DiceExpressionBuilder(ComplexDice firstDice) { - baking = firstDice; - } - - /** * Build a dice expression from a seed dice expression * * @param seed diff --git a/dice-lang/src/main/java/bjc/dicelang/Die.java b/dice-lang/src/main/java/bjc/dicelang/Die.java index c6c6ddd..5ad5d79 100644 --- a/dice-lang/src/main/java/bjc/dicelang/Die.java +++ b/dice-lang/src/main/java/bjc/dicelang/Die.java @@ -30,7 +30,7 @@ public class Die implements IDiceExpression { throw new UnsupportedOperationException( "Dice with less than 1 side are not supported"); } - + this.nSides = nSides; } @@ -53,4 +53,14 @@ public class Die implements IDiceExpression { public String toString() { return "d" + nSides; } + + @Override + public int optimize() { + return 1; + } + + @Override + public boolean canOptimize() { + return nSides == 1; + } } diff --git a/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java b/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java index 93a75b9..c6aa0a7 100644 --- a/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java +++ b/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java @@ -14,4 +14,27 @@ public interface IDiceExpression { * @return The result of rowing the dice */ public int roll(); -} + + /** + * Optimize this expression to a scalar value + * + * @return This expression, optimized to a scalar value + * + * @throws UnsupportedOperationException + * if this type of expression can't be optimized + */ + public default int optimize() { + throw new UnsupportedOperationException( + "Can't optimize this type of expression"); + } + + /** + * Check if this expression can be optimized to a scalar value + * + * @return Whether or not this expression can be optimized to a scalar + * value + */ + public default boolean canOptimize() { + return false; + } +}
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/OperatorDiceExpression.java b/dice-lang/src/main/java/bjc/dicelang/OperatorDiceExpression.java index 4ca2568..e8cf871 100644 --- a/dice-lang/src/main/java/bjc/dicelang/OperatorDiceExpression.java +++ b/dice-lang/src/main/java/bjc/dicelang/OperatorDiceExpression.java @@ -87,4 +87,4 @@ public class OperatorDiceExpression implements IDiceExpression { return "dice-exp[type=" + det + ", l=" + left.toString() + ", r=" + right.toString() + "]"; } -} +}
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/ReferenceDiceExpression.java b/dice-lang/src/main/java/bjc/dicelang/ReferenceDiceExpression.java index 27ec609..866747a 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ReferenceDiceExpression.java +++ b/dice-lang/src/main/java/bjc/dicelang/ReferenceDiceExpression.java @@ -72,4 +72,4 @@ public class ReferenceDiceExpression implements IDiceExpression { return name; } } -} +}
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/ScalarDiceExpression.java b/dice-lang/src/main/java/bjc/dicelang/ScalarDiceExpression.java index 03b2f83..185ff5f 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ScalarDiceExpression.java +++ b/dice-lang/src/main/java/bjc/dicelang/ScalarDiceExpression.java @@ -77,4 +77,4 @@ public class ScalarDiceExpression implements IDiceExpression { return "scalar-exp[type=" + det + ", l=" + scalar + ", r=" + exp.toString() + "]"; } -} +}
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/ScalarDie.java b/dice-lang/src/main/java/bjc/dicelang/ScalarDie.java index fbdfb7e..fa25818 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ScalarDie.java +++ b/dice-lang/src/main/java/bjc/dicelang/ScalarDie.java @@ -41,4 +41,14 @@ public class ScalarDie implements IDiceExpression { public String toString() { return Integer.toString(num); } + + @Override + public int optimize() { + return num; + } + + @Override + public boolean canOptimize() { + return true; + } }
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java index 385d827..3552926 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java @@ -4,10 +4,7 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Function; -import org.apache.commons.lang3.StringUtils; - import bjc.dicelang.ComplexDice; -import bjc.dicelang.CompoundDice; import bjc.dicelang.IDiceExpression; import bjc.dicelang.ast.nodes.DiceASTType; import bjc.dicelang.ast.nodes.IDiceASTNode; @@ -50,10 +47,9 @@ public class DiceASTExpression implements IDiceExpression { * The enviroment to evaluate bindings and such against * @return The operations to use when collapsing the AST */ - private static Map<IDiceASTNode, IOperatorCollapser> - buildOperations(Map<String, DiceASTExpression> enviroment) { - Map<IDiceASTNode, IOperatorCollapser> operatorCollapsers = - new HashMap<>(); + private static Map<IDiceASTNode, IOperatorCollapser> buildOperations( + Map<String, DiceASTExpression> enviroment) { + Map<IDiceASTNode, IOperatorCollapser> operatorCollapsers = new HashMap<>(); operatorCollapsers.put(OperatorDiceNode.ADD, (leftNode, rightNode) -> { @@ -133,9 +129,8 @@ public class DiceASTExpression implements IDiceExpression { GenHolder<Boolean> selfReference = new GenHolder<>(false); - DiceASTReferenceChecker refChecker = - new DiceASTReferenceChecker(selfReference, - variableName); + DiceASTReferenceChecker refChecker = new DiceASTReferenceChecker( + selfReference, variableName); rightAST.traverse(TreeLinearizationMethod.PREORDER, refChecker); @@ -168,8 +163,8 @@ public class DiceASTExpression implements IDiceExpression { Pair<Integer, AST<IDiceASTNode>> rightNode) { return leftNode.merge((leftValue, leftAST) -> { return rightNode.merge((rightValue, rightAST) -> { - int compoundValue = - Integer.parseInt(Integer.toString(leftValue) + int compoundValue = Integer + .parseInt(Integer.toString(leftValue) + Integer.toString(rightValue)); return new Pair<>(compoundValue, new AST<>( @@ -195,8 +190,8 @@ public class DiceASTExpression implements IDiceExpression { + rightAST); } - int rolledValue = - new ComplexDice(leftValue, rightValue).roll(); + int rolledValue = new ComplexDice(leftValue, rightValue) + .roll(); return new Pair<>(rolledValue, new AST<>( OperatorDiceNode.GROUP, leftAST, rightAST)); @@ -231,62 +226,37 @@ public class DiceASTExpression implements IDiceExpression { /** * Expand a leaf AST token into a pair for evaluation * - * @param tokn + * @param leafNode * The token to evaluate * @return A pair consisting of the token's value and the AST it * represents */ - private Pair<Integer, AST<IDiceASTNode>> evalLeaf(IDiceASTNode tokn) { - if (tokn.getType() == DiceASTType.VARIABLE) { - return parseVariable(tokn); - } else if (tokn.getType() == DiceASTType.LITERAL) { - return parseLiteral(tokn); + private Pair<Integer, AST<IDiceASTNode>> evaluateLeaf( + IDiceASTNode leafNode) { + if (leafNode.getType() == DiceASTType.VARIABLE) { + VariableDiceNode node = (VariableDiceNode) leafNode; + + return parseVariable(node); + } else if (leafNode.getType() == DiceASTType.LITERAL) { + LiteralDiceNode node = (LiteralDiceNode) leafNode; + + return node.toParseValue(); } else { throw new UnsupportedOperationException("Found leaf operator " - + tokn + ". These aren't supported."); + + leafNode + ". These aren't supported."); } } - private static Pair<Integer, AST<IDiceASTNode>> - parseLiteral(IDiceASTNode tokn) { - LiteralDiceNode literalNode = (LiteralDiceNode) tokn; - String dat = literalNode.getData(); - - if (isValidInfixOperator(dat, "c")) { - String[] strangs = dat.split("c"); - - return new Pair<>(new CompoundDice(strangs).roll(), - new AST<>(tokn)); - } else if (isValidInfixOperator(dat, "d")) { - /* - * Handle dice groups - */ - return new Pair<>(ComplexDice.fromString(dat).roll(), - new AST<>(tokn)); - } else { - try { - return new Pair<>(Integer.parseInt(dat), new AST<>(tokn)); - } catch (NumberFormatException nfex) { - throw new UnsupportedOperationException( - "Found malformed leaf token " + tokn); - } - } - } - - private static boolean isValidInfixOperator(String dat, String op) { - return StringUtils.countMatches(dat, op) == 1 - && !dat.equalsIgnoreCase(op) && !dat.startsWith(op); - } - - private Pair<Integer, AST<IDiceASTNode>> - parseVariable(IDiceASTNode tokn) { - String varName = ((VariableDiceNode) tokn).getVariable(); + private Pair<Integer, AST<IDiceASTNode>> parseVariable( + VariableDiceNode leafNode) { + String varName = leafNode.getVariable(); if (env.containsKey(varName)) { - return new Pair<>(env.get(varName).roll(), new AST<>(tokn)); + return new Pair<>(env.get(varName).roll(), + new AST<>(leafNode)); } else { // Handle special case for defining variables - return new Pair<>(0, new AST<>(tokn)); + return new Pair<>(0, new AST<>(leafNode)); } } @@ -306,10 +276,10 @@ public class DiceASTExpression implements IDiceExpression { */ @Override public int roll() { - Map<IDiceASTNode, IOperatorCollapser> operations = - buildOperations(env); + Map<IDiceASTNode, IOperatorCollapser> operations = buildOperations( + env); - return ast.collapse(this::evalLeaf, operations::get, + return ast.collapse(this::evaluateLeaf, operations::get, (returnedValue) -> returnedValue .merge((left, right) -> left)); } @@ -323,4 +293,15 @@ public class DiceASTExpression implements IDiceExpression { public String toString() { return ast.toString(); } + + @Override + public int optimize() { + throw new UnsupportedOperationException( + "Use DiceASTOptimizer for optimizing these"); + } + + @Override + public boolean canOptimize() { + return false; + } }
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java deleted file mode 100644 index 6fa4883..0000000 --- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java +++ /dev/null @@ -1,136 +0,0 @@ -package bjc.dicelang.ast; - -import java.util.function.Function; - -import bjc.dicelang.ast.nodes.DiceASTType; -import bjc.dicelang.ast.nodes.IDiceASTNode; -import bjc.dicelang.ast.nodes.VariableDiceNode; -import bjc.utils.funcdata.FunctionalList; -import bjc.utils.funcdata.FunctionalMap; -import bjc.utils.parserutils.AST; - -/** - * Freeze references in a dice AST, replacing variable references with what - * the variables refer to - * - * @author ben - * - */ -public class DiceASTFreezer { - private static class NodeFreezer - implements Function<IDiceASTNode, AST<IDiceASTNode>> { - private FunctionalMap<String, AST<IDiceASTNode>> enviroment; - - public NodeFreezer(FunctionalMap<String, AST<IDiceASTNode>> env) { - enviroment = env; - } - - @Override - public AST<IDiceASTNode> apply(IDiceASTNode nod) { - if (nod.getType() == DiceASTType.VARIABLE) { - return expandNode((VariableDiceNode) nod); - } else { - return new AST<>(nod); - } - } - - protected AST<IDiceASTNode> - expandNode(VariableDiceNode variableNode) { - String varName = variableNode.getVariable(); - - if (!enviroment.containsKey(varName)) { - throw new IllegalArgumentException( - "Attempted to freeze reference" - + " to an undefined variable " + varName); - } - - return enviroment.get(varName); - } - } - - private static final class SelectiveFreezer extends NodeFreezer { - - private FunctionalList<String> variableNames; - - public SelectiveFreezer( - FunctionalMap<String, AST<IDiceASTNode>> env, - FunctionalList<String> varNames) { - super(env); - - variableNames = varNames; - } - - @Override - protected AST<IDiceASTNode> - expandNode(VariableDiceNode variableNode) { - if (variableNames.contains(variableNode.getVariable())) { - return super.expandNode(variableNode); - } else { - return new AST<>(variableNode); - } - } - } - - /** - * Freeze the references in an AST - * - * @param tree - * The tree to freeze references in - * @param env - * The enviroment to get reference values from - * @return The tree with references frozen - */ - public static AST<IDiceASTNode> freezeAST(AST<IDiceASTNode> tree, - FunctionalMap<String, AST<IDiceASTNode>> env) { - return selectiveFreeze(tree, env); - } - - /** - * Freeze the references in an expression backed by an AST - * - * @param tree - * The tree-backed expression to freeze references in - * @param env - * The enviroment to get reference values from - * @return The tree with references frozen - */ - public static AST<IDiceASTNode> freezeAST(DiceASTExpression tree, - FunctionalMap<String, DiceASTExpression> env) { - return freezeAST(tree.getAst(), - env.mapValues(expression -> expression.getAst())); - } - - /** - * Freeze references to specified variables - * - * @param tree - * The tree-backed expression to freeze references in - * @param env - * The enviroment to resolve variables against - * @param varNames - * The names of the variables to freeze - * @return An AST with the specified variables frozen - */ - public static AST<IDiceASTNode> selectiveFreeze(AST<IDiceASTNode> tree, - FunctionalMap<String, AST<IDiceASTNode>> env, - String... varNames) { - return selectiveFreeze(tree, env, new FunctionalList<>(varNames)); - } - - /** - * Freeze references to specified variables - * - * @param tree - * The tree-backed expression to freeze references in - * @param env - * The enviroment to resolve variables against - * @param varNames - * The names of the variables to freeze - * @return An AST with the specified variables frozen - */ - public static AST<IDiceASTNode> selectiveFreeze(AST<IDiceASTNode> tree, - FunctionalMap<String, AST<IDiceASTNode>> env, - FunctionalList<String> varNames) { - return tree.expand(new SelectiveFreezer(env, varNames)); - } -}
\ No newline at end of file diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java new file mode 100644 index 0000000..f5a6696 --- /dev/null +++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java @@ -0,0 +1,144 @@ +package bjc.dicelang.ast; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.BinaryOperator; + +import bjc.dicelang.IDiceExpression; +import bjc.dicelang.ast.nodes.DiceASTType; +import bjc.dicelang.ast.nodes.IDiceASTNode; +import bjc.dicelang.ast.nodes.LiteralDiceNode; +import bjc.dicelang.ast.nodes.OperatorDiceNode; + +import static bjc.dicelang.ast.nodes.DiceASTType.*; + +import bjc.utils.parserutils.AST; + +/** + * Optimize an AST + * + * @author ben + * + */ +public class DiceASTOptimizer { + private static final class ArithmeticOperationCollapser + implements BinaryOperator<AST<IDiceASTNode>> { + private IDiceASTNode type; + private BiFunction<Integer, Integer, Integer> valueCollapser; + private boolean doSwap; + + public ArithmeticOperationCollapser(IDiceASTNode type, + BiFunction<Integer, Integer, Integer> valueCollapser, + boolean doSwap) { + this.type = type; + this.valueCollapser = valueCollapser; + this.doSwap = doSwap; + } + + @Override + public AST<IDiceASTNode> apply(AST<IDiceASTNode> leftAST, + AST<IDiceASTNode> rightAST) { + boolean isLeftConstant = + DiceASTOptimizer.checkNodeType(leftAST, LITERAL) + && DiceASTOptimizer.isNodeConstant(leftAST); + + boolean isRightConstant = + DiceASTOptimizer.checkNodeType(rightAST, LITERAL) + && DiceASTOptimizer.isNodeConstant(leftAST); + + if (isLeftConstant) { + if (isRightConstant) { + int combinedValue = valueCollapser.apply( + getNodeValue(leftAST), getNodeValue(rightAST)); + + return new AST<>(new LiteralDiceNode(combinedValue)); + } + + if (doSwap) { + return new AST<>(type, rightAST, leftAST); + } + } + + return new AST<>(type, leftAST, rightAST); + } + } + + private static Map<IDiceASTNode, BinaryOperator<AST<IDiceASTNode>>> + buildConstantCollapsers() { + Map<IDiceASTNode, BinaryOperator<AST<IDiceASTNode>>> operatorCollapsers = + new HashMap<>(); + + operatorCollapsers.put(OperatorDiceNode.ADD, + new ArithmeticOperationCollapser(OperatorDiceNode.ADD, + (leftVal, rightVal) -> leftVal + rightVal, true)); + operatorCollapsers.put(OperatorDiceNode.SUBTRACT, + new ArithmeticOperationCollapser(OperatorDiceNode.SUBTRACT, + (leftVal, rightVal) -> leftVal - rightVal, false)); + operatorCollapsers.put(OperatorDiceNode.DIVIDE, + new ArithmeticOperationCollapser(OperatorDiceNode.DIVIDE, + (leftVal, rightVal) -> leftVal / rightVal, false)); + operatorCollapsers.put(OperatorDiceNode.MULTIPLY, + new ArithmeticOperationCollapser(OperatorDiceNode.MULTIPLY, + (leftVal, rightVal) -> leftVal * rightVal, true)); + + return null; + } + + private static AST<IDiceASTNode> collapseLeaf(IDiceASTNode leaf) { + // Can't optimize a simple reference + if (leaf.getType() == VARIABLE) { + return new AST<>(leaf); + } else if (leaf.getType() == LITERAL) { + LiteralDiceNode node = (LiteralDiceNode) leaf; + + return new AST<>(optimizeLiteral(node, node.toExpression())); + } else { + throw new UnsupportedOperationException( + "Found leaf operator. This isn't supported"); + } + } + + private static IDiceASTNode optimizeLiteral(LiteralDiceNode node, + IDiceExpression leaf) { + if (leaf.canOptimize()) { + return new LiteralDiceNode(Integer.toString(leaf.optimize())); + } else { + return node; + } + } + + private static AST<IDiceASTNode> finishTree(AST<IDiceASTNode> tree) { + return tree; + } + + /** + * Optimize a tree of expressions into a simpler form + * + * @param tree + * The tree to optimize + * @return The optimized tree + */ + public static AST<IDiceASTNode> optimizeTree(AST<IDiceASTNode> tree) { + AST<IDiceASTNode> astWithFoldedConstants = + tree.collapse(DiceASTOptimizer::collapseLeaf, + buildConstantCollapsers()::get, + DiceASTOptimizer::finishTree); + return astWithFoldedConstants; + } + + private static boolean checkNodeType(AST<IDiceASTNode> ast, + DiceASTType type) { + return ast.applyToHead((node) -> node.getType()) == type; + } + + private static boolean isNodeConstant(AST<IDiceASTNode> ast) { + return ast.applyToHead( + (node) -> ((LiteralDiceNode) node).isConstant()); + } + + private static int getNodeValue(AST<IDiceASTNode> ast) { + return ast.applyToHead( + (node) -> ((LiteralDiceNode) node).toConstant()); + } +} diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/LiteralDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/LiteralDiceNode.java index fe4c402..e689c7f 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/LiteralDiceNode.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/LiteralDiceNode.java @@ -1,5 +1,14 @@ package bjc.dicelang.ast.nodes; +import org.apache.commons.lang3.StringUtils; + +import bjc.dicelang.ComplexDice; +import bjc.dicelang.CompoundDice; +import bjc.dicelang.IDiceExpression; +import bjc.dicelang.ScalarDie; +import bjc.utils.data.Pair; +import bjc.utils.parserutils.AST; + /** * A AST node that represents a literal value * @@ -7,6 +16,11 @@ package bjc.dicelang.ast.nodes; * */ public class LiteralDiceNode implements IDiceASTNode { + private static boolean isValidInfixOperator(String dat, String op) { + return StringUtils.countMatches(dat, op) == 1 + && !dat.equalsIgnoreCase(op) && !dat.startsWith(op); + } + /** * The value contained by this node */ @@ -22,6 +36,14 @@ public class LiteralDiceNode implements IDiceASTNode { this.value = data; } + /** + * Create a new node with the given value + * @param val The value for this node + */ + public LiteralDiceNode(int val) { + this(Integer.toString(val)); + } + /* * (non-Javadoc) * @@ -82,6 +104,48 @@ public class LiteralDiceNode implements IDiceASTNode { return false; } + /** + * Parse this node into an expression + * + * @return The node in expression form + */ + public IDiceExpression toExpression() { + String literalData = this.getData(); + + if (LiteralDiceNode.isValidInfixOperator(literalData, "c")) { + String[] strangs = literalData.split("c"); + + return new CompoundDice(strangs); + } else if (LiteralDiceNode.isValidInfixOperator(literalData, + "d")) { + /* + * Handle dice groups + */ + return ComplexDice.fromString(literalData); + } else { + try { + return new ScalarDie(Integer.parseInt(literalData)); + } catch (NumberFormatException nfex) { + throw new UnsupportedOperationException( + "Found malformed leaf token " + this); + } + } + } + + /** + * Parse this node into an expression + * + * @return The node as a pair of a sample value and the AST it + * represents + */ + public Pair<Integer, AST<IDiceASTNode>> toParseValue() { + AST<IDiceASTNode> returnedAST = new AST<>(this); + + IDiceExpression expression = toExpression(); + + return new Pair<>(expression.roll(), returnedAST); + } + /* * (non-Javadoc) * @@ -91,4 +155,31 @@ public class LiteralDiceNode implements IDiceASTNode { public String toString() { return value; } + + /** + * Check if this node represents a constant value + * + * @return Whether or not this node represents a constant value + */ + public boolean isConstant() { + try { + Integer.parseInt(value); + return true; + } catch (NumberFormatException nfex) { + return false; + } + } + + /** + * Return the constant value this node represents + * + * @return The constant value of this node + * + * @throws NumberFormatException + * if you call this on a node that doesn't represent a + * constant value + */ + public int toConstant() { + return Integer.parseInt(value); + } }
\ No newline at end of file |
