From 75fe5c351630ce26a9bd4db631809bb8d5b26357 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 10 Apr 2016 22:05:24 -0400 Subject: Restored basic functionality with new system --- .../bjc/dicelang/examples/DiceASTLanguageTest.java | 90 +++++++++++++ .../dicelang/examples/DiceExpressionPreparer.java | 61 +++++++++ .../java/bjc/dicelang/ast/DiceASTEvaluator.java | 147 +++++++++++---------- .../bjc/dicelang/ast/nodes/DiceLiteralNode.java | 5 + .../bjc/dicelang/ast/nodes/IntegerLiteralNode.java | 5 + 5 files changed, 236 insertions(+), 72 deletions(-) create mode 100644 dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java create mode 100644 dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java (limited to 'dice-lang/src') diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java new file mode 100644 index 0000000..94186dd --- /dev/null +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java @@ -0,0 +1,90 @@ +package bjc.dicelang.examples; + +import java.util.Scanner; + +import bjc.dicelang.ast.DiceASTEvaluator; +import bjc.dicelang.ast.DiceASTParser; +import bjc.dicelang.ast.nodes.IDiceASTNode; + +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalList; +import bjc.utils.funcdata.IFunctionalMap; +import bjc.utils.parserutils.AST; + +/** + * Test interface for AST-based dice language + * + * @author ben + * + */ +public class DiceASTLanguageTest { + /** + * Main method of class + * + * @param args + * Unused CLI args + */ + public static void main(String[] args) { + Scanner inputSource = new Scanner(System.in); + int commandNumber = 0; + + System.out.print("dice-lang-" + commandNumber + "> "); + String currentLine = inputSource.nextLine(); + + // The enviroment for variables + IFunctionalMap> enviroment = + new FunctionalMap<>(); + + while (!currentLine.equalsIgnoreCase("quit")) { + // Build an AST from the string expression + AST builtAST; + + IFunctionalList preparedTokens = + DiceExpressionPreparer.prepareCommand(currentLine); + + try { + builtAST = DiceASTParser.createFromString(preparedTokens); + } catch (IllegalStateException isex) { + System.out.println("ERROR: " + isex.getLocalizedMessage()); + + currentLine = getNextCommand(inputSource, commandNumber); + + continue; + } + + int sampleRoll; + + try { + sampleRoll = + DiceASTEvaluator.evaluateAST(builtAST, enviroment); + } catch (UnsupportedOperationException usex) { + System.out.println("ERROR: " + usex.getLocalizedMessage()); + + currentLine = getNextCommand(inputSource, commandNumber); + + continue; + } + + // Print out results + System.out.println("\tParsed: " + builtAST.toString()); + System.out.println("\t\tSample Roll: " + sampleRoll); + + // Increase the number of commands + commandNumber++; + + currentLine = getNextCommand(inputSource, commandNumber); + } + + System.out.println("Bye."); + + // Cleanup after ourselves + inputSource.close(); + } + + private static String getNextCommand(Scanner inputSource, + int commandNumber) { + System.out.print("dice-lang-" + commandNumber + "> "); + + return inputSource.nextLine(); + } +} diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java new file mode 100644 index 0000000..1d46cc9 --- /dev/null +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java @@ -0,0 +1,61 @@ +package bjc.dicelang.examples; + +import java.util.Deque; +import java.util.LinkedList; + +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.ShuntingYard; + +/** + * Prepare a dice expression to be parsed + * + * @author ben + * + */ +public class DiceExpressionPreparer { + /** + * The yard to use for shunting expressions + */ + private static ShuntingYard 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 + } + + static IFunctionalList prepareCommand(String currentLine) { + IFunctionalList tokens = + FunctionalStringTokenizer.fromString(currentLine).toList(); + + Deque> ops = new LinkedList<>(); + + ops.add(new Pair<>("+", "\\+")); + ops.add(new Pair<>("-", "-")); + ops.add(new Pair<>("*", "\\*")); + ops.add(new Pair<>("/", "/")); + ops.add(new Pair<>(":=", ":=")); + + IFunctionalList semiExpandedTokens = + ListUtils.splitTokens(tokens, ops); + + ops = new LinkedList<>(); + + ops.add(new Pair<>("(", "\\(")); + ops.add(new Pair<>(")", "\\)")); + + IFunctionalList fullyExpandedTokens = + ListUtils.deAffixTokens(semiExpandedTokens, ops); + + return yard.postfix(fullyExpandedTokens, (token) -> token); + } +} diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java index 93b56de..0257b91 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java @@ -28,6 +28,12 @@ import bjc.utils.parserutils.AST; * */ public class DiceASTEvaluator { + /** + * Responsible for collapsing arithmetic operators + * + * @author ben + * + */ private static final class ArithmeticCollapser implements IOperatorCollapser { private OperatorDiceNode type; @@ -60,27 +66,6 @@ public class DiceASTEvaluator { } } - /** - * 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 expression, - IFunctionalMap> enviroment) { - IFunctionalMap 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 * @@ -123,6 +108,73 @@ public class DiceASTEvaluator { return operatorCollapsers; } + /** + * 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 expression, + IFunctionalMap> enviroment) { + IFunctionalMap collapsers = + buildOperations(enviroment); + + return expression.collapse( + (node) -> evaluateLeaf(node, enviroment), collapsers::get, + (pair) -> pair.merge((left, right) -> left)); + } + + private static IPair> evaluateLeaf( + IDiceASTNode leafNode, + IFunctionalMap> 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; + } + private static IPair> parseBinding( IFunctionalMap> enviroment, IPair> left, @@ -148,8 +200,7 @@ public class DiceASTEvaluator { rightAST.traverse(TreeLinearizationMethod.PREORDER, refChecker); - // Ignore meta-variable that'll be auto-frozen to restore - // definition sanity + // Ignore meta-variable if (selfReference.unwrap((bool) -> bool) && !variableName.equals("last")) { throw new UnsupportedOperationException( @@ -161,7 +212,7 @@ public class DiceASTEvaluator { if (!variableName.equals("last")) { enviroment.put(variableName, rightAST); } else { - // Do nothing, last is a auto-handled meta-variable + // Do nothing, last is an auto-handled meta-variable } return new Pair<>(rightValue, new AST<>( @@ -210,52 +261,4 @@ public class DiceASTEvaluator { }); }); } - - private static IPair> evaluateLeaf( - IDiceASTNode leafNode, - IFunctionalMap> 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/nodes/DiceLiteralNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralNode.java index 82c764d..b2e1825 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralNode.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/DiceLiteralNode.java @@ -54,4 +54,9 @@ public class DiceLiteralNode implements ILiteralDiceNode { public int optimize() { return expression.optimize(); } + + @Override + public String toString() { + return expression.toString(); + } } 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 index 415f30f..0ed2c2c 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IntegerLiteralNode.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/IntegerLiteralNode.java @@ -32,4 +32,9 @@ public class IntegerLiteralNode implements ILiteralDiceNode { public int getValue() { return value; } + + @Override + public String toString() { + return Integer.toString(value); + } } -- cgit v1.2.3