diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-04-03 17:45:05 -0400 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-04-03 17:45:05 -0400 |
| commit | c8ae1ec096f5d1ac6db4f3a0035f7da106444e4e (patch) | |
| tree | 6c32c65d84d11efcea2bad699d0b68fbbb362290 /dice-lang/src/examples/java/bjc/dicelang | |
| parent | 9a6ac8c88689073cd0769da15b40c4fe091f0813 (diff) | |
General code refactoring and maintenance
Diffstat (limited to 'dice-lang/src/examples/java/bjc/dicelang')
3 files changed, 258 insertions, 86 deletions
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java new file mode 100644 index 0000000..3eaf6b0 --- /dev/null +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguagePragmaHandlers.java @@ -0,0 +1,81 @@ +package bjc.dicelang.examples; + +import java.util.Map; +import java.util.function.BiConsumer; + +import bjc.dicelang.ast.DiceASTExpression; +import bjc.dicelang.ast.DiceASTFreezer; +import bjc.dicelang.ast.DiceASTParser; +import bjc.dicelang.ast.IDiceASTNode; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.parserutils.AST; + +/** + * Container for pragma handlers + * + * @author ben + * + */ +public class DiceASTLanguagePragmaHandlers { + /** + * Handles freezing a specified expression to a new name + * + * @author ben + * + */ + public static final class FreezeHandler implements + BiConsumer<DiceASTParser, Map<String, DiceASTExpression>> { + private String expressionToFreeze; + private String resultingVariable; + + /** + * Create a new freeze handler + * + * @param expressionToFreeze + * The name of the expression to freeze + * @param resultingVariable + * The name of the variable to bind the frozen + * expression to + */ + public FreezeHandler(String expressionToFreeze, + String resultingVariable) { + this.expressionToFreeze = expressionToFreeze; + this.resultingVariable = resultingVariable; + } + + @Override + public void accept(DiceASTParser astParser, + Map<String, DiceASTExpression> enviroment) { + if (enviroment.containsKey(expressionToFreeze)) { + System.err.println( + "ERROR: There is no expression bound to the variable " + + expressionToFreeze + "."); + } else { + AST<IDiceASTNode> frozenAST = DiceASTFreezer.freezeAST( + enviroment.get(expressionToFreeze), + new FunctionalMap<>(enviroment)); + + enviroment.put(resultingVariable, + new DiceASTExpression(frozenAST, enviroment)); + } + } + } + + /** + * Print the enviroment for debugging/inspection purposes + * + * @author ben + * + */ + public static final class EnviromentPrinter implements + BiConsumer<DiceASTParser, Map<String, DiceASTExpression>> { + @Override + public void accept(DiceASTParser astParser, + Map<String, DiceASTExpression> enviroment) { + enviroment.forEach((variable, boundExpression) -> System.out + .println("\tKey: " + variable + "\n\t\tExp: " + + boundExpression.toString())); + } + } + +} diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java index f5a6a29..92e75e3 100644 --- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageState.java @@ -2,8 +2,8 @@ package bjc.dicelang.examples; import java.util.Map; -import bjc.dicelang.DiceExpressionParser; import bjc.dicelang.ast.DiceASTExpression; +import bjc.dicelang.ast.DiceASTParser; import bjc.utils.data.Pair; /** @@ -12,8 +12,8 @@ import bjc.utils.data.Pair; * @author ben * */ -public class DiceASTLanguageState extends - Pair<DiceExpressionParser, Map<String, DiceASTExpression>> { +public class DiceASTLanguageState + extends Pair<DiceASTParser, Map<String, DiceASTExpression>> { /** * Create a new state @@ -29,8 +29,8 @@ public class DiceASTLanguageState extends * @param right * The enviroment to use */ - public DiceASTLanguageState(DiceExpressionParser left, + public DiceASTLanguageState(DiceASTParser left, Map<String, DiceASTExpression> right) { super(left, right); } -} +}
\ No newline at end of file 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 e0f276d..a21ed66 100644 --- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java @@ -4,16 +4,18 @@ import java.util.HashMap; import java.util.Map; import java.util.Scanner; import java.util.function.BiConsumer; -import java.util.function.Consumer; -import bjc.dicelang.DiceExpressionParser; import bjc.dicelang.IDiceExpression; import bjc.dicelang.ast.DiceASTExpression; import bjc.dicelang.ast.DiceASTFreezer; import bjc.dicelang.ast.DiceASTParser; +import bjc.dicelang.ast.DiceASTReferenceChecker; import bjc.dicelang.ast.IDiceASTNode; -import bjc.dicelang.ast.VariableDiceNode; + +import static bjc.dicelang.examples.DiceASTLanguagePragmaHandlers.*; + import bjc.utils.data.GenHolder; +import bjc.utils.funcdata.FunctionalMap; import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod; import bjc.utils.parserutils.AST; @@ -24,75 +26,127 @@ import bjc.utils.parserutils.AST; * */ public class DiceASTLanguageTest { - private static final class LastChecker - implements Consumer<IDiceASTNode> { - private GenHolder<Boolean> canUpdateLast; + /** + * The 'special commands' that aren't normal expressions that can be + * invoked from the prompt + */ + private static Map<String, BiConsumer<String, DiceASTLanguageState>> specialCommands; - public LastChecker(GenHolder<Boolean> canUpdateLast) { - this.canUpdateLast = canUpdateLast; - } + static { + specialCommands = new HashMap<>(); - @Override - public void accept(IDiceASTNode tn) { - if (tn instanceof VariableDiceNode && ((VariableDiceNode) tn) - .getVariable().equals("last")) { - canUpdateLast.transform((s) -> false); - } else { - canUpdateLast.transform((s) -> true); - } - } + // Put all the defined special commands in place + specialCommands.put("roll", DiceASTLanguageTest::rollReference); + specialCommands.put("env", DiceASTLanguageTest::printEnv); + specialCommands.put("freeze", DiceASTLanguageTest::freezeVar); } - private static Map<String, BiConsumer<String, DiceASTLanguageState>> acts; - - static { - acts = new HashMap<>(); + /** + * Freeze the references in an expression. + * + * This means replace variable references with the current contents of + * the variables they refer to + * + * @param command + * The command and its arguments + * @param languageState + * The state of the language at the moment + */ + private static void freezeVar(String command, + DiceASTLanguageState languageState) { + // Split the string into components + String[] args = command.split(" "); + + // Make sure we have the correct amount of arguments + if (args.length != 3) { + System.err.println( + "ERROR: Freeze requires you provide the name of expression" + + " to freeze, as well as the name of the variable to bind" + + " the result to."); + return; + } - acts.put("roll", DiceASTLanguageTest::rollReference); - acts.put("env", DiceASTLanguageTest::printEnv); - acts.put("freeze", DiceASTLanguageTest::freezeVar); - } + String expressionToFreeze = args[1]; - private static void freezeVar(String ln, DiceASTLanguageState stat) { - String[] strangs = ln.split(" "); + String resultingVariable = args[2]; - System.out.println("Freezing references in " + strangs[1]); + System.out.println("Freezing references in " + args[1] + + " and binding to " + resultingVariable); - stat.doWith((dep, env) -> { - env.put(strangs[1], new DiceASTExpression( - DiceASTFreezer.freezeAST(env.get(strangs[1]), env), - env)); - }); + languageState.doWith( + new FreezeHandler(expressionToFreeze, resultingVariable)); } /** - * @param ln - * Unused parameter, kept in place to conform to expected - * type sig + * Print all bound variables in the current enviroment, as well as what + * they're bound to + * + * @param command + * The command and its arguments + * @param stat + * The state of the language at the moment */ - private static void printEnv(String ln, DiceASTLanguageState stat) { + private static void printEnv(String command, + DiceASTLanguageState 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()))); + stat.doWith(new EnviromentPrinter()); } - private static void rollReference(String ln, - DiceASTLanguageState stat) { - String[] strangs = ln.split(" "); + /** + * Roll an expression a given number of times + * + * @param command + * The command and its arguments + * @param languageState + * The state of the language at the moments + */ + private static void rollReference(String command, + DiceASTLanguageState languageState) { + String[] args = command.split(" "); + + if (args.length != 3) { + System.err.println("ERROR: Roll requires two arguments." + + " The name of the expression to roll, " + + "followed by the number of times to roll it"); + return; + } - System.out.println("\tRolling dice expression " + strangs[1] + " " - + strangs[2] + " times."); + System.out.println("\tRolling dice expression " + args[1] + " " + + args[2] + " times."); - int nRolls = Integer.parseInt(strangs[2]); + String expressionName = args[1]; - IDiceExpression dexp = - stat.merge((dep, env) -> env.get(strangs[1])); + int numberOfRolls; - for (int i = 1; i <= nRolls; i++) { - int roll = dexp.roll(); + try { + numberOfRolls = Integer.parseInt(args[2]); + } catch (NumberFormatException nfex) { + System.err.println( + "ERROR: The second argument must be a valid number, and " + + args[2] + " is not one."); + return; + } - System.out.println("\tRolled " + roll); + IDiceExpression expressionToRoll = + languageState.merge((astParser, enviroment) -> { + if (!enviroment.containsKey(expressionName)) { + return null; + } else { + return enviroment.get(expressionName); + } + }); + + if (expressionToRoll == null) { + System.err.println( + "ERROR: There is no expression bound to the variable " + + expressionName + "."); + } + + for (int i = 1; i <= numberOfRolls; i++) { + int currentRoll = expressionToRoll.roll(); + + System.out.println("\tRolled " + currentRoll); } } @@ -103,49 +157,86 @@ public class DiceASTLanguageTest { * Unused CLI args */ public static void main(String[] args) { - Scanner scn = new Scanner(System.in); - int i = 0; + Scanner inputSource = new Scanner(System.in); + int commandNumber = 0; - System.out.print("dice-lang-" + i + "> "); - String ln = scn.nextLine(); + System.out.print("dice-lang-" + commandNumber + "> "); + String currentLine = inputSource.nextLine(); - DiceASTParser dap = new DiceASTParser(); + // The enviroment for variables + Map<String, DiceASTExpression> enviroment = new HashMap<>(); - DiceExpressionParser dep = new DiceExpressionParser(); - Map<String, DiceASTExpression> env = new HashMap<>(); - DiceASTLanguageState state = new DiceASTLanguageState(dep, env); + // The parser to turn strings into AST's + DiceASTParser astParser = new DiceASTParser(); - while (!ln.equalsIgnoreCase("quit")) { - String header = ln.split(" ")[0]; + DiceASTLanguageState languageState = + new DiceASTLanguageState(astParser, enviroment); - if (acts.containsKey(header)) { - acts.get(header).accept(ln, state); - } else { + while (!currentLine.equalsIgnoreCase("quit")) { + String prospectiveCommandName = currentLine.split(" ")[0]; - AST<IDiceASTNode> builtAST = dap.buildAST(ln); - DiceASTExpression exp = - new DiceASTExpression(builtAST, env); - - System.out.println("\tParsed: " + exp.toString()); - System.out.println("\tSample Roll: " + exp.roll()); - - GenHolder<Boolean> canUpdateLast = new GenHolder<>(false); - - exp.getAst().traverse(TreeLinearizationMethod.PREORDER, - new LastChecker(canUpdateLast)); + // Handle special commands + if (specialCommands.containsKey(prospectiveCommandName)) { + specialCommands.get(prospectiveCommandName) + .accept(currentLine, languageState); + } else { - if (canUpdateLast.unwrap((s) -> s)) { - env.put("last", exp); + // Build an AST from the string expression + AST<IDiceASTNode> builtAST = + astParser.buildAST(currentLine); + + // Build a rollable expression from the AST + DiceASTExpression expression = + new DiceASTExpression(builtAST, enviroment); + + // Print out results + System.out.println("\tParsed: " + expression.toString()); + System.out + .println("\t\tSample Roll: " + expression.roll()); + + // Assume we can update last by default + GenHolder<Boolean> canUpdateLast = new GenHolder<>(true); + + // Check that no node references last + expression.getAst().traverse( + TreeLinearizationMethod.PREORDER, + new DiceASTReferenceChecker(canUpdateLast, + "last")); + + // Update last if we can + if (canUpdateLast.unwrap((flag) -> flag)) { + enviroment.put("last", expression); + } else { + // We need to freeze out references to last + enviroment.put("last", + freezeOutLast(enviroment, builtAST)); } } - i++; + // Increase the number of commands + commandNumber++; - System.out.print("dice-lang-" + i + "> "); - ln = scn.nextLine(); + // Read a new command + System.out.print("dice-lang-" + commandNumber + "> "); + currentLine = inputSource.nextLine(); } System.out.println("Bye."); - scn.close(); + + // Cleanup after ourselves + inputSource.close(); + } + + private static DiceASTExpression freezeOutLast( + Map<String, DiceASTExpression> enviroment, + AST<IDiceASTNode> builtAST) { + FunctionalMap<String, AST<IDiceASTNode>> transformedEnviroment = + new FunctionalMap<>(enviroment) + .mapValues((expr) -> expr.getAst()); + + AST<IDiceASTNode> expressionSansLast = DiceASTFreezer + .selectiveFreeze(builtAST, transformedEnviroment, "last"); + + return new DiceASTExpression(expressionSansLast, enviroment); } } |
