summaryrefslogtreecommitdiff
path: root/dice-lang/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'dice-lang/src/main/java')
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ComplexDice.java16
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/CompoundDice.java12
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/DiceExpressionBuilder.java10
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/Die.java12
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java25
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/OperatorDiceExpression.java2
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ReferenceDiceExpression.java2
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ScalarDiceExpression.java2
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ScalarDie.java10
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java101
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java136
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java144
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/LiteralDiceNode.java91
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