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 org.antlr.analysis.DFA;
31import org.antlr.analysis.NFAState;
32import org.antlr.grammar.v3.ANTLRParser;
33import org.antlr.misc.IntSet;
34import org.antlr.misc.Interval;
35import org.antlr.runtime.CommonToken;
36import org.antlr.runtime.Token;
37import org.antlr.runtime.TokenSource;
38import org.antlr.runtime.tree.CommonTree;
39import org.antlr.runtime.tree.Tree;
40import org.antlr.runtime.tree.TreeAdaptor;
41import org.stringtemplate.v4.ST;
42import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName;
43
44import java.util.*;
45
46/** Grammars are first converted to ASTs using this class and then are
47 *  converted to NFAs via a tree walker.
48 *
49 *  The reader may notice that I have made a very non-OO decision in this
50 *  class to track variables for many different kinds of nodes.  It wastes
51 *  space for nodes that don't need the values and OO principles cry out
52 *  for a new class type for each kind of node in my tree.  I am doing this
53 *  on purpose for a variety of reasons.  I don't like using the type
54 *  system for different node types; it yields too many damn class files
55 *  which I hate.  Perhaps if I put them all in one file.  Most importantly
56 *  though I hate all the type casting that would have to go on.  I would
57 *  have all sorts of extra work to do.  Ick.  Anyway, I'm doing all this
58 *  on purpose, not out of ignorance. ;)
59 */
60public class GrammarAST extends CommonTree {
61	static int count = 0;
62
63	public int ID = ++count;
64
65	private String textOverride;
66
67    public String enclosingRuleName;
68
69    /** If this is a decision node, what is the lookahead DFA? */
70    public DFA lookaheadDFA = null;
71
72    /** What NFA start state was built from this node? */
73    public NFAState NFAStartState = null;
74
75	/** This is used for TREE_BEGIN nodes to point into
76	 *  the NFA.  TREE_BEGINs point at left edge of DOWN for LOOK computation
77     *  purposes (Nullable tree child list needs special code gen when matching).
78	 */
79	public NFAState NFATreeDownState = null;
80
81	/** Rule ref nodes, token refs, set, and NOT set refs need to track their
82	 *  location in the generated NFA so that local FOLLOW sets can be
83	 *  computed during code gen for automatic error recovery.
84	 */
85	public NFAState followingNFAState = null;
86
87	/** If this is a SET node, what are the elements? */
88    protected IntSet setValue = null;
89
90    /** If this is a BLOCK node, track options here */
91    protected Map<String,Object> blockOptions;
92
93	/** If this is a BLOCK node for a rewrite rule, track referenced
94	 *  elements here.  Don't track elements in nested subrules.
95	 */
96	public Set<GrammarAST> rewriteRefsShallow;
97
98	/*	If REWRITE node, track EVERY element and label ref to right of ->
99	 *  for this rewrite rule.  There could be multiple of these per
100	 *  rule:
101	 *
102	 *     a : ( ... -> ... | ... -> ... ) -> ... ;
103	 *
104	 *  We may need a list of all refs to do definitions for whole rewrite
105	 *  later.
106	 *
107	 *  If BLOCK then tracks every element at that level and below.
108	 */
109	public Set<GrammarAST> rewriteRefsDeep;
110
111	public Map<String,Object> terminalOptions;
112
113	/** if this is an ACTION node, this is the outermost enclosing
114	 *  alt num in rule.  For actions, define.g sets these (used to
115	 *  be codegen.g).  We need these set so we can examine actions
116	 *  early, before code gen, for refs to rule predefined properties
117	 *  and rule labels.  For most part define.g sets outerAltNum, but
118	 *  codegen.g does the ones for %foo(a={$ID.text}) type refs as
119	 *  the {$ID...} is not seen as an action until code gen pulls apart.
120	 */
121	public int outerAltNum;
122
123	/** if this is a TOKEN_REF or RULE_REF node, this is the code ST
124	 *  generated for this node.  We need to update it later to add
125	 *  a label if someone does $tokenref or $ruleref in an action.
126	 */
127	public ST code;
128
129    /**
130     *
131     * @return
132     */
133    public Map<String, Object> getBlockOptions() {
134        return blockOptions;
135    }
136
137    /**
138     *
139     * @param blockOptions
140     */
141    public void setBlockOptions(Map<String, Object> blockOptions) {
142        this.blockOptions = blockOptions;
143    }
144
145	public GrammarAST() {;}
146
147	public GrammarAST(int t, String txt) {
148		initialize(t,txt);
149	}
150
151	public GrammarAST(Token token) {
152		initialize(token);
153	}
154
155	public void initialize(int i, String s) {
156        token = new CommonToken(i,s);
157		token.setTokenIndex(-1);
158    }
159
160    public void initialize(Tree ast) {
161		GrammarAST t = ((GrammarAST)ast);
162		this.startIndex = t.startIndex;
163		this.stopIndex = t.stopIndex;
164		this.token = t.token;
165		this.enclosingRuleName = t.enclosingRuleName;
166		this.setValue = t.setValue;
167		this.blockOptions = t.blockOptions;
168		this.outerAltNum = t.outerAltNum;
169	}
170
171    public void initialize(Token token) {
172        this.token = token;
173		if ( token!=null ) {
174			startIndex = token.getTokenIndex();
175			stopIndex = startIndex;
176		}
177    }
178
179    public DFA getLookaheadDFA() {
180        return lookaheadDFA;
181    }
182
183    public void setLookaheadDFA(DFA lookaheadDFA) {
184        this.lookaheadDFA = lookaheadDFA;
185    }
186
187    public NFAState getNFAStartState() {
188        return NFAStartState;
189    }
190
191    public void setNFAStartState(NFAState nfaStartState) {
192		this.NFAStartState = nfaStartState;
193	}
194
195	/** Save the option key/value pair and process it; return the key
196	 *  or null if invalid option.
197	 */
198	public String setBlockOption(Grammar grammar, String key, Object value) {
199		if ( blockOptions == null ) {
200			blockOptions = new HashMap();
201		}
202		return setOption(blockOptions, Grammar.legalBlockOptions, grammar, key, value);
203	}
204
205	public String setTerminalOption(Grammar grammar, String key, Object value) {
206		if ( terminalOptions == null ) {
207			terminalOptions = new HashMap<String,Object>();
208		}
209		return setOption(terminalOptions, Grammar.legalTokenOptions, grammar, key, value);
210	}
211
212	public String setOption(Map options, Set legalOptions, Grammar grammar, String key, Object value) {
213		if ( !legalOptions.contains(key) ) {
214			ErrorManager.grammarError(ErrorManager.MSG_ILLEGAL_OPTION,
215									  grammar,
216									  token,
217									  key);
218			return null;
219		}
220		if ( value instanceof String ) {
221			String vs = (String)value;
222			if ( vs.charAt(0)=='"' ) {
223				value = vs.substring(1,vs.length()-1); // strip quotes
224            }
225        }
226		if ( key.equals("k") ) {
227			grammar.numberOfManualLookaheadOptions++;
228		}
229        if ( key.equals("backtrack") && value.toString().equals("true") ) {
230            grammar.composite.getRootGrammar().atLeastOneBacktrackOption = true;
231        }
232        options.put(key, value);
233		return key;
234    }
235
236    public Object getBlockOption(String key) {
237		Object value = null;
238		if ( blockOptions != null ) {
239			value = blockOptions.get(key);
240		}
241		return value;
242	}
243
244    public void setOptions(Grammar grammar, Map options) {
245		if ( options==null ) {
246			this.blockOptions = null;
247			return;
248		}
249		String[] keys = (String[])options.keySet().toArray(new String[options.size()]);
250		for (String optionName : keys) {
251			String stored= setBlockOption(grammar, optionName, options.get(optionName));
252			if ( stored==null ) {
253				options.remove(optionName);
254			}
255		}
256    }
257
258    @Override
259    public String getText() {
260		if ( textOverride!=null ) return textOverride;
261        if ( token!=null ) {
262            return token.getText();
263        }
264        return "";
265    }
266
267	public void setType(int type) {
268		token.setType(type);
269	}
270
271	public void setText(String text) {
272		textOverride = text; // don't alt tokens as others might see
273	}
274
275    @Override
276    public int getType() {
277        if ( token!=null ) {
278            return token.getType();
279        }
280        return -1;
281    }
282
283    @Override
284    public int getLine() {
285		int line=0;
286        if ( token!=null ) {
287            line = token.getLine();
288        }
289		if ( line==0 ) {
290			Tree child = getChild(0);
291			if ( child!=null ) {
292				line = child.getLine();
293			}
294		}
295        return line;
296    }
297
298    @Override
299    public int getCharPositionInLine(){
300		int col=0;
301        if ( token!=null ) {
302            col = token.getCharPositionInLine();
303        }
304		if ( col==0 ) {
305			Tree child = getChild(0);
306			if ( child!=null ) {
307				col = child.getCharPositionInLine();
308			}
309		}
310        return col;
311    }
312
313    public void setLine(int line) {
314        token.setLine(line);
315    }
316
317    public void setCharPositionInLine(int value){
318        token.setCharPositionInLine(value);
319    }
320
321 	public IntSet getSetValue() {
322        return setValue;
323    }
324
325    public void setSetValue(IntSet setValue) {
326        this.setValue = setValue;
327    }
328
329    public GrammarAST getLastChild() {
330        if (getChildCount() == 0)
331            return null;
332        return (GrammarAST)getChild(getChildCount() - 1);
333    }
334
335    public GrammarAST getNextSibling() {
336        return (GrammarAST)getParent().getChild(getChildIndex() + 1);
337    }
338
339    public GrammarAST getLastSibling() {
340        Tree parent = getParent();
341        if ( parent==null ) {
342            return null;
343        }
344        return (GrammarAST)parent.getChild(parent.getChildCount() - 1);
345    }
346
347
348    public GrammarAST[] getChildrenAsArray() {
349        return (GrammarAST[])getChildren().toArray(new GrammarAST[getChildCount()]);
350    }
351
352    private static final GrammarAST DescendantDownNode = new GrammarAST(Token.DOWN, "DOWN");
353    private static final GrammarAST DescendantUpNode = new GrammarAST(Token.UP, "UP");
354
355    public static List<Tree> descendants(Tree root){
356        return descendants(root, false);
357    }
358
359    public static List<Tree> descendants(Tree root, boolean insertDownUpNodes){
360        List<Tree> result = new ArrayList<Tree>();
361        int count = root.getChildCount();
362
363        if (insertDownUpNodes){
364            result.add(root);
365            result.add(DescendantDownNode);
366
367            for (int i = 0 ; i < count ; i++){
368                Tree child = root.getChild(i);
369                for (Tree subchild : descendants(child, true))
370                    result.add(subchild);
371            }
372
373            result.add(DescendantUpNode);
374        }else{
375            result.add(root);
376            for (int i = 0 ; i < count ; i++){
377                Tree child = root.getChild(i);
378                for (Tree subchild : descendants(child, false))
379                    result.add(subchild);
380            }
381        }
382
383        return result;
384    }
385
386	public GrammarAST findFirstType(int ttype) {
387		// check this node (the root) first
388		if ( this.getType()==ttype ) {
389			return this;
390		}
391		// else check children
392		List<Tree> descendants = descendants(this);
393		for (Tree child : descendants) {
394			if ( child.getType()==ttype ) {
395				return (GrammarAST)child;
396			}
397		}
398		return null;
399	}
400
401	public List<GrammarAST> findAllType(int ttype) {
402		List<GrammarAST> nodes = new ArrayList<GrammarAST>();
403		_findAllType(ttype, nodes);
404		return nodes;
405	}
406
407	public void _findAllType(int ttype, List<GrammarAST> nodes) {
408		// check this node (the root) first
409		if ( this.getType()==ttype ) nodes.add(this);
410		// check children
411		for (int i = 0; i < getChildCount(); i++){
412			GrammarAST child = (GrammarAST)getChild(i);
413			child._findAllType(ttype, nodes);
414		}
415	}
416
417    /** Make nodes unique based upon Token so we can add them to a Set; if
418	 *  not a GrammarAST, check type.
419	 */
420	@Override
421	public boolean equals(Object ast) {
422		if ( this == ast ) {
423			return true;
424		}
425		if ( !(ast instanceof GrammarAST) ) {
426			return this.getType() == ((Tree)ast).getType();
427		}
428		GrammarAST t = (GrammarAST)ast;
429		return token.getLine() == t.getLine() &&
430			   token.getCharPositionInLine() == t.getCharPositionInLine();
431	}
432
433    /** Make nodes unique based upon Token so we can add them to a Set; if
434	 *  not a GrammarAST, check type.
435	 */
436    @Override
437    public int hashCode(){
438        if (token == null)
439            return 0;
440
441        return token.hashCode();
442    }
443
444	/** See if tree has exact token types and structure; no text */
445	public boolean hasSameTreeStructure(Tree other) {
446		// check roots first.
447		if (this.getType() != other.getType()) return false;
448		// if roots match, do full list match test on children.
449		Iterator<Tree> thisDescendants = descendants(this, true).iterator();
450		Iterator<Tree> otherDescendants = descendants(other, true).iterator();
451		while (thisDescendants.hasNext()) {
452			if (!otherDescendants.hasNext())
453				return false;
454			if (thisDescendants.next().getType() != otherDescendants.next().getType())
455				return false;
456		}
457		return !otherDescendants.hasNext();
458	}
459
460	public static GrammarAST dup(Tree t) {
461		if ( t==null ) {
462			return null;
463		}
464		GrammarAST dup_t = new GrammarAST();
465		dup_t.initialize(t);
466		return dup_t;
467	}
468
469    @Override
470    public Tree dupNode(){
471        return dup(this);
472    }
473
474	/**Duplicate a tree, assuming this is a root node of a tree--
475	 * duplicate that node and what's below; ignore siblings of root node.
476	 */
477	public static GrammarAST dupTreeNoActions(GrammarAST t, GrammarAST parent) {
478		if ( t==null ) {
479			return null;
480		}
481		GrammarAST result = (GrammarAST)t.dupNode();
482		for (GrammarAST subchild : getChildrenForDupTree(t)) {
483			result.addChild(dupTreeNoActions(subchild, result));
484		}
485		return result;
486	}
487
488	private static List<GrammarAST> getChildrenForDupTree(GrammarAST t) {
489		List<GrammarAST> result = new ArrayList<GrammarAST>();
490		for (int i = 0; i < t.getChildCount(); i++){
491			GrammarAST child = (GrammarAST)t.getChild(i);
492			int ttype = child.getType();
493			if (ttype == ANTLRParser.REWRITES || ttype == ANTLRParser.REWRITE || ttype==ANTLRParser.ACTION) {
494				continue;
495			}
496
497			if (ttype == ANTLRParser.BANG || ttype == ANTLRParser.ROOT) {
498				for (GrammarAST subchild : getChildrenForDupTree(child))
499					result.add(subchild);
500			} else {
501				result.add(child);
502			}
503		}
504		if ( result.size()==1 && result.get(0).getType()==ANTLRParser.EOA &&
505			 t.getType()==ANTLRParser.ALT )
506		{
507			// can't have an empty alt, insert epsilon
508			result.add(0, new GrammarAST(ANTLRParser.EPSILON, "epsilon"));
509		}
510
511		return result;
512	}
513
514	public static GrammarAST dupTree(GrammarAST t) {
515		if ( t==null ) {
516			return null;
517		}
518		GrammarAST root = dup(t);		// make copy of root
519		// copy all children of root.
520		for (int i= 0; i < t.getChildCount(); i++) {
521			GrammarAST child = (GrammarAST)t.getChild(i);
522			root.addChild(dupTree(child));
523		}
524		return root;
525	}
526
527	public void setTreeEnclosingRuleNameDeeply(String rname) {
528		enclosingRuleName = rname;
529		if (getChildCount() == 0) return;
530		for (Object child : getChildren()) {
531			if (!(child instanceof GrammarAST)) {
532				continue;
533			}
534			GrammarAST grammarAST = (GrammarAST)child;
535			grammarAST.setTreeEnclosingRuleNameDeeply(rname);
536		}
537	}
538
539	String toStringList() {
540		return "";
541	}
542
543	/** Track start/stop token for subtree root created for a rule.
544	 *  Only works with Tree nodes.  For rules that match nothing,
545	 *  seems like this will yield start=i and stop=i-1 in a nil node.
546	 *  Might be useful info so I'll not force to be i..i.
547	 */
548	public void setTokenBoundaries(Token startToken, Token stopToken) {
549		if ( startToken!=null ) startIndex = startToken.getTokenIndex();
550		if ( stopToken!=null ) stopIndex = stopToken.getTokenIndex();
551	}
552
553	public GrammarAST getBlockALT(int i) {
554		if ( this.getType()!=ANTLRParser.BLOCK ) return null;
555		int alts = 0;
556		for (int j =0 ; j < getChildCount(); j++) {
557			if (getChild(j).getType() == ANTLRParser.ALT) {
558				alts++;
559			}
560			if (alts == i) {
561				return (GrammarAST)getChild(j);
562			}
563		}
564		return null;
565	}
566}
567