From c8ae1ec096f5d1ac6db4f3a0035f7da106444e4e Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 3 Apr 2016 17:45:05 -0400 Subject: General code refactoring and maintenance --- .../java/bjc/dicelang/ast/DiceASTExpression.java | 102 +++++++++------ .../main/java/bjc/dicelang/ast/DiceASTFreezer.java | 144 +++++++++++++-------- .../bjc/dicelang/ast/DiceASTReferenceChecker.java | 63 +++++++++ .../main/java/bjc/dicelang/ast/DiceASTType.java | 27 ++++ .../main/java/bjc/dicelang/ast/IDiceASTNode.java | 9 +- .../java/bjc/dicelang/ast/IOperatorCollapser.java | 17 +++ .../java/bjc/dicelang/ast/LiteralDiceNode.java | 60 ++++++++- .../java/bjc/dicelang/ast/OperatorDiceNode.java | 5 + .../java/bjc/dicelang/ast/VariableDiceNode.java | 62 ++++++++- 9 files changed, 379 insertions(+), 110 deletions(-) create mode 100644 dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java create mode 100644 dice-lang/src/main/java/bjc/dicelang/ast/DiceASTType.java create mode 100644 dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java (limited to 'dice-lang/src/main/java') 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>>> - buildOperations(Map env) { - Map>>> opCollapsers = + private static Map + buildOperations(Map enviroment) { + Map 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>>> operations = + Map 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 expandNode(VariableDiceNode vnode, - Map> env) { - return env.get(vnode.getVariable()); + private static class NodeFreezer + implements Function> { + private FunctionalMap> enviroment; + + public NodeFreezer(FunctionalMap> env) { + enviroment = env; + } + + @Override + public AST apply(IDiceASTNode nod) { + if (nod.getType() == DiceASTType.VARIABLE) { + return expandNode((VariableDiceNode) nod); + } else { + return new AST<>(nod); + } + } + + protected AST + 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 expandNode2(VariableDiceNode vnode, - Map env) { - return env.get(vnode.getVariable()).getAst(); + private static final class SelectiveFreezer extends NodeFreezer { + + private FunctionalList variableNames; + + public SelectiveFreezer( + FunctionalMap> env, + FunctionalList varNames) { + super(env); + variableNames = varNames; + } + + @Override + protected AST + 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 freezeAST(AST tree, - Map> 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(nod); - } - } , (op) -> (left, right) -> { - return new AST(op, left, right); - } , (r) -> r); + FunctionalMap> 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 freezeAST(DiceASTExpression tree, - Map 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(nod); - } - } , (op) -> (left, right) -> { - return new AST(op, left, right); - } , (r) -> r); + FunctionalMap 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 selectiveFreeze(AST tree, + FunctionalMap> 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 selectiveFreeze(AST tree, + FunctionalMap> env, + FunctionalList 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 { + /** + * This is true if the specified node references the set variable + */ + private GenHolder 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 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>> { + +} 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 -- cgit v1.2.3