While there is currently no real support or tools for rewriting the tree, this is very possible to do. It doesn't even hurt so much.
ParseTreeListener or your MyBaseListener can be used with ParseTreeWalker to traverse the parse tree.
Here you can delete nodes using ParserRuleContext.removeLastChild() , however you should keep track of ParseTreeWalker.walk :
public void walk(ParseTreeListener listener, ParseTree t) { if ( t instanceof ErrorNode) { listener.visitErrorNode((ErrorNode)t); return; } else if ( t instanceof TerminalNode) { listener.visitTerminal((TerminalNode)t); return; } RuleNode r = (RuleNode)t; enterRule(listener, r); int n = r.getChildCount(); for (int i = 0; i<n; i++) { walk(listener, r.getChild(i)); } exitRule(listener, r); }
You must replace the remote nodes with something, if the walker visited the parents of these nodes, I usually select empty ParseRuleContext objects (this is due to the cached value of n in the method above). This prevents the release of ParseTreeWalker NPE.
When adding nodes, be sure to set the mutable parent to ParseRuleContext for the new parent. Also, because of cached n in the above method, a good strategy is to detect where the changes should be before , you get where you want your changes to go in walk , so ParseTreeWalker will go through them in the same pass (otherwise you will need a few passes ...)
Your pseudo code should look like this:
public void enterRewriteTarget(@NotNull MyParser.RewriteTargetContext ctx){ if(shouldRewrite(ctx)){ ArrayList<ParseTree> nodesReplaced = replaceNodes(ctx); addChildTo(ctx, createNewParentFor(nodesReplaced)); } }
I used this method to write a transpiler that compiled a synchronous internal language into asynchronous javascript. It was pretty painful.
Thalk source share