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().__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 77class 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 786if __name__ == '__main__': 787 unittest.main() 788