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.RecognitionException;
32
33import java.util.List;
34import java.util.ArrayList;
35
36/** Broadcast debug events to multiple listeners.  Lets you debug and still
37 *  use the event mechanism to build parse trees etc...  Not thread-safe.
38 *  Don't add events in one thread while parser fires events in another.
39 *
40 *  @see also DebugEventRepeater
41 */
42public class DebugEventHub implements DebugEventListener {
43	protected List listeners = new ArrayList();
44
45	public DebugEventHub(DebugEventListener listener) {
46		listeners.add(listener);
47	}
48
49	public DebugEventHub(DebugEventListener a, DebugEventListener b) {
50		listeners.add(a);
51		listeners.add(b);
52	}
53
54	/** Add another listener to broadcast events too.  Not thread-safe.
55	 *  Don't add events in one thread while parser fires events in another.
56	 */
57	public void addListener(DebugEventListener listener) {
58		listeners.add(listener);
59	}
60
61	/* To avoid a mess like this:
62		public void enterRule(final String ruleName) {
63			broadcast(new Code(){
64				public void exec(DebugEventListener listener) {listener.enterRule(ruleName);}}
65				);
66		}
67		I am dup'ing the for-loop in each.  Where are Java closures!? blech!
68	 */
69
70	public void enterRule(String grammarFileName, String ruleName) {
71		for (int i = 0; i < listeners.size(); i++) {
72			DebugEventListener listener = (DebugEventListener)listeners.get(i);
73			listener.enterRule(grammarFileName,ruleName);
74		}
75	}
76
77	public void exitRule(String grammarFileName, String ruleName) {
78		for (int i = 0; i < listeners.size(); i++) {
79			DebugEventListener listener = (DebugEventListener)listeners.get(i);
80			listener.exitRule(grammarFileName, ruleName);
81		}
82	}
83
84	public void enterAlt(int alt) {
85		for (int i = 0; i < listeners.size(); i++) {
86			DebugEventListener listener = (DebugEventListener)listeners.get(i);
87			listener.enterAlt(alt);
88		}
89	}
90
91	public void enterSubRule(int decisionNumber) {
92		for (int i = 0; i < listeners.size(); i++) {
93			DebugEventListener listener = (DebugEventListener)listeners.get(i);
94			listener.enterSubRule(decisionNumber);
95		}
96	}
97
98	public void exitSubRule(int decisionNumber) {
99		for (int i = 0; i < listeners.size(); i++) {
100			DebugEventListener listener = (DebugEventListener)listeners.get(i);
101			listener.exitSubRule(decisionNumber);
102		}
103	}
104
105	public void enterDecision(int decisionNumber, boolean couldBacktrack) {
106		for (int i = 0; i < listeners.size(); i++) {
107			DebugEventListener listener = (DebugEventListener)listeners.get(i);
108			listener.enterDecision(decisionNumber, couldBacktrack);
109		}
110	}
111
112	public void exitDecision(int decisionNumber) {
113		for (int i = 0; i < listeners.size(); i++) {
114			DebugEventListener listener = (DebugEventListener)listeners.get(i);
115			listener.exitDecision(decisionNumber);
116		}
117	}
118
119	public void location(int line, int pos) {
120		for (int i = 0; i < listeners.size(); i++) {
121			DebugEventListener listener = (DebugEventListener)listeners.get(i);
122			listener.location(line, pos);
123		}
124	}
125
126	public void consumeToken(Token token) {
127		for (int i = 0; i < listeners.size(); i++) {
128			DebugEventListener listener = (DebugEventListener)listeners.get(i);
129			listener.consumeToken(token);
130		}
131	}
132
133	public void consumeHiddenToken(Token token) {
134		for (int i = 0; i < listeners.size(); i++) {
135			DebugEventListener listener = (DebugEventListener)listeners.get(i);
136			listener.consumeHiddenToken(token);
137		}
138	}
139
140	public void LT(int index, Token t) {
141		for (int i = 0; i < listeners.size(); i++) {
142			DebugEventListener listener = (DebugEventListener)listeners.get(i);
143			listener.LT(index, t);
144		}
145	}
146
147	public void mark(int index) {
148		for (int i = 0; i < listeners.size(); i++) {
149			DebugEventListener listener = (DebugEventListener)listeners.get(i);
150			listener.mark(index);
151		}
152	}
153
154	public void rewind(int index) {
155		for (int i = 0; i < listeners.size(); i++) {
156			DebugEventListener listener = (DebugEventListener)listeners.get(i);
157			listener.rewind(index);
158		}
159	}
160
161	public void rewind() {
162		for (int i = 0; i < listeners.size(); i++) {
163			DebugEventListener listener = (DebugEventListener)listeners.get(i);
164			listener.rewind();
165		}
166	}
167
168	public void beginBacktrack(int level) {
169		for (int i = 0; i < listeners.size(); i++) {
170			DebugEventListener listener = (DebugEventListener)listeners.get(i);
171			listener.beginBacktrack(level);
172		}
173	}
174
175	public void endBacktrack(int level, boolean successful) {
176		for (int i = 0; i < listeners.size(); i++) {
177			DebugEventListener listener = (DebugEventListener)listeners.get(i);
178			listener.endBacktrack(level, successful);
179		}
180	}
181
182	public void recognitionException(RecognitionException e) {
183		for (int i = 0; i < listeners.size(); i++) {
184			DebugEventListener listener = (DebugEventListener)listeners.get(i);
185			listener.recognitionException(e);
186		}
187	}
188
189	public void beginResync() {
190		for (int i = 0; i < listeners.size(); i++) {
191			DebugEventListener listener = (DebugEventListener)listeners.get(i);
192			listener.beginResync();
193		}
194	}
195
196	public void endResync() {
197		for (int i = 0; i < listeners.size(); i++) {
198			DebugEventListener listener = (DebugEventListener)listeners.get(i);
199			listener.endResync();
200		}
201	}
202
203	public void semanticPredicate(boolean result, String predicate) {
204		for (int i = 0; i < listeners.size(); i++) {
205			DebugEventListener listener = (DebugEventListener)listeners.get(i);
206			listener.semanticPredicate(result, predicate);
207		}
208	}
209
210	public void commence() {
211		for (int i = 0; i < listeners.size(); i++) {
212			DebugEventListener listener = (DebugEventListener)listeners.get(i);
213			listener.commence();
214		}
215	}
216
217	public void terminate() {
218		for (int i = 0; i < listeners.size(); i++) {
219			DebugEventListener listener = (DebugEventListener)listeners.get(i);
220			listener.terminate();
221		}
222	}
223
224
225	// Tree parsing stuff
226
227	public void consumeNode(Object t) {
228		for (int i = 0; i < listeners.size(); i++) {
229			DebugEventListener listener = (DebugEventListener)listeners.get(i);
230			listener.consumeNode(t);
231		}
232	}
233
234	public void LT(int index, Object t) {
235		for (int i = 0; i < listeners.size(); i++) {
236			DebugEventListener listener = (DebugEventListener)listeners.get(i);
237			listener.LT(index, t);
238		}
239	}
240
241
242	// AST Stuff
243
244	public void nilNode(Object t) {
245		for (int i = 0; i < listeners.size(); i++) {
246			DebugEventListener listener = (DebugEventListener)listeners.get(i);
247			listener.nilNode(t);
248		}
249	}
250
251	public void errorNode(Object t) {
252		for (int i = 0; i < listeners.size(); i++) {
253			DebugEventListener listener = (DebugEventListener)listeners.get(i);
254			listener.errorNode(t);
255		}
256	}
257
258	public void createNode(Object t) {
259		for (int i = 0; i < listeners.size(); i++) {
260			DebugEventListener listener = (DebugEventListener)listeners.get(i);
261			listener.createNode(t);
262		}
263	}
264
265	public void createNode(Object node, Token token) {
266		for (int i = 0; i < listeners.size(); i++) {
267			DebugEventListener listener = (DebugEventListener)listeners.get(i);
268			listener.createNode(node, token);
269		}
270	}
271
272	public void becomeRoot(Object newRoot, Object oldRoot) {
273		for (int i = 0; i < listeners.size(); i++) {
274			DebugEventListener listener = (DebugEventListener)listeners.get(i);
275			listener.becomeRoot(newRoot, oldRoot);
276		}
277	}
278
279	public void addChild(Object root, Object child) {
280		for (int i = 0; i < listeners.size(); i++) {
281			DebugEventListener listener = (DebugEventListener)listeners.get(i);
282			listener.addChild(root, child);
283		}
284	}
285
286	public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
287		for (int i = 0; i < listeners.size(); i++) {
288			DebugEventListener listener = (DebugEventListener)listeners.get(i);
289			listener.setTokenBoundaries(t, tokenStartIndex, tokenStopIndex);
290		}
291	}
292}
293