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(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 
     73 class 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 
    782 if __name__ == '__main__':
    783     unittest.main()
    784