1/*
2 * [The "BSD license"]
3 *  Copyright (c) 2010 Terence Parr
4 *  All rights reserved.
5 *
6 *  Redistribution and use in source and binary forms, with or without
7 *  modification, are permitted provided that the following conditions
8 *  are met:
9 *  1. Redistributions of source code must retain the above copyright
10 *      notice, this list of conditions and the following disclaimer.
11 *  2. Redistributions in binary form must reproduce the above copyright
12 *      notice, this list of conditions and the following disclaimer in the
13 *      documentation and/or other materials provided with the distribution.
14 *  3. The name of the author may not be used to endorse or promote products
15 *      derived from this software without specific prior written permission.
16 *
17 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28package org.antlr.tool;
29
30import java.util.ArrayList;
31import java.util.List;
32
33/** A tree of grammars */
34public class CompositeGrammarTree {
35	protected List<CompositeGrammarTree> children;
36	public Grammar grammar;
37
38	/** Who is the parent node of this node; if null, implies node is root */
39	public CompositeGrammarTree parent;
40
41	public CompositeGrammarTree(Grammar g) {
42		grammar = g;
43	}
44
45	public void addChild(CompositeGrammarTree t) {
46		//System.out.println("add "+t.toStringTree()+" as child to "+this.toStringTree());
47		if ( t==null ) {
48			return; // do nothing upon addChild(null)
49		}
50		if ( children==null ) {
51			children = new ArrayList<CompositeGrammarTree>();
52		}
53		children.add(t);
54		t.parent = this;
55	}
56
57	/** Find a rule by looking in current grammar then down towards the
58	 *  delegate grammars.
59	 */
60	public Rule getRule(String ruleName) {
61		Rule r = grammar.getLocallyDefinedRule(ruleName);
62		for (int i = 0; r==null && children!=null && i < children.size(); i++) {
63			CompositeGrammarTree child = children.get(i);
64			r = child.getRule(ruleName);
65		}
66		return r;
67	}
68
69	/** Find an option by looking up towards the root grammar rather than down */
70	public Object getOption(String key) {
71		if ( grammar.tool!=null && key!=null && key.equals("language") &&
72			 grammar.tool.forcedLanguageOption!=null ) {
73			return grammar.tool.forcedLanguageOption;
74		}
75		Object o = grammar.getLocallyDefinedOption(key);
76		if ( o!=null ) {
77			return o;
78		}
79		if ( parent!=null ) {
80			return parent.getOption(key);
81		}
82		return null; // not found
83	}
84
85	public CompositeGrammarTree findNode(Grammar g) {
86		if ( g==null ) {
87			return null;
88		}
89		if ( this.grammar == g ) {
90			return this;
91		}
92		CompositeGrammarTree n = null;
93		for (int i = 0; n==null && children!=null && i < children.size(); i++) {
94			CompositeGrammarTree child = children.get(i);
95			n = child.findNode(g);
96		}
97		return n;
98	}
99
100	public CompositeGrammarTree findNode(String grammarName) {
101		if ( grammarName==null ) {
102			return null;
103		}
104		if ( grammarName.equals(this.grammar.name) ) {
105			return this;
106		}
107		CompositeGrammarTree n = null;
108		for (int i = 0; n==null && children!=null && i < children.size(); i++) {
109			CompositeGrammarTree child = children.get(i);
110			n = child.findNode(grammarName);
111		}
112		return n;
113	}
114
115	/** Return a postorder list of grammars; root is last in list */
116	public List<Grammar> getPostOrderedGrammarList() {
117		List<Grammar> grammars = new ArrayList<Grammar>();
118		_getPostOrderedGrammarList(grammars);
119		return grammars;
120	}
121
122	/** work for getPostOrderedGrammarList */
123	protected void _getPostOrderedGrammarList(List<Grammar> grammars) {
124		for (int i = 0; children!=null && i < children.size(); i++) {
125			CompositeGrammarTree child = children.get(i);
126			child._getPostOrderedGrammarList(grammars);
127		}
128		grammars.add(this.grammar);
129	}
130
131	/** Return a preorder list of grammars; root is first in list */
132	public List<Grammar> getPreOrderedGrammarList() {
133		List<Grammar> grammars = new ArrayList<Grammar>();
134		_getPreOrderedGrammarList(grammars);
135		return grammars;
136	}
137
138	protected void _getPreOrderedGrammarList(List<Grammar> grammars) {
139		grammars.add(this.grammar);
140		for (int i = 0; children!=null && i < children.size(); i++) {
141			CompositeGrammarTree child = children.get(i);
142			child._getPreOrderedGrammarList(grammars);
143		}
144	}
145
146	public void trimLexerImportsIntoCombined() {
147		CompositeGrammarTree p = this;
148		if ( p.grammar.type == Grammar.LEXER && p.parent!=null &&
149			 p.parent.grammar.type == Grammar.COMBINED )
150		{
151			//System.out.println("wacking "+p.grammar.name+" from "+p.parent.grammar.name);
152			p.parent.children.remove(this);
153		}
154		for (int i = 0; children!=null && i < children.size(); i++) {
155			CompositeGrammarTree child = children.get(i);
156			child.trimLexerImportsIntoCombined();
157		}
158	}
159}