summaryrefslogtreecommitdiff
path: root/dice-lang/src
diff options
context:
space:
mode:
Diffstat (limited to 'dice-lang/src')
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java80
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java36
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java333
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java35
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java261
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java34
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java (renamed from dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTReferenceChecker.java)8
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java (renamed from dice-lang/src/main/java/bjc/dicelang/old/ast/IOperatorCollapser.java)8
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceASTType.java (renamed from dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/DiceASTType.java)2
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralNode.java57
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralType.java18
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceOperatorType.java25
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/IDiceASTNode.java (renamed from dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/IDiceASTNode.java)14
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/ILiteralDiceNode.java54
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/IntegerLiteralNode.java35
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java (renamed from dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/OperatorDiceNode.java)32
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/VariableDiceNode.java (renamed from dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/VariableDiceNode.java)4
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/package-info.java6
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTDefinedChecker.java61
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTExpression.java332
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTFlattener.java145
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTInliner.java138
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java119
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/LiteralDiceNode.java217
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/package-info.java6
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/optimization/DiceASTOptimizer.java209
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/optimization/package-info.java6
27 files changed, 555 insertions, 1720 deletions
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java
deleted file mode 100644
index f079835..0000000
--- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package bjc.dicelang.examples;
-
-import java.util.Map;
-import java.util.function.BiConsumer;
-
-import bjc.dicelang.old.ast.DiceASTExpression;
-import bjc.dicelang.old.ast.DiceASTInliner;
-import bjc.dicelang.old.ast.DiceASTParser;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.utils.funcdata.FunctionalMap;
-import bjc.utils.parserutils.AST;
-
-/**
- * Container for pragma handlers
- *
- * @author ben
- *
- */
-public class DiceASTLanguagePragmaHandlers {
- /**
- * Handles inlining a specified expression to a new name
- *
- * @author ben
- *
- */
- public static final class InlineHandler implements
- BiConsumer<DiceASTParser, Map<String, DiceASTExpression>> {
- private String expressionToInline;
- private String resultingVariable;
-
- /**
- * Create a new inlining handler
- *
- * @param expressionToInline
- * The name of the expression to inline
- * @param resultingVariable
- * The name of the variable to bind the inline
- * expression to
- */
- public InlineHandler(String expressionToInline,
- String resultingVariable) {
- this.expressionToInline = expressionToInline;
- this.resultingVariable = resultingVariable;
- }
-
- @Override
- public void accept(DiceASTParser astParser,
- Map<String, DiceASTExpression> enviroment) {
- if (enviroment.containsKey(expressionToInline)) {
- System.err.println(
- "ERROR: There is no expression bound to the variable "
- + expressionToInline + ".");
- } else {
- AST<IDiceASTNode> inlinedAST = DiceASTInliner.inlineAST(
- enviroment.get(expressionToInline),
- new FunctionalMap<>(enviroment));
-
- enviroment.put(resultingVariable,
- new DiceASTExpression(inlinedAST, enviroment));
- }
- }
- }
-
- /**
- * Print the enviroment for debugging/inspection purposes
- *
- * @author ben
- *
- */
- public static final class EnviromentPrinter implements
- BiConsumer<DiceASTParser, Map<String, DiceASTExpression>> {
- @Override
- public void accept(DiceASTParser astParser,
- Map<String, DiceASTExpression> enviroment) {
- enviroment.forEach((variable, boundExpression) -> System.out
- .println("\tKey: " + variable + "\n\t\tExp: "
- + boundExpression.toString()));
- }
- }
-} \ No newline at end of file
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java
deleted file mode 100644
index 7db6ab3..0000000
--- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package bjc.dicelang.examples;
-
-import java.util.Map;
-
-import bjc.dicelang.old.ast.DiceASTExpression;
-import bjc.dicelang.old.ast.DiceASTParser;
-import bjc.utils.data.Pair;
-
-/**
- * Internal state of the AST-based dice langugae
- *
- * @author ben
- *
- */
-public class DiceASTLanguageState
- extends Pair<DiceASTParser, Map<String, DiceASTExpression>> {
-
- /**
- * Create a new state
- */
- public DiceASTLanguageState() {
- }
-
- /**
- * Create a new state with the given contents
- *
- * @param left
- * The parser to use
- * @param right
- * The enviroment to use
- */
- public DiceASTLanguageState(DiceASTParser left,
- Map<String, DiceASTExpression> right) {
- super(left, right);
- }
-} \ No newline at end of file
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java
deleted file mode 100644
index 23718ff..0000000
--- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java
+++ /dev/null
@@ -1,333 +0,0 @@
-package bjc.dicelang.examples;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.function.BiConsumer;
-
-import bjc.dicelang.IDiceExpression;
-import bjc.dicelang.old.ast.DiceASTDefinedChecker;
-import bjc.dicelang.old.ast.DiceASTExpression;
-import bjc.dicelang.old.ast.DiceASTInliner;
-import bjc.dicelang.old.ast.DiceASTParser;
-import bjc.dicelang.old.ast.DiceASTReferenceChecker;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.optimization.DiceASTOptimizer;
-
-import static bjc.dicelang.examples.DiceASTLanguagePragmaHandlers.*;
-
-import bjc.utils.data.GenHolder;
-import bjc.utils.data.IHolder;
-import bjc.utils.funcdata.FunctionalMap;
-import bjc.utils.funcdata.IFunctionalMap;
-import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod;
-import bjc.utils.parserutils.AST;
-
-/**
- * A test of the AST based dice language
- *
- * @author ben
- *
- */
-public class DiceASTLanguageTest {
- /**
- * The 'special commands' that aren't normal expressions that can be
- * invoked from the prompt
- */
- private static Map<String, BiConsumer<String, DiceASTLanguageState>> specialCommands;
-
- static {
- specialCommands = new HashMap<>();
-
- // Put all the defined special commands in place
- specialCommands.put("roll", DiceASTLanguageTest::rollReference);
- specialCommands.put("env", DiceASTLanguageTest::printEnv);
- specialCommands.put("inline", DiceASTLanguageTest::inlineVariable);
- specialCommands.put("optimize",
- DiceASTLanguageTest::optimizeReference);
- }
-
- private static void optimizeReference(String command,
- DiceASTLanguageState languageState) {
- String[] args = command.split(" ");
-
- if (args.length != 2) {
- System.err.println(
- "ERROR: Optimize requires the name of the expression to optimize");
- }
-
- languageState.doWith((astParser, enviroment) -> {
- if (!enviroment.containsKey(args[1])) {
- System.err.println(
- "ERROR: Attempted to optimize undefined variable "
- + args[1]);
- }
-
- AST<IDiceASTNode> optimizedTree = DiceASTOptimizer
- .optimizeTree(enviroment.get(args[1]).getAst());
-
- System.out.println("Optimized: " + optimizedTree);
- });
- }
-
- /**
- * Inline the references in an expression.
- *
- * This means replace variable references with the current contents of
- * the variables they refer to
- *
- * @param command
- * The command and its arguments
- * @param languageState
- * The state of the language at the moment
- */
- private static void inlineVariable(String command,
- DiceASTLanguageState languageState) {
- // Split the string into components
- String[] args = command.split(" ");
-
- // Make sure we have the correct amount of arguments
- if (args.length != 3) {
- System.err.println(
- "ERROR: Inline requires you provide the name of expression"
- + " to inline, as well as the name of the variable to bind"
- + " the result to.");
- return;
- }
-
- String expressionToInline = args[1];
-
- String resultingVariable = args[2];
-
- System.out.println("Inlining references in " + args[1]
- + " and binding to " + resultingVariable);
-
- languageState.doWith(
- new InlineHandler(expressionToInline, resultingVariable));
- }
-
- /**
- * Print all bound variables in the current enviroment, as well as what
- * they're bound to
- *
- * @param command
- * The command and its arguments
- * @param stat
- * The state of the language at the moment
- */
- private static void printEnv(String command,
- DiceASTLanguageState stat) {
- System.out.println("Printing enviroment for debugging purposes.");
-
- stat.doWith(new EnviromentPrinter());
- }
-
- /**
- * Roll an expression a given number of times
- *
- * @param command
- * The command and its arguments
- * @param languageState
- * The state of the language at the moments
- */
- private static void rollReference(String command,
- DiceASTLanguageState languageState) {
- String[] args = command.split(" ");
-
- if (args.length != 3) {
- System.err.println("ERROR: Roll requires two arguments."
- + " The name of the expression to roll, "
- + "followed by the number of times to roll it");
- return;
- }
-
- System.out.println("\tRolling dice expression " + args[1] + " "
- + args[2] + " times.");
-
- String expressionName = args[1];
-
- int numberOfRolls;
-
- try {
- numberOfRolls = Integer.parseInt(args[2]);
- } catch (@SuppressWarnings("unused") NumberFormatException nfex) {
- // Don't care about details
- System.err.println(
- "ERROR: The second argument must be a valid number, and "
- + args[2] + " is not one.");
- return;
- }
-
- IDiceExpression expressionToRoll = languageState
- .merge((astParser, enviroment) -> {
- if (!enviroment.containsKey(expressionName)) {
- return null;
- }
-
- return enviroment.get(expressionName);
- });
-
- if (expressionToRoll == null) {
- System.err.println(
- "ERROR: There is no expression bound to the variable "
- + expressionName + ".");
- return;
- }
-
- for (int i = 1; i <= numberOfRolls; i++) {
- int currentRoll = expressionToRoll.roll();
-
- System.out.println("\tRolled " + currentRoll);
- }
- }
-
- /**
- * Main method of class
- *
- * @param args
- * Unused CLI args
- */
- public static void main(String[] args) {
- Scanner inputSource = new Scanner(System.in);
- int commandNumber = 0;
-
- System.out.print("dice-lang-" + commandNumber + "> ");
- String currentLine = inputSource.nextLine();
-
- // The enviroment for variables
- Map<String, DiceASTExpression> enviroment = new HashMap<>();
-
- // The parser to turn strings into AST's
- DiceASTParser astParser = new DiceASTParser();
-
- DiceASTLanguageState languageState = new DiceASTLanguageState(
- astParser, enviroment);
-
- while (!currentLine.equalsIgnoreCase("quit")) {
- String prospectiveCommandName = currentLine.split(" ")[0];
-
- // Handle special commands
- if (specialCommands.containsKey(prospectiveCommandName)) {
- specialCommands.get(prospectiveCommandName)
- .accept(currentLine, languageState);
- } else {
-
- // Build an AST from the string expression
- AST<IDiceASTNode> builtAST;
-
- try {
- builtAST = DiceASTParser.buildAST(currentLine);
- } catch (IllegalStateException isex) {
- System.out.println(
- "ERROR: " + isex.getLocalizedMessage());
-
- currentLine = getNextCommand(inputSource,
- commandNumber);
-
- continue;
- }
-
- // Build a rollable expression from the AST
- DiceASTExpression expression = new DiceASTExpression(
- builtAST, enviroment);
-
- int sampleRoll;
-
- try {
- sampleRoll = expression.roll();
- } catch (UnsupportedOperationException usex) {
- System.out.println(
- "ERROR: " + usex.getLocalizedMessage());
-
- currentLine = getNextCommand(inputSource,
- commandNumber);
-
- continue;
- }
-
- if (checkUndefined(enviroment, expression)) {
- System.out.println(
- "ERROR: Expression contains undefined variables."
- + " Problematic expression: \n\t"
- + expression);
-
- currentLine = getNextCommand(inputSource,
- commandNumber);
-
- continue;
- }
-
- expression = handleUpdateLast(enviroment, expression);
-
- // Print out results
- System.out.println("\tParsed: " + expression.toString());
- System.out.println("\t\tSample Roll: " + sampleRoll);
- }
-
- // Increase the number of commands
- commandNumber++;
-
- currentLine = getNextCommand(inputSource, commandNumber);
- }
-
- System.out.println("Bye.");
-
- // Cleanup after ourselves
- inputSource.close();
- }
-
- private static DiceASTExpression handleUpdateLast(
- Map<String, DiceASTExpression> enviroment,
- DiceASTExpression expression) {
- IHolder<Boolean> canUpdateLast = new GenHolder<>(true);
-
- // Check that no node references last
- expression.getAst().traverse(TreeLinearizationMethod.PREORDER,
- new DiceASTReferenceChecker(canUpdateLast, "last"));
-
- // Update last if we can
- if (canUpdateLast.unwrap((flag) -> flag)) {
- enviroment.put("last", expression);
- } else {
- // We need to freeze out references to last
- expression = freezeOutLast(enviroment, expression.getAst());
-
- enviroment.put("last", expression);
- }
-
- return expression;
- }
-
- private static boolean checkUndefined(
- Map<String, DiceASTExpression> enviroment,
- DiceASTExpression expression) {
- IHolder<Boolean> containsUndefined = new GenHolder<>(false);
-
- // Check that no node references last
- expression.getAst().traverse(TreeLinearizationMethod.PREORDER,
- new DiceASTDefinedChecker(containsUndefined, enviroment));
-
- return containsUndefined.unwrap((bool) -> bool);
- }
-
- private static String getNextCommand(Scanner inputSource,
- int commandNumber) {
- String currentLine;
- // Read a new command
- System.out.print("dice-lang-" + commandNumber + "> ");
- currentLine = inputSource.nextLine();
- return currentLine;
- }
-
- private static DiceASTExpression freezeOutLast(
- Map<String, DiceASTExpression> enviroment,
- AST<IDiceASTNode> builtAST) {
- IFunctionalMap<String, AST<IDiceASTNode>> transformedEnviroment = new FunctionalMap<>(
- enviroment).mapValues((expr) -> expr.getAst());
-
- AST<IDiceASTNode> expressionSansLast = DiceASTInliner
- .selectiveInline(builtAST, transformedEnviroment, "last");
-
- return new DiceASTExpression(expressionSansLast, enviroment);
- }
-}
diff --git a/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java b/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java
index c6aa0a7..16e1761 100644
--- a/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java
+++ b/dice-lang/src/main/java/bjc/dicelang/IDiceExpression.java
@@ -1,5 +1,7 @@
package bjc.dicelang;
+import bjc.utils.funcutils.StringUtils;
+
/**
* An expression for something that can be rolled like a polyhedral die
*
@@ -37,4 +39,37 @@ public interface IDiceExpression {
public default boolean canOptimize() {
return false;
}
+
+ /**
+ * Parse this node into an expression
+ * @param exp The string to convert to an expression
+ *
+ * @return The node in expression form
+ */
+ static IDiceExpression toExpression(String exp) {
+ String literalData = exp;
+
+ if (StringUtils.containsInfixOperator(literalData, "c")) {
+ String[] strangs = literalData.split("c");
+
+ return new CompoundDice(strangs);
+ } else if (StringUtils.containsInfixOperator(literalData,
+ "d")) {
+ /*
+ * Handle dice groups
+ */
+ return ComplexDice.fromString(literalData);
+ } else {
+ try {
+ return new ScalarDie(Integer.parseInt(literalData));
+ } catch (NumberFormatException nfex) {
+ UnsupportedOperationException usex = new UnsupportedOperationException(
+ "Found malformed leaf token " + exp);
+
+ usex.initCause(nfex);
+
+ throw usex;
+ }
+ }
+ }
} \ 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
new file mode 100644
index 0000000..93b56de
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java
@@ -0,0 +1,261 @@
+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;
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+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.Pair;
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IFunctionalMap;
+import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod;
+import bjc.utils.parserutils.AST;
+
+/**
+ * Evaluate a dice AST to an integer value
+ *
+ * @author ben
+ *
+ */
+public class DiceASTEvaluator {
+ 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.merge((leftValue, leftAST) -> {
+ return rightNode.merge((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));
+ });
+ });
+ }
+ }
+
+ /**
+ * Evaluate the provided AST to a numeric value
+ *
+ * @param expression
+ * The expression to evaluate
+ * @param enviroment
+ * 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);
+
+ return expression.collapse((node) -> {
+ return evaluateLeaf(node, enviroment);
+ }, collapsers::get, (pair) -> {
+ return pair.merge((left, right) -> left);
+ });
+ }
+
+ /**
+ * 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<>();
+
+ operatorCollapsers.put(OperatorDiceNode.ADD,
+ new ArithmeticCollapser(OperatorDiceNode.ADD,
+ (left, right) -> left + right));
+
+ operatorCollapsers.put(OperatorDiceNode.SUBTRACT,
+ new ArithmeticCollapser(OperatorDiceNode.SUBTRACT,
+ (left, right) -> left - right));
+
+ operatorCollapsers.put(OperatorDiceNode.MULTIPLY,
+ new ArithmeticCollapser(OperatorDiceNode.MULTIPLY,
+ (left, right) -> left * right));
+
+ operatorCollapsers.put(OperatorDiceNode.DIVIDE,
+ new ArithmeticCollapser(OperatorDiceNode.DIVIDE,
+ (left, right) -> left / right));
+
+ operatorCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
+ return parseBinding(enviroment, left, right);
+ });
+
+ operatorCollapsers.put(OperatorDiceNode.COMPOUND,
+ DiceASTEvaluator::parseCompound);
+
+ operatorCollapsers.put(OperatorDiceNode.GROUP,
+ DiceASTEvaluator::parseGroup);
+
+ return operatorCollapsers;
+ }
+
+ private static IPair<Integer, AST<IDiceASTNode>> parseBinding(
+ IFunctionalMap<String, AST<IDiceASTNode>> enviroment,
+ IPair<Integer, AST<IDiceASTNode>> left,
+ IPair<Integer, AST<IDiceASTNode>> right) {
+ return left.merge((leftValue, leftAST) -> {
+ return right.merge((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 that'll be auto-frozen to restore
+ // definition sanity
+ if (selfReference.unwrap((bool) -> bool)
+ && !variableName.equals("last")) {
+ throw new UnsupportedOperationException(
+ "Variable '" + variableName
+ + "' references itself. Problematic definition: \n\t"
+ + rightAST);
+ }
+
+ if (!variableName.equals("last")) {
+ enviroment.put(variableName, rightAST);
+ } else {
+ // Do nothing, last is a auto-handled meta-variable
+ }
+
+ return new Pair<>(rightValue, new AST<>(
+ OperatorDiceNode.ASSIGN, leftAST, rightAST));
+ });
+ });
+ }
+
+ private static IPair<Integer, AST<IDiceASTNode>> parseCompound(
+ IPair<Integer, AST<IDiceASTNode>> leftNode,
+ IPair<Integer, AST<IDiceASTNode>> rightNode) {
+ return leftNode.merge((leftValue, leftAST) -> {
+ return rightNode.merge((rightValue, rightAST) -> {
+ int compoundValue =
+ Integer.parseInt(Integer.toString(leftValue)
+ + Integer.toString(rightValue));
+
+ return new Pair<>(compoundValue, new AST<>(
+ OperatorDiceNode.COMPOUND, leftAST, rightAST));
+ });
+ });
+ }
+
+ private static IPair<Integer, AST<IDiceASTNode>> parseGroup(
+ IPair<Integer, AST<IDiceASTNode>> leftNode,
+ IPair<Integer, AST<IDiceASTNode>> rightNode) {
+ return leftNode.merge((leftValue, leftAST) -> {
+ return rightNode.merge((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);
+ }
+
+ int rolledValue =
+ new ComplexDice(leftValue, rightValue).roll();
+
+ return new Pair<>(rolledValue, new AST<>(
+ OperatorDiceNode.GROUP, leftAST, rightAST));
+ });
+ });
+ }
+
+ private static IPair<Integer, AST<IDiceASTNode>> evaluateLeaf(
+ IDiceASTNode leafNode,
+ IFunctionalMap<String, AST<IDiceASTNode>> enviroment) {
+ int returnedValue = 0;
+
+ switch (leafNode.getType()) {
+ case LITERAL:
+ returnedValue = evaluateLiteral(leafNode, returnedValue);
+
+ break;
+ case VARIABLE:
+ String variableName =
+ ((VariableDiceNode) leafNode).getVariable();
+
+ returnedValue = evaluateAST(enviroment.get(variableName),
+ enviroment);
+ break;
+ case OPERATOR:
+ throw new UnsupportedOperationException(
+ "Operator '" + leafNode + "' cannot be a leaf.");
+ default:
+ break;
+
+ }
+
+ return new Pair<>(returnedValue, new AST<>(leafNode));
+ }
+
+ private static int evaluateLiteral(IDiceASTNode leafNode,
+ int returnedValue) {
+ DiceLiteralType literalType =
+ ((ILiteralDiceNode) leafNode).getLiteralType();
+
+ switch (literalType) {
+ case DICE:
+ returnedValue = ((DiceLiteralNode) leafNode).getValue();
+ break;
+ case INTEGER:
+ returnedValue = ((IntegerLiteralNode) leafNode).getValue();
+ break;
+ default:
+ throw new UnsupportedOperationException("Literal value '"
+ + leafNode + "' is of a type (" + literalType
+ + ") not currently supported.");
+ }
+ return returnedValue;
+ }
+}
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 db2ba98..f6500e3 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
@@ -2,10 +2,14 @@ package bjc.dicelang.ast;
import java.util.InputMismatchException;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.LiteralDiceNode;
-import bjc.dicelang.old.ast.nodes.OperatorDiceNode;
-import bjc.dicelang.old.ast.nodes.VariableDiceNode;
+import bjc.dicelang.IDiceExpression;
+import bjc.dicelang.ast.nodes.DiceLiteralNode;
+import bjc.dicelang.ast.nodes.DiceLiteralType;
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+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.funcdata.IFunctionalList;
import bjc.utils.parserutils.AST;
import bjc.utils.parserutils.TreeConstructor;
@@ -26,8 +30,8 @@ public class DiceASTParser {
*/
public static AST<IDiceASTNode> createFromString(
IFunctionalList<String> tokens) {
- AST<String> rawTokens =
- TreeConstructor.constructTree(tokens, (token) -> {
+ AST<String> rawTokens = TreeConstructor.constructTree(tokens,
+ (token) -> {
return isOperatorNode(token);
}, (operator) -> false, null);
// The last argument is valid because there are no special
@@ -48,8 +52,22 @@ public class DiceASTParser {
}
private static IDiceASTNode convertLeafNode(String leafNode) {
- if (LiteralDiceNode.isLiteral(leafNode)) {
- return new LiteralDiceNode(leafNode);
+ DiceLiteralType literalType = ILiteralDiceNode
+ .getLiteralType(leafNode);
+
+ if (literalType != null) {
+ switch (literalType) {
+ case DICE:
+ return new DiceLiteralNode(
+ IDiceExpression.toExpression(leafNode));
+ case INTEGER:
+ return new IntegerLiteralNode(
+ Integer.parseInt(leafNode));
+ default:
+ throw new InputMismatchException(
+ "Cannot convert string '" + leafNode
+ + "' into a literal.");
+ }
}
return new VariableDiceNode(leafNode);
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTReferenceChecker.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java
index 3e0ceec..809243a 100644
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTReferenceChecker.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java
@@ -1,10 +1,10 @@
-package bjc.dicelang.old.ast;
+package bjc.dicelang.ast;
import java.util.function.Consumer;
-import bjc.dicelang.old.ast.nodes.DiceASTType;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.VariableDiceNode;
+import bjc.dicelang.ast.nodes.DiceASTType;
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+import bjc.dicelang.ast.nodes.VariableDiceNode;
import bjc.utils.data.IHolder;
/**
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/IOperatorCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
index 36243a6..ed818d4 100644
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/IOperatorCollapser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
@@ -1,9 +1,9 @@
-package bjc.dicelang.old.ast;
+package bjc.dicelang.ast;
import java.util.function.BinaryOperator;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.utils.data.Pair;
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+import bjc.utils.data.IPair;
import bjc.utils.parserutils.AST;
/**
@@ -13,6 +13,6 @@ import bjc.utils.parserutils.AST;
*
*/
public interface IOperatorCollapser
- extends BinaryOperator<Pair<Integer, AST<IDiceASTNode>>> {
+ extends BinaryOperator<IPair<Integer, AST<IDiceASTNode>>> {
// Just an alias
}
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/DiceASTType.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceASTType.java
index 633d1d9..9feb461 100644
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/DiceASTType.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceASTType.java
@@ -1,4 +1,4 @@
-package bjc.dicelang.old.ast.nodes;
+package bjc.dicelang.ast.nodes;
/**
* An enum to represent the type of node an AST node is
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralNode.java
new file mode 100644
index 0000000..82c764d
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralNode.java
@@ -0,0 +1,57 @@
+package bjc.dicelang.ast.nodes;
+
+import bjc.dicelang.IDiceExpression;
+
+/**
+ * Represents a literal backed by a dice expression
+ *
+ * @author ben
+ *
+ */
+public class DiceLiteralNode implements ILiteralDiceNode {
+ private IDiceExpression expression;
+
+ /**
+ * Create a new literal from an expression
+ *
+ * @param exp
+ * The expression to attempt to create a literal from
+ */
+ public DiceLiteralNode(IDiceExpression exp) {
+ expression = exp;
+ }
+
+ /**
+ * Check if this node can be optimized to a constant
+ *
+ * @return Whether or not this node can be optimized to a constant
+ * @see bjc.dicelang.IDiceExpression#canOptimize()
+ */
+ public boolean canOptimize() {
+ return expression.canOptimize();
+ }
+
+ @Override
+ public DiceLiteralType getLiteralType() {
+ return DiceLiteralType.DICE;
+ }
+
+ /**
+ * Return a value from the expression being represented
+ *
+ * @return A value from the expression being represented
+ */
+ public int getValue() {
+ return expression.roll();
+ }
+
+ /**
+ * Optimize this node to a constant if possible
+ *
+ * @return This node in constant form if possible
+ * @see bjc.dicelang.IDiceExpression#optimize()
+ */
+ public int optimize() {
+ return expression.optimize();
+ }
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralType.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralType.java
new file mode 100644
index 0000000..41c6b05
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralType.java
@@ -0,0 +1,18 @@
+package bjc.dicelang.ast.nodes;
+
+/**
+ * Represents the type of literals that can be in an AST
+ *
+ * @author ben
+ *
+ */
+public enum DiceLiteralType {
+ /**
+ * Represents a integral constant
+ */
+ INTEGER,
+ /**
+ * Represents a dice literal
+ */
+ DICE;
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceOperatorType.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceOperatorType.java
new file mode 100644
index 0000000..76aa2e3
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceOperatorType.java
@@ -0,0 +1,25 @@
+package bjc.dicelang.ast.nodes;
+
+/**
+ * Represents the different type of operators.
+ *
+ * Mostly, what distinguishes groups is that all the operators in a group
+ * have similiar precedence, and operate on similiar things
+ *
+ * @author ben
+ *
+ */
+public enum DiceOperatorType {
+ /**
+ * Represents operators that do math operations
+ */
+ MATH,
+ /**
+ * Represents operators that do things with dice
+ */
+ DICE,
+ /**
+ * Represents operators that do things with expressions
+ */
+ EXPRESSION;
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/IDiceASTNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IDiceASTNode.java
index 579c595..b7bf9a6 100644
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/IDiceASTNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IDiceASTNode.java
@@ -1,4 +1,4 @@
-package bjc.dicelang.old.ast.nodes;
+package bjc.dicelang.ast.nodes;
/**
* The interface for a node in a dice AST
@@ -8,16 +8,16 @@ package bjc.dicelang.old.ast.nodes;
*/
public interface IDiceASTNode {
/**
- * Check if this node represents an operator or not
+ * Get the type of AST node this node is
*
- * @return Whether or not this node represents an operator
+ * @return The type of AST node this AST node is
*/
- public boolean isOperator();
+ public DiceASTType getType();
/**
- * Get the type of AST node this node is
+ * Check if this node represents an operator or not
*
- * @return The type of AST node this AST node is
+ * @return Whether or not this node represents an operator
*/
- public DiceASTType getType();
+ public boolean isOperator();
} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/ILiteralDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/ILiteralDiceNode.java
new file mode 100644
index 0000000..b12b516
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/ILiteralDiceNode.java
@@ -0,0 +1,54 @@
+package bjc.dicelang.ast.nodes;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Represents a literal of some type in the AST
+ *
+ * @author ben
+ *
+ */
+public interface ILiteralDiceNode extends IDiceASTNode {
+ @Override
+ default DiceASTType getType() {
+ return DiceASTType.LITERAL;
+ }
+
+ @Override
+ default boolean isOperator() {
+ return false;
+ }
+
+ /**
+ * Get the type of literal this node represents
+ *
+ * @return The type of literal this node represents
+ */
+ DiceLiteralType getLiteralType();
+
+ /**
+ * Check if a token represents a literal, and if so, what type
+ *
+ * @param tok
+ * The token to check
+ * @return The type the literal would be if it is one, or null
+ * otherwise
+ */
+ static DiceLiteralType getLiteralType(String tok) {
+ if (StringUtils.countMatches(tok, 'c') == 1
+ && !tok.equalsIgnoreCase("c")) {
+ return DiceLiteralType.DICE;
+ } else if (StringUtils.countMatches(tok, 'd') == 1
+ && !tok.equalsIgnoreCase("d")) {
+ return DiceLiteralType.DICE;
+ } else {
+ try {
+ Integer.parseInt(tok);
+ return DiceLiteralType.INTEGER;
+ } catch (@SuppressWarnings("unused") NumberFormatException nfex) {
+ // We don't care about details
+ return null;
+ }
+ }
+ }
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IntegerLiteralNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IntegerLiteralNode.java
new file mode 100644
index 0000000..415f30f
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IntegerLiteralNode.java
@@ -0,0 +1,35 @@
+package bjc.dicelang.ast.nodes;
+
+/**
+ * Represents an integer literal of some kind
+ *
+ * @author ben
+ *
+ */
+public class IntegerLiteralNode implements ILiteralDiceNode {
+ private int value;
+
+ /**
+ * Create a new integer literal from the given number
+ *
+ * @param val
+ * The value this node represents
+ */
+ public IntegerLiteralNode(int val) {
+ value = val;
+ }
+
+ @Override
+ public DiceLiteralType getLiteralType() {
+ return DiceLiteralType.INTEGER;
+ }
+
+ /**
+ * Get the value this node represents
+ *
+ * @return The integer value of this node
+ */
+ public int getValue() {
+ return value;
+ }
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/OperatorDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java
index 3c06553..d034943 100644
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/OperatorDiceNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java
@@ -1,4 +1,6 @@
-package bjc.dicelang.old.ast.nodes;
+package bjc.dicelang.ast.nodes;
+
+import static bjc.dicelang.ast.nodes.DiceOperatorType.*;
// The following classes need to be changed upon addition of a new operator
// 1. DiceASTExpression
@@ -14,35 +16,41 @@ public enum OperatorDiceNode implements IDiceASTNode {
/**
* Represents adding two nodes
*/
- ADD,
+ ADD(MATH),
/**
* Represents assigning one node to another
*/
- ASSIGN,
+ ASSIGN(EXPRESSION),
/**
* Representings combining two node values together
*/
- COMPOUND,
+ COMPOUND(DICE),
/**
* Represents dividing two nodes
*/
- DIVIDE,
+ DIVIDE(MATH),
/**
* Represents using one node a variable number of times
*/
- GROUP,
+ GROUP(DICE),
/**
* Represents multiplying two nodes
*/
- MULTIPLY,
+ MULTIPLY(MATH),
/**
* Represents subtracting two nodes
*/
- SUBTRACT,
+ SUBTRACT(MATH);
+
/**
- * Represents executing one statement in the context of the other
+ * Represents the group of operator this operator is sorted into.
+ *
*/
- LET;
+ public final DiceOperatorType type;
+
+ private OperatorDiceNode(DiceOperatorType ty) {
+ type = ty;
+ }
/**
* Create a operator node from a string
@@ -64,11 +72,11 @@ public enum OperatorDiceNode implements IDiceASTNode {
case "/":
return DIVIDE;
case "d":
+ case "group":
return GROUP;
case "c":
+ case "compound":
return COMPOUND;
- case "->":
- return LET;
default:
throw new IllegalArgumentException(
s + " is not a valid operator node");
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/VariableDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/VariableDiceNode.java
index 262f99b..da66608 100644
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/VariableDiceNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/VariableDiceNode.java
@@ -1,7 +1,7 @@
-package bjc.dicelang.old.ast.nodes;
+package bjc.dicelang.ast.nodes;
/**
- * A node that represents a variable reference
+ * A node that represents a reference to a variable
*
* @author ben
*
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/package-info.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/package-info.java
new file mode 100644
index 0000000..cfa2511
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Classes for nodes in the dice-lang AST
+ * @author ben
+ *
+ */
+package bjc.dicelang.ast.nodes; \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTDefinedChecker.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTDefinedChecker.java
deleted file mode 100644
index e279d8e..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTDefinedChecker.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package bjc.dicelang.old.ast;
-
-import java.util.Map;
-import java.util.function.Consumer;
-
-import bjc.dicelang.old.ast.nodes.DiceASTType;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.VariableDiceNode;
-import bjc.utils.data.IHolder;
-
-/**
- * Check if the specified node references a particular variable
- *
- * @author ben
- *
- */
-public final class DiceASTDefinedChecker
- implements Consumer<IDiceASTNode> {
- /**
- * This is true if the specified node references the set variable
- */
- private IHolder<Boolean> referencesVariable;
-
- private Map<String, DiceASTExpression> enviroment;
-
- /**
- * Create a new reference checker
- *
- * @param referencesVar
- * The holder of whether the variable is referenced or not
- * @param env
- * The enviroment to check undefinedness against
- */
- public DiceASTDefinedChecker(IHolder<Boolean> referencesVar,
- Map<String, DiceASTExpression> env) {
- this.referencesVariable = referencesVar;
- this.enviroment = env;
- }
-
- @Override
- public void accept(IDiceASTNode astNode) {
- referencesVariable.transform((bool) -> checkUndefined(astNode));
- }
-
- /**
- * Check if a given AST node references an undefined variable
- *
- * @param astNode
- * The node to check
- * @return Whether or not the node directly the variable
- */
- private boolean checkUndefined(IDiceASTNode astNode) {
- if (astNode.getType() == DiceASTType.VARIABLE) {
- VariableDiceNode node = (VariableDiceNode) astNode;
-
- return !enviroment.containsKey(node.getVariable());
- }
-
- return false;
- }
-} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTExpression.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTExpression.java
deleted file mode 100644
index e6dca9e..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTExpression.java
+++ /dev/null
@@ -1,332 +0,0 @@
-package bjc.dicelang.old.ast;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-
-import bjc.dicelang.ComplexDice;
-import bjc.dicelang.IDiceExpression;
-import bjc.dicelang.old.ast.nodes.DiceASTType;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.LiteralDiceNode;
-import bjc.dicelang.old.ast.nodes.OperatorDiceNode;
-import bjc.dicelang.old.ast.nodes.VariableDiceNode;
-import bjc.utils.data.GenHolder;
-import bjc.utils.data.Pair;
-import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod;
-import bjc.utils.parserutils.AST;
-
-/**
- * An implementation of {@link IDiceExpression} backed by an AST of
- * {@link IDiceASTNode}s
- *
- * @author ben
- *
- */
-public class DiceASTExpression implements IDiceExpression {
- 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 Pair<Integer, AST<IDiceASTNode>> apply(
- Pair<Integer, AST<IDiceASTNode>> leftNode,
- Pair<Integer, AST<IDiceASTNode>> rightNode) {
- return leftNode.merge((leftValue, leftAST) -> {
- return rightNode.merge((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));
- });
- });
- }
- }
-
- private static final class VariableRetriever
- implements Function<IDiceASTNode, String> {
- @Override
- public String apply(IDiceASTNode node) {
- if (node.getType() != DiceASTType.VARIABLE) {
- throw new UnsupportedOperationException(
- "Attempted to assign to something that isn't a variable."
- + " This isn't supported yet. The problem node is "
- + node);
- }
-
- return ((VariableDiceNode) node).getVariable();
- }
- }
-
- /**
- * 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 Map<IDiceASTNode, IOperatorCollapser> buildOperations(
- Map<String, DiceASTExpression> enviroment) {
- Map<IDiceASTNode, IOperatorCollapser> operatorCollapsers =
- new HashMap<>();
-
- operatorCollapsers.put(OperatorDiceNode.ADD,
- new ArithmeticCollapser(OperatorDiceNode.ADD,
- (left, right) -> left + right));
-
- operatorCollapsers.put(OperatorDiceNode.SUBTRACT,
- new ArithmeticCollapser(OperatorDiceNode.SUBTRACT,
- (left, right) -> left - right));
-
- operatorCollapsers.put(OperatorDiceNode.MULTIPLY,
- new ArithmeticCollapser(OperatorDiceNode.MULTIPLY,
- (left, right) -> left * right));
-
- operatorCollapsers.put(OperatorDiceNode.DIVIDE,
- new ArithmeticCollapser(OperatorDiceNode.DIVIDE,
- (left, right) -> left / right));
-
- operatorCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
- return parseBinding(enviroment, left, right);
- });
-
- operatorCollapsers.put(OperatorDiceNode.COMPOUND,
- DiceASTExpression::parseCompound);
-
- operatorCollapsers.put(OperatorDiceNode.GROUP,
- DiceASTExpression::parseGroup);
-
- operatorCollapsers.put(OperatorDiceNode.LET, (left, right) -> {
- return doLet(left, right);
- });
-
- return operatorCollapsers;
- }
-
- private static Pair<Integer, AST<IDiceASTNode>> doLet(
- Pair<Integer, AST<IDiceASTNode>> left,
- Pair<Integer, AST<IDiceASTNode>> right) {
- return left.merge((leftValue, leftAST) -> {
- return right.merge((rightValue, rightAST) -> {
- if (!leftAST
- .applyToHead(DiceASTExpression::isAssignNode)) {
- // Just ignore the left block then
- return new Pair<>(rightValue, rightAST);
- }
-
- return null;
- });
- });
- }
-
- private static Boolean isAssignNode(IDiceASTNode node) {
- return node.getType() == DiceASTType.OPERATOR
- && node == OperatorDiceNode.ASSIGN;
- }
-
- private static Pair<Integer, AST<IDiceASTNode>> parseBinding(
- Map<String, DiceASTExpression> enviroment,
- Pair<Integer, AST<IDiceASTNode>> left,
- Pair<Integer, AST<IDiceASTNode>> right) {
- return left.merge((leftValue, leftAST) -> {
- return right.merge((rightValue, rightAST) -> {
- String variableName = leftAST
- .collapse(new VariableRetriever(), (operator) -> {
- throw new UnsupportedOperationException(
- "Can only assign to plain variable names. The problem operator is "
- + operator);
- }, (returnedAST) -> returnedAST);
-
- GenHolder<Boolean> selfReference = new GenHolder<>(false);
-
- DiceASTReferenceChecker refChecker =
- new DiceASTReferenceChecker(selfReference,
- variableName);
-
- rightAST.traverse(TreeLinearizationMethod.PREORDER,
- refChecker);
-
- // Ignore meta-variable that'll be auto-frozen to restore
- // definition sanity
- if (selfReference.unwrap((bool) -> bool)
- && !variableName.equals("last")) {
- throw new UnsupportedOperationException(
- "Variable '" + variableName
- + "' references itself. Problematic definition: \n\t"
- + rightAST);
- }
-
- if (!variableName.equals("last")) {
- enviroment.put(variableName,
- new DiceASTExpression(rightAST, enviroment));
- } else {
- // Do nothing, last is a auto-handled meta-variable
- }
-
- return new Pair<>(rightValue, new AST<>(
- OperatorDiceNode.ASSIGN, leftAST, rightAST));
- });
- });
- }
-
- private static Pair<Integer, AST<IDiceASTNode>> parseCompound(
- Pair<Integer, AST<IDiceASTNode>> leftNode,
- Pair<Integer, AST<IDiceASTNode>> rightNode) {
- return leftNode.merge((leftValue, leftAST) -> {
- return rightNode.merge((rightValue, rightAST) -> {
- int compoundValue =
- Integer.parseInt(Integer.toString(leftValue)
- + Integer.toString(rightValue));
-
- return new Pair<>(compoundValue, new AST<>(
- OperatorDiceNode.COMPOUND, leftAST, rightAST));
- });
- });
- }
-
- private static Pair<Integer, AST<IDiceASTNode>> parseGroup(
- Pair<Integer, AST<IDiceASTNode>> leftNode,
- Pair<Integer, AST<IDiceASTNode>> rightNode) {
- return leftNode.merge((leftValue, leftAST) -> {
- return rightNode.merge((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);
- }
-
- int rolledValue =
- new ComplexDice(leftValue, rightValue).roll();
-
- return new Pair<>(rolledValue, new AST<>(
- OperatorDiceNode.GROUP, leftAST, rightAST));
- });
- });
- }
-
- /**
- * The AST this expression will evaluate
- */
- private AST<IDiceASTNode> ast;
-
- /**
- * The enviroment to evaluate bindings and such against
- */
- private Map<String, DiceASTExpression> env;
-
- /**
- * Create a new dice expression backed by an AST
- *
- * @param ast
- * The AST backing this expression
- * @param env
- * The enviroment to evaluate bindings against
- */
- public DiceASTExpression(AST<IDiceASTNode> ast,
- Map<String, DiceASTExpression> env) {
- this.ast = ast;
- this.env = env;
- }
-
- /**
- * Expand a leaf AST token into a pair for evaluation
- *
- * @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>> 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 "
- + leafNode + ". These aren't supported.");
- }
- }
-
- 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<>(leafNode));
- }
-
- // Handle special case for defining variables
- return new Pair<>(0, new AST<>(leafNode));
- }
-
- /**
- * Get the AST bound to this expression
- *
- * @return the ast
- */
- public AST<IDiceASTNode> getAst() {
- return ast;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see bjc.utils.dice.IDiceExpression#roll()
- */
- @Override
- public int roll() {
- Map<IDiceASTNode, IOperatorCollapser> operations =
- buildOperations(env);
-
- return ast.collapse(this::evaluateLeaf, operations::get,
- (returnedValue) -> returnedValue
- .merge((left, right) -> left));
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#toString()
- */
- @Override
- 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/old/ast/DiceASTFlattener.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTFlattener.java
deleted file mode 100644
index 39c0797..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTFlattener.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package bjc.dicelang.old.ast;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-
-import org.apache.commons.lang3.StringUtils;
-
-import bjc.dicelang.BindingDiceExpression;
-import bjc.dicelang.ComplexDice;
-import bjc.dicelang.CompoundDice;
-import bjc.dicelang.OperatorDiceExpression;
-import bjc.dicelang.DiceExpressionType;
-import bjc.dicelang.IDiceExpression;
-import bjc.dicelang.ReferenceDiceExpression;
-import bjc.dicelang.ScalarDie;
-import bjc.dicelang.old.ast.nodes.DiceASTType;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.LiteralDiceNode;
-import bjc.dicelang.old.ast.nodes.OperatorDiceNode;
-import bjc.dicelang.old.ast.nodes.VariableDiceNode;
-import bjc.utils.parserutils.AST;
-
-/**
- * Flatten an {@link AST} of {@link IDiceASTNode} into a
- * {@link IDiceExpression}
- *
- * @author ben
- *
- */
-public class DiceASTFlattener {
- private static final class NodeCollapser
- implements Function<IDiceASTNode, IDiceExpression> {
- private Map<String, IDiceExpression> enviroment;
-
- public NodeCollapser(Map<String, IDiceExpression> env) {
- this.enviroment = env;
- }
-
- @Override
- public IDiceExpression apply(IDiceASTNode nod) {
- if (nod.getType() == DiceASTType.LITERAL) {
- return expFromLiteral((LiteralDiceNode) nod);
- } else if (nod.getType() == DiceASTType.VARIABLE) {
- String varName = ((VariableDiceNode) nod).getVariable();
-
- return new ReferenceDiceExpression(varName, enviroment);
- } else {
- throw new UnsupportedOperationException(
- "Attempted to flatten something that can't be"
- + " flattened. The culprit is " + nod);
- }
- }
-
- /**
- * Create a dice expression from a literal token
- *
- * @param tok
- * The token to convert to an expression
- * @return The dice expression represented by the token
- */
- private static IDiceExpression
- expFromLiteral(LiteralDiceNode tok) {
- String data = tok.getData();
-
- if (data.equals("")) {
- throw new UnsupportedOperationException(
- "Can't convert a blank token into a literal");
- }
-
- if (StringUtils.countMatches(data, 'c') == 1
- && !data.equalsIgnoreCase("c")) {
- String[] strangs = data.split("c");
-
- return new CompoundDice(ComplexDice.fromString(strangs[0]),
- ComplexDice.fromString(strangs[1]));
- } else if (StringUtils.countMatches(data, 'd') == 1
- && !data.equalsIgnoreCase("d")) {
- return ComplexDice.fromString(data);
- } else {
- return new ScalarDie(Integer.parseInt(data));
- }
- }
- }
-
- /**
- * Build the operations to use for tree flattening
- *
- * @param env
- * The enviroment the tree will be flattened against
- * @return The operations needed for tree flattening
- */
- private static Map<IDiceASTNode, BinaryOperator<IDiceExpression>>
- buildOperations(Map<String, IDiceExpression> env) {
- Map<IDiceASTNode, BinaryOperator<IDiceExpression>> opCollapsers =
- new HashMap<>();
-
- opCollapsers.put(OperatorDiceNode.ADD, (left, right) -> {
- return new OperatorDiceExpression(right, left,
- DiceExpressionType.ADD);
- });
- opCollapsers.put(OperatorDiceNode.SUBTRACT, (left, right) -> {
- return new OperatorDiceExpression(right, left,
- DiceExpressionType.SUBTRACT);
- });
- opCollapsers.put(OperatorDiceNode.MULTIPLY, (left, right) -> {
- return new OperatorDiceExpression(right, left,
- DiceExpressionType.MULTIPLY);
- });
- opCollapsers.put(OperatorDiceNode.DIVIDE, (left, right) -> {
- return new OperatorDiceExpression(right, left,
- DiceExpressionType.DIVIDE);
- });
- opCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
- return new BindingDiceExpression(left, right, env);
- });
- opCollapsers.put(OperatorDiceNode.COMPOUND, (left, right) -> {
- return new CompoundDice(left, right);
- });
- opCollapsers.put(OperatorDiceNode.GROUP, (left, right) -> {
- return new ComplexDice(left, right);
- });
-
- return opCollapsers;
- }
-
- /**
- * Flatten a AST into a dice expression
- *
- * @param ast
- * The AST to flatten
- * @param env
- * The enviroment to flatten against
- * @return The AST, flattened into a dice expression
- */
- public static IDiceExpression flatten(AST<IDiceASTNode> ast,
- Map<String, IDiceExpression> env) {
- Map<IDiceASTNode, BinaryOperator<IDiceExpression>> opCollapsers =
- buildOperations(env);
-
- return ast.collapse(new NodeCollapser(env), opCollapsers::get,
- (r) -> r);
- }
-}
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTInliner.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTInliner.java
deleted file mode 100644
index 802741f..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTInliner.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package bjc.dicelang.old.ast;
-
-import java.util.function.Function;
-
-import bjc.dicelang.old.ast.nodes.DiceASTType;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.VariableDiceNode;
-import bjc.utils.funcdata.FunctionalList;
-import bjc.utils.funcdata.FunctionalMap;
-import bjc.utils.funcdata.IFunctionalList;
-import bjc.utils.funcdata.IFunctionalMap;
-import bjc.utils.parserutils.AST;
-
-/**
- * Inline references in a dice AST, replacing variable references with what
- * the variables refer to
- *
- * @author ben
- *
- */
-public class DiceASTInliner {
- private static class NodeInliner
- implements Function<IDiceASTNode, AST<IDiceASTNode>> {
- private IFunctionalMap<String, AST<IDiceASTNode>> enviroment;
-
- public NodeInliner(IFunctionalMap<String, AST<IDiceASTNode>> env) {
- enviroment = env;
- }
-
- @Override
- public AST<IDiceASTNode> apply(IDiceASTNode nod) {
- if (nod.getType() == DiceASTType.VARIABLE) {
- return expandNode((VariableDiceNode) nod);
- }
-
- 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 SelectiveInliner extends NodeInliner {
-
- private IFunctionalList<String> variableNames;
-
- public SelectiveInliner(
- IFunctionalMap<String, AST<IDiceASTNode>> env,
- IFunctionalList<String> varNames) {
- super(env);
-
- variableNames = varNames;
- }
-
- @Override
- protected AST<IDiceASTNode> expandNode(
- VariableDiceNode variableNode) {
- if (variableNames.contains(variableNode.getVariable())) {
- return super.expandNode(variableNode);
- }
-
- return new AST<>(variableNode);
- }
- }
-
- /**
- * Inline the references in an AST
- *
- * @param tree
- * The tree to inline references in
- * @param env
- * The enviroment to get reference values from
- * @return The tree with references inlined
- */
- public static AST<IDiceASTNode> inlineAST(AST<IDiceASTNode> tree,
- IFunctionalMap<String, AST<IDiceASTNode>> env) {
- return selectiveInline(tree, env);
- }
-
- /**
- * Inline the references in an expression backed by an AST
- *
- * @param tree
- * The tree-backed expression to inline references in
- * @param env
- * The enviroment to get reference values from
- * @return The tree with references inlined
- */
- public static AST<IDiceASTNode> inlineAST(DiceASTExpression tree,
- FunctionalMap<String, DiceASTExpression> env) {
- return inlineAST(tree.getAst(),
- env.mapValues(expression -> expression.getAst()));
- }
-
- /**
- * Inline references to specified variables
- *
- * @param tree
- * The tree-backed expression to inline references in
- * @param env
- * The enviroment to resolve variables against
- * @param varNames
- * The names of the variables to inline
- * @return An AST with the specified variables inlined
- */
- public static AST<IDiceASTNode> selectiveInline(AST<IDiceASTNode> tree,
- IFunctionalMap<String, AST<IDiceASTNode>> env,
- String... varNames) {
- return selectiveInline(tree, env, new FunctionalList<>(varNames));
- }
-
- /**
- * Inline references to specified variables
- *
- * @param tree
- * The tree-backed expression to inline references in
- * @param env
- * The enviroment to resolve variables against
- * @param varNames
- * The names of the variables to inline
- * @return An AST with the specified variables inline
- */
- public static AST<IDiceASTNode> selectiveInline(AST<IDiceASTNode> tree,
- IFunctionalMap<String, AST<IDiceASTNode>> env,
- IFunctionalList<String> varNames) {
- return tree.flatMapTree(new SelectiveInliner(env, varNames));
- }
-} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java
deleted file mode 100644
index c9b48c8..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package bjc.dicelang.old.ast;
-
-import java.util.Deque;
-import java.util.LinkedList;
-import java.util.function.Function;
-
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.LiteralDiceNode;
-import bjc.dicelang.old.ast.nodes.OperatorDiceNode;
-import bjc.dicelang.old.ast.nodes.VariableDiceNode;
-import bjc.utils.data.IPair;
-import bjc.utils.data.Pair;
-import bjc.utils.funcdata.FunctionalStringTokenizer;
-import bjc.utils.funcdata.IFunctionalList;
-import bjc.utils.funcutils.ListUtils;
-import bjc.utils.parserutils.AST;
-import bjc.utils.parserutils.ShuntingYard;
-import bjc.utils.parserutils.TreeConstructor;
-
-/**
- * Create an AST from a string expression
- *
- * @author ben
- *
- */
-public class DiceASTParser {
- private static final class NodeBaker
- implements Function<String, IDiceASTNode> {
- @Override
- public IDiceASTNode apply(String tok) {
- if (isOperator(tok)) {
- return OperatorDiceNode.fromString(tok);
- } else if (LiteralDiceNode.isLiteral(tok)) {
- return new LiteralDiceNode(tok);
- } else {
- return new VariableDiceNode(tok);
- }
- }
- }
-
- /**
- * The yard to use for shunting expressions
- */
- private static ShuntingYard<String> yard;
-
- static {
- yard = new ShuntingYard<>();
-
- yard.addOp("d", 5); // dice operator: use for creating variable
- // size dice groups
- yard.addOp("c", 6); // compound operator: use for creating compound
- // dice from expressions
- yard.addOp(":=", 0); // binding operator: Bind a name to a variable
- // expression
- }
-
- /**
- * Build an AST from a string expression
- *
- * @param exp
- * The string to build from
- * @return An AST built from the passed in string
- */
- public static AST<IDiceASTNode> buildAST(String exp) {
- IFunctionalList<String> tokens = FunctionalStringTokenizer
- .fromString(exp).toList();
-
- Deque<IPair<String, String>> ops = new LinkedList<>();
-
- ops.add(new Pair<>("+", "\\+"));
- ops.add(new Pair<>("-", "-"));
- ops.add(new Pair<>("*", "\\*"));
- ops.add(new Pair<>("/", "/"));
- ops.add(new Pair<>(":=", ":="));
-
- IFunctionalList<String> semiExpandedTokens = ListUtils
- .splitTokens(tokens, ops);
-
- ops = new LinkedList<>();
-
- ops.add(new Pair<>("(", "\\("));
- ops.add(new Pair<>(")", "\\)"));
-
- IFunctionalList<String> fullyExpandedTokens = ListUtils
- .deAffixTokens(semiExpandedTokens, ops);
-
- IFunctionalList<String> shunted = yard.postfix(fullyExpandedTokens,
- (s) -> s);
-
- AST<String> rawAST = TreeConstructor.constructTree(shunted,
- DiceASTParser::isOperator);
-
- AST<IDiceASTNode> bakedAST = rawAST.transmuteAST(new NodeBaker());
-
- return bakedAST;
- }
-
- /**
- * Check if a token represents an operator
- *
- * @param tok
- * The token to check if it represents an operator
- * @return Whether or not the token represents an operator
- */
- private static boolean isOperator(String tok) {
- switch (tok) {
- case ":=":
- case "+":
- case "-":
- case "*":
- case "/":
- case "c":
- case "d":
- return true;
- default:
- return false;
- }
- }
-}
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/LiteralDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/LiteralDiceNode.java
deleted file mode 100644
index 46c84d0..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/LiteralDiceNode.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package bjc.dicelang.old.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
- *
- * @author ben
- *
- */
-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
- */
- private String value;
-
- /**
- * Create a new node with the given value
- *
- * @param data
- * The value to be in this node
- */
- public LiteralDiceNode(String data) {
- 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)
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- } else if (obj == null) {
- return false;
- } else if (getClass() != obj.getClass()) {
- return false;
- } else {
- LiteralDiceNode other = (LiteralDiceNode) obj;
-
- if (value == null) {
- if (other.value != null) {
- return false;
- }
- } else if (!value.equals(other.value)) {
- return false;
- }
-
- return true;
- }
- }
-
- /**
- * Get the data stored in this AST node
- *
- * @return the data stored in this AST node
- */
- public String getData() {
- return value;
- }
-
- @Override
- public DiceASTType getType() {
- return DiceASTType.LITERAL;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((value == null) ? 0 : value.hashCode());
- return result;
- }
-
- @Override
- public boolean isOperator() {
- 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) {
- UnsupportedOperationException usex = new UnsupportedOperationException(
- "Found malformed leaf token " + this);
-
- usex.initCause(nfex);
-
- throw usex;
- }
- }
- }
-
- /**
- * 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)
- *
- * @see java.lang.Object#toString()
- */
- @Override
- 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 (@SuppressWarnings("unused") NumberFormatException nfex) {
- // We don't care about details
- 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);
- }
-
- /**
- * Check if a token represents a literal
- *
- * @param tok
- * The token to check
- * @return Whether or not the token represents a literal
- */
- public static boolean isLiteral(String tok) {
- if (StringUtils.countMatches(tok, 'c') == 1
- && !tok.equalsIgnoreCase("c")) {
- return true;
- } else if (StringUtils.countMatches(tok, 'd') == 1
- && !tok.equalsIgnoreCase("d")) {
- return true;
- } else {
- try {
- Integer.parseInt(tok);
- return true;
- } catch (@SuppressWarnings("unused") NumberFormatException nfex) {
- // We don't care about details
- return false;
- }
- }
- }
-} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/package-info.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/package-info.java
deleted file mode 100644
index f99776f..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/nodes/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * This package contains the various Node types in the Dice AST
- * @author ben
- *
- */
-package bjc.dicelang.old.ast.nodes; \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/old/ast/optimization/DiceASTOptimizer.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/optimization/DiceASTOptimizer.java
deleted file mode 100644
index dead812..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/optimization/DiceASTOptimizer.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package bjc.dicelang.old.ast.optimization;
-
-import static bjc.dicelang.old.ast.nodes.DiceASTType.*;
-
-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.old.ast.nodes.DiceASTType;
-import bjc.dicelang.old.ast.nodes.IDiceASTNode;
-import bjc.dicelang.old.ast.nodes.LiteralDiceNode;
-import bjc.dicelang.old.ast.nodes.OperatorDiceNode;
-import bjc.utils.parserutils.AST;
-
-/**
- * Optimize an AST
- *
- * @author ben
- *
- */
-public class DiceASTOptimizer {
- private static final class NestedArithmeticOperationCollapser
- implements BinaryOperator<AST<IDiceASTNode>> {
- private IDiceASTNode type;
- private BiFunction<Integer, Integer, Integer> valueCollapser;
-
- public NestedArithmeticOperationCollapser(IDiceASTNode type,
- BiFunction<Integer, Integer, Integer> valueCollapser) {
- this.type = type;
- this.valueCollapser = valueCollapser;
- }
-
- @Override
- public AST<IDiceASTNode> apply(AST<IDiceASTNode> leftAST,
- AST<IDiceASTNode> rightAST) {
- AST<IDiceASTNode> rightBranchOfLeftAST = leftAST
- .applyToRight((rightSideAST) -> rightSideAST);
- AST<IDiceASTNode> leftBranchOfLeftAST = leftAST
- .applyToRight((rightSideAST) -> rightSideAST);
-
- boolean leftContainsNestedConstant = DiceASTOptimizer
- .checkNodeType(rightBranchOfLeftAST, LITERAL)
- && DiceASTOptimizer.isNodeConstant(leftAST);
-
- boolean isRightConstant = DiceASTOptimizer
- .checkNodeType(rightAST, LITERAL)
- && DiceASTOptimizer.isNodeConstant(leftAST);
-
- if (leftContainsNestedConstant && isRightConstant) {
- int combinedValue = valueCollapser.apply(
- getNodeValue(rightBranchOfLeftAST),
- getNodeValue(rightAST));
-
- AST<IDiceASTNode> newRightBranch = new AST<>(
- new LiteralDiceNode(combinedValue));
-
- return new AST<>(type, leftBranchOfLeftAST,
- newRightBranch);
- }
-
- return new AST<>(type, leftAST, rightAST);
- }
- }
-
- 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.MULTIPLY,
- new ArithmeticOperationCollapser(OperatorDiceNode.MULTIPLY,
- (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));
-
- return operatorCollapsers;
- }
-
- private static Map<IDiceASTNode, BinaryOperator<AST<IDiceASTNode>>> buildNestedConstantCollapsers() {
- Map<IDiceASTNode, BinaryOperator<AST<IDiceASTNode>>> operatorCollapsers = new HashMap<>();
-
- operatorCollapsers.put(OperatorDiceNode.ADD,
- new NestedArithmeticOperationCollapser(
- OperatorDiceNode.ADD,
- (leftVal, rightVal) -> leftVal + rightVal));
-
- operatorCollapsers.put(OperatorDiceNode.MULTIPLY,
- new NestedArithmeticOperationCollapser(
- OperatorDiceNode.MULTIPLY,
- (leftVal, rightVal) -> leftVal * rightVal));
-
- return operatorCollapsers;
- }
-
- 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()));
- }
-
- 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> astWithConstantsFolded = tree.collapse(
- DiceASTOptimizer::collapseLeaf,
- buildConstantCollapsers()::get,
- DiceASTOptimizer::finishTree);
-
- AST<IDiceASTNode> astWithNestedConstantsFolded = astWithConstantsFolded
- .collapse(DiceASTOptimizer::collapseLeaf,
- buildNestedConstantCollapsers()::get,
- DiceASTOptimizer::finishTree);
-
- return astWithNestedConstantsFolded;
- }
-
- 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/old/ast/optimization/package-info.java b/dice-lang/src/main/java/bjc/dicelang/old/ast/optimization/package-info.java
deleted file mode 100644
index ef39522..0000000
--- a/dice-lang/src/main/java/bjc/dicelang/old/ast/optimization/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * Contains classes for optimizing ASTs
- * @author ben
- *
- */
-package bjc.dicelang.old.ast.optimization; \ No newline at end of file