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