summaryrefslogtreecommitdiff
path: root/dice-lang/src/main/java/bjc/dicelang/ast
diff options
context:
space:
mode:
Diffstat (limited to 'dice-lang/src/main/java/bjc/dicelang/ast')
-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.java60
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java18
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceASTType.java27
-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.java23
-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.java100
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/VariableDiceNode.java101
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/package-info.java6
14 files changed, 811 insertions, 8 deletions
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/ast/DiceASTReferenceChecker.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java
new file mode 100644
index 0000000..809243a
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceChecker.java
@@ -0,0 +1,60 @@
+package bjc.dicelang.ast;
+
+import java.util.function.Consumer;
+
+import bjc.dicelang.ast.nodes.DiceASTType;
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+import bjc.dicelang.ast.nodes.VariableDiceNode;
+import bjc.utils.data.IHolder;
+
+/**
+ * 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 IHolder<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(IHolder<Boolean> referencesVar,
+ String varName) {
+ this.referencesVariable = referencesVar;
+ this.varName = varName;
+ }
+
+ @Override
+ public void accept(IDiceASTNode astNode) {
+ referencesVariable.transform((bool) -> isDirectReference(astNode));
+ }
+
+ /**
+ * Check if a given AST node directly references the specified variable
+ *
+ * @param astNode
+ * The node to check
+ * @return Whether or not the node directly the variable
+ */
+ private boolean isDirectReference(IDiceASTNode astNode) {
+ if (astNode.getType() == DiceASTType.VARIABLE) {
+ VariableDiceNode node = (VariableDiceNode) astNode;
+
+ return node.getVariable().equals(varName);
+ }
+
+ return false;
+ }
+} \ 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..ed818d4
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
@@ -0,0 +1,18 @@
+package bjc.dicelang.ast;
+
+import java.util.function.BinaryOperator;
+
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+import bjc.utils.data.IPair;
+import bjc.utils.parserutils.AST;
+
+/**
+ * Alias for operator collapsers. Because 68-char types are too long
+ *
+ * @author ben
+ *
+ */
+public interface IOperatorCollapser
+ extends BinaryOperator<IPair<Integer, AST<IDiceASTNode>>> {
+ // Just an alias
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceASTType.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceASTType.java
new file mode 100644
index 0000000..9feb461
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceASTType.java
@@ -0,0 +1,27 @@
+package bjc.dicelang.ast.nodes;
+
+/**
+ * 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/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/ast/nodes/IDiceASTNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IDiceASTNode.java
new file mode 100644
index 0000000..b7bf9a6
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IDiceASTNode.java
@@ -0,0 +1,23 @@
+package bjc.dicelang.ast.nodes;
+
+/**
+ * The interface for a node in a dice AST
+ *
+ * @author ben
+ *
+ */
+public interface IDiceASTNode {
+ /**
+ * Get the type of AST node this node is
+ *
+ * @return The type of AST node this AST node is
+ */
+ public DiceASTType getType();
+
+ /**
+ * Check if this node represents an operator or not
+ *
+ * @return Whether or not this node represents an operator
+ */
+ 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/ast/nodes/OperatorDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java
new file mode 100644
index 0000000..d034943
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java
@@ -0,0 +1,100 @@
+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
+// 2. DiceASTFlattener
+// 3. DiceASTParser
+/**
+ * A node that represents an operator
+ *
+ * @author ben
+ *
+ */
+public enum OperatorDiceNode implements IDiceASTNode {
+ /**
+ * Represents adding two nodes
+ */
+ ADD(MATH),
+ /**
+ * Represents assigning one node to another
+ */
+ ASSIGN(EXPRESSION),
+ /**
+ * Representings combining two node values together
+ */
+ COMPOUND(DICE),
+ /**
+ * Represents dividing two nodes
+ */
+ DIVIDE(MATH),
+ /**
+ * Represents using one node a variable number of times
+ */
+ GROUP(DICE),
+ /**
+ * Represents multiplying two nodes
+ */
+ MULTIPLY(MATH),
+ /**
+ * Represents subtracting two nodes
+ */
+ SUBTRACT(MATH);
+
+ /**
+ * Represents the group of operator this operator is sorted into.
+ *
+ */
+ public final DiceOperatorType type;
+
+ private OperatorDiceNode(DiceOperatorType ty) {
+ type = ty;
+ }
+
+ /**
+ * Create a operator node from a string
+ *
+ * @param s
+ * The string to convert to a node
+ * @return The operator corresponding to the node
+ */
+ public static OperatorDiceNode fromString(String s) {
+ switch (s) {
+ case ":=":
+ return ASSIGN;
+ case "+":
+ return ADD;
+ case "-":
+ return SUBTRACT;
+ case "*":
+ return MULTIPLY;
+ case "/":
+ return DIVIDE;
+ case "d":
+ case "group":
+ return GROUP;
+ case "c":
+ case "compound":
+ return COMPOUND;
+ default:
+ throw new IllegalArgumentException(
+ s + " is not a valid operator node");
+ }
+ }
+
+ @Override
+ public DiceASTType getType() {
+ return DiceASTType.OPERATOR;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see bjc.utils.dice.ast.IDiceASTNode#isOperator()
+ */
+ @Override
+ public boolean isOperator() {
+ return true;
+ }
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/VariableDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/VariableDiceNode.java
new file mode 100644
index 0000000..da66608
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/VariableDiceNode.java
@@ -0,0 +1,101 @@
+package bjc.dicelang.ast.nodes;
+
+/**
+ * A node that represents a reference to a variable
+ *
+ * @author ben
+ *
+ */
+public class VariableDiceNode implements IDiceASTNode {
+ /**
+ * The variable referenced by this node
+ */
+ private String variableName;
+
+ /**
+ * Create a new node representing the specified variable
+ *
+ * @param varName
+ * The name of the variable being referenced
+ */
+ 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;
+ }
+
+ /**
+ * Get the variable referenced by this AST node
+ *
+ * @return the variable referenced by this AST node
+ */
+ public String getVariable() {
+ 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;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see bjc.utils.dice.ast.IDiceASTNode#isOperator()
+ */
+ @Override
+ public boolean isOperator() {
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return variableName;
+ }
+} \ No newline at end of file
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