summaryrefslogtreecommitdiff
path: root/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2016-04-08 13:29:48 -0400
committerbculkin2442 <bjculkin@mix.wvu.edu>2016-04-08 13:29:48 -0400
commit90d1cc6c9f47f1b6f74fb57e07865795a46c23b8 (patch)
treeb74cd5b9989c9f5a1bbde1e1b8c751faf9cb7086 /dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java
parentb1df3ff8c890bf6d4cc16fb4f28ddb7833512d71 (diff)
Change to data interfaces, as well as prepare to rewrite parser
Diffstat (limited to 'dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java')
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java146
1 files changed, 146 insertions, 0 deletions
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
new file mode 100644
index 0000000..d8e13f7
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/old/ast/DiceASTParser.java
@@ -0,0 +1,146 @@
+package bjc.dicelang.old.ast;
+
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.function.Function;
+
+import org.apache.commons.lang3.StringUtils;
+
+import bjc.dicelang.ast.nodes.IDiceASTNode;
+import bjc.dicelang.ast.nodes.LiteralDiceNode;
+import bjc.dicelang.ast.nodes.OperatorDiceNode;
+import bjc.dicelang.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 (NodeBaker.isLiteral(tok)) {
+ return new LiteralDiceNode(tok);
+ } else {
+ return new VariableDiceNode(tok);
+ }
+ }
+
+ /**
+ * Check if a token represents a literal
+ *
+ * @param tok
+ * The token to check
+ * @return Whether or not the token represents a literal
+ */
+ private 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;
+ }
+ }
+ }
+ }
+
+ /**
+ * 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;
+ }
+ }
+}