From e7413128ff4e376997de6e94e4bea5eca14811ef Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Thu, 27 Oct 2016 21:56:18 -0400 Subject: Moved examples --- .../dicelang/ast/DiceASTReferenceSanitizer.java | 201 +++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 dice-lang/src/bjc/dicelang/ast/DiceASTReferenceSanitizer.java (limited to 'dice-lang/src/bjc/dicelang/ast/DiceASTReferenceSanitizer.java') diff --git a/dice-lang/src/bjc/dicelang/ast/DiceASTReferenceSanitizer.java b/dice-lang/src/bjc/dicelang/ast/DiceASTReferenceSanitizer.java new file mode 100644 index 0000000..d8f658e --- /dev/null +++ b/dice-lang/src/bjc/dicelang/ast/DiceASTReferenceSanitizer.java @@ -0,0 +1,201 @@ +package bjc.dicelang.ast; + +import bjc.utils.data.IHolder; +import bjc.utils.data.Identity; +import bjc.utils.funcdata.IMap; +import bjc.utils.funcdata.ITree; +import bjc.utils.funcdata.TopDownTransformResult; +import bjc.utils.funcdata.Tree; + +import bjc.dicelang.ast.nodes.IDiceASTNode; +import bjc.dicelang.ast.nodes.OperatorDiceNode; +import bjc.dicelang.ast.nodes.VariableDiceNode; + +/** + * Sanitize the references in an AST so that a variable that refers to + * itself in its definition has the occurance of it replaced with its + * previous definition + * + * @author ben + * + */ +public class DiceASTReferenceSanitizer { + private static ITree doSanitize(ITree ast, + IMap> enviroment) { + if (ast.getChildrenCount() != 2) { + throw new UnsupportedOperationException( + "Assignment must have two arguments."); + } + + ITree nameTree = ast.getChild(0); + ITree valueTree = ast.getChild(1); + + if (!DiceASTUtils.containsSimpleVariable(nameTree)) { + if (nameTree.getHead() == OperatorDiceNode.ARRAY) { + IHolder allSimpleVariables = new Identity<>(true); + + nameTree.doForChildren((child) -> { + if (allSimpleVariables.getValue()) { + boolean isSimple = DiceASTUtils + .containsSimpleVariable(child); + + allSimpleVariables.replace(isSimple); + } + }); + + if (!allSimpleVariables.getValue()) { + throw new UnsupportedOperationException( + "Array assignment must be between variables and" + + " a expression/array of expressions"); + } + + if (valueTree.getHead() == OperatorDiceNode.ARRAY) { + if (nameTree.getChildrenCount() != valueTree + .getChildrenCount()) { + throw new UnsupportedOperationException( + "Array assignment between arrays must be" + + " between two arrays of equal length"); + } + } + } else { + throw new UnsupportedOperationException( + "Assignment must be between a variable and a expression"); + } + } + + if (nameTree.getHead() == OperatorDiceNode.ARRAY) { + if (valueTree.getHead() == OperatorDiceNode.ARRAY) { + IHolder childCounter = new Identity<>(0); + + ITree returnTree = new Tree<>( + OperatorDiceNode.ARRAY); + + nameTree.doForChildren((child) -> { + String variableName = child.transformHead((node) -> { + return ((VariableDiceNode) node).getVariable(); + }); + + ITree currentValue = valueTree + .getChild(childCounter.getValue()); + + ITree sanitizedSubtree = doSingleSanitize( + ast, enviroment, child, currentValue, + variableName); + + if (sanitizedSubtree == null) { + ITree oldTree = new Tree<>( + ast.getHead(), child, currentValue); + + returnTree.addChild(oldTree); + } else { + returnTree.addChild(sanitizedSubtree); + } + + childCounter.transform((count) -> count + 1); + }); + + return returnTree; + } + + ITree returnTree = new Tree<>( + OperatorDiceNode.ARRAY); + + nameTree.doForChildren((child) -> { + String variableName = child.transformHead( + (node) -> ((VariableDiceNode) node).getVariable()); + + ITree sanitizedChild = doSingleSanitize(ast, + enviroment, child, valueTree, variableName); + if (sanitizedChild == null) { + ITree oldTree = new Tree<>(ast.getHead(), + child, valueTree); + + returnTree.addChild(oldTree); + } else { + returnTree.addChild(sanitizedChild); + } + }); + + return returnTree; + } + + String variableName = nameTree.transformHead( + (node) -> ((VariableDiceNode) node).getVariable()); + + ITree sanitizedTree = doSingleSanitize(ast, + enviroment, nameTree, valueTree, variableName); + + if (sanitizedTree == null) { + return ast; + } + + return sanitizedTree; + } + + private static ITree doSingleSanitize( + ITree ast, + IMap> enviroment, + ITree nameTree, ITree valueTree, + String variableName) { + if (enviroment.containsKey(variableName)) { + // @ is a meta-variable standing for the left side of an + // assignment + ITree oldVal = enviroment.put("@", + enviroment.get(variableName)); + + // We should always inline out references to last, because it + // will always change + ITree inlinedValue = DiceASTInliner + .selectiveInline(valueTree, enviroment, variableName, + "last", "@"); + + if (oldVal != null) { + enviroment.put("@", oldVal); + } else { + enviroment.remove("@"); + } + + return new Tree<>(ast.getHead(), nameTree, inlinedValue); + } + + return null; + } + + /** + * Sanitize the references in an AST + * + * @param ast + * @param enviroment + * @return The sanitized AST + */ + public static ITree sanitize(ITree ast, + IMap> enviroment) { + return ast.topDownTransform( + DiceASTReferenceSanitizer::shouldSanitize, (subTree) -> { + return doSanitize(subTree, enviroment); + }); + } + + private static TopDownTransformResult shouldSanitize( + IDiceASTNode node) { + if (!node.isOperator()) { + return TopDownTransformResult.SKIP; + } + + switch (((OperatorDiceNode) node)) { + case ASSIGN: + return TopDownTransformResult.TRANSFORM; + case ARRAY: + case LET: + return TopDownTransformResult.PASSTHROUGH; + case ADD: + case COMPOUND: + case DIVIDE: + case GROUP: + case MULTIPLY: + case SUBTRACT: + default: + return TopDownTransformResult.SKIP; + } + } +} -- cgit v1.2.3