diff options
9 files changed, 197 insertions, 37 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 8d87aee..a6d5c75 100644 --- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java @@ -9,6 +9,7 @@ import bjc.dicelang.ast.DiceASTParser; import bjc.dicelang.ast.DiceASTReferenceSanitizer; import bjc.dicelang.ast.nodes.IDiceASTNode; import bjc.dicelang.ast.optimization.ConstantCollapser; +import bjc.dicelang.ast.optimization.OperationCondenser; import bjc.utils.funcdata.FunctionalMap; import bjc.utils.funcdata.FunctionalStringTokenizer; import bjc.utils.funcdata.IFunctionalList; @@ -166,8 +167,11 @@ public class DiceASTLanguageTest { ITree<IDiceASTNode> optimizedTree = optimizer.optimizeTree(builtAST, enviroment); + ITree<IDiceASTNode> condensedTree = + OperationCondenser.condense(optimizedTree); + ITree<IDiceASTNode> sanitizedTree = DiceASTReferenceSanitizer - .sanitize(optimizedTree, enviroment); + .sanitize(condensedTree, enviroment); return sanitizedTree; } 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 91abf7d..caf7f37 100644 --- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java +++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java @@ -20,17 +20,31 @@ public class DiceExpressionPreparer { /** * The yard to use for shunting expressions */ - private static ShuntingYard<String> yard; + 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; 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 + yard = new ShuntingYard<>(false); + + // 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 } static IFunctionalList<String> prepareCommand(String currentLine) { @@ -44,6 +58,7 @@ public class DiceExpressionPreparer { ops.add(new Pair<>("*", "\\*")); ops.add(new Pair<>("/", "/")); ops.add(new Pair<>(":=", ":=")); + ops.add(new Pair<>("=>", "=>")); IFunctionalList<String> semiExpandedTokens = ListUtils.splitTokens(tokens, ops); @@ -52,11 +67,6 @@ public class DiceExpressionPreparer { ops.add(new Pair<>("(", "\\(")); ops.add(new Pair<>(")", "\\)")); - ops.add(new Pair<>("+", "\\+")); - ops.add(new Pair<>("-", "-")); - ops.add(new Pair<>("*", "\\*")); - ops.add(new Pair<>("/", "/")); - ops.add(new Pair<>(":=", ":=")); IFunctionalList<String> fullyExpandedTokens = ListUtils.deAffixTokens(semiExpandedTokens, ops); diff --git a/dice-lang/src/main/java/bjc/dicelang/DiceExpressionParser.java b/dice-lang/src/main/java/bjc/dicelang/DiceExpressionParser.java index 76ccdd4..d0e013a 100644 --- a/dice-lang/src/main/java/bjc/dicelang/DiceExpressionParser.java +++ b/dice-lang/src/main/java/bjc/dicelang/DiceExpressionParser.java @@ -36,7 +36,7 @@ public class DiceExpressionParser { /* * Create a shunter to rewrite the expression */ - ShuntingYard<String> yard = new ShuntingYard<>(); + ShuntingYard<String> yard = new ShuntingYard<>(true); /* * Add our custom operators to the yard 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 411212e..aeecb38 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java @@ -67,9 +67,38 @@ public class DiceASTEvaluator { operatorCollapsers.put(OperatorDiceNode.GROUP, DiceASTEvaluator::parseGroup); + operatorCollapsers.put(OperatorDiceNode.LET, (nodes) -> { + return parseLet(enviroment, nodes); + }); + return operatorCollapsers; } + private static IPair<Integer, ITree<IDiceASTNode>> parseLet( + IFunctionalMap<String, ITree<IDiceASTNode>> enviroment, + IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) { + if (nodes.getSize() != 2) { + throw new UnsupportedOperationException( + "Can only use let with two expressions."); + } + + ITree<IDiceASTNode> bindTree = nodes.getByIndex(0).getRight(); + ITree<IDiceASTNode> expressionTree = + nodes.getByIndex(1).getRight(); + + IFunctionalMap<String, ITree<IDiceASTNode>> letEnviroment = + enviroment.extend(); + + evaluateAST(bindTree, letEnviroment); + int exprResult = evaluateAST(expressionTree, letEnviroment); + + IFunctionalList<ITree<IDiceASTNode>> childrn = + nodes.map((pair) -> pair.getRight()); + + return new Pair<>(exprResult, + new Tree<>(OperatorDiceNode.LET, childrn)); + } + /** * Evaluate the provided AST to a numeric value * @@ -121,8 +150,9 @@ public class DiceASTEvaluator { return result; } - // Value to allow for assignments - return 0; + throw new UnsupportedOperationException( + "Attempted to dereference unbound variable " + + variableName); } private static int evaluateLiteral(IDiceASTNode leafNode) { diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java index 00ac871..7676fac 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTOptimizer.java @@ -44,14 +44,16 @@ public class DiceASTOptimizer { */ public ITree<IDiceASTNode> optimizeTree(ITree<IDiceASTNode> ast, IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) { - return passes.reduceAux(ast, (currentPass, currentTree) -> { - return currentTree.collapse(currentPass::optimizeLeaf, - (operator) -> { - return (nodes) -> { - return currentPass.optimizeOperator(operator, - nodes); - }; - }, (tree) -> tree); - }, (tree) -> tree); + ITree<IDiceASTNode> optimizedTree = + passes.reduceAux(ast, (currentPass, currentTree) -> { + return currentTree.collapse(currentPass::optimizeLeaf, + (operator) -> { + return (nodes) -> { + return currentPass.optimizeOperator( + operator, nodes); + }; + }, (tree) -> tree); + }, (tree) -> tree); + return optimizedTree; } } diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java index 08f84e3..05fddf6 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java @@ -41,6 +41,8 @@ public class DiceASTReferenceSanitizer { switch (((OperatorDiceNode) node)) { case ASSIGN: return TopDownTransformResult.TRANSFORM; + case LET: + return TopDownTransformResult.PASSTHROUGH; case ADD: case COMPOUND: case DIVIDE: diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java index ab47b56..c0f7bd3 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java @@ -14,29 +14,33 @@ public enum OperatorDiceNode implements IDiceASTNode { */ ADD(MATH), /** - * Represents assigning one node to another + * Represents dividing two nodes */ - ASSIGN(EXPRESSION), + DIVIDE(MATH), /** - * Representings combining two node values together + * Represents multiplying two nodes */ - COMPOUND(DICE), + MULTIPLY(MATH), /** - * Represents dividing two nodes + * Represents subtracting two nodes */ - DIVIDE(MATH), + SUBTRACT(MATH), + /** + * Representings combining two node values together + */ + COMPOUND(DICE), /** * Represents using one node a variable number of times */ GROUP(DICE), /** - * Represents multiplying two nodes + * Represents assigning one node to another */ - MULTIPLY(MATH), + ASSIGN(EXPRESSION), /** - * Represents subtracting two nodes + * Represents evaluating one expression in the context of another */ - SUBTRACT(MATH); + LET(EXPRESSION); /** * Represents the group of operator this operator is sorted into. @@ -73,6 +77,8 @@ public enum OperatorDiceNode implements IDiceASTNode { case "c": case "compound": return COMPOUND; + case "=>": + return LET; default: throw new IllegalArgumentException( s + " is not a valid operator node"); diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java index 5062170..e476d74 100644 --- a/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java +++ b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java @@ -78,6 +78,7 @@ public class ConstantCollapser implements IOptimizationPass { return new Tree<>(operator, children); case ASSIGN: + case LET: default: // We don't optimize these operators return new Tree<>(operator, children); diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java new file mode 100644 index 0000000..f41a3ef --- /dev/null +++ b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java @@ -0,0 +1,105 @@ +package bjc.dicelang.ast.optimization; + +import bjc.dicelang.ast.nodes.DiceASTType; +import bjc.dicelang.ast.nodes.IDiceASTNode; +import bjc.dicelang.ast.nodes.OperatorDiceNode; +import bjc.utils.data.IHolder; +import bjc.utils.data.Identity; +import bjc.utils.funcdata.ITree; +import bjc.utils.funcdata.TopDownTransformResult; +import bjc.utils.funcdata.Tree; + +/** + * Condenses chained operations into a single level + * + * @author ben + * + */ +public class OperationCondenser { + /** + * Condense chained similiar operations into a single level + * + * @param ast + * The AST to condense + * @return The condensed AST + */ + public static ITree<IDiceASTNode> condense(ITree<IDiceASTNode> ast) { + return ast.topDownTransform(OperationCondenser::pickNode, + OperationCondenser::doCondense); + } + + private static TopDownTransformResult pickNode(IDiceASTNode node) { + switch (node.getType()) { + case LITERAL: + return TopDownTransformResult.SKIP; + case OPERATOR: + return pickOperator((OperatorDiceNode) node); + case VARIABLE: + return TopDownTransformResult.SKIP; + default: + throw new UnsupportedOperationException( + "Attempted to traverse unknown node type " + node); + } + } + + private static TopDownTransformResult + pickOperator(OperatorDiceNode node) { + switch (node) { + case ADD: + case MULTIPLY: + case SUBTRACT: + case DIVIDE: + case COMPOUND: + return TopDownTransformResult.PUSHDOWN; + case ASSIGN: + case GROUP: + case LET: + return TopDownTransformResult.PASSTHROUGH; + default: + throw new UnsupportedOperationException( + "Attempted to traverse unknown operator " + node); + } + } + + private static ITree<IDiceASTNode> + doCondense(ITree<IDiceASTNode> ast) { + OperatorDiceNode operation = + ast.transformHead((node) -> (OperatorDiceNode) node); + + IHolder<Boolean> canCondense = new Identity<>(true); + + ast.doForChildren((child) -> { + if (canCondense.getValue()) { + canCondense.replace(child.transformHead((node) -> { + if (node.getType() == DiceASTType.OPERATOR) { + if (operation.equals(node)) { + return true; + } + + return false; + } + + return true; + })); + } + }); + + if (!canCondense.getValue()) { + return ast; + } + + ITree<IDiceASTNode> condensedAST = new Tree<>(operation); + + ast.doForChildren((child) -> { + if (child.getHead().getType() == DiceASTType.OPERATOR) { + child.doForChildren((subChild) -> { + condensedAST.addChild(subChild); + }); + } else { + condensedAST.addChild(child); + } + }); + + return condensedAST; + } +} |
