summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2016-03-21 21:42:27 -0400
committerbculkin2442 <bjculkin@mix.wvu.edu>2016-03-21 21:42:27 -0400
commit523eea5fdbecaea141f3aafe89b307f1e9e75b25 (patch)
tree360112827177793cb6fc89ba1bc1d2f689359c22 /BJC-Utils2/src
parent6d1c64021b9887f943b24732adae364d16bb0eb3 (diff)
Polished up work on AST-based dice
Diffstat (limited to 'BJC-Utils2/src')
-rw-r--r--BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageState.java19
-rw-r--r--BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageTest.java38
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTExpression.java144
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java2
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFreezer.java47
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java5
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java6
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java5
8 files changed, 254 insertions, 12 deletions
diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageState.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageState.java
new file mode 100644
index 0000000..82dccf5
--- /dev/null
+++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageState.java
@@ -0,0 +1,19 @@
+package bjc.utils.examples.parsing;
+
+import java.util.Map;
+
+import bjc.utils.data.Pair;
+import bjc.utils.dice.DiceExpressionParser;
+import bjc.utils.dice.ast.DiceASTExpression;
+
+public class DiceASTLanguageState
+ extends Pair<DiceExpressionParser, Map<String, DiceASTExpression>> {
+
+ public DiceASTLanguageState() {
+ }
+
+ public DiceASTLanguageState(DiceExpressionParser left,
+ Map<String, DiceASTExpression> right) {
+ super(left, right);
+ }
+}
diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageTest.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageTest.java
index 1a93da9..f8034c8 100644
--- a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageTest.java
+++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/DiceASTLanguageTest.java
@@ -7,27 +7,44 @@ import java.util.function.BiConsumer;
import bjc.utils.dice.DiceExpressionParser;
import bjc.utils.dice.IDiceExpression;
-import bjc.utils.dice.ast.DiceASTFlattener;
+import bjc.utils.dice.ast.DiceASTExpression;
+import bjc.utils.dice.ast.DiceASTFreezer;
import bjc.utils.dice.ast.DiceASTParser;
+import bjc.utils.dice.ast.IDiceASTNode;
+import bjc.utils.parserutils.AST;
public class DiceASTLanguageTest {
- private static Map<String, BiConsumer<String, DiceLanguageState>> acts;
+ private static Map<String, BiConsumer<String, DiceASTLanguageState>> acts;
static {
acts = new HashMap<>();
acts.put("roll", DiceASTLanguageTest::rollReference);
acts.put("env", DiceASTLanguageTest::printEnv);
+ acts.put("freeze", DiceASTLanguageTest::freezeVar);
}
- public static void printEnv(String ln, DiceLanguageState stat) {
+ private static void freezeVar(String ln, DiceASTLanguageState stat) {
+ String[] strangs = ln.split(" ");
+
+ System.out.println("Freezing references in " + strangs[1]);
+
+ stat.doWith((dep, env) -> {
+ env.put(strangs[1], new DiceASTExpression(
+ DiceASTFreezer.freezeAST(env.get(strangs[1]), env),
+ env));
+ });
+ }
+
+ public static void printEnv(String ln, 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())));
}
- public static void rollReference(String ln, DiceLanguageState stat) {
+ public static void rollReference(String ln,
+ DiceASTLanguageState stat) {
String[] strangs = ln.split(" ");
System.out.println("\tRolling dice expression " + strangs[1] + " "
@@ -35,8 +52,8 @@ public class DiceASTLanguageTest {
int nRolls = Integer.parseInt(strangs[2]);
- IDiceExpression dexp = stat
- .merge((dep, env) -> env.get(strangs[1]));
+ IDiceExpression dexp =
+ stat.merge((dep, env) -> env.get(strangs[1]));
for (int i = 1; i <= nRolls; i++) {
int roll = dexp.roll();
@@ -55,8 +72,8 @@ public class DiceASTLanguageTest {
DiceASTParser dap = new DiceASTParser();
DiceExpressionParser dep = new DiceExpressionParser();
- Map<String, IDiceExpression> env = new HashMap<>();
- DiceLanguageState state = new DiceLanguageState(dep, env);
+ Map<String, DiceASTExpression> env = new HashMap<>();
+ DiceASTLanguageState state = new DiceASTLanguageState(dep, env);
while (!ln.equalsIgnoreCase("quit")) {
String header = ln.split(" ")[0];
@@ -65,8 +82,9 @@ public class DiceASTLanguageTest {
acts.get(header).accept(ln, state);
} else {
- IDiceExpression exp = DiceASTFlattener
- .flatten(dap.buildAST(ln), env);
+ 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());
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTExpression.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTExpression.java
new file mode 100644
index 0000000..3b81888
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTExpression.java
@@ -0,0 +1,144 @@
+package bjc.utils.dice.ast;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BinaryOperator;
+
+import org.apache.commons.lang3.StringUtils;
+
+import bjc.utils.data.Pair;
+import bjc.utils.dice.ComplexDice;
+import bjc.utils.dice.CompoundDice;
+import bjc.utils.dice.IDiceExpression;
+import bjc.utils.parserutils.AST;
+
+public class DiceASTExpression implements IDiceExpression {
+ private AST<IDiceASTNode> ast;
+ private Map<String, DiceASTExpression> env;
+
+ public DiceASTExpression(AST<IDiceASTNode> ast,
+ Map<String, DiceASTExpression> env) {
+ this.ast = ast;
+ this.env = env;
+ }
+
+ private Pair<Integer, AST<IDiceASTNode>> evalLeaf(IDiceASTNode tokn) {
+ if (tokn instanceof VariableDiceNode) {
+ String varName = ((VariableDiceNode) tokn).getVariable();
+
+ if (env.containsKey(varName)) {
+ return new Pair<>(env.get(varName).roll(), new AST<>(tokn));
+ } else {
+ // Handle special case for defining variables
+ return new Pair<>(0, new AST<>(tokn));
+ }
+ } else {
+ LiteralDiceNode lnod = (LiteralDiceNode) tokn;
+ String dat = lnod.getData();
+
+ if (StringUtils.countMatches(dat, 'c') == 1
+ && !dat.equalsIgnoreCase("c")) {
+ String[] strangs = dat.split("c");
+ return new Pair<>(new CompoundDice(strangs).roll(),
+ new AST<>(tokn));
+ } else if (StringUtils.countMatches(dat, 'd') == 1
+ && !dat.equalsIgnoreCase("d")) {
+ /*
+ * Handle dice groups
+ */
+ return new Pair<>(ComplexDice.fromString(dat).roll(),
+ new AST<>(tokn));
+ } else {
+ return new Pair<>(Integer.parseInt(dat), new AST<>(tokn));
+ }
+ }
+ }
+
+ private static
+ Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>>
+ buildOperations(Map<String, DiceASTExpression> env) {
+ Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> opCollapsers =
+ 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) -> {
+ 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) -> {
+ 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));
+
+ 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) -> {
+ return left.merge((lval, last) -> right.merge((rval, rast) -> {
+
+ return new Pair<>(new ComplexDice(lval, rval).roll(),
+ new AST<>(OperatorDiceNode.GROUP, last, rast));
+ }));
+ });
+
+ return opCollapsers;
+ }
+
+ @Override
+ public int roll() {
+ Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> operations =
+ buildOperations(env);
+
+ return ast.collapse(this::evalLeaf, operations::get,
+ (r) -> r.merge((left, right) -> left));
+ }
+
+ @Override
+ public String toString() {
+ return ast.toString();
+ }
+
+ /**
+ * @return the ast
+ */
+ public AST<IDiceASTNode> getAst() {
+ return ast;
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java
index 3cf1d4e..da402c3 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java
@@ -29,7 +29,7 @@ public class DiceASTFlattener {
return new ReferenceDiceExpression(
((VariableDiceNode) nod).getVariable(), env);
}
- } , opCollapsers, (r) -> r);
+ } , opCollapsers::get, (r) -> r);
}
private static Map<IDiceASTNode, BinaryOperator<IDiceExpression>> buildOperations(
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFreezer.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFreezer.java
new file mode 100644
index 0000000..04cc99b
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFreezer.java
@@ -0,0 +1,47 @@
+package bjc.utils.dice.ast;
+
+import java.util.Map;
+
+import bjc.utils.parserutils.AST;
+
+public class DiceASTFreezer {
+ 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);
+ }
+
+ 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);
+ }
+
+ private static AST<IDiceASTNode> expandNode(VariableDiceNode vnode,
+ Map<String, AST<IDiceASTNode>> env) {
+ return env.get(vnode.getVariable());
+ }
+
+ private static AST<IDiceASTNode> expandNode2(VariableDiceNode vnode,
+ Map<String, DiceASTExpression> env) {
+ return env.get(vnode.getVariable()).getAst();
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java
index 5bfbc85..20358fb 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java
@@ -20,4 +20,9 @@ public class LiteralDiceNode implements IDiceASTNode {
public String getData() {
return data;
}
+
+ @Override
+ public String toString() {
+ return data;
+ }
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java
index 84f45aa..92b49b7 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java
@@ -1,8 +1,12 @@
package bjc.utils.dice.ast;
+// The following classes need to be changed upon addition of a new operator
+// 1. DiceASTExpression
+// 2. DiceASTFlattener
+// 3. DiceASTParser
public enum OperatorDiceNode implements IDiceASTNode {
ASSIGN, ADD, SUBTRACT, MULTIPLY, DIVIDE, GROUP, COMPOUND;
-
+
@Override
public boolean isOperator() {
return true;
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java
index 1d3a63c..6ae3189 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java
@@ -20,4 +20,9 @@ public class VariableDiceNode implements IDiceASTNode {
public String getVariable() {
return var;
}
+
+ @Override
+ public String toString() {
+ return var;
+ }
}