diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-10-27 21:56:18 -0400 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-10-27 22:12:47 -0400 |
| commit | e7413128ff4e376997de6e94e4bea5eca14811ef (patch) | |
| tree | 0749e270fdb754d04dc223abd95d47436508047f /dice-lang/src/bjc/dicelang/examples | |
| parent | e13a6981bd278c2cfc3b5ecb2517367b117f7a52 (diff) | |
Moved examples
Diffstat (limited to 'dice-lang/src/bjc/dicelang/examples')
6 files changed, 568 insertions, 0 deletions
diff --git a/dice-lang/src/bjc/dicelang/examples/DiceASTLanguageTest.java b/dice-lang/src/bjc/dicelang/examples/DiceASTLanguageTest.java new file mode 100644 index 0000000..fa92fd2 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/examples/DiceASTLanguageTest.java @@ -0,0 +1,261 @@ +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.dicelang.ast.DiceASTEvaluator; +import bjc.dicelang.ast.DiceASTInliner; +import bjc.dicelang.ast.DiceASTOptimizer; +import bjc.dicelang.ast.DiceASTParser; +import bjc.dicelang.ast.DiceASTReferenceSanitizer; +import bjc.dicelang.ast.IResult; +import bjc.dicelang.ast.nodes.IDiceASTNode; +import bjc.dicelang.ast.optimization.ConstantCollapser; +import bjc.dicelang.ast.optimization.OperationCondenser; + +/** + * Test interface for AST-based dice language + * + * @author ben + * + */ +public class DiceASTLanguageTest { + private static IMap<String, DiceASTPragma> actions; + + 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(); + } + + private static void handleInlineAction( + FunctionalStringTokenizer tokenizer, + IMap<String, ITree<IDiceASTNode>> enviroment) { + // 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); + } + } + + /** + * Main method of class + * + * @param 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; + + // 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; + } + + // 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); + + System.out.println("Command prepared in " + + (double) (System.nanoTime() - time) / 1000000000 + + " s"); + + try { + // Time the AST creation + time = System.nanoTime(); + + // Create the AST + builtAST = DiceASTParser.createFromString(preparedTokens); + + System.out + .println( + "Command parsed in " + + (double) (System.nanoTime() + - time) / 1000000000 + + " s"); + } catch (InputMismatchException | IllegalStateException + | UnsupportedOperationException ex) { + // 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 parsed AST + System.out.println("\tParsed: " + builtAST.toString()); + + // Time AST transformation + time = System.nanoTime(); + + // Transform the AST + ITree<IDiceASTNode> transformedAST = transformAST(builtAST, + enviroment); + + System.out.println("Command transformed in " + + (double) (System.nanoTime() - time) / 1000000000 + + " s"); + + // Print out the transformed AST + System.out + .println("\tTransformed: " + transformedAST.toString()); + + + try { + // Time the evaluation + time = System.nanoTime(); + + // Evaluate the expression once + IResult sampleResult = DiceASTEvaluator.evaluateAST(transformedAST, + enviroment); + + System.out + .println( + "Command evaluated in " + + (double) (System.nanoTime() + - 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) { + // 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; + } + + + // Increase the number of commands + commandNumber++; + + // Get the next command + currentLine = getNextCommand(inputSource, commandNumber); + } + + System.out.println("Bye."); + + // Cleanup after ourselves + 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/bjc/dicelang/examples/DiceASTPragma.java b/dice-lang/src/bjc/dicelang/examples/DiceASTPragma.java new file mode 100644 index 0000000..4900e46 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/examples/DiceASTPragma.java @@ -0,0 +1,22 @@ +package bjc.dicelang.examples; + +import java.util.function.BiConsumer; + +import bjc.utils.funcdata.FunctionalStringTokenizer; +import bjc.utils.funcdata.IMap; +import bjc.utils.funcdata.ITree; + +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 + * + */ +public interface DiceASTPragma extends + BiConsumer<FunctionalStringTokenizer, IMap<String, ITree<IDiceASTNode>>> { + // Just an alias +} diff --git a/dice-lang/src/bjc/dicelang/examples/DiceExpressionParserTest.java b/dice-lang/src/bjc/dicelang/examples/DiceExpressionParserTest.java new file mode 100644 index 0000000..b31f3a0 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/examples/DiceExpressionParserTest.java @@ -0,0 +1,59 @@ +package bjc.dicelang.examples; + +import java.util.HashMap; +import java.util.Scanner; + +import bjc.dicelang.DiceExpressionParser; +import bjc.dicelang.IDiceExpression; + +/** + * Driver class for testing expression parser + * + * @author ben + * + */ +public class DiceExpressionParserTest { + /** + * Run the parser test + * + * @param args + * Unused CLI arguments + */ + public static void main(String[] args) { + /* + * Get a scanner for input + */ + Scanner scn = new Scanner(System.in); + + /* + * Ask to enter a expression + */ + System.out.print("Enter dice expression: "); + + String exp = scn.nextLine(); + + /* + * Enter amount of times to roll an expression + */ + System.out.print("Enter number of times to roll: "); + + int nTimes = Integer.parseInt(scn.nextLine()); + + IDiceExpression dexp = DiceExpressionParser.parse(exp, + new HashMap<>()); + + /* + * Roll the dice a specified amount of times + */ + for (int i = 1; i <= nTimes; i++) { + int roll = dexp.roll(); + + System.out.println("Rolled " + roll); + } + + /* + * Clean up after ourselves + */ + scn.close(); + } +} diff --git a/dice-lang/src/bjc/dicelang/examples/DiceExpressionPreparer.java b/dice-lang/src/bjc/dicelang/examples/DiceExpressionPreparer.java new file mode 100644 index 0000000..5488b5d --- /dev/null +++ b/dice-lang/src/bjc/dicelang/examples/DiceExpressionPreparer.java @@ -0,0 +1,93 @@ +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.IList; +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<String> yard; + + private static final int MATH_PREC = 20; + 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); + + yard.addOp("*", 1 + MATH_PREC); + yard.addOp("/", 1 + MATH_PREC); + + yard.addOp("d", 0 + DICE_PREC); // dice operator: use for creating + // variable size dice groups + yard.addOp("c", 1 + DICE_PREC); // compound operator: use for + // creating compound dice from expressions + + yard.addOp("=>", 0 + EXPR_PREC); // let operator: evaluate an + // expression in the context of another + yard.addOp(":=", 1 + EXPR_PREC); // binding operator: Bind a name + // to a variable expression + } + + // 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<>("*", "\\*")); + ops.add(new Pair<>("/", "/")); + 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); + } +} diff --git a/dice-lang/src/bjc/dicelang/examples/DiceLanguageState.java b/dice-lang/src/bjc/dicelang/examples/DiceLanguageState.java new file mode 100644 index 0000000..fbb103f --- /dev/null +++ b/dice-lang/src/bjc/dicelang/examples/DiceLanguageState.java @@ -0,0 +1,37 @@ +package bjc.dicelang.examples; + +import java.util.Map; + +import bjc.utils.data.Pair; + +import bjc.dicelang.DiceExpressionParser; +import bjc.dicelang.IDiceExpression; + +/** + * Internal state of dice language + * + * @author ben + * + */ +public class DiceLanguageState + extends Pair<DiceExpressionParser, Map<String, IDiceExpression>> { + + /** + * Create a new state + */ + public DiceLanguageState() { + } + + /** + * Create a new state with the desired parameters + * + * @param left + * The parser to use + * @param right + * The enviroment to use + */ + public DiceLanguageState(DiceExpressionParser left, + Map<String, IDiceExpression> right) { + super(left, right); + } +} diff --git a/dice-lang/src/bjc/dicelang/examples/DiceLanguageTest.java b/dice-lang/src/bjc/dicelang/examples/DiceLanguageTest.java new file mode 100644 index 0000000..bd6270e --- /dev/null +++ b/dice-lang/src/bjc/dicelang/examples/DiceLanguageTest.java @@ -0,0 +1,96 @@ +package bjc.dicelang.examples; + +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; +import java.util.function.BiConsumer; + +import bjc.dicelang.DiceExpressionParser; +import bjc.dicelang.IDiceExpression; + +/** + * Test of dice language + * + * @author ben + * + */ +public class DiceLanguageTest { + private static Map<String, BiConsumer<String, DiceLanguageState>> acts; + + static { + acts = new HashMap<>(); + + acts.put("roll", DiceLanguageTest::rollReference); + acts.put("env", DiceLanguageTest::printEnv); + } + + /** + * Main method + * + * @param args + * Unused CLI args + */ + public static void main(String[] args) { + Scanner scn = new Scanner(System.in); + int i = 0; + + System.out.print("dice-lang-" + i + "> "); + String ln = scn.nextLine(); + + DiceExpressionParser dep = new DiceExpressionParser(); + Map<String, IDiceExpression> env = new HashMap<>(); + DiceLanguageState state = new DiceLanguageState(dep, env); + + while (!ln.equalsIgnoreCase("quit")) { + String header = ln.split(" ")[0]; + + if (acts.containsKey(header)) { + acts.get(header).accept(ln, state); + } else { + IDiceExpression exp = DiceExpressionParser.parse(ln, env); + + System.out.println("\tParsed: " + exp.toString()); + System.out.println("\tSample Roll: " + exp.roll()); + + env.put("last", exp); + } + + i++; + + System.out.print("dice-lang-" + i + "> "); + ln = scn.nextLine(); + } + + System.out.println("Bye."); + scn.close(); + } + + /** + * @param ln + * Unused parameter, kept to comply with expected type sig + */ + private static void printEnv(String ln, DiceLanguageState stat) { + System.out.println("Printing enviroment for debugging purposes."); + + stat.doWith((dep, env) -> env.forEach((key, exp) -> System.out + .println("\tKey: " + key + "\tExp: " + exp.toString()))); + } + + private static void rollReference(String ln, DiceLanguageState stat) { + String[] strangs = ln.split(" "); + + System.out.println("\tRolling dice expression " + strangs[1] + " " + + strangs[2] + " times."); + + int nRolls = Integer.parseInt(strangs[2]); + + IDiceExpression dexp = stat + .merge((dep, env) -> env.get(strangs[1])); + + for (int i = 1; i <= nRolls; i++) { + int roll = dexp.roll(); + + System.out.println("\tRolled " + roll); + } + } +} |
