diff options
Diffstat (limited to 'dice-lang/src/examples/java/bjc/dicelang')
3 files changed, 71 insertions, 14 deletions
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java index b331535..fa92fd2 100644 --- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java @@ -3,11 +3,11 @@ package bjc.dicelang.examples; import java.util.InputMismatchException; import java.util.Scanner; +import bjc.utils.data.ITree; import bjc.utils.funcdata.FunctionalMap; import bjc.utils.funcdata.FunctionalStringTokenizer; import bjc.utils.funcdata.IList; import bjc.utils.funcdata.IMap; -import bjc.utils.funcdata.ITree; import bjc.dicelang.ast.DiceASTEvaluator; import bjc.dicelang.ast.DiceASTInliner; @@ -30,26 +30,33 @@ public class DiceASTLanguageTest { private static DiceASTOptimizer optimizer; + // Set up things that need to be configured static { actions = new FunctionalMap<>(); + // Inline all the variables in a given expression actions.put("inline", DiceASTLanguageTest::handleInlineAction); + // Print out the enviroment actions.put("env", (tokenizer, enviroment) -> { enviroment.forEach((varName, varValue) -> { System.out.println(varName + " is bound to " + varValue); }); }); - + + // Create and configure the optimizer optimizer = new DiceASTOptimizer(); optimizer.addPass(new ConstantCollapser()); } + // Read in a command private static String getNextCommand(Scanner inputSource, int commandNumber) { + // Print a prompt using the current command number System.out.print("\ndice-lang-" + commandNumber + "> "); + // Read in the next command return inputSource.nextLine(); } @@ -59,24 +66,30 @@ public class DiceASTLanguageTest { // Skip the pragma name tokenizer.nextToken(); + // Get the pragma arguments IList<String> pragmaArgs = tokenizer.toList(); if (pragmaArgs.getSize() < 3) { + // Complain about pragma arguments not being valid System.err.println( "ERROR: Inline requires at least 3 parameters. They are:" + "\n\t1. The name of the expression to inline." + "\n\t2. The name of the variable to bind the result to." + "\n\t3 and onwards. Names of variables to inline in the expression."); } else { + // Get arguments String inlineExpression = pragmaArgs.getByIndex(0); String variableName = pragmaArgs.getByIndex(1); + // Grab the variables we want to inline IList<String> inlinedVariables = pragmaArgs.tail().tail(); + // Actually inline the variable ITree<IDiceASTNode> inlinedExpression = DiceASTInliner .selectiveInline(enviroment.get(inlineExpression), enviroment, inlinedVariables); + // Stick the inlined variable into the enviroment enviroment.put(variableName, inlinedExpression); } } @@ -85,39 +98,47 @@ public class DiceASTLanguageTest { * Main method of class * * @param args - * Unused CLI args + * Unused CLI args */ public static void main(String[] args) { + // Prepare the things we need for input Scanner inputSource = new Scanner(System.in); int commandNumber = 0; - System.out.print("dice-lang-" + commandNumber + "> "); - String currentLine = inputSource.nextLine(); + // Grab the initial command + String currentLine = getNextCommand(inputSource, commandNumber); // The enviroment for variables IMap<String, ITree<IDiceASTNode>> enviroment = new FunctionalMap<>(); + // Handle commands while (!currentLine.equalsIgnoreCase("quit")) { + // Get the name of a possible action String possibleActionName = currentLine.split(" ")[0]; + // Check and see if we're executing an action if (actions.containsKey(possibleActionName)) { // Execute action FunctionalStringTokenizer tokenizer = new FunctionalStringTokenizer( currentLine); + // Execute the action actions.get(possibleActionName).accept(tokenizer, enviroment); + // Get the next command currentLine = getNextCommand(inputSource, commandNumber); continue; } - // Build an AST from the string expression + // The AST we are going to build ITree<IDiceASTNode> builtAST; + // Time command preparation long time = System.nanoTime(); + // Prepare the command IList<String> preparedTokens = DiceExpressionPreparer .prepareCommand(currentLine); @@ -126,8 +147,10 @@ public class DiceASTLanguageTest { + " s"); try { + // Time the AST creation time = System.nanoTime(); + // Create the AST builtAST = DiceASTParser.createFromString(preparedTokens); System.out @@ -138,18 +161,22 @@ public class DiceASTLanguageTest { + " s"); } catch (InputMismatchException | IllegalStateException | UnsupportedOperationException ex) { - System.out.println("ERROR: " + ex.getLocalizedMessage()); + // Tell the user there was an error in parsing + System.out.println("PARSING ERROR: " + ex.getLocalizedMessage()); + // Move onto the next command currentLine = getNextCommand(inputSource, commandNumber); continue; } - // Print out results + // Print out parsed AST System.out.println("\tParsed: " + builtAST.toString()); + // Time AST transformation time = System.nanoTime(); + // Transform the AST ITree<IDiceASTNode> transformedAST = transformAST(builtAST, enviroment); @@ -157,15 +184,17 @@ public class DiceASTLanguageTest { + (double) (System.nanoTime() - time) / 1000000000 + " s"); + // Print out the transformed AST System.out - .println("\tEvaluated: " + transformedAST.toString()); + .println("\tTransformed: " + transformedAST.toString()); - IResult sampleRoll; try { + // Time the evaluation time = System.nanoTime(); - sampleRoll = DiceASTEvaluator.evaluateAST(transformedAST, + // Evaluate the expression once + IResult sampleResult = DiceASTEvaluator.evaluateAST(transformedAST, enviroment); System.out @@ -175,20 +204,27 @@ public class DiceASTLanguageTest { - time) / 1000000000 + " s"); + // Print out the result of evaluating the expression + System.out.println("\t\tSample Result: " + sampleResult); + + // Update the 'last' meta-variable enviroment.put("last", transformedAST); } catch (UnsupportedOperationException usex) { - System.out.println("ERROR: " + usex.getLocalizedMessage()); + // Tell the user there was an error in evaluation + System.out.println("EVALUATION ERROR: " + usex.getLocalizedMessage()); + // Get the next command currentLine = getNextCommand(inputSource, commandNumber); + // Process it continue; } - System.out.println("\t\tSample Roll: " + sampleRoll); // Increase the number of commands commandNumber++; + // Get the next command currentLine = getNextCommand(inputSource, commandNumber); } @@ -198,20 +234,26 @@ public class DiceASTLanguageTest { inputSource.close(); } + // Transform a parsed AST private static ITree<IDiceASTNode> transformAST( ITree<IDiceASTNode> builtAST, IMap<String, ITree<IDiceASTNode>> enviroment) { + // Optimize the tree first ITree<IDiceASTNode> optimizedTree = optimizer .optimizeTree(builtAST, enviroment); + // Then, condense unnecessary operations ITree<IDiceASTNode> condensedTree = OperationCondenser .condense(optimizedTree); + // Next, sanitize references ITree<IDiceASTNode> sanitizedTree = DiceASTReferenceSanitizer .sanitize(condensedTree, enviroment); + // Re-optimize the sanitized & condensed tree optimizedTree = optimizer.optimizeTree(sanitizedTree, enviroment); + // Re-condense the newly optimized tree condensedTree = OperationCondenser.condense(optimizedTree); return condensedTree; diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTPragma.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTPragma.java index 87065f1..4900e46 100644 --- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTPragma.java +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTPragma.java @@ -11,6 +11,8 @@ import bjc.dicelang.ast.nodes.IDiceASTNode; /** * Alias for the type of a 'pragma' or special language command * + * To explain it, a pragma is a function that takes a tokenizer with the rest + * of the line, and an enviroment that contains variable bindings * @author ben * */ diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java index b9b4aab..5488b5d 100644 --- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java @@ -26,9 +26,12 @@ public class DiceExpressionPreparer { private static final int DICE_PREC = 10; private static final int EXPR_PREC = 0; + // Do initialization for all parsers static { + // The shunter we're going to use yard = new ShuntingYard<>(false); + // Configure the shunters operators // Basic mathematical operators yard.addOp("+", 0 + MATH_PREC); yard.addOp("-", 0 + MATH_PREC); @@ -47,12 +50,16 @@ public class DiceExpressionPreparer { // to a variable expression } - static IList<String> prepareCommand(String currentLine) { + // Prepare a command, turning raw tokens into input for the tree builder + public static IList<String> prepareCommand(String currentLine) { + // Split the command into tokens IList<String> tokens = FunctionalStringTokenizer .fromString(currentLine).toList(); + // The linked list to use for handling tokens Deque<IPair<String, String>> ops = new LinkedList<>(); + // Prepare the list for operator expansion ops.add(new Pair<>("+", "\\+")); ops.add(new Pair<>("-", "-")); ops.add(new Pair<>("*", "\\*")); @@ -60,21 +67,27 @@ public class DiceExpressionPreparer { ops.add(new Pair<>(":=", ":=")); ops.add(new Pair<>("=>", "=>")); + // Expand infix single tokens to multiple infix tokens IList<String> semiExpandedTokens = ListUtils.splitTokens(tokens, ops); + // Reinitialize the list ops = new LinkedList<>(); + // Prepare the list for deaffixation ops.add(new Pair<>("(", "\\(")); ops.add(new Pair<>(")", "\\)")); ops.add(new Pair<>("[", "\\[")); ops.add(new Pair<>("]", "\\]")); + // Deaffix ('s and ['s from tokens IList<String> fullyExpandedTokens = ListUtils .deAffixTokens(semiExpandedTokens, ops); + // Remove blank tokens fullyExpandedTokens.removeIf((strang) -> strang.equals("")); + // Shunt the tokens, and hand them back return yard.postfix(fullyExpandedTokens, (token) -> token); } } |
