package de.skuzzle.polly.core.parser.ast.visitor; import java.util.HashMap; import java.util.Map; import de.skuzzle.polly.core.parser.ast.Identifier; import de.skuzzle.polly.core.parser.ast.Node; import de.skuzzle.polly.core.parser.ast.ResolvableIdentifier; import de.skuzzle.polly.core.parser.ast.Root; import de.skuzzle.polly.core.parser.ast.declarations.Declaration; import de.skuzzle.polly.core.parser.ast.expressions.Assignment; import de.skuzzle.polly.core.parser.ast.expressions.Braced; import de.skuzzle.polly.core.parser.ast.expressions.Call; import de.skuzzle.polly.core.parser.ast.expressions.Delete; import de.skuzzle.polly.core.parser.ast.expressions.Expression; import de.skuzzle.polly.core.parser.ast.expressions.Inspect; import de.skuzzle.polly.core.parser.ast.expressions.NamespaceAccess; import de.skuzzle.polly.core.parser.ast.expressions.Native; import de.skuzzle.polly.core.parser.ast.expressions.OperatorCall; import de.skuzzle.polly.core.parser.ast.expressions.VarAccess; import de.skuzzle.polly.core.parser.ast.expressions.Delete.DeleteableIdentifier; import de.skuzzle.polly.core.parser.ast.expressions.literals.BooleanLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.ChannelLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.DateLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.FunctionLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.HelpLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.ListLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.NumberLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.ProductLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.StringLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.TimespanLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.UserLiteral; /** * This class can collect changes that are to be made on an abstract syntax tree and then * perform all those changes in one pass. * * @author Simon Taddiken */ public class ASTRewrite { private final Map<Node, Node> nodeMap; public ASTRewrite() { this.nodeMap = new HashMap<Node, Node>(); } /** * Returns whether this rewriter contains any changes to be made. * * @return Whether this rewriter contains any changes to be made. */ public boolean hasChanges() { return !this.nodeMap.isEmpty(); } /** * Notes the given source node to be replaced with the given target node. * * @param source The node to be replaced. * @param with The replacement. */ public void rewrite(Node source, Node with) { this.nodeMap.put(source, with); } /** * Applies all collected replacement rules to the given (sub) tree and returns the * possibly new root. Nodes for which exists no replacement rule will be left * unchanged in the AST. Thus this method will return the same node which was provided * as parameter if there is no replacement rule for it. * * @param root The root node where to start node replacement. * @return The possibly new root created by replacements. * @throws ASTTraversalException If traversal of the AST fails for any reason. */ @SuppressWarnings("unchecked") public <T extends Node> T apply(T root) throws ASTTraversalException { final Transformation rewriteTransform = new NullTransform() { @Override public Expression transformVarAccess(VarAccess node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformVarAccess(node) : (Expression) rewrite; } @Override public Expression transformUser(UserLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformUser(node) : (Expression) rewrite; } @Override public Expression transformTimeSpan(TimespanLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformTimeSpan(node) : (Expression) rewrite; } @Override public Expression transformString(StringLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformString(node) : (Expression) rewrite; } @Override public Expression transformString(ChannelLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformString(node) : (Expression) rewrite; } @Override public Root transformRoot(Root node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformRoot(node) : (Root) rewrite; } @Override public ProductLiteral transformProduct(ProductLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformProduct(node) : (ProductLiteral) rewrite; } @Override public Expression transformOperatorCall(OperatorCall node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformOperatorCall(node) : (Expression) rewrite; } @Override public Expression transformNumber(NumberLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformNumber(node) : (Expression) rewrite; } @Override public Expression transformNative(Native node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformNative(node) : (Expression) rewrite; } @Override public Expression transformList(ListLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformList(node) : (Expression) rewrite; } @Override public Inspect transformInspect(Inspect node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformInspect(node) : (Inspect) rewrite; } @Override public DeleteableIdentifier transformIdentifier(DeleteableIdentifier node) { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformIdentifier(node) : (DeleteableIdentifier) rewrite; } @Override public ResolvableIdentifier transformIdentifier(ResolvableIdentifier node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformIdentifier(node) : (ResolvableIdentifier) rewrite; } @Override public Identifier transformIdentifier(Identifier node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformIdentifier(node) : (Identifier) rewrite; } @Override public HelpLiteral transformHelp(HelpLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformHelp(node) : (HelpLiteral) rewrite; } @Override public Expression transformFunction(FunctionLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformFunction(node) : (Expression) rewrite; } @Override public Expression transformDelete(Delete node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformDelete(node) : (Expression) rewrite; } @Override public Declaration transformDeclaration(Declaration node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformDeclaration(node) : (Declaration) rewrite; } @Override public Expression transformDate(DateLiteral node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformDate(node) : (Expression) rewrite; } @Override public Expression transformCall(Call node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformCall(node) : (Expression) rewrite; } @Override public Expression transformBraced(Braced node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformBraced(node) : (Expression) rewrite; } @Override public Expression transformBoolean(BooleanLiteral node) { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformBoolean(node) : (Expression) rewrite; } @Override public Expression transformAssignment(Assignment node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformAssignment(node) : (Expression) rewrite; } @Override public Expression transformAccess(NamespaceAccess node) throws ASTTraversalException { final Node rewrite = nodeMap.get(node); return rewrite == null ? super.transformAccess(node) : (Expression) rewrite; } }; // HACK: using seconds pass to update parents return (T) root.transform(rewriteTransform).updateParents(); } }