1	package antlr.debug;
2	
3	import java.util.Vector;
4	import java.util.Hashtable;
5	import java.util.Enumeration;
6	import antlr.collections.impl.BitSet;
7	import antlr.ParserException;
8	
9	
10	/** A class to assist in firing parser events
11	 *  NOTE: I intentionally _did_not_ synchronize the event firing and
12	 *        add/remove listener methods.  This is because the add/remove should
13	 *        _only_ be called by the parser at its start/end, and the _same_thread_
14	 *        should be performing the parsing.  This should help performance a tad...
15	 */
16	public class ParserEventSupport {
17		private Object source;
18		private Hashtable doneListeners;
19		private Vector matchListeners;
20		private Vector messageListeners;
21		private Vector tokenListeners;
22		private Vector traceListeners;
23		private Vector semPredListeners;
24		private Vector synPredListeners;
25		private Vector newLineListeners;
26		private ParserMatchEvent        matchEvent;
27		private MessageEvent            messageEvent;
28		private ParserTokenEvent        tokenEvent;
29		private SemanticPredicateEvent  semPredEvent;
30		private SyntacticPredicateEvent synPredEvent;
31		private TraceEvent              traceEvent;
32		private NewLineEvent            newLineEvent;
33		private ParserController        controller;
34		protected static final int CONSUME=0;
35		protected static final int ENTER_RULE=1;
36		protected static final int EXIT_RULE=2;
37		protected static final int LA=3;
38		protected static final int MATCH=4;
39		protected static final int MATCH_NOT=5;
40		protected static final int MISMATCH=6;
41		protected static final int MISMATCH_NOT=7;
42		protected static final int REPORT_ERROR=8;
43		protected static final int REPORT_WARNING=9;
44		protected static final int SEMPRED=10;
45		protected static final int SYNPRED_FAILED=11;
46		protected static final int SYNPRED_STARTED=12;
47		protected static final int SYNPRED_SUCCEEDED=13;
48		protected static final int NEW_LINE=14;
49		protected static final int DONE_PARSING=15;
50		private int ruleDepth = 0;
51	
52	
53		public ParserEventSupport(Object source) {
54			matchEvent   = new ParserMatchEvent(source);
55			messageEvent = new MessageEvent(source);
56			tokenEvent   = new ParserTokenEvent(source);
57			traceEvent   = new TraceEvent(source);
58			semPredEvent = new SemanticPredicateEvent(source);
59			synPredEvent = new SyntacticPredicateEvent(source);
60			newLineEvent = new NewLineEvent(source);
61			this.source = source;
62		}
63		public void addDoneListener(ListenerBase l) {
64			if (doneListeners == null) doneListeners = new Hashtable();
65			Integer i = (Integer)doneListeners.get(l);
66			int val;
67			if (i != null)
68				val = i.intValue() + 1;
69			else
70				val = 1;
71			doneListeners.put(l, new Integer(val));
72		}
73		public void addMessageListener(MessageListener l) {
74			if (messageListeners == null) messageListeners = new Vector();
75			messageListeners.addElement(l);
76			addDoneListener(l);
77		}
78		public void addNewLineListener(NewLineListener l) {
79			if (newLineListeners == null) newLineListeners = new Vector();
80			newLineListeners.addElement(l);
81			addDoneListener(l);
82		}
83		public void addParserListener(ParserListener l) {
84			if (l instanceof ParserController) {
85				((ParserController)l).setParserEventSupport(this);
86				controller = (ParserController)l;
87			}	
88			addParserMatchListener(l);
89			addParserTokenListener(l);
90	
91			addMessageListener(l);
92			addTraceListener(l);
93			addSemanticPredicateListener(l);
94			addSyntacticPredicateListener(l);
95		}
96		public void addParserMatchListener(ParserMatchListener l) {
97			if (matchListeners == null) matchListeners = new Vector();
98			matchListeners.addElement(l);
99			addDoneListener(l);
100		}
101		public void addParserTokenListener(ParserTokenListener l) {
102			if (tokenListeners == null) tokenListeners = new Vector();
103			tokenListeners.addElement(l);
104			addDoneListener(l);
105		}
106		public void addSemanticPredicateListener(SemanticPredicateListener l) {
107			if (semPredListeners == null) semPredListeners = new Vector();
108			semPredListeners.addElement(l);
109			addDoneListener(l);
110		}
111		public void addSyntacticPredicateListener(SyntacticPredicateListener l) {
112			if (synPredListeners == null) synPredListeners = new Vector();
113			synPredListeners.addElement(l);
114			addDoneListener(l);
115		}
116		public void addTraceListener(TraceListener l) {
117			if (traceListeners == null) traceListeners = new Vector();
118			traceListeners.addElement(l);
119			addDoneListener(l);
120		}
121		public void fireConsume(int value) {
122			tokenEvent.setValues(ParserTokenEvent.CONSUME, 1, value);
123			fireEvents(CONSUME, tokenListeners);		
124		}
125		public void fireDoneParsing() {
126			traceEvent.setValues(TraceEvent.DONE_PARSING, 0,0,0);
127	
128			Hashtable targets=null;
129	//		Hashtable targets=doneListeners;
130			ListenerBase l=null;
131			
132			synchronized (this) {
133				if (doneListeners == null) return;
134				targets = (Hashtable)doneListeners.clone();
135			}
136			
137			if (targets != null) {
138				Enumeration e = targets.keys();
139				while(e.hasMoreElements()) {
140					l = (ListenerBase)e.nextElement();
141					fireEvent(DONE_PARSING, l);
142				}
143			}	
144			if (controller != null)
145				controller.checkBreak();
146		}
147		public void fireEnterRule(int ruleNum, int guessing, int data) {
148			ruleDepth++;
149			traceEvent.setValues(TraceEvent.ENTER, ruleNum, guessing, data);
150			fireEvents(ENTER_RULE, traceListeners);
151		}
152		public void fireEvent(int type, ListenerBase l) {
153			switch(type) {
154				case CONSUME:    ((ParserTokenListener)l).parserConsume(tokenEvent); break;
155				case LA:         ((ParserTokenListener)l).parserLA(tokenEvent);      break;
156	
157				case ENTER_RULE: ((TraceListener)l).enterRule(traceEvent);           break;
158				case EXIT_RULE:  ((TraceListener)l).exitRule(traceEvent);            break;
159	
160				case MATCH:        ((ParserMatchListener)l).parserMatch(matchEvent);       break;
161				case MATCH_NOT:    ((ParserMatchListener)l).parserMatchNot(matchEvent);    break;
162				case MISMATCH:     ((ParserMatchListener)l).parserMismatch(matchEvent);    break;
163				case MISMATCH_NOT: ((ParserMatchListener)l).parserMismatchNot(matchEvent); break;
164	
165				case SEMPRED:      ((SemanticPredicateListener)l).semanticPredicateEvaluated(semPredEvent); break;
166	
167				case SYNPRED_STARTED:   ((SyntacticPredicateListener)l).syntacticPredicateStarted(synPredEvent);   break;
168				case SYNPRED_FAILED:    ((SyntacticPredicateListener)l).syntacticPredicateFailed(synPredEvent);    break;
169				case SYNPRED_SUCCEEDED: ((SyntacticPredicateListener)l).syntacticPredicateSucceeded(synPredEvent); break;
170	
171				case REPORT_ERROR:   ((MessageListener)l).reportError(messageEvent);   break;
172				case REPORT_WARNING: ((MessageListener)l).reportWarning(messageEvent); break;
173	
174				case DONE_PARSING: l.doneParsing(traceEvent); break;
175				case NEW_LINE:     ((NewLineListener)l).hitNewLine(newLineEvent); break;
176				
177				default:
178					throw new IllegalArgumentException("bad type "+type+" for fireEvent()");
179			}	
180		}
181		public void fireEvents(int type, Vector listeners) {
182			ListenerBase l=null;
183			
184			if (listeners != null)
185				for (int i = 0; i < listeners.size(); i++) {
186					l = (ListenerBase)listeners.elementAt(i);
187					fireEvent(type, l);
188				}
189			if (controller != null)
190				controller.checkBreak();
191		}
192		public void fireExitRule(int ruleNum, int guessing, int data) {
193			traceEvent.setValues(TraceEvent.EXIT, ruleNum, guessing, data);
194			fireEvents(EXIT_RULE, traceListeners);
195			ruleDepth--;
196			if (ruleDepth == 0)
197				fireDoneParsing();
198		}
199		public void fireLA(int k, int la) {
200			tokenEvent.setValues(ParserTokenEvent.LA, k, la);
201			fireEvents(LA, tokenListeners);
202		}
203		public void fireMatch(char c, int guessing) {
204			matchEvent.setValues(ParserMatchEvent.CHAR, c, new Character(c), null, guessing, false, true);
205			fireEvents(MATCH, matchListeners);
206		}
207		public void fireMatch(char value, BitSet b, int guessing) {
208			matchEvent.setValues(ParserMatchEvent.CHAR_BITSET, value, b, null, guessing, false, true);
209			fireEvents(MATCH, matchListeners);
210		}
211		public void fireMatch(char value, String target, int guessing) {
212			matchEvent.setValues(ParserMatchEvent.CHAR_RANGE, value, target, null, guessing, false, true);
213			fireEvents(MATCH, matchListeners);
214		}
215		public void fireMatch(int value, BitSet b, String text, int guessing) {
216			matchEvent.setValues(ParserMatchEvent.BITSET, value, b, text, guessing, false, true);
217			fireEvents(MATCH, matchListeners);
218		}
219		public void fireMatch(int n, String text, int guessing) {
220			matchEvent.setValues(ParserMatchEvent.TOKEN, n, new Integer(n), text, guessing, false, true);
221			fireEvents(MATCH, matchListeners);
222		}
223		public void fireMatch(String s, int guessing) {
224			matchEvent.setValues(ParserMatchEvent.STRING, 0, s, null, guessing, false, true);
225			fireEvents(MATCH, matchListeners);
226		}
227		public void fireMatchNot(char value, char n, int guessing) {
228			matchEvent.setValues(ParserMatchEvent.CHAR, value, new Character(n), null, guessing, true, true);
229			fireEvents(MATCH_NOT, matchListeners);
230		}
231		public void fireMatchNot(int value, int n, String text, int guessing) {
232			matchEvent.setValues(ParserMatchEvent.TOKEN, value, new Integer(n), text, guessing, true, true);
233			fireEvents(MATCH_NOT, matchListeners);
234		}
235		public void fireMismatch(char value, char n, int guessing) {
236			matchEvent.setValues(ParserMatchEvent.CHAR, value, new Character(n), null, guessing, false, false);
237			fireEvents(MISMATCH, matchListeners);
238		}
239		public void fireMismatch(char value, BitSet b, int guessing) {
240			matchEvent.setValues(ParserMatchEvent.CHAR_BITSET, value, b, null, guessing, false, true);
241			fireEvents(MISMATCH, matchListeners);
242		}
243		public void fireMismatch(char value, String target, int guessing) {
244			matchEvent.setValues(ParserMatchEvent.CHAR_RANGE, value, target, null, guessing, false, true);
245			fireEvents(MISMATCH, matchListeners);
246		}
247		public void fireMismatch(int value, int n, String text, int guessing) {
248			matchEvent.setValues(ParserMatchEvent.TOKEN, value, new Integer(n), text, guessing, false, false);
249			fireEvents(MISMATCH, matchListeners);
250		}
251		public void fireMismatch(int value, BitSet b, String text, int guessing) {
252			matchEvent.setValues(ParserMatchEvent.BITSET, value, b, text, guessing, false, true);
253			fireEvents(MISMATCH, matchListeners);
254		}
255		public void fireMismatch(String value, String text, int guessing) {
256			matchEvent.setValues(ParserMatchEvent.STRING, 0, text, value, guessing, false, true);
257			fireEvents(MISMATCH, matchListeners);
258		}
259		public void fireMismatchNot(char value, char c, int guessing) {
260			matchEvent.setValues(ParserMatchEvent.CHAR, value, new Character(c), null, guessing, true, true);
261			fireEvents(MISMATCH_NOT, matchListeners);
262		}
263		public void fireMismatchNot(int value, int n, String text, int guessing) {
264			matchEvent.setValues(ParserMatchEvent.TOKEN, value, new Integer(n), text, guessing, true, true);
265			fireEvents(MISMATCH_NOT, matchListeners);
266		}
267		public void fireNewLine(int line) {
268			newLineEvent.setValues(line);
269			fireEvents(NEW_LINE, newLineListeners);
270		}
271		public void fireReportError(Exception e) {
272			messageEvent.setValues(MessageEvent.ERROR, e.toString());
273			fireEvents(REPORT_ERROR, messageListeners);
274		}
275		public void fireReportError(String s) {
276			messageEvent.setValues(MessageEvent.ERROR, s);
277			fireEvents(REPORT_ERROR, messageListeners);
278		}
279		public void fireReportWarning(String s) {
280			messageEvent.setValues(MessageEvent.WARNING, s);
281			fireEvents(REPORT_WARNING, messageListeners);
282		}
283		public boolean fireSemanticPredicateEvaluated(int type, int condition, boolean result, int guessing) {
284			semPredEvent.setValues(type, condition, result, guessing);
285			fireEvents(SEMPRED, semPredListeners);
286			return result;
287		}
288		public void fireSyntacticPredicateFailed(int guessing) {
289			synPredEvent.setValues(0, guessing);
290			fireEvents(SYNPRED_FAILED, synPredListeners);
291		}
292		public void fireSyntacticPredicateStarted(int guessing) {
293			synPredEvent.setValues(0, guessing);
294			fireEvents(SYNPRED_STARTED, synPredListeners);
295		}
296		public void fireSyntacticPredicateSucceeded(int guessing) {
297			synPredEvent.setValues(0, guessing);
298			fireEvents(SYNPRED_SUCCEEDED, synPredListeners);
299		}
300		protected void refresh(Vector listeners) {
301			Vector v;
302			synchronized (listeners) {
303				v = (Vector)listeners.clone();
304			}
305			if (v != null)
306				for (int i = 0; i < v.size(); i++)
307					((ListenerBase)v.elementAt(i)).refresh();
308		}
309		public void refreshListeners() {
310			refresh(matchListeners);
311			refresh(messageListeners);
312			refresh(tokenListeners);
313			refresh(traceListeners);
314			refresh(semPredListeners);
315			refresh(synPredListeners);
316		}
317		public void removeDoneListener(ListenerBase l) {
318			if (doneListeners == null) return;
319			Integer i = (Integer)doneListeners.get(l);
320			int val=0;
321			if (i != null)
322				val = i.intValue() - 1;
323	
324			if (val == 0) 
325				doneListeners.remove(l);
326			else
327				doneListeners.put(l, new Integer(val));
328		}
329		public void removeMessageListener(MessageListener l) {
330			if (messageListeners != null)
331				messageListeners.removeElement(l);
332			removeDoneListener(l);
333		}
334		public void removeNewLineListener(NewLineListener l) {
335			if (newLineListeners != null)
336				newLineListeners.removeElement(l);
337			removeDoneListener(l);
338		}
339		public void removeParserListener(ParserListener l) {
340			removeParserMatchListener(l);
341			removeMessageListener(l);
342			removeParserTokenListener(l);
343			removeTraceListener(l);
344			removeSemanticPredicateListener(l);
345			removeSyntacticPredicateListener(l);
346		}
347		public void removeParserMatchListener(ParserMatchListener l) {
348			if (matchListeners != null)
349				matchListeners.removeElement(l);
350			removeDoneListener(l);
351		}
352		public void removeParserTokenListener(ParserTokenListener l) {
353			if (tokenListeners != null)
354				tokenListeners.removeElement(l);
355			removeDoneListener(l);
356		}
357		public void removeSemanticPredicateListener(SemanticPredicateListener l) {
358			if (semPredListeners != null)
359				semPredListeners.removeElement(l);
360			removeDoneListener(l);
361		}
362		public void removeSyntacticPredicateListener(SyntacticPredicateListener l) {
363			if (synPredListeners != null)
364				synPredListeners.removeElement(l);
365			removeDoneListener(l);
366		}
367		public void removeTraceListener(TraceListener l) {
368			if (traceListeners != null)
369				traceListeners.removeElement(l);
370			removeDoneListener(l);
371		}
372	}
373