/* * Copyright (c) 2012-2016 The ANTLR Project. All rights reserved. * Use of this file is governed by the BSD 3-clause license that * can be found in the LICENSE.txt file in the project root. */ package org.antlr.v4.tool.ast; import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonToken; import org.antlr.runtime.Token; import org.antlr.runtime.tree.CommonTree; import org.antlr.runtime.tree.CommonTreeNodeStream; import org.antlr.runtime.tree.Tree; import org.antlr.v4.parse.ANTLRParser; import org.antlr.v4.parse.GrammarASTAdaptor; import org.antlr.v4.runtime.atn.ATNState; import org.antlr.v4.runtime.misc.IntervalSet; import org.antlr.v4.tool.Grammar; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class GrammarAST extends CommonTree { /** For error msgs, nice to know which grammar this AST lives in */ // TODO: try to remove public Grammar g; /** If we build an ATN, we make AST node point at left edge of ATN construct */ public ATNState atnState; public String textOverride; public GrammarAST() {} public GrammarAST(Token t) { super(t); } public GrammarAST(GrammarAST node) { super(node); this.g = node.g; this.atnState = node.atnState; this.textOverride = node.textOverride; } public GrammarAST(int type) { super(new CommonToken(type, ANTLRParser.tokenNames[type])); } public GrammarAST(int type, Token t) { this(new CommonToken(t)); token.setType(type); } public GrammarAST(int type, Token t, String text) { this(new CommonToken(t)); token.setType(type); token.setText(text); } public GrammarAST[] getChildrenAsArray() { return children.toArray(new GrammarAST[children.size()]); } public List getNodesWithType(int ttype) { return getNodesWithType(IntervalSet.of(ttype)); } public List getAllChildrenWithType(int type) { List nodes = new ArrayList(); for (int i = 0; children!=null && i < children.size(); i++) { Tree t = (Tree) children.get(i); if ( t.getType()==type ) { nodes.add((GrammarAST)t); } } return nodes; } public List getNodesWithType(IntervalSet types) { List nodes = new ArrayList(); List work = new LinkedList(); work.add(this); GrammarAST t; while ( !work.isEmpty() ) { t = work.remove(0); if ( types==null || types.contains(t.getType()) ) nodes.add(t); if ( t.children!=null ) { work.addAll(Arrays.asList(t.getChildrenAsArray())); } } return nodes; } public List getNodesWithTypePreorderDFS(IntervalSet types) { ArrayList nodes = new ArrayList(); getNodesWithTypePreorderDFS_(nodes, types); return nodes; } public void getNodesWithTypePreorderDFS_(List nodes, IntervalSet types) { if ( types.contains(this.getType()) ) nodes.add(this); // walk all children of root. for (int i= 0; i < getChildCount(); i++) { GrammarAST child = (GrammarAST)getChild(i); child.getNodesWithTypePreorderDFS_(nodes, types); } } public GrammarAST getNodeWithTokenIndex(int index) { if ( this.getToken()!=null && this.getToken().getTokenIndex()==index ) { return this; } // walk all children of root. for (int i= 0; i < getChildCount(); i++) { GrammarAST child = (GrammarAST)getChild(i); GrammarAST result = child.getNodeWithTokenIndex(index); if ( result!=null ) { return result; } } return null; } public AltAST getOutermostAltNode() { if ( this instanceof AltAST && parent.parent instanceof RuleAST ) { return (AltAST)this; } if ( parent!=null ) return ((GrammarAST)parent).getOutermostAltNode(); return null; } /** Walk ancestors of this node until we find ALT with * alt!=null or leftRecursiveAltInfo!=null. Then grab label if any. * If not a rule element, just returns null. */ public String getAltLabel() { List ancestors = this.getAncestors(); if ( ancestors==null ) return null; for (int i=ancestors.size()-1; i>=0; i--) { GrammarAST p = (GrammarAST)ancestors.get(i); if ( p.getType()== ANTLRParser.ALT ) { AltAST a = (AltAST)p; if ( a.altLabel!=null ) return a.altLabel.getText(); if ( a.leftRecursiveAltInfo!=null ) { return a.leftRecursiveAltInfo.altLabel; } } } return null; } public boolean deleteChild(org.antlr.runtime.tree.Tree t) { for (int i=0; i