1/*
2 [The "BSD license"]
3 Copyright (c) 2005-2009 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.runtime.debug;
29
30import org.antlr.runtime.Token;
31import org.antlr.runtime.TokenStream;
32import org.antlr.runtime.RecognitionException;
33import org.antlr.runtime.tree.TreeAdaptor;
34
35/** A TreeAdaptor proxy that fires debugging events to a DebugEventListener
36 *  delegate and uses the TreeAdaptor delegate to do the actual work.  All
37 *  AST events are triggered by this adaptor; no code gen changes are needed
38 *  in generated rules.  Debugging events are triggered *after* invoking
39 *  tree adaptor routines.
40 *
41 *  Trees created with actions in rewrite actions like "-> ^(ADD {foo} {bar})"
42 *  cannot be tracked as they might not use the adaptor to create foo, bar.
43 *  The debug listener has to deal with tree node IDs for which it did
44 *  not see a createNode event.  A single <unknown> node is sufficient even
45 *  if it represents a whole tree.
46 */
47public class DebugTreeAdaptor implements TreeAdaptor {
48	protected DebugEventListener dbg;
49	protected TreeAdaptor adaptor;
50
51	public DebugTreeAdaptor(DebugEventListener dbg, TreeAdaptor adaptor) {
52		this.dbg = dbg;
53		this.adaptor = adaptor;
54	}
55
56	public Object create(Token payload) {
57		if ( payload.getTokenIndex() < 0 ) {
58			// could be token conjured up during error recovery
59			return create(payload.getType(), payload.getText());
60		}
61		Object node = adaptor.create(payload);
62		dbg.createNode(node, payload);
63		return node;
64	}
65
66	public Object errorNode(TokenStream input, Token start, Token stop,
67							RecognitionException e)
68	{
69		Object node = adaptor.errorNode(input, start, stop, e);
70		if ( node!=null ) {
71			dbg.errorNode(node);
72		}
73		return node;
74	}
75
76	public Object dupTree(Object tree) {
77		Object t = adaptor.dupTree(tree);
78		// walk the tree and emit create and add child events
79		// to simulate what dupTree has done. dupTree does not call this debug
80		// adapter so I must simulate.
81		simulateTreeConstruction(t);
82		return t;
83	}
84
85	/** ^(A B C): emit create A, create B, add child, ...*/
86	protected void simulateTreeConstruction(Object t) {
87		dbg.createNode(t);
88		int n = adaptor.getChildCount(t);
89		for (int i=0; i<n; i++) {
90			Object child = adaptor.getChild(t, i);
91			simulateTreeConstruction(child);
92			dbg.addChild(t, child);
93		}
94	}
95
96	public Object dupNode(Object treeNode) {
97		Object d = adaptor.dupNode(treeNode);
98		dbg.createNode(d);
99		return d;
100	}
101
102	public Object nil() {
103		Object node = adaptor.nil();
104		dbg.nilNode(node);
105		return node;
106	}
107
108	public boolean isNil(Object tree) {
109		return adaptor.isNil(tree);
110	}
111
112	public void addChild(Object t, Object child) {
113		if ( t==null || child==null ) {
114			return;
115		}
116		adaptor.addChild(t,child);
117		dbg.addChild(t, child);
118	}
119
120	public Object becomeRoot(Object newRoot, Object oldRoot) {
121		Object n = adaptor.becomeRoot(newRoot, oldRoot);
122		dbg.becomeRoot(newRoot, oldRoot);
123		return n;
124	}
125
126	public Object rulePostProcessing(Object root) {
127		return adaptor.rulePostProcessing(root);
128	}
129
130	public void addChild(Object t, Token child) {
131		Object n = this.create(child);
132		this.addChild(t, n);
133	}
134
135	public Object becomeRoot(Token newRoot, Object oldRoot) {
136		Object n = this.create(newRoot);
137		adaptor.becomeRoot(n, oldRoot);
138		dbg.becomeRoot(newRoot, oldRoot);
139		return n;
140	}
141
142	public Object create(int tokenType, Token fromToken) {
143		Object node = adaptor.create(tokenType, fromToken);
144		dbg.createNode(node);
145		return node;
146	}
147
148	public Object create(int tokenType, Token fromToken, String text) {
149		Object node = adaptor.create(tokenType, fromToken, text);
150		dbg.createNode(node);
151		return node;
152	}
153
154	public Object create(int tokenType, String text) {
155		Object node = adaptor.create(tokenType, text);
156		dbg.createNode(node);
157		return node;
158	}
159
160	public int getType(Object t) {
161		return adaptor.getType(t);
162	}
163
164	public void setType(Object t, int type) {
165		adaptor.setType(t, type);
166	}
167
168	public String getText(Object t) {
169		return adaptor.getText(t);
170	}
171
172	public void setText(Object t, String text) {
173		adaptor.setText(t, text);
174	}
175
176	public Token getToken(Object t) {
177		return adaptor.getToken(t);
178	}
179
180	public void setTokenBoundaries(Object t, Token startToken, Token stopToken) {
181		adaptor.setTokenBoundaries(t, startToken, stopToken);
182		if ( t!=null && startToken!=null && stopToken!=null ) {
183			dbg.setTokenBoundaries(
184				t, startToken.getTokenIndex(),
185				stopToken.getTokenIndex());
186		}
187	}
188
189	public int getTokenStartIndex(Object t) {
190		return adaptor.getTokenStartIndex(t);
191	}
192
193	public int getTokenStopIndex(Object t) {
194		return adaptor.getTokenStopIndex(t);
195	}
196
197	public Object getChild(Object t, int i) {
198		return adaptor.getChild(t, i);
199	}
200
201	public void setChild(Object t, int i, Object child) {
202		adaptor.setChild(t, i, child);
203	}
204
205	public Object deleteChild(Object t, int i) {
206		return deleteChild(t, i);
207	}
208
209	public int getChildCount(Object t) {
210		return adaptor.getChildCount(t);
211	}
212
213	public int getUniqueID(Object node) {
214		return adaptor.getUniqueID(node);
215	}
216
217	public Object getParent(Object t) {
218		return adaptor.getParent(t);
219	}
220
221	public int getChildIndex(Object t) {
222		return adaptor.getChildIndex(t);
223	}
224
225	public void setParent(Object t, Object parent) {
226		adaptor.setParent(t, parent);
227	}
228
229	public void setChildIndex(Object t, int index) {
230		adaptor.setChildIndex(t, index);
231	}
232
233	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
234		adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
235	}
236
237	// support
238
239	public DebugEventListener getDebugListener() {
240		return dbg;
241	}
242
243	public void setDebugListener(DebugEventListener dbg) {
244		this.dbg = dbg;
245	}
246
247	public TreeAdaptor getTreeAdaptor() {
248		return adaptor;
249	}
250}
251