summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2016-04-03 17:45:05 -0400
committerbculkin2442 <bjculkin@mix.wvu.edu>2016-04-03 17:45:05 -0400
commitc8ae1ec096f5d1ac6db4f3a0035f7da106444e4e (patch)
tree6c32c65d84d11efcea2bad699d0b68fbbb362290
parent9a6ac8c88689073cd0769da15b40c4fe091f0813 (diff)
General code refactoring and maintenance
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java81
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java10
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java253
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java102
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java144
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java63
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTType.java27
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IDiceASTNode.java9
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java17
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/LiteralDiceNode.java60
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/OperatorDiceNode.java5
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/VariableDiceNode.java62
12 files changed, 637 insertions, 196 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
new file mode 100644
index 0000000..3eaf6b0
--- /dev/null
+++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java
@@ -0,0 +1,81 @@
+package bjc.dicelang.examples;
+
+import java.util.Map;
+import java.util.function.BiConsumer;
+
+import bjc.dicelang.ast.DiceASTExpression;
+import bjc.dicelang.ast.DiceASTFreezer;
+import bjc.dicelang.ast.DiceASTParser;
+import bjc.dicelang.ast.IDiceASTNode;
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.parserutils.AST;
+
+/**
+ * Container for pragma handlers
+ *
+ * @author ben
+ *
+ */
+public class DiceASTLanguagePragmaHandlers {
+ /**
+ * Handles freezing a specified expression to a new name
+ *
+ * @author ben
+ *
+ */
+ public static final class FreezeHandler implements
+ BiConsumer<DiceASTParser, Map<String, DiceASTExpression>> {
+ private String expressionToFreeze;
+ private String resultingVariable;
+
+ /**
+ * Create a new freeze handler
+ *
+ * @param expressionToFreeze
+ * The name of the expression to freeze
+ * @param resultingVariable
+ * The name of the variable to bind the frozen
+ * expression to
+ */
+ public FreezeHandler(String expressionToFreeze,
+ String resultingVariable) {
+ this.expressionToFreeze = expressionToFreeze;
+ this.resultingVariable = resultingVariable;
+ }
+
+ @Override
+ public void accept(DiceASTParser astParser,
+ Map<String, DiceASTExpression> enviroment) {
+ if (enviroment.containsKey(expressionToFreeze)) {
+ System.err.println(
+ "ERROR: There is no expression bound to the variable "
+ + expressionToFreeze + ".");
+ } else {
+ AST<IDiceASTNode> frozenAST = DiceASTFreezer.freezeAST(
+ enviroment.get(expressionToFreeze),
+ new FunctionalMap<>(enviroment));
+
+ enviroment.put(resultingVariable,
+ new DiceASTExpression(frozenAST, 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()));
+ }
+ }
+
+}
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java
index f5a6a29..92e75e3 100644
--- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java
+++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java
@@ -2,8 +2,8 @@ package bjc.dicelang.examples;
import java.util.Map;
-import bjc.dicelang.DiceExpressionParser;
import bjc.dicelang.ast.DiceASTExpression;
+import bjc.dicelang.ast.DiceASTParser;
import bjc.utils.data.Pair;
/**
@@ -12,8 +12,8 @@ import bjc.utils.data.Pair;
* @author ben
*
*/
-public class DiceASTLanguageState extends
- Pair<DiceExpressionParser, Map<String, DiceASTExpression>> {
+public class DiceASTLanguageState
+ extends Pair<DiceASTParser, Map<String, DiceASTExpression>> {
/**
* Create a new state
@@ -29,8 +29,8 @@ public class DiceASTLanguageState extends
* @param right
* The enviroment to use
*/
- public DiceASTLanguageState(DiceExpressionParser left,
+ 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
index e0f276d..a21ed66 100644
--- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java
+++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java
@@ -4,16 +4,18 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import bjc.dicelang.DiceExpressionParser;
import bjc.dicelang.IDiceExpression;
import bjc.dicelang.ast.DiceASTExpression;
import bjc.dicelang.ast.DiceASTFreezer;
import bjc.dicelang.ast.DiceASTParser;
+import bjc.dicelang.ast.DiceASTReferenceChecker;
import bjc.dicelang.ast.IDiceASTNode;
-import bjc.dicelang.ast.VariableDiceNode;
+
+import static bjc.dicelang.examples.DiceASTLanguagePragmaHandlers.*;
+
import bjc.utils.data.GenHolder;
+import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod;
import bjc.utils.parserutils.AST;
@@ -24,75 +26,127 @@ import bjc.utils.parserutils.AST;
*
*/
public class DiceASTLanguageTest {
- private static final class LastChecker
- implements Consumer<IDiceASTNode> {
- private GenHolder<Boolean> canUpdateLast;
+ /**
+ * The 'special commands' that aren't normal expressions that can be
+ * invoked from the prompt
+ */
+ private static Map<String, BiConsumer<String, DiceASTLanguageState>> specialCommands;
- public LastChecker(GenHolder<Boolean> canUpdateLast) {
- this.canUpdateLast = canUpdateLast;
- }
+ static {
+ specialCommands = new HashMap<>();
- @Override
- public void accept(IDiceASTNode tn) {
- if (tn instanceof VariableDiceNode && ((VariableDiceNode) tn)
- .getVariable().equals("last")) {
- canUpdateLast.transform((s) -> false);
- } else {
- canUpdateLast.transform((s) -> true);
- }
- }
+ // Put all the defined special commands in place
+ specialCommands.put("roll", DiceASTLanguageTest::rollReference);
+ specialCommands.put("env", DiceASTLanguageTest::printEnv);
+ specialCommands.put("freeze", DiceASTLanguageTest::freezeVar);
}
- private static Map<String, BiConsumer<String, DiceASTLanguageState>> acts;
-
- static {
- acts = new HashMap<>();
+ /**
+ * Freeze 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 freezeVar(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: Freeze requires you provide the name of expression"
+ + " to freeze, as well as the name of the variable to bind"
+ + " the result to.");
+ return;
+ }
- acts.put("roll", DiceASTLanguageTest::rollReference);
- acts.put("env", DiceASTLanguageTest::printEnv);
- acts.put("freeze", DiceASTLanguageTest::freezeVar);
- }
+ String expressionToFreeze = args[1];
- private static void freezeVar(String ln, DiceASTLanguageState stat) {
- String[] strangs = ln.split(" ");
+ String resultingVariable = args[2];
- System.out.println("Freezing references in " + strangs[1]);
+ System.out.println("Freezing references in " + args[1]
+ + " and binding to " + resultingVariable);
- stat.doWith((dep, env) -> {
- env.put(strangs[1], new DiceASTExpression(
- DiceASTFreezer.freezeAST(env.get(strangs[1]), env),
- env));
- });
+ languageState.doWith(
+ new FreezeHandler(expressionToFreeze, resultingVariable));
}
/**
- * @param ln
- * Unused parameter, kept in place to conform to expected
- * type sig
+ * 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 ln, DiceASTLanguageState stat) {
+ private static void printEnv(String command,
+ DiceASTLanguageState stat) {
System.out.println("Printing enviroment for debugging purposes.");
- stat.doWith((dep, env) -> env.forEach((key, exp) -> System.out
- .println("\tKey: " + key + "\tExp: " + exp.toString())));
+ stat.doWith(new EnviromentPrinter());
}
- private static void rollReference(String ln,
- DiceASTLanguageState stat) {
- String[] strangs = ln.split(" ");
+ /**
+ * 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 " + strangs[1] + " "
- + strangs[2] + " times.");
+ System.out.println("\tRolling dice expression " + args[1] + " "
+ + args[2] + " times.");
- int nRolls = Integer.parseInt(strangs[2]);
+ String expressionName = args[1];
- IDiceExpression dexp =
- stat.merge((dep, env) -> env.get(strangs[1]));
+ int numberOfRolls;
- for (int i = 1; i <= nRolls; i++) {
- int roll = dexp.roll();
+ try {
+ numberOfRolls = Integer.parseInt(args[2]);
+ } catch (NumberFormatException nfex) {
+ System.err.println(
+ "ERROR: The second argument must be a valid number, and "
+ + args[2] + " is not one.");
+ return;
+ }
- System.out.println("\tRolled " + roll);
+ IDiceExpression expressionToRoll =
+ languageState.merge((astParser, enviroment) -> {
+ if (!enviroment.containsKey(expressionName)) {
+ return null;
+ } else {
+ return enviroment.get(expressionName);
+ }
+ });
+
+ if (expressionToRoll == null) {
+ System.err.println(
+ "ERROR: There is no expression bound to the variable "
+ + expressionName + ".");
+ }
+
+ for (int i = 1; i <= numberOfRolls; i++) {
+ int currentRoll = expressionToRoll.roll();
+
+ System.out.println("\tRolled " + currentRoll);
}
}
@@ -103,49 +157,86 @@ public class DiceASTLanguageTest {
* Unused CLI args
*/
public static void main(String[] args) {
- Scanner scn = new Scanner(System.in);
- int i = 0;
+ Scanner inputSource = new Scanner(System.in);
+ int commandNumber = 0;
- System.out.print("dice-lang-" + i + "> ");
- String ln = scn.nextLine();
+ System.out.print("dice-lang-" + commandNumber + "> ");
+ String currentLine = inputSource.nextLine();
- DiceASTParser dap = new DiceASTParser();
+ // The enviroment for variables
+ Map<String, DiceASTExpression> enviroment = new HashMap<>();
- DiceExpressionParser dep = new DiceExpressionParser();
- Map<String, DiceASTExpression> env = new HashMap<>();
- DiceASTLanguageState state = new DiceASTLanguageState(dep, env);
+ // The parser to turn strings into AST's
+ DiceASTParser astParser = new DiceASTParser();
- while (!ln.equalsIgnoreCase("quit")) {
- String header = ln.split(" ")[0];
+ DiceASTLanguageState languageState =
+ new DiceASTLanguageState(astParser, enviroment);
- if (acts.containsKey(header)) {
- acts.get(header).accept(ln, state);
- } else {
+ while (!currentLine.equalsIgnoreCase("quit")) {
+ String prospectiveCommandName = currentLine.split(" ")[0];
- AST<IDiceASTNode> builtAST = dap.buildAST(ln);
- DiceASTExpression exp =
- new DiceASTExpression(builtAST, env);
-
- System.out.println("\tParsed: " + exp.toString());
- System.out.println("\tSample Roll: " + exp.roll());
-
- GenHolder<Boolean> canUpdateLast = new GenHolder<>(false);
-
- exp.getAst().traverse(TreeLinearizationMethod.PREORDER,
- new LastChecker(canUpdateLast));
+ // Handle special commands
+ if (specialCommands.containsKey(prospectiveCommandName)) {
+ specialCommands.get(prospectiveCommandName)
+ .accept(currentLine, languageState);
+ } else {
- if (canUpdateLast.unwrap((s) -> s)) {
- env.put("last", exp);
+ // Build an AST from the string expression
+ AST<IDiceASTNode> builtAST =
+ astParser.buildAST(currentLine);
+
+ // Build a rollable expression from the AST
+ DiceASTExpression expression =
+ new DiceASTExpression(builtAST, enviroment);
+
+ // Print out results
+ System.out.println("\tParsed: " + expression.toString());
+ System.out
+ .println("\t\tSample Roll: " + expression.roll());
+
+ // Assume we can update last by default
+ GenHolder<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
+ enviroment.put("last",
+ freezeOutLast(enviroment, builtAST));
}
}
- i++;
+ // Increase the number of commands
+ commandNumber++;
- System.out.print("dice-lang-" + i + "> ");
- ln = scn.nextLine();
+ // Read a new command
+ System.out.print("dice-lang-" + commandNumber + "> ");
+ currentLine = inputSource.nextLine();
}
System.out.println("Bye.");
- scn.close();
+
+ // Cleanup after ourselves
+ inputSource.close();
+ }
+
+ private static DiceASTExpression freezeOutLast(
+ Map<String, DiceASTExpression> enviroment,
+ AST<IDiceASTNode> builtAST) {
+ FunctionalMap<String, AST<IDiceASTNode>> transformedEnviroment =
+ new FunctionalMap<>(enviroment)
+ .mapValues((expr) -> expr.getAst());
+
+ AST<IDiceASTNode> expressionSansLast = DiceASTFreezer
+ .selectiveFreeze(builtAST, transformedEnviroment, "last");
+
+ return new DiceASTExpression(expressionSansLast, enviroment);
}
}
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 a79c466..078c952 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java
@@ -2,13 +2,12 @@ package bjc.dicelang.ast;
import java.util.HashMap;
import java.util.Map;
-import java.util.function.BinaryOperator;
-
import org.apache.commons.lang3.StringUtils;
import bjc.dicelang.ComplexDice;
import bjc.dicelang.CompoundDice;
import bjc.dicelang.IDiceExpression;
+
import bjc.utils.data.Pair;
import bjc.utils.parserutils.AST;
@@ -24,67 +23,84 @@ public class DiceASTExpression implements IDiceExpression {
/**
* Build the map of operations to use when collapsing the AST
*
- * @param env
+ * @param enviroment
* The enviroment to evaluate bindings and such against
* @return The operations to use when collapsing the AST
*/
- private static
- Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>>
- buildOperations(Map<String, DiceASTExpression> env) {
- Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> opCollapsers =
+ private static Map<IDiceASTNode, IOperatorCollapser>
+ buildOperations(Map<String, DiceASTExpression> enviroment) {
+ Map<IDiceASTNode, IOperatorCollapser> operatorCollapsers =
new HashMap<>();
- opCollapsers.put(OperatorDiceNode.ADD, (left, right) -> {
- return left.merge((lval, last) -> right.merge((rval, rast) -> {
- return new Pair<>(lval + rval,
- new AST<>(OperatorDiceNode.ADD, last, rast));
- }));
-
- });
- opCollapsers.put(OperatorDiceNode.SUBTRACT, (left, right) -> {
- return left.merge((lval, last) -> right.merge((rval, rast) -> {
- return new Pair<>(lval - rval,
- new AST<>(OperatorDiceNode.SUBTRACT, last, rast));
- }));
-
- });
- opCollapsers.put(OperatorDiceNode.MULTIPLY, (left, right) -> {
- return left.merge((lval, last) -> right.merge((rval, rast) -> {
- return new Pair<>(lval * rval,
- new AST<>(OperatorDiceNode.MULTIPLY, last, rast));
- }));
-
- });
- opCollapsers.put(OperatorDiceNode.DIVIDE, (left, right) -> {
+ operatorCollapsers.put(OperatorDiceNode.ADD,
+ (leftNode, rightNode) -> {
+ return leftNode.merge((leftValue, leftAST) -> {
+ return rightNode.merge((rightValue, rightAST) -> {
+ return new Pair<>(leftValue + rightValue,
+ new AST<>(OperatorDiceNode.ADD,
+ leftAST, rightAST));
+ });
+ });
+
+ });
+ operatorCollapsers.put(OperatorDiceNode.SUBTRACT,
+ (left, right) -> {
+ return left.merge(
+ (lval, last) -> right.merge((rval, rast) -> {
+ return new Pair<>(lval - rval,
+ new AST<>(
+ OperatorDiceNode.SUBTRACT,
+ last, rast));
+ }));
+
+ });
+ operatorCollapsers.put(OperatorDiceNode.MULTIPLY,
+ (left, right) -> {
+ return left.merge(
+ (lval, last) -> right.merge((rval, rast) -> {
+ return new Pair<>(lval * rval,
+ new AST<>(
+ OperatorDiceNode.MULTIPLY,
+ last, rast));
+ }));
+
+ });
+ operatorCollapsers.put(OperatorDiceNode.DIVIDE, (left, right) -> {
return left.merge((lval, last) -> right.merge((rval, rast) -> {
return new Pair<>(lval / rval,
new AST<>(OperatorDiceNode.DIVIDE, last, rast));
}));
});
- opCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
+ operatorCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
return left.merge((lval, last) -> right.merge((rval, rast) -> {
String nam = last.collapse((nod) -> {
return ((VariableDiceNode) nod).getVariable();
}, (v) -> (lv, rv) -> null, (r) -> r);
- env.put(nam, new DiceASTExpression(rast, env));
+ enviroment.put(nam,
+ new DiceASTExpression(rast, enviroment));
return new Pair<>(rval,
new AST<>(OperatorDiceNode.ASSIGN, last, rast));
}));
});
- opCollapsers.put(OperatorDiceNode.COMPOUND, (left, right) -> {
- return left.merge((lval, last) -> right.merge((rval, rast) -> {
- int ival = Integer.parseInt(
- Integer.toString(lval) + Integer.toString(rval));
-
- return new Pair<>(ival,
- new AST<>(OperatorDiceNode.COMPOUND, last, rast));
- }));
- });
- opCollapsers.put(OperatorDiceNode.GROUP, (left, right) -> {
+ operatorCollapsers.put(OperatorDiceNode.COMPOUND,
+ (left, right) -> {
+ return left.merge(
+ (lval, last) -> right.merge((rval, rast) -> {
+ int ival = Integer
+ .parseInt(Integer.toString(lval)
+ + Integer.toString(rval));
+
+ return new Pair<>(ival,
+ new AST<>(
+ OperatorDiceNode.COMPOUND,
+ last, rast));
+ }));
+ });
+ operatorCollapsers.put(OperatorDiceNode.GROUP, (left, right) -> {
return left.merge((lval, last) -> right.merge((rval, rast) -> {
return new Pair<>(new ComplexDice(lval, rval).roll(),
@@ -92,7 +108,7 @@ public class DiceASTExpression implements IDiceExpression {
}));
});
- return opCollapsers;
+ return operatorCollapsers;
}
/**
@@ -176,7 +192,7 @@ public class DiceASTExpression implements IDiceExpression {
*/
@Override
public int roll() {
- Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> operations =
+ Map<IDiceASTNode, IOperatorCollapser> operations =
buildOperations(env);
return ast.collapse(this::evalLeaf, operations::get,
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java
index 0e2134b..bad24f8 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java
@@ -1,7 +1,9 @@
package bjc.dicelang.ast;
-import java.util.Map;
+import java.util.function.Function;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.parserutils.AST;
/**
@@ -12,32 +14,57 @@ import bjc.utils.parserutils.AST;
*
*/
public class DiceASTFreezer {
- /**
- * Expand a reference
- *
- * @param vnode
- * The node containing the reference to expand
- * @param env
- * The enviroment to expand against
- * @return The expanded reference
- */
- private static AST<IDiceASTNode> expandNode(VariableDiceNode vnode,
- Map<String, AST<IDiceASTNode>> env) {
- return env.get(vnode.getVariable());
+ 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);
+ }
}
- /**
- * Expand a reference
- *
- * @param vnode
- * The node containing the reference to expand
- * @param env
- * The enviroment to expand against
- * @return The expanded reference
- */
- private static AST<IDiceASTNode> expandNode2(VariableDiceNode vnode,
- Map<String, DiceASTExpression> env) {
- return env.get(vnode.getVariable()).getAst();
+ 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);
+ }
+ }
}
/**
@@ -49,20 +76,9 @@ public class DiceASTFreezer {
* The enviroment to get reference values from
* @return The tree with references frozen
*/
- @SuppressWarnings("unused")
public static AST<IDiceASTNode> freezeAST(AST<IDiceASTNode> tree,
- Map<String, AST<IDiceASTNode>> env) {
- return tree.collapse((nod) -> {
- if (nod instanceof VariableDiceNode) {
- return expandNode((VariableDiceNode) nod, env);
- } else {
- // Type is specified here so compiler can know the type
- // we're using
- return new AST<IDiceASTNode>(nod);
- }
- } , (op) -> (left, right) -> {
- return new AST<IDiceASTNode>(op, left, right);
- } , (r) -> r);
+ FunctionalMap<String, AST<IDiceASTNode>> env) {
+ return selectiveFreeze(tree, env);
}
/**
@@ -74,19 +90,43 @@ public class DiceASTFreezer {
* The enviroment to get reference values from
* @return The tree with references frozen
*/
- @SuppressWarnings("unused")
public static AST<IDiceASTNode> freezeAST(DiceASTExpression tree,
- Map<String, DiceASTExpression> env) {
- return tree.getAst().collapse((nod) -> {
- if (nod instanceof VariableDiceNode) {
- return expandNode2((VariableDiceNode) nod, env);
- } else {
- // Type is specified here so compiler can know the type
- // we're using
- return new AST<IDiceASTNode>(nod);
- }
- } , (op) -> (left, right) -> {
- return new AST<IDiceASTNode>(op, left, right);
- } , (r) -> r);
+ 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/DiceASTReferenceChecker.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java
new file mode 100644
index 0000000..aaabe8b
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java
@@ -0,0 +1,63 @@
+package bjc.dicelang.ast;
+
+import java.util.function.Consumer;
+
+import bjc.utils.data.GenHolder;
+
+/**
+ * Check if the specified node references a particular variable
+ *
+ * @author ben
+ *
+ */
+public final class DiceASTReferenceChecker
+ implements Consumer<IDiceASTNode> {
+ /**
+ * This is true if the specified node references the set variable
+ */
+ private GenHolder<Boolean> referencesVariable;
+
+ private String varName;
+
+ /**
+ * Create a new reference checker
+ *
+ * @param referencesVar
+ * The holder of whether the variable is referenced or
+ * not
+ * @param varName
+ * The variable to check for references in
+ */
+ public DiceASTReferenceChecker(GenHolder<Boolean> referencesVar,
+ String varName) {
+ this.referencesVariable = referencesVar;
+ this.varName = varName;
+ }
+
+ @Override
+ public void accept(IDiceASTNode astNode) {
+ if (!referencesVariable.unwrap(bool -> bool)) {
+ if (isDirectReferenceToLast(astNode)) {
+ referencesVariable.transform((bool) -> false);
+ }
+ }
+ }
+
+ /**
+ * Check if a given AST node directly references the meta-variable
+ * last
+ *
+ * @param astNode
+ * The node to check
+ * @return Whether or not the node directly references last
+ */
+ private boolean isDirectReferenceToLast(IDiceASTNode astNode) {
+ if (astNode.getType() == DiceASTType.VARIABLE) {
+ VariableDiceNode node = (VariableDiceNode) astNode;
+
+ return node.getVariable().equals(varName);
+ } else {
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTType.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTType.java
new file mode 100644
index 0000000..0a128f5
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTType.java
@@ -0,0 +1,27 @@
+package bjc.dicelang.ast;
+
+/**
+ * An enum to represent the type of node an AST node is
+ *
+ * @author ben
+ *
+ */
+public enum DiceASTType {
+ /**
+ * A node that contains a literal value
+ */
+ LITERAL,
+ /**
+ * A node that contains an operator expression
+ */
+ OPERATOR,
+ /**
+ * A node that contains a variable reference
+ */
+ VARIABLE;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/IDiceASTNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/IDiceASTNode.java
index 439bdac..38a1cc1 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/IDiceASTNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IDiceASTNode.java
@@ -13,4 +13,11 @@ public interface IDiceASTNode {
* @return Whether or not this node represents an operator
*/
public boolean isOperator();
-}
+
+ /**
+ * Get the type of AST node this node is
+ *
+ * @return The type of AST node this AST node is
+ */
+ public DiceASTType getType();
+} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
new file mode 100644
index 0000000..ebd0436
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
@@ -0,0 +1,17 @@
+package bjc.dicelang.ast;
+
+import java.util.function.BinaryOperator;
+
+import bjc.utils.data.Pair;
+import bjc.utils.parserutils.AST;
+
+/**
+ * Alias for operator collapsers. Because 68-char types are too long
+ *
+ * @author ben
+ *
+ */
+public interface IOperatorCollapser
+ extends BinaryOperator<Pair<Integer, AST<IDiceASTNode>>> {
+
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/LiteralDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/LiteralDiceNode.java
index 8157844..b80f1a4 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/LiteralDiceNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/LiteralDiceNode.java
@@ -10,7 +10,7 @@ public class LiteralDiceNode implements IDiceASTNode {
/**
* The value contained by this node
*/
- private String data;
+ private String value;
/**
* Create a new node with the given value
@@ -19,12 +19,35 @@ public class LiteralDiceNode implements IDiceASTNode {
* The value to be in this node
*/
public LiteralDiceNode(String data) {
- this.data = data;
+ this.value = data;
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
@Override
- public boolean isOperator() {
- return false;
+ 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;
+ }
}
/**
@@ -33,7 +56,30 @@ public class LiteralDiceNode implements IDiceASTNode {
* @return the data stored in this AST node
*/
public String getData() {
- return data;
+ 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;
}
/*
@@ -43,6 +89,6 @@ public class LiteralDiceNode implements IDiceASTNode {
*/
@Override
public String toString() {
- return data;
+ return value;
}
-}
+} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/OperatorDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/OperatorDiceNode.java
index 45c3d58..90e08b7 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/OperatorDiceNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/OperatorDiceNode.java
@@ -69,6 +69,11 @@ public enum OperatorDiceNode implements IDiceASTNode {
}
}
+ @Override
+ public DiceASTType getType() {
+ return DiceASTType.OPERATOR;
+ }
+
/*
* (non-Javadoc)
*
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/VariableDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/VariableDiceNode.java
index e02952d..e2dec64 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/VariableDiceNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/VariableDiceNode.java
@@ -10,16 +10,50 @@ public class VariableDiceNode implements IDiceASTNode {
/**
* The variable referenced by this node
*/
- private String var;
+ private String variableName;
/**
* Create a new node representing the specified variable
*
- * @param data
+ * @param varName
* The name of the variable being referenced
*/
- public VariableDiceNode(String data) {
- this.var = data;
+ public VariableDiceNode(String varName) {
+ this.variableName = varName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ // Handle special cases
+ if (this == obj) {
+ return true;
+ } else if (obj == null) {
+ return false;
+ } else if (getClass() != obj.getClass()) {
+ return false;
+ } else {
+ VariableDiceNode other = (VariableDiceNode) obj;
+
+ if (variableName == null) {
+ if (other.variableName != null) {
+ return false;
+ }
+ } else if (!variableName.equals(other.variableName)) {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ @Override
+ public DiceASTType getType() {
+ return DiceASTType.VARIABLE;
}
/**
@@ -28,7 +62,21 @@ public class VariableDiceNode implements IDiceASTNode {
* @return the variable referenced by this AST node
*/
public String getVariable() {
- return var;
+ return variableName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((variableName == null) ? 0 : variableName.hashCode());
+ return result;
}
/*
@@ -48,6 +96,6 @@ public class VariableDiceNode implements IDiceASTNode {
*/
@Override
public String toString() {
- return var;
+ return variableName;
}
-}
+} \ No newline at end of file