1import unittest
2import textwrap
3import antlr3
4import antlr3.tree
5import antlr3.debug
6import testbase
7import sys
8import threading
9import socket
10import errno
11import time
12
13class Debugger(threading.Thread):
14    def __init__(self, port):
15        super(Debugger, self).__init__()
16        self.events = []
17        self.success = False
18        self.port = port
19
20    def run(self):
21        # create listening socket
22        s = None
23        tstart = time.time()
24        while time.time() - tstart < 10:
25            try:
26                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
27                s.connect(('127.0.0.1', self.port))
28                break
29            except socket.error, exc:
30                if exc.args[0] != errno.ECONNREFUSED:
31                    raise
32                time.sleep(0.1)
33
34        if s is None:
35            self.events.append(['nosocket'])
36            return
37
38        s.setblocking(1)
39        s.settimeout(10.0)
40
41        output = s.makefile('w', 0)
42        input = s.makefile('r', 0)
43
44        try:
45            # handshake
46            l = input.readline().strip()
47            assert l == 'ANTLR 2'
48            l = input.readline().strip()
49            assert l.startswith('grammar "')
50
51            output.write('ACK\n')
52            output.flush()
53
54            while True:
55                event = input.readline().strip()
56                self.events.append(event.split('\t'))
57
58                output.write('ACK\n')
59                output.flush()
60
61                if event == 'terminate':
62                    self.success = True
63                    break
64
65        except socket.timeout:
66            self.events.append(['timeout'])
67        except socket.error, exc:
68            self.events.append(['socketerror', exc.args])
69
70        s.close()
71
72
73class T(testbase.ANTLRTest):
74    def execParser(self, grammar, grammarEntry, input, listener,
75                   parser_args={}):
76        if listener is None:
77            port = 49100
78            debugger = Debugger(port)
79            debugger.start()
80            # TODO(pink): install alarm, so it doesn't hang forever in case of a bug
81
82        else:
83            port = None
84
85        try:
86            lexerCls, parserCls = self.compileInlineGrammar(
87                grammar, options='-debug')
88
89            cStream = antlr3.StringStream(input)
90            lexer = lexerCls(cStream)
91            tStream = antlr3.CommonTokenStream(lexer)
92            parser = parserCls(tStream, dbg=listener, port=port, **parser_args)
93            getattr(parser, grammarEntry)()
94
95        finally:
96            if listener is None:
97                debugger.join()
98                return debugger
99
100    def testBasicParser(self):
101        grammar = textwrap.dedent(
102        r'''
103        grammar T;
104        options {
105            language=Python;
106        }
107        a : ID EOF;
108        ID : 'a'..'z'+ ;
109        WS : (' '|'\n') {$channel=HIDDEN;} ;
110        ''')
111
112        listener = antlr3.debug.RecordDebugEventListener()
113
114        self.execParser(
115            grammar, 'a',
116            input="a",
117            listener=listener)
118
119        # We only check that some LT events are present. How many is subject
120        # to change (at the time of writing there are two, which is one too
121        # many).
122        lt_events = [event for event in listener.events
123                     if event.startswith("LT ")]
124        self.assertNotEqual(lt_events, [])
125
126        # For the rest, filter out LT events to get a reliable test.
127        expected = ["enterRule a",
128                    "location 6:1",
129                    "location 6:5",
130                    "location 6:8",
131                    "location 6:11",
132                    "exitRule a"]
133        found = [event for event in listener.events
134                 if not event.startswith("LT ")]
135        self.assertListEqual(found, expected)
136
137    def testSocketProxy(self):
138        grammar = textwrap.dedent(
139        r'''
140        grammar T;
141        options {
142            language=Python;
143        }
144        a : ID EOF;
145        ID : 'a'..'z'+ ;
146        WS : (' '|'\n') {$channel=HIDDEN;} ;
147        ''')
148
149        debugger = self.execParser(
150            grammar, 'a',
151            input="a",
152            listener=None)
153
154        self.assertTrue(debugger.success)
155        expected = [['enterRule', 'T.g', 'a'],
156                    ['location', '6', '1'],
157                    ['enterAlt', '1'],
158                    ['location', '6', '5'],
159                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
160                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
161                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
162                    ['location', '6', '8'],
163                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
164                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
165                    ['consumeToken', '-1', '-1', '0', '1', '1', '"<EOF>'],
166                    ['location', '6', '11'],
167                    ['exitRule', 'T.g', 'a'],
168                    ['terminate']]
169
170        self.assertListEqual(debugger.events, expected)
171
172    def testRecognitionException(self):
173        grammar = textwrap.dedent(
174        r'''
175        grammar T;
176        options {
177            language=Python;
178        }
179        a : ID EOF;
180        ID : 'a'..'z'+ ;
181        WS : (' '|'\n') {$channel=HIDDEN;} ;
182        ''')
183
184        debugger = self.execParser(
185            grammar, 'a',
186            input="a b",
187            listener=None)
188
189        self.assertTrue(debugger.success)
190        expected = [['enterRule', 'T.g', 'a'],
191                    ['location', '6', '1'],
192                    ['enterAlt', '1'],
193                    ['location', '6', '5'],
194                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
195                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
196                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
197                    ['consumeHiddenToken', '1', '5', '99', '1', '1', '"'],
198                    ['location', '6', '8'],
199                    ['LT', '1', '2', '4', '0', '1', '2', '"b'],
200                    ['LT', '1', '2', '4', '0', '1', '2', '"b'],
201                    ['LT', '2', '-1', '-1', '0', '1', '3', '"<EOF>'],
202                    ['LT', '1', '2', '4', '0', '1', '2', '"b'],
203                    ['LT', '1', '2', '4', '0', '1', '2', '"b'],
204                    ['beginResync'],
205                    ['consumeToken', '2', '4', '0', '1', '2', '"b'],
206                    ['endResync'],
207                    ['exception', 'UnwantedTokenException', '2', '1', '2'],
208                    ['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
209                    ['consumeToken', '-1', '-1', '0', '1', '3', '"<EOF>'],
210                    ['location', '6', '11'],
211                    ['exitRule', 'T.g', 'a'],
212                    ['terminate']]
213
214        self.assertListEqual(debugger.events, expected)
215
216
217    def testSemPred(self):
218        grammar = textwrap.dedent(
219        r'''
220        grammar T;
221        options {
222            language=Python;
223        }
224        a : {True}? ID EOF;
225        ID : 'a'..'z'+ ;
226        WS : (' '|'\n') {$channel=HIDDEN;} ;
227        ''')
228
229        debugger = self.execParser(
230            grammar, 'a',
231            input="a",
232            listener=None)
233
234        self.assertTrue(debugger.success)
235        expected = [['enterRule', 'T.g', 'a'],
236                    ['location', '6', '1'],
237                    ['enterAlt', '1'],
238                    ['location', '6', '5'],
239                    ['semanticPredicate', '1', 'True'],
240                    ['location', '6', '13'],
241                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
242                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
243                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
244                    ['location', '6', '16'],
245                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
246                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
247                    ['consumeToken', '-1', '-1', '0', '1', '1', '"<EOF>'],
248                    ['location', '6', '19'],
249                    ['exitRule', 'T.g', 'a'],
250                    ['terminate']]
251
252        self.assertListEqual(debugger.events, expected)
253
254
255    def testPositiveClosureBlock(self):
256        grammar = textwrap.dedent(
257        r'''
258        grammar T;
259        options {
260            language=Python;
261        }
262        a : ID ( ID | INT )+ EOF;
263        ID : 'a'..'z'+ ;
264        INT : '0'..'9'+ ;
265        WS : (' '|'\n') {$channel=HIDDEN;} ;
266        ''')
267
268        debugger = self.execParser(
269            grammar, 'a',
270            input="a 1 b c 3",
271            listener=None)
272
273        self.assertTrue(debugger.success)
274        expected = [['enterRule', 'T.g', 'a'],
275                    ['location', '6', '1'],
276                    ['enterAlt', '1'],
277                    ['location', '6', '5'],
278                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
279                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
280                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
281                    ['consumeHiddenToken', '1', '6', '99', '1', '1', '"'],
282                    ['location', '6', '8'],
283                    ['enterSubRule', '1'],
284                    ['enterDecision', '1', '0'],
285                    ['LT', '1', '2', '5', '0', '1', '2', '"1'],
286                    ['exitDecision', '1'],
287                    ['enterAlt', '1'],
288                    ['location', '6', '8'],
289                    ['LT', '1', '2', '5', '0', '1', '2', '"1'],
290                    ['consumeToken', '2', '5', '0', '1', '2', '"1'],
291                    ['consumeHiddenToken', '3', '6', '99', '1', '3', '"'],
292                    ['enterDecision', '1', '0'],
293                    ['LT', '1', '4', '4', '0', '1', '4', '"b'],
294                    ['exitDecision', '1'],
295                    ['enterAlt', '1'],
296                    ['location', '6', '8'],
297                    ['LT', '1', '4', '4', '0', '1', '4', '"b'],
298                    ['consumeToken', '4', '4', '0', '1', '4', '"b'],
299                    ['consumeHiddenToken', '5', '6', '99', '1', '5', '"'],
300                    ['enterDecision', '1', '0'],
301                    ['LT', '1', '6', '4', '0', '1', '6', '"c'],
302                    ['exitDecision', '1'],
303                    ['enterAlt', '1'],
304                    ['location', '6', '8'],
305                    ['LT', '1', '6', '4', '0', '1', '6', '"c'],
306                    ['consumeToken', '6', '4', '0', '1', '6', '"c'],
307                    ['consumeHiddenToken', '7', '6', '99', '1', '7', '"'],
308                    ['enterDecision', '1', '0'],
309                    ['LT', '1', '8', '5', '0', '1', '8', '"3'],
310                    ['exitDecision', '1'],
311                    ['enterAlt', '1'],
312                    ['location', '6', '8'],
313                    ['LT', '1', '8', '5', '0', '1', '8', '"3'],
314                    ['consumeToken', '8', '5', '0', '1', '8', '"3'],
315                    ['enterDecision', '1', '0'],
316                    ['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
317                    ['exitDecision', '1'],
318                    ['exitSubRule', '1'],
319                    ['location', '6', '22'],
320                    ['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
321                    ['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
322                    ['consumeToken', '-1', '-1', '0', '1', '9', '"<EOF>'],
323                    ['location', '6', '25'],
324                    ['exitRule', 'T.g', 'a'],
325                    ['terminate']]
326
327        self.assertListEqual(debugger.events, expected)
328
329
330    def testClosureBlock(self):
331        grammar = textwrap.dedent(
332        r'''
333        grammar T;
334        options {
335            language=Python;
336        }
337        a : ID ( ID | INT )* EOF;
338        ID : 'a'..'z'+ ;
339        INT : '0'..'9'+ ;
340        WS : (' '|'\n') {$channel=HIDDEN;} ;
341        ''')
342
343        debugger = self.execParser(
344            grammar, 'a',
345            input="a 1 b c 3",
346            listener=None)
347
348        self.assertTrue(debugger.success)
349        expected = [['enterRule', 'T.g', 'a'],
350                    ['location', '6', '1'],
351                    ['enterAlt', '1'],
352                    ['location', '6', '5'],
353                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
354                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
355                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
356                    ['consumeHiddenToken', '1', '6', '99', '1', '1', '"'],
357                    ['location', '6', '8'],
358                    ['enterSubRule', '1'],
359                    ['enterDecision', '1', '0'],
360                    ['LT', '1', '2', '5', '0', '1', '2', '"1'],
361                    ['exitDecision', '1'],
362                    ['enterAlt', '1'],
363                    ['location', '6', '8'],
364                    ['LT', '1', '2', '5', '0', '1', '2', '"1'],
365                    ['consumeToken', '2', '5', '0', '1', '2', '"1'],
366                    ['consumeHiddenToken', '3', '6', '99', '1', '3', '"'],
367                    ['enterDecision', '1', '0'],
368                    ['LT', '1', '4', '4', '0', '1', '4', '"b'],
369                    ['exitDecision', '1'],
370                    ['enterAlt', '1'],
371                    ['location', '6', '8'],
372                    ['LT', '1', '4', '4', '0', '1', '4', '"b'],
373                    ['consumeToken', '4', '4', '0', '1', '4', '"b'],
374                    ['consumeHiddenToken', '5', '6', '99', '1', '5', '"'],
375                    ['enterDecision', '1', '0'],
376                    ['LT', '1', '6', '4', '0', '1', '6', '"c'],
377                    ['exitDecision', '1'],
378                    ['enterAlt', '1'],
379                    ['location', '6', '8'],
380                    ['LT', '1', '6', '4', '0', '1', '6', '"c'],
381                    ['consumeToken', '6', '4', '0', '1', '6', '"c'],
382                    ['consumeHiddenToken', '7', '6', '99', '1', '7', '"'],
383                    ['enterDecision', '1', '0'],
384                    ['LT', '1', '8', '5', '0', '1', '8', '"3'],
385                    ['exitDecision', '1'],
386                    ['enterAlt', '1'],
387                    ['location', '6', '8'],
388                    ['LT', '1', '8', '5', '0', '1', '8', '"3'],
389                    ['consumeToken', '8', '5', '0', '1', '8', '"3'],
390                    ['enterDecision', '1', '0'],
391                    ['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
392                    ['exitDecision', '1'],
393                    ['exitSubRule', '1'],
394                    ['location', '6', '22'],
395                    ['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
396                    ['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
397                    ['consumeToken', '-1', '-1', '0', '1', '9', '"<EOF>'],
398                    ['location', '6', '25'],
399                    ['exitRule', 'T.g', 'a'],
400                    ['terminate']]
401
402        self.assertListEqual(debugger.events, expected)
403
404
405    def testMismatchedSetException(self):
406        grammar = textwrap.dedent(
407        r'''
408        grammar T;
409        options {
410            language=Python;
411        }
412        a : ID ( ID | INT ) EOF;
413        ID : 'a'..'z'+ ;
414        INT : '0'..'9'+ ;
415        WS : (' '|'\n') {$channel=HIDDEN;} ;
416        ''')
417
418        debugger = self.execParser(
419            grammar, 'a',
420            input="a",
421            listener=None)
422
423        self.assertTrue(debugger.success)
424        expected = [['enterRule', 'T.g', 'a'],
425                    ['location', '6', '1'],
426                    ['enterAlt', '1'],
427                    ['location', '6', '5'],
428                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
429                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
430                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
431                    ['location', '6', '8'],
432                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
433                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
434                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
435                    ['exception', 'MismatchedSetException', '1', '1', '1'],
436                    ['exception', 'MismatchedSetException', '1', '1', '1'],
437                    ['beginResync'],
438                    ['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
439                    ['endResync'],
440                    ['location', '6', '24'],
441                    ['exitRule', 'T.g', 'a'],
442                    ['terminate']]
443
444        self.assertListEqual(debugger.events, expected)
445
446
447    def testBlock(self):
448        grammar = textwrap.dedent(
449        r'''
450        grammar T;
451        options {
452            language=Python;
453        }
454        a : ID ( b | c ) EOF;
455        b : ID;
456        c : INT;
457        ID : 'a'..'z'+ ;
458        INT : '0'..'9'+ ;
459        WS : (' '|'\n') {$channel=HIDDEN;} ;
460        ''')
461
462        debugger = self.execParser(
463            grammar, 'a',
464            input="a 1",
465            listener=None)
466
467        self.assertTrue(debugger.success)
468        expected =  [['enterRule', 'T.g', 'a'],
469                     ['location', '6', '1'],
470                     ['enterAlt', '1'],
471                     ['location', '6', '5'],
472                     ['LT', '1', '0', '4', '0', '1', '0', '"a'],
473                     ['LT', '1', '0', '4', '0', '1', '0', '"a'],
474                     ['consumeToken', '0', '4', '0', '1', '0', '"a'],
475                     ['consumeHiddenToken', '1', '6', '99', '1', '1', '"'],
476                     ['location', '6', '8'],
477                     ['enterSubRule', '1'],
478                     ['enterDecision', '1', '0'],
479                     ['LT', '1', '2', '5', '0', '1', '2', '"1'],
480                     ['exitDecision', '1'],
481                     ['enterAlt', '2'],
482                     ['location', '6', '14'],
483                     ['enterRule', 'T.g', 'c'],
484                     ['location', '8', '1'],
485                     ['enterAlt', '1'],
486                     ['location', '8', '5'],
487                     ['LT', '1', '2', '5', '0', '1', '2', '"1'],
488                     ['LT', '1', '2', '5', '0', '1', '2', '"1'],
489                     ['consumeToken', '2', '5', '0', '1', '2', '"1'],
490                     ['location', '8', '8'],
491                     ['exitRule', 'T.g', 'c'],
492                     ['exitSubRule', '1'],
493                     ['location', '6', '18'],
494                     ['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
495                     ['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
496                     ['consumeToken', '-1', '-1', '0', '1', '3', '"<EOF>'],
497                     ['location', '6', '21'],
498                     ['exitRule', 'T.g', 'a'],
499                     ['terminate']]
500
501        self.assertListEqual(debugger.events, expected)
502
503
504    def testNoViableAlt(self):
505        grammar = textwrap.dedent(
506        r'''
507        grammar T;
508        options {
509            language=Python;
510        }
511        a : ID ( b | c ) EOF;
512        b : ID;
513        c : INT;
514        ID : 'a'..'z'+ ;
515        INT : '0'..'9'+ ;
516        BANG : '!' ;
517        WS : (' '|'\n') {$channel=HIDDEN;} ;
518        ''')
519
520        debugger = self.execParser(
521            grammar, 'a',
522            input="a !",
523            listener=None)
524
525        self.assertTrue(debugger.success)
526        expected =  [['enterRule', 'T.g', 'a'],
527                     ['location', '6', '1'],
528                     ['enterAlt', '1'],
529                     ['location', '6', '5'],
530                     ['LT', '1', '0', '5', '0', '1', '0', '"a'],
531                     ['LT', '1', '0', '5', '0', '1', '0', '"a'],
532                     ['consumeToken', '0', '5', '0', '1', '0', '"a'],
533                     ['consumeHiddenToken', '1', '7', '99', '1', '1', '"'],
534                     ['location', '6', '8'],
535                     ['enterSubRule', '1'],
536                     ['enterDecision', '1', '0'],
537                     ['LT', '1', '2', '4', '0', '1', '2', '"!'],
538                     ['LT', '1', '2', '4', '0', '1', '2', '"!'],
539                     ['LT', '1', '2', '4', '0', '1', '2', '"!'],
540                     ['exception', 'NoViableAltException', '2', '1', '2'],
541                     ['exitDecision', '1'],
542                     ['exitSubRule', '1'],
543                     ['exception', 'NoViableAltException', '2', '1', '2'],
544                     ['beginResync'],
545                     ['LT', '1', '2', '4', '0', '1', '2', '"!'],
546                     ['consumeToken', '2', '4', '0', '1', '2', '"!'],
547                     ['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
548                     ['endResync'],
549                     ['location', '6', '21'],
550                     ['exitRule', 'T.g', 'a'],
551                     ['terminate']]
552
553        self.assertListEqual(debugger.events, expected)
554
555
556    def testRuleBlock(self):
557        grammar = textwrap.dedent(
558        r'''
559        grammar T;
560        options {
561            language=Python;
562        }
563        a : b | c;
564        b : ID;
565        c : INT;
566        ID : 'a'..'z'+ ;
567        INT : '0'..'9'+ ;
568        WS : (' '|'\n') {$channel=HIDDEN;} ;
569        ''')
570
571        debugger = self.execParser(
572            grammar, 'a',
573            input="1",
574            listener=None)
575
576        self.assertTrue(debugger.success)
577        expected = [['enterRule', 'T.g', 'a'],
578                    ['location', '6', '1'],
579                    ['enterDecision', '1', '0'],
580                    ['LT', '1', '0', '5', '0', '1', '0', '"1'],
581                    ['exitDecision', '1'],
582                    ['enterAlt', '2'],
583                    ['location', '6', '9'],
584                    ['enterRule', 'T.g', 'c'],
585                    ['location', '8', '1'],
586                    ['enterAlt', '1'],
587                    ['location', '8', '5'],
588                    ['LT', '1', '0', '5', '0', '1', '0', '"1'],
589                    ['LT', '1', '0', '5', '0', '1', '0', '"1'],
590                    ['consumeToken', '0', '5', '0', '1', '0', '"1'],
591                    ['location', '8', '8'],
592                    ['exitRule', 'T.g', 'c'],
593                    ['location', '6', '10'],
594                    ['exitRule', 'T.g', 'a'],
595                    ['terminate']]
596
597        self.assertListEqual(debugger.events, expected)
598
599
600    def testRuleBlockSingleAlt(self):
601        grammar = textwrap.dedent(
602        r'''
603        grammar T;
604        options {
605            language=Python;
606        }
607        a : b;
608        b : ID;
609        ID : 'a'..'z'+ ;
610        INT : '0'..'9'+ ;
611        WS : (' '|'\n') {$channel=HIDDEN;} ;
612        ''')
613
614        debugger = self.execParser(
615            grammar, 'a',
616            input="a",
617            listener=None)
618
619        self.assertTrue(debugger.success)
620        expected = [['enterRule', 'T.g', 'a'],
621                    ['location', '6', '1'],
622                    ['enterAlt', '1'],
623                    ['location', '6', '5'],
624                    ['enterRule', 'T.g', 'b'],
625                    ['location', '7', '1'],
626                    ['enterAlt', '1'],
627                    ['location', '7', '5'],
628                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
629                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
630                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
631                    ['location', '7', '7'],
632                    ['exitRule', 'T.g', 'b'],
633                    ['location', '6', '6'],
634                    ['exitRule', 'T.g', 'a'],
635                    ['terminate']]
636
637        self.assertListEqual(debugger.events, expected)
638
639
640    def testBlockSingleAlt(self):
641        grammar = textwrap.dedent(
642        r'''
643        grammar T;
644        options {
645            language=Python;
646        }
647        a : ( b );
648        b : ID;
649        ID : 'a'..'z'+ ;
650        INT : '0'..'9'+ ;
651        WS : (' '|'\n') {$channel=HIDDEN;} ;
652        ''')
653
654        debugger = self.execParser(
655            grammar, 'a',
656            input="a",
657            listener=None)
658
659        self.assertTrue(debugger.success)
660        expected = [['enterRule', 'T.g', 'a'],
661                    ['location', '6', '1'],
662                    ['enterAlt', '1'],
663                    ['location', '6', '5'],
664                    ['enterAlt', '1'],
665                    ['location', '6', '7'],
666                    ['enterRule', 'T.g', 'b'],
667                    ['location', '7', '1'],
668                    ['enterAlt', '1'],
669                    ['location', '7', '5'],
670                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
671                    ['LT', '1', '0', '4', '0', '1', '0', '"a'],
672                    ['consumeToken', '0', '4', '0', '1', '0', '"a'],
673                    ['location', '7', '7'],
674                    ['exitRule', 'T.g', 'b'],
675                    ['location', '6', '10'],
676                    ['exitRule', 'T.g', 'a'],
677                    ['terminate']]
678
679        self.assertListEqual(debugger.events, expected)
680
681
682    def testDFA(self):
683        grammar = textwrap.dedent(
684        r'''
685        grammar T;
686        options {
687            language=Python;
688        }
689        a : ( b | c ) EOF;
690        b : ID* INT;
691        c : ID+ BANG;
692        ID : 'a'..'z'+ ;
693        INT : '0'..'9'+ ;
694        BANG : '!';
695        WS : (' '|'\n') {$channel=HIDDEN;} ;
696        ''')
697
698        debugger = self.execParser(
699            grammar, 'a',
700            input="a!",
701            listener=None)
702
703        self.assertTrue(debugger.success)
704        expected = [['enterRule', 'T.g', 'a'],
705                    ['location', '6', '1'],
706                    ['enterAlt', '1'],
707                    ['location', '6', '5'],
708                    ['enterSubRule', '1'],
709                    ['enterDecision', '1', '0'],
710                    ['mark', '0'],
711                    ['LT', '1', '0', '5', '0', '1', '0', '"a'],
712                    ['consumeToken', '0', '5', '0', '1', '0', '"a'],
713                    ['LT', '1', '1', '4', '0', '1', '1', '"!'],
714                    ['consumeToken', '1', '4', '0', '1', '1', '"!'],
715                    ['rewind', '0'],
716                    ['exitDecision', '1'],
717                    ['enterAlt', '2'],
718                    ['location', '6', '11'],
719                    ['enterRule', 'T.g', 'c'],
720                    ['location', '8', '1'],
721                    ['enterAlt', '1'],
722                    ['location', '8', '5'],
723                    ['enterSubRule', '3'],
724                    ['enterDecision', '3', '0'],
725                    ['LT', '1', '0', '5', '0', '1', '0', '"a'],
726                    ['exitDecision', '3'],
727                    ['enterAlt', '1'],
728                    ['location', '8', '5'],
729                    ['LT', '1', '0', '5', '0', '1', '0', '"a'],
730                    ['LT', '1', '0', '5', '0', '1', '0', '"a'],
731                    ['consumeToken', '0', '5', '0', '1', '0', '"a'],
732                    ['enterDecision', '3', '0'],
733                    ['LT', '1', '1', '4', '0', '1', '1', '"!'],
734                    ['exitDecision', '3'],
735                    ['exitSubRule', '3'],
736                    ['location', '8', '9'],
737                    ['LT', '1', '1', '4', '0', '1', '1', '"!'],
738                    ['LT', '1', '1', '4', '0', '1', '1', '"!'],
739                    ['consumeToken', '1', '4', '0', '1', '1', '"!'],
740                    ['location', '8', '13'],
741                    ['exitRule', 'T.g', 'c'],
742                    ['exitSubRule', '1'],
743                    ['location', '6', '15'],
744                    ['LT', '1', '-1', '-1', '0', '1', '2', '"<EOF>'],
745                    ['LT', '1', '-1', '-1', '0', '1', '2', '"<EOF>'],
746                    ['consumeToken', '-1', '-1', '0', '1', '2', '"<EOF>'],
747                    ['location', '6', '18'],
748                    ['exitRule', 'T.g', 'a'],
749                    ['terminate']]
750
751        self.assertListEqual(debugger.events, expected)
752
753
754    def testBasicAST(self):
755        grammar = textwrap.dedent(
756        r'''
757        grammar T;
758        options {
759            language=Python;
760            output=AST;
761        }
762        a : ( b | c ) EOF!;
763        b : ID* INT -> ^(INT ID*);
764        c : ID+ BANG -> ^(BANG ID+);
765        ID : 'a'..'z'+ ;
766        INT : '0'..'9'+ ;
767        BANG : '!';
768        WS : (' '|'\n') {$channel=HIDDEN;} ;
769        ''')
770
771        listener = antlr3.debug.RecordDebugEventListener()
772
773        self.execParser(
774            grammar, 'a',
775            input="a!",
776            listener=listener)
777
778        # don't check output for now (too dynamic), I'm satisfied if it
779        # doesn't crash
780
781
782if __name__ == '__main__':
783    unittest.main()
784