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