1import unittest 2import textwrap 3import antlr3 4import antlr3.tree 5import testbase 6import sys 7 8class TestRewriteAST(testbase.ANTLRTest): 9 def parserClass(self, base): 10 class TParser(base): 11 def __init__(self, *args, **kwargs): 12 super().__init__(*args, **kwargs) 13 14 self._errors = [] 15 self._output = "" 16 17 18 def capture(self, t): 19 self._output += t 20 21 22 def traceIn(self, ruleName, ruleIndex): 23 self.traces.append('>'+ruleName) 24 25 26 def traceOut(self, ruleName, ruleIndex): 27 self.traces.append('<'+ruleName) 28 29 30 def emitErrorMessage(self, msg): 31 self._errors.append(msg) 32 33 34 return TParser 35 36 37 def lexerClass(self, base): 38 class TLexer(base): 39 def __init__(self, *args, **kwargs): 40 super().__init__(*args, **kwargs) 41 42 self._output = "" 43 44 45 def capture(self, t): 46 self._output += t 47 48 49 def traceIn(self, ruleName, ruleIndex): 50 self.traces.append('>'+ruleName) 51 52 53 def traceOut(self, ruleName, ruleIndex): 54 self.traces.append('<'+ruleName) 55 56 57 def recover(self, input, re): 58 # no error recovery yet, just crash! 59 raise 60 61 return TLexer 62 63 64 def execParser(self, grammar, grammarEntry, input, expectErrors=False): 65 lexerCls, parserCls = self.compileInlineGrammar(grammar) 66 67 cStream = antlr3.StringStream(input) 68 lexer = lexerCls(cStream) 69 tStream = antlr3.CommonTokenStream(lexer) 70 parser = parserCls(tStream) 71 r = getattr(parser, grammarEntry)() 72 73 if not expectErrors: 74 self.assertEqual(len(parser._errors), 0, parser._errors) 75 76 result = "" 77 78 if r: 79 if hasattr(r, 'result'): 80 result += r.result 81 82 if r.tree: 83 result += r.tree.toStringTree() 84 85 if not expectErrors: 86 return result 87 88 else: 89 return result, parser._errors 90 91 92 def execTreeParser(self, grammar, grammarEntry, treeGrammar, treeEntry, input): 93 lexerCls, parserCls = self.compileInlineGrammar(grammar) 94 walkerCls = self.compileInlineGrammar(treeGrammar) 95 96 cStream = antlr3.StringStream(input) 97 lexer = lexerCls(cStream) 98 tStream = antlr3.CommonTokenStream(lexer) 99 parser = parserCls(tStream) 100 r = getattr(parser, grammarEntry)() 101 nodes = antlr3.tree.CommonTreeNodeStream(r.tree) 102 nodes.setTokenStream(tStream) 103 walker = walkerCls(nodes) 104 r = getattr(walker, treeEntry)() 105 106 if r: 107 return r.tree.toStringTree() 108 109 return "" 110 111 112 def testDelete(self): 113 grammar = textwrap.dedent( 114 r''' 115 grammar T; 116 options {language=Python3;output=AST;} 117 a : ID INT -> ; 118 ID : 'a'..'z'+ ; 119 INT : '0'..'9'+; 120 WS : (' '|'\n') {$channel=HIDDEN} ; 121 ''') 122 123 found = self.execParser(grammar, "a", "abc 34") 124 self.assertEqual("", found) 125 126 127 def testSingleToken(self): 128 grammar = textwrap.dedent( 129 r''' 130 grammar T; 131 options {language=Python3;output=AST;} 132 a : ID -> ID; 133 ID : 'a'..'z'+ ; 134 INT : '0'..'9'+; 135 WS : (' '|'\n') {$channel=HIDDEN} ; 136 ''') 137 138 found = self.execParser(grammar, "a", "abc") 139 self.assertEqual("abc", found) 140 141 142 def testSingleTokenToNewNode(self): 143 grammar = textwrap.dedent( 144 r''' 145 grammar T; 146 options {language=Python3;output=AST;} 147 a : ID -> ID["x"]; 148 ID : 'a'..'z'+ ; 149 INT : '0'..'9'+; 150 WS : (' '|'\n') {$channel=HIDDEN} ; 151 ''') 152 153 found = self.execParser(grammar, "a", "abc") 154 self.assertEqual("x", found) 155 156 157 def testSingleTokenToNewNodeRoot(self): 158 grammar = textwrap.dedent( 159 r''' 160 grammar T; 161 options {language=Python3;output=AST;} 162 a : ID -> ^(ID["x"] INT); 163 ID : 'a'..'z'+ ; 164 INT : '0'..'9'+; 165 WS : (' '|'\n') {$channel=HIDDEN} ; 166 ''') 167 168 found = self.execParser(grammar, "a", "abc") 169 self.assertEqual("(x INT)", found) 170 171 172 def testSingleTokenToNewNode2(self): 173 # Allow creation of new nodes w/o args. 174 grammar = textwrap.dedent( 175 r''' 176 grammar TT; 177 options {language=Python3;output=AST;} 178 a : ID -> ID[ ]; 179 ID : 'a'..'z'+ ; 180 INT : '0'..'9'+; 181 WS : (' '|'\n') {$channel=HIDDEN} ; 182 ''') 183 184 found = self.execParser(grammar, "a", "abc") 185 self.assertEqual("ID", found) 186 187 188 def testSingleCharLiteral(self): 189 grammar = textwrap.dedent( 190 r''' 191 grammar T; 192 options {language=Python3;output=AST;} 193 a : 'c' -> 'c'; 194 ID : 'a'..'z'+ ; 195 INT : '0'..'9'+; 196 WS : (' '|'\n') {$channel=HIDDEN} ; 197 ''') 198 199 found = self.execParser(grammar, "a", "c") 200 self.assertEqual("c", found) 201 202 203 def testSingleStringLiteral(self): 204 grammar = textwrap.dedent( 205 r''' 206 grammar T; 207 options {language=Python3;output=AST;} 208 a : 'ick' -> 'ick'; 209 ID : 'a'..'z'+ ; 210 INT : '0'..'9'+; 211 WS : (' '|'\n') {$channel=HIDDEN} ; 212 ''') 213 214 found = self.execParser(grammar, "a", "ick") 215 self.assertEqual("ick", found) 216 217 218 def testSingleRule(self): 219 grammar = textwrap.dedent( 220 r''' 221 grammar T; 222 options {language=Python3;output=AST;} 223 a : b -> b; 224 b : ID ; 225 ID : 'a'..'z'+ ; 226 INT : '0'..'9'+; 227 WS : (' '|'\n') {$channel=HIDDEN} ; 228 ''') 229 230 found = self.execParser(grammar, "a", "abc") 231 self.assertEqual("abc", found) 232 233 234 def testReorderTokens(self): 235 grammar = textwrap.dedent( 236 r''' 237 grammar T; 238 options {language=Python3;output=AST;} 239 a : ID INT -> INT ID; 240 ID : 'a'..'z'+ ; 241 INT : '0'..'9'+; 242 WS : (' '|'\n') {$channel=HIDDEN} ; 243 ''') 244 245 found = self.execParser(grammar, "a", "abc 34") 246 self.assertEqual("34 abc", found) 247 248 249 def testReorderTokenAndRule(self): 250 grammar = textwrap.dedent( 251 r''' 252 grammar T; 253 options {language=Python3;output=AST;} 254 a : b INT -> INT b; 255 b : ID ; 256 ID : 'a'..'z'+ ; 257 INT : '0'..'9'+; 258 WS : (' '|'\n') {$channel=HIDDEN} ; 259 ''') 260 261 found = self.execParser(grammar, "a", "abc 34") 262 self.assertEqual("34 abc", found) 263 264 265 def testTokenTree(self): 266 grammar = textwrap.dedent( 267 r''' 268 grammar T; 269 options {language=Python3;output=AST;} 270 a : ID INT -> ^(INT ID); 271 ID : 'a'..'z'+ ; 272 INT : '0'..'9'+; 273 WS : (' '|'\n') {$channel=HIDDEN} ; 274 ''') 275 276 found = self.execParser(grammar, "a", "abc 34") 277 self.assertEqual("(34 abc)", found) 278 279 280 def testTokenTreeAfterOtherStuff(self): 281 grammar = textwrap.dedent( 282 r''' 283 grammar T; 284 options {language=Python3;output=AST;} 285 a : 'void' ID INT -> 'void' ^(INT ID); 286 ID : 'a'..'z'+ ; 287 INT : '0'..'9'+; 288 WS : (' '|'\n') {$channel=HIDDEN} ; 289 ''') 290 291 found = self.execParser(grammar, "a", "void abc 34") 292 self.assertEqual("void (34 abc)", found) 293 294 295 def testNestedTokenTreeWithOuterLoop(self): 296 # verify that ID and INT both iterate over outer index variable 297 grammar = textwrap.dedent( 298 r''' 299 grammar T; 300 options {language=Python3;output=AST;} 301 tokens {DUH;} 302 a : ID INT ID INT -> ^( DUH ID ^( DUH INT) )+ ; 303 ID : 'a'..'z'+ ; 304 INT : '0'..'9'+; 305 WS : (' '|'\n') {$channel=HIDDEN} ; 306 ''') 307 308 found = self.execParser(grammar, "a", "a 1 b 2") 309 self.assertEqual("(DUH a (DUH 1)) (DUH b (DUH 2))", found) 310 311 312 def testOptionalSingleToken(self): 313 grammar = textwrap.dedent( 314 r''' 315 grammar T; 316 options {language=Python3;output=AST;} 317 a : ID -> ID? ; 318 ID : 'a'..'z'+ ; 319 INT : '0'..'9'+; 320 WS : (' '|'\n') {$channel=HIDDEN} ; 321 ''') 322 323 found = self.execParser(grammar, "a", "abc") 324 self.assertEqual("abc", found) 325 326 327 def testClosureSingleToken(self): 328 grammar = textwrap.dedent( 329 r''' 330 grammar T; 331 options {language=Python3;output=AST;} 332 a : ID ID -> ID* ; 333 ID : 'a'..'z'+ ; 334 INT : '0'..'9'+; 335 WS : (' '|'\n') {$channel=HIDDEN} ; 336 ''') 337 338 found = self.execParser(grammar, "a", "a b") 339 self.assertEqual("a b", found) 340 341 342 def testPositiveClosureSingleToken(self): 343 grammar = textwrap.dedent( 344 r''' 345 grammar T; 346 options {language=Python3;output=AST;} 347 a : ID ID -> ID+ ; 348 ID : 'a'..'z'+ ; 349 INT : '0'..'9'+; 350 WS : (' '|'\n') {$channel=HIDDEN} ; 351 ''') 352 353 found = self.execParser(grammar, "a", "a b") 354 self.assertEqual("a b", found) 355 356 357 def testOptionalSingleRule(self): 358 grammar = textwrap.dedent( 359 r''' 360 grammar T; 361 options {language=Python3;output=AST;} 362 a : b -> b?; 363 b : ID ; 364 ID : 'a'..'z'+ ; 365 INT : '0'..'9'+; 366 WS : (' '|'\n') {$channel=HIDDEN} ; 367 ''') 368 369 found = self.execParser(grammar, "a", "abc") 370 self.assertEqual("abc", found) 371 372 373 def testClosureSingleRule(self): 374 grammar = textwrap.dedent( 375 r''' 376 grammar T; 377 options {language=Python3;output=AST;} 378 a : b b -> b*; 379 b : ID ; 380 ID : 'a'..'z'+ ; 381 INT : '0'..'9'+; 382 WS : (' '|'\n') {$channel=HIDDEN} ; 383 ''') 384 385 found = self.execParser(grammar, "a", "a b") 386 self.assertEqual("a b", found) 387 388 389 def testClosureOfLabel(self): 390 grammar = textwrap.dedent( 391 r''' 392 grammar T; 393 options {language=Python3;output=AST;} 394 a : x+=b x+=b -> $x*; 395 b : ID ; 396 ID : 'a'..'z'+ ; 397 INT : '0'..'9'+; 398 WS : (' '|'\n') {$channel=HIDDEN} ; 399 ''') 400 401 found = self.execParser(grammar, "a", "a b") 402 self.assertEqual("a b", found) 403 404 405 def testOptionalLabelNoListLabel(self): 406 grammar = textwrap.dedent( 407 r''' 408 grammar T; 409 options {language=Python3;output=AST;} 410 a : (x=ID)? -> $x?; 411 ID : 'a'..'z'+ ; 412 INT : '0'..'9'+; 413 WS : (' '|'\n') {$channel=HIDDEN} ; 414 ''') 415 416 found = self.execParser(grammar, "a", "a") 417 self.assertEqual("a", found) 418 419 420 def testPositiveClosureSingleRule(self): 421 grammar = textwrap.dedent( 422 r''' 423 grammar T; 424 options {language=Python3;output=AST;} 425 a : b b -> b+; 426 b : ID ; 427 ID : 'a'..'z'+ ; 428 INT : '0'..'9'+; 429 WS : (' '|'\n') {$channel=HIDDEN} ; 430 ''') 431 432 found = self.execParser(grammar, "a", "a b") 433 self.assertEqual("a b", found) 434 435 436 def testSinglePredicateT(self): 437 grammar = textwrap.dedent( 438 r''' 439 grammar T; 440 options {language=Python3;output=AST;} 441 a : ID -> {True}? ID -> ; 442 ID : 'a'..'z'+ ; 443 INT : '0'..'9'+; 444 WS : (' '|'\n') {$channel=HIDDEN} ; 445 ''') 446 447 found = self.execParser(grammar, "a", "abc") 448 self.assertEqual("abc", found) 449 450 451 def testSinglePredicateF(self): 452 grammar = textwrap.dedent( 453 r''' 454 grammar T; 455 options {language=Python3;output=AST;} 456 a : ID -> {False}? ID -> ; 457 ID : 'a'..'z'+ ; 458 INT : '0'..'9'+; 459 WS : (' '|'\n') {$channel=HIDDEN} ; 460 ''') 461 462 found = self.execParser(grammar, "a", "abc") 463 self.assertEqual("", found) 464 465 466 def testMultiplePredicate(self): 467 grammar = textwrap.dedent( 468 r''' 469 grammar T; 470 options {language=Python3;output=AST;} 471 a : ID INT -> {False}? ID 472 -> {True}? INT 473 -> 474 ; 475 ID : 'a'..'z'+ ; 476 INT : '0'..'9'+; 477 WS : (' '|'\n') {$channel=HIDDEN} ; 478 ''') 479 480 found = self.execParser(grammar, "a", "a 2") 481 self.assertEqual("2", found) 482 483 484 def testMultiplePredicateTrees(self): 485 grammar = textwrap.dedent( 486 r''' 487 grammar T; 488 options {language=Python3;output=AST;} 489 a : ID INT -> {False}? ^(ID INT) 490 -> {True}? ^(INT ID) 491 -> ID 492 ; 493 ID : 'a'..'z'+ ; 494 INT : '0'..'9'+; 495 WS : (' '|'\n') {$channel=HIDDEN} ; 496 ''') 497 498 found = self.execParser(grammar, "a", "a 2") 499 self.assertEqual("(2 a)", found) 500 501 502 def testSimpleTree(self): 503 grammar = textwrap.dedent( 504 r''' 505 grammar T; 506 options {language=Python3;output=AST;} 507 a : op INT -> ^(op INT); 508 op : '+'|'-' ; 509 ID : 'a'..'z'+ ; 510 INT : '0'..'9'+; 511 WS : (' '|'\n') {$channel=HIDDEN} ; 512 ''') 513 514 found = self.execParser(grammar, "a", "-34") 515 self.assertEqual("(- 34)", found) 516 517 518 def testSimpleTree2(self): 519 grammar = textwrap.dedent( 520 r''' 521 grammar T; 522 options {language=Python3;output=AST;} 523 a : op INT -> ^(INT op); 524 op : '+'|'-' ; 525 ID : 'a'..'z'+ ; 526 INT : '0'..'9'+; 527 WS : (' '|'\n') {$channel=HIDDEN} ; 528 ''') 529 530 found = self.execParser(grammar, "a", "+ 34") 531 self.assertEqual("(34 +)", found) 532 533 534 535 def testNestedTrees(self): 536 grammar = textwrap.dedent( 537 r''' 538 grammar T; 539 options {language=Python3;output=AST;} 540 a : 'var' (ID ':' type ';')+ -> ^('var' ^(':' ID type)+) ; 541 type : 'int' | 'float' ; 542 ID : 'a'..'z'+ ; 543 INT : '0'..'9'+; 544 WS : (' '|'\n') {$channel=HIDDEN} ; 545 ''') 546 547 found = self.execParser(grammar, "a", "var a:int; b:float;") 548 self.assertEqual("(var (: a int) (: b float))", found) 549 550 551 def testImaginaryTokenCopy(self): 552 grammar = textwrap.dedent( 553 r''' 554 grammar T; 555 options {language=Python3;output=AST;} 556 tokens {VAR;} 557 a : ID (',' ID)*-> ^(VAR ID)+ ; 558 type : 'int' | 'float' ; 559 ID : 'a'..'z'+ ; 560 INT : '0'..'9'+; 561 WS : (' '|'\n') {$channel=HIDDEN} ; 562 ''') 563 564 found = self.execParser(grammar, "a", "a,b,c") 565 self.assertEqual("(VAR a) (VAR b) (VAR c)", found) 566 567 568 def testTokenUnreferencedOnLeftButDefined(self): 569 grammar = textwrap.dedent( 570 r''' 571 grammar T; 572 options {language=Python3;output=AST;} 573 tokens {VAR;} 574 a : b -> ID ; 575 b : ID ; 576 ID : 'a'..'z'+ ; 577 INT : '0'..'9'+; 578 WS : (' '|'\n') {$channel=HIDDEN} ; 579 ''') 580 581 found = self.execParser(grammar, "a", "a") 582 self.assertEqual("ID", found) 583 584 585 def testImaginaryTokenCopySetText(self): 586 grammar = textwrap.dedent( 587 r''' 588 grammar T; 589 options {language=Python3;output=AST;} 590 tokens {VAR;} 591 a : ID (',' ID)*-> ^(VAR["var"] ID)+ ; 592 type : 'int' | 'float' ; 593 ID : 'a'..'z'+ ; 594 INT : '0'..'9'+; 595 WS : (' '|'\n') {$channel=HIDDEN} ; 596 ''') 597 598 found = self.execParser(grammar, "a", "a,b,c") 599 self.assertEqual("(var a) (var b) (var c)", found) 600 601 602 def testImaginaryTokenNoCopyFromToken(self): 603 grammar = textwrap.dedent( 604 r''' 605 grammar T; 606 options {language=Python3;output=AST;} 607 tokens {BLOCK;} 608 a : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; 609 type : 'int' | 'float' ; 610 ID : 'a'..'z'+ ; 611 INT : '0'..'9'+; 612 WS : (' '|'\n') {$channel=HIDDEN} ; 613 ''') 614 615 found = self.execParser(grammar, "a", "{a b c}") 616 self.assertEqual("({ a b c)", found) 617 618 619 def testImaginaryTokenNoCopyFromTokenSetText(self): 620 grammar = textwrap.dedent( 621 r''' 622 grammar T; 623 options {language=Python3;output=AST;} 624 tokens {BLOCK;} 625 a : lc='{' ID+ '}' -> ^(BLOCK[$lc,"block"] ID+) ; 626 type : 'int' | 'float' ; 627 ID : 'a'..'z'+ ; 628 INT : '0'..'9'+; 629 WS : (' '|'\n') {$channel=HIDDEN} ; 630 ''') 631 632 found = self.execParser(grammar, "a", "{a b c}") 633 self.assertEqual("(block a b c)", found) 634 635 636 def testMixedRewriteAndAutoAST(self): 637 grammar = textwrap.dedent( 638 r''' 639 grammar T; 640 options {language=Python3;output=AST;} 641 tokens {BLOCK;} 642 a : b b^ ; // 2nd b matches only an INT; can make it root 643 b : ID INT -> INT ID 644 | INT 645 ; 646 ID : 'a'..'z'+ ; 647 INT : '0'..'9'+; 648 WS : (' '|'\n') {$channel=HIDDEN} ; 649 ''') 650 651 found = self.execParser(grammar, "a", "a 1 2") 652 self.assertEqual("(2 1 a)", found) 653 654 655 def testSubruleWithRewrite(self): 656 grammar = textwrap.dedent( 657 r''' 658 grammar T; 659 options {language=Python3;output=AST;} 660 tokens {BLOCK;} 661 a : b b ; 662 b : (ID INT -> INT ID | INT INT -> INT+ ) 663 ; 664 ID : 'a'..'z'+ ; 665 INT : '0'..'9'+; 666 WS : (' '|'\n') {$channel=HIDDEN} ; 667 ''') 668 669 found = self.execParser(grammar, "a", "a 1 2 3") 670 self.assertEqual("1 a 2 3", found) 671 672 673 def testSubruleWithRewrite2(self): 674 grammar = textwrap.dedent( 675 r''' 676 grammar T; 677 options {language=Python3;output=AST;} 678 tokens {TYPE;} 679 a : b b ; 680 b : 'int' 681 ( ID -> ^(TYPE 'int' ID) 682 | ID '=' INT -> ^(TYPE 'int' ID INT) 683 ) 684 ';' 685 ; 686 ID : 'a'..'z'+ ; 687 INT : '0'..'9'+; 688 WS : (' '|'\n') {$channel=HIDDEN} ; 689 ''') 690 691 found = self.execParser(grammar, "a", "int a; int b=3;") 692 self.assertEqual("(TYPE int a) (TYPE int b 3)", found) 693 694 695 def testNestedRewriteShutsOffAutoAST(self): 696 grammar = textwrap.dedent( 697 r''' 698 grammar T; 699 options {language=Python3;output=AST;} 700 tokens {BLOCK;} 701 a : b b ; 702 b : ID ( ID (last=ID -> $last)+ ) ';' // get last ID 703 | INT // should still get auto AST construction 704 ; 705 ID : 'a'..'z'+ ; 706 INT : '0'..'9'+; 707 WS : (' '|'\n') {$channel=HIDDEN} ; 708 ''') 709 710 found = self.execParser(grammar, "a", "a b c d; 42") 711 self.assertEqual("d 42", found) 712 713 714 def testRewriteActions(self): 715 grammar = textwrap.dedent( 716 r''' 717 grammar T; 718 options {language=Python3;output=AST;} 719 a : atom -> ^({self.adaptor.create(INT,"9")} atom) ; 720 atom : INT ; 721 ID : 'a'..'z'+ ; 722 INT : '0'..'9'+; 723 WS : (' '|'\n') {$channel=HIDDEN} ; 724 ''') 725 726 found = self.execParser(grammar, "a", "3") 727 self.assertEqual("(9 3)", found) 728 729 730 def testRewriteActions2(self): 731 grammar = textwrap.dedent( 732 r''' 733 grammar T; 734 options {language=Python3;output=AST;} 735 a : atom -> {self.adaptor.create(INT,"9")} atom ; 736 atom : INT ; 737 ID : 'a'..'z'+ ; 738 INT : '0'..'9'+; 739 WS : (' '|'\n') {$channel=HIDDEN} ; 740 ''') 741 742 found = self.execParser(grammar, "a", "3") 743 self.assertEqual("9 3", found) 744 745 746 def testRefToOldValue(self): 747 grammar = textwrap.dedent( 748 r''' 749 grammar T; 750 options {language=Python3;output=AST;} 751 tokens {BLOCK;} 752 a : (atom -> atom) (op='+' r=atom -> ^($op $a $r) )* ; 753 atom : INT ; 754 ID : 'a'..'z'+ ; 755 INT : '0'..'9'+; 756 WS : (' '|'\n') {$channel=HIDDEN} ; 757 ''') 758 759 found = self.execParser(grammar, "a", "3+4+5") 760 self.assertEqual("(+ (+ 3 4) 5)", found) 761 762 763 def testCopySemanticsForRules(self): 764 grammar = textwrap.dedent( 765 r''' 766 grammar T; 767 options {language=Python3;output=AST;} 768 tokens {BLOCK;} 769 a : atom -> ^(atom atom) ; // NOT CYCLE! (dup atom) 770 atom : INT ; 771 ID : 'a'..'z'+ ; 772 INT : '0'..'9'+; 773 WS : (' '|'\n') {$channel=HIDDEN} ; 774 ''') 775 776 found = self.execParser(grammar, "a", "3") 777 self.assertEqual("(3 3)", found) 778 779 780 def testCopySemanticsForRules2(self): 781 # copy type as a root for each invocation of (...)+ in rewrite 782 grammar = textwrap.dedent( 783 r''' 784 grammar T; 785 options {language=Python3;output=AST;} 786 a : type ID (',' ID)* ';' -> ^(type ID)+ ; 787 type : 'int' ; 788 ID : 'a'..'z'+ ; 789 WS : (' '|'\n') {$channel=HIDDEN} ; 790 ''') 791 792 found = self.execParser(grammar, "a", "int a,b,c;") 793 self.assertEqual("(int a) (int b) (int c)", found) 794 795 796 def testCopySemanticsForRules3(self): 797 # copy type *and* modifier even though it's optional 798 # for each invocation of (...)+ in rewrite 799 grammar = textwrap.dedent( 800 r''' 801 grammar T; 802 options {language=Python3;output=AST;} 803 a : modifier? type ID (',' ID)* ';' -> ^(type modifier? ID)+ ; 804 type : 'int' ; 805 modifier : 'public' ; 806 ID : 'a'..'z'+ ; 807 WS : (' '|'\n') {$channel=HIDDEN} ; 808 ''') 809 810 found = self.execParser(grammar, "a", "public int a,b,c;") 811 self.assertEqual("(int public a) (int public b) (int public c)", found) 812 813 814 def testCopySemanticsForRules3Double(self): 815 # copy type *and* modifier even though it's optional 816 # for each invocation of (...)+ in rewrite 817 grammar = textwrap.dedent( 818 r''' 819 grammar T; 820 options {language=Python3;output=AST;} 821 a : modifier? type ID (',' ID)* ';' -> ^(type modifier? ID)+ ^(type modifier? ID)+ ; 822 type : 'int' ; 823 modifier : 'public' ; 824 ID : 'a'..'z'+ ; 825 WS : (' '|'\n') {$channel=HIDDEN} ; 826 ''') 827 828 found = self.execParser(grammar, "a", "public int a,b,c;") 829 self.assertEqual("(int public a) (int public b) (int public c) (int public a) (int public b) (int public c)", found) 830 831 832 def testCopySemanticsForRules4(self): 833 # copy type *and* modifier even though it's optional 834 # for each invocation of (...)+ in rewrite 835 grammar = textwrap.dedent( 836 r''' 837 grammar T; 838 options {language=Python3;output=AST;} 839 tokens {MOD;} 840 a : modifier? type ID (',' ID)* ';' -> ^(type ^(MOD modifier)? ID)+ ; 841 type : 'int' ; 842 modifier : 'public' ; 843 ID : 'a'..'z'+ ; 844 WS : (' '|'\n') {$channel=HIDDEN} ; 845 ''') 846 847 found = self.execParser(grammar, "a", "public int a,b,c;") 848 self.assertEqual("(int (MOD public) a) (int (MOD public) b) (int (MOD public) c)", found) 849 850 851 def testCopySemanticsLists(self): 852 grammar = textwrap.dedent( 853 r''' 854 grammar T; 855 options {language=Python3;output=AST;} 856 tokens {MOD;} 857 a : ID (',' ID)* ';' -> ID+ ID+ ; 858 ID : 'a'..'z'+ ; 859 WS : (' '|'\n') {$channel=HIDDEN} ; 860 ''') 861 862 found = self.execParser(grammar, "a", "a,b,c;") 863 self.assertEqual("a b c a b c", found) 864 865 866 def testCopyRuleLabel(self): 867 grammar = textwrap.dedent( 868 r''' 869 grammar T; 870 options {language=Python3;output=AST;} 871 tokens {BLOCK;} 872 a : x=b -> $x $x; 873 b : ID ; 874 ID : 'a'..'z'+ ; 875 WS : (' '|'\n') {$channel=HIDDEN} ; 876 ''') 877 878 found = self.execParser(grammar, "a", "a") 879 self.assertEqual("a a", found) 880 881 882 def testCopyRuleLabel2(self): 883 grammar = textwrap.dedent( 884 r''' 885 grammar T; 886 options {language=Python3;output=AST;} 887 tokens {BLOCK;} 888 a : x=b -> ^($x $x); 889 b : ID ; 890 ID : 'a'..'z'+ ; 891 WS : (' '|'\n') {$channel=HIDDEN} ; 892 ''') 893 894 found = self.execParser(grammar, "a", "a") 895 self.assertEqual("(a a)", found) 896 897 898 def testQueueingOfTokens(self): 899 grammar = textwrap.dedent( 900 r''' 901 grammar T; 902 options {language=Python3;output=AST;} 903 a : 'int' ID (',' ID)* ';' -> ^('int' ID+) ; 904 op : '+'|'-' ; 905 ID : 'a'..'z'+ ; 906 INT : '0'..'9'+; 907 WS : (' '|'\n') {$channel=HIDDEN} ; 908 ''') 909 910 found = self.execParser(grammar, "a", "int a,b,c;") 911 self.assertEqual("(int a b c)", found) 912 913 914 def testCopyOfTokens(self): 915 grammar = textwrap.dedent( 916 r''' 917 grammar T; 918 options {language=Python3;output=AST;} 919 a : 'int' ID ';' -> 'int' ID 'int' ID ; 920 op : '+'|'-' ; 921 ID : 'a'..'z'+ ; 922 INT : '0'..'9'+; 923 WS : (' '|'\n') {$channel=HIDDEN} ; 924 ''') 925 926 found = self.execParser(grammar, "a", "int a;") 927 self.assertEqual("int a int a", found) 928 929 930 def testTokenCopyInLoop(self): 931 grammar = textwrap.dedent( 932 r''' 933 grammar T; 934 options {language=Python3;output=AST;} 935 a : 'int' ID (',' ID)* ';' -> ^('int' ID)+ ; 936 op : '+'|'-' ; 937 ID : 'a'..'z'+ ; 938 INT : '0'..'9'+; 939 WS : (' '|'\n') {$channel=HIDDEN} ; 940 ''') 941 942 found = self.execParser(grammar, "a", "int a,b,c;") 943 self.assertEqual("(int a) (int b) (int c)", found) 944 945 946 def testTokenCopyInLoopAgainstTwoOthers(self): 947 # must smear 'int' copies across as root of multiple trees 948 grammar = textwrap.dedent( 949 r''' 950 grammar T; 951 options {language=Python3;output=AST;} 952 a : 'int' ID ':' INT (',' ID ':' INT)* ';' -> ^('int' ID INT)+ ; 953 op : '+'|'-' ; 954 ID : 'a'..'z'+ ; 955 INT : '0'..'9'+; 956 WS : (' '|'\n') {$channel=HIDDEN} ; 957 ''') 958 959 found = self.execParser(grammar, "a", "int a:1,b:2,c:3;") 960 self.assertEqual("(int a 1) (int b 2) (int c 3)", found) 961 962 963 def testListRefdOneAtATime(self): 964 grammar = textwrap.dedent( 965 r''' 966 grammar T; 967 options {language=Python3;output=AST;} 968 a : ID+ -> ID ID ID ; // works if 3 input IDs 969 op : '+'|'-' ; 970 ID : 'a'..'z'+ ; 971 INT : '0'..'9'+; 972 WS : (' '|'\n') {$channel=HIDDEN} ; 973 ''') 974 975 found = self.execParser(grammar, "a", "a b c") 976 self.assertEqual("a b c", found) 977 978 979 def testSplitListWithLabels(self): 980 grammar = textwrap.dedent( 981 r''' 982 grammar T; 983 options {language=Python3;output=AST;} 984 tokens {VAR;} 985 a : first=ID others+=ID* -> $first VAR $others+ ; 986 op : '+'|'-' ; 987 ID : 'a'..'z'+ ; 988 INT : '0'..'9'+; 989 WS : (' '|'\n') {$channel=HIDDEN} ; 990 ''') 991 992 found = self.execParser(grammar, "a", "a b c") 993 self.assertEqual("a VAR b c", found) 994 995 996 def testComplicatedMelange(self): 997 grammar = textwrap.dedent( 998 r''' 999 grammar T; 1000 options {language=Python3;output=AST;} 1001 tokens {BLOCK;} 1002 a : A A b=B B b=B c+=C C c+=C D {s=$D.text} -> A+ B+ C+ D ; 1003 type : 'int' | 'float' ; 1004 A : 'a' ; 1005 B : 'b' ; 1006 C : 'c' ; 1007 D : 'd' ; 1008 WS : (' '|'\n') {$channel=HIDDEN} ; 1009 ''') 1010 1011 found = self.execParser(grammar, "a", "a a b b b c c c d") 1012 self.assertEqual("a a b b b c c c d", found) 1013 1014 1015 def testRuleLabel(self): 1016 grammar = textwrap.dedent( 1017 r''' 1018 grammar T; 1019 options {language=Python3;output=AST;} 1020 tokens {BLOCK;} 1021 a : x=b -> $x; 1022 b : ID ; 1023 ID : 'a'..'z'+ ; 1024 WS : (' '|'\n') {$channel=HIDDEN} ; 1025 ''') 1026 1027 found = self.execParser(grammar, "a", "a") 1028 self.assertEqual("a", found) 1029 1030 1031 def testAmbiguousRule(self): 1032 grammar = textwrap.dedent( 1033 r''' 1034 grammar T; 1035 options {language=Python3;output=AST;} 1036 a : ID a -> a | INT ; 1037 ID : 'a'..'z'+ ; 1038 INT: '0'..'9'+ ; 1039 WS : (' '|'\n') {$channel=HIDDEN} ; 1040 ''') 1041 1042 found = self.execParser(grammar, 1043 "a", "abc 34") 1044 self.assertEqual("34", found) 1045 1046 1047 def testRuleListLabel(self): 1048 grammar = textwrap.dedent( 1049 r''' 1050 grammar T; 1051 options {language=Python3;output=AST;} 1052 tokens {BLOCK;} 1053 a : x+=b x+=b -> $x+; 1054 b : ID ; 1055 ID : 'a'..'z'+ ; 1056 WS : (' '|'\n') {$channel=HIDDEN} ; 1057 ''') 1058 1059 found = self.execParser(grammar, "a", "a b") 1060 self.assertEqual("a b", found) 1061 1062 1063 def testRuleListLabel2(self): 1064 grammar = textwrap.dedent( 1065 r''' 1066 grammar T; 1067 options {language=Python3;output=AST;} 1068 tokens {BLOCK;} 1069 a : x+=b x+=b -> $x $x*; 1070 b : ID ; 1071 ID : 'a'..'z'+ ; 1072 WS : (' '|'\n') {$channel=HIDDEN} ; 1073 ''') 1074 1075 found = self.execParser(grammar, "a", "a b") 1076 self.assertEqual("a b", found) 1077 1078 1079 def testOptional(self): 1080 grammar = textwrap.dedent( 1081 r''' 1082 grammar T; 1083 options {language=Python3;output=AST;} 1084 tokens {BLOCK;} 1085 a : x=b (y=b)? -> $x $y?; 1086 b : ID ; 1087 ID : 'a'..'z'+ ; 1088 WS : (' '|'\n') {$channel=HIDDEN} ; 1089 ''') 1090 1091 found = self.execParser(grammar, "a", "a") 1092 self.assertEqual("a", found) 1093 1094 1095 def testOptional2(self): 1096 grammar = textwrap.dedent( 1097 r''' 1098 grammar T; 1099 options {language=Python3;output=AST;} 1100 tokens {BLOCK;} 1101 a : x=ID (y=b)? -> $x $y?; 1102 b : ID ; 1103 ID : 'a'..'z'+ ; 1104 WS : (' '|'\n') {$channel=HIDDEN} ; 1105 ''') 1106 1107 found = self.execParser(grammar, "a", "a b") 1108 self.assertEqual("a b", found) 1109 1110 1111 def testOptional3(self): 1112 grammar = textwrap.dedent( 1113 r''' 1114 grammar T; 1115 options {language=Python3;output=AST;} 1116 tokens {BLOCK;} 1117 a : x=ID (y=b)? -> ($x $y)?; 1118 b : ID ; 1119 ID : 'a'..'z'+ ; 1120 WS : (' '|'\n') {$channel=HIDDEN} ; 1121 ''') 1122 1123 found = self.execParser(grammar, "a", "a b") 1124 self.assertEqual("a b", found) 1125 1126 1127 def testOptional4(self): 1128 grammar = textwrap.dedent( 1129 r''' 1130 grammar T; 1131 options {language=Python3;output=AST;} 1132 tokens {BLOCK;} 1133 a : x+=ID (y=b)? -> ($x $y)?; 1134 b : ID ; 1135 ID : 'a'..'z'+ ; 1136 WS : (' '|'\n') {$channel=HIDDEN} ; 1137 ''') 1138 1139 found = self.execParser(grammar, "a", "a b") 1140 self.assertEqual("a b", found) 1141 1142 1143 def testOptional5(self): 1144 grammar = textwrap.dedent( 1145 r''' 1146 grammar T; 1147 options {language=Python3;output=AST;} 1148 tokens {BLOCK;} 1149 a : ID -> ID? ; // match an ID to optional ID 1150 b : ID ; 1151 ID : 'a'..'z'+ ; 1152 WS : (' '|'\n') {$channel=HIDDEN} ; 1153 ''') 1154 1155 found = self.execParser(grammar, "a", "a") 1156 self.assertEqual("a", found) 1157 1158 1159 def testArbitraryExprType(self): 1160 grammar = textwrap.dedent( 1161 r''' 1162 grammar T; 1163 options {language=Python3;output=AST;} 1164 tokens {BLOCK;} 1165 a : x+=b x+=b -> {CommonTree(None)}; 1166 b : ID ; 1167 ID : 'a'..'z'+ ; 1168 WS : (' '|'\n') {$channel=HIDDEN} ; 1169 ''') 1170 1171 found = self.execParser(grammar, "a", "a b") 1172 self.assertEqual("", found) 1173 1174 1175 def testSet(self): 1176 grammar = textwrap.dedent( 1177 r''' 1178 grammar T; 1179 options {language=Python3;output=AST;} 1180 a: (INT|ID)+ -> INT+ ID+ ; 1181 INT: '0'..'9'+; 1182 ID : 'a'..'z'+; 1183 WS : (' '|'\n') {$channel=HIDDEN} ; 1184 ''') 1185 1186 found = self.execParser(grammar, "a", "2 a 34 de") 1187 self.assertEqual("2 34 a de", found) 1188 1189 1190 def testSet2(self): 1191 grammar = textwrap.dedent( 1192 r''' 1193 grammar T; 1194 options {language=Python3;output=AST;} 1195 a: (INT|ID) -> INT? ID? ; 1196 INT: '0'..'9'+; 1197 ID : 'a'..'z'+; 1198 WS : (' '|'\n') {$channel=HIDDEN} ; 1199 ''') 1200 1201 found = self.execParser(grammar, "a", "2") 1202 self.assertEqual("2", found) 1203 1204 1205 @testbase.broken("http://www.antlr.org:8888/browse/ANTLR-162", 1206 antlr3.tree.RewriteEmptyStreamException) 1207 def testSetWithLabel(self): 1208 grammar = textwrap.dedent( 1209 r''' 1210 grammar T; 1211 options {language=Python3;output=AST;} 1212 a : x=(INT|ID) -> $x ; 1213 INT: '0'..'9'+; 1214 ID : 'a'..'z'+; 1215 WS : (' '|'\n') {$channel=HIDDEN} ; 1216 ''') 1217 1218 found = self.execParser(grammar, "a", "2") 1219 self.assertEqual("2", found) 1220 1221 1222 def testRewriteAction(self): 1223 grammar = textwrap.dedent( 1224 r''' 1225 grammar T; 1226 options {language=Python3;output=AST;} 1227 tokens { FLOAT; } 1228 r 1229 : INT -> {CommonTree(CommonToken(type=FLOAT, text=$INT.text+".0"))} 1230 ; 1231 INT : '0'..'9'+; 1232 WS: (' ' | '\n' | '\t')+ {$channel = HIDDEN}; 1233 ''') 1234 1235 found = self.execParser(grammar, "r", "25") 1236 self.assertEqual("25.0", found) 1237 1238 1239 def testOptionalSubruleWithoutRealElements(self): 1240 # copy type *and* modifier even though it's optional 1241 # for each invocation of (...)+ in rewrite 1242 grammar = textwrap.dedent( 1243 r""" 1244 grammar T; 1245 options {language=Python3;output=AST;} 1246 tokens {PARMS;} 1247 1248 modulo 1249 : 'modulo' ID ('(' parms+ ')')? -> ^('modulo' ID ^(PARMS parms+)?) 1250 ; 1251 parms : '#'|ID; 1252 ID : ('a'..'z' | 'A'..'Z')+; 1253 WS : (' '|'\n') {$channel=HIDDEN} ; 1254 """) 1255 1256 found = self.execParser(grammar, "modulo", "modulo abc (x y #)") 1257 self.assertEqual("(modulo abc (PARMS x y #))", found) 1258 1259 1260 ## C A R D I N A L I T Y I S S U E S 1261 1262 def testCardinality(self): 1263 grammar = textwrap.dedent( 1264 r''' 1265 grammar T; 1266 options {language=Python3;output=AST;} 1267 tokens {BLOCK;} 1268 a : ID ID INT INT INT -> (ID INT)+; 1269 ID : 'a'..'z'+ ; 1270 INT : '0'..'9'+; 1271 WS : (' '|'\n') {$channel=HIDDEN} ; 1272 ''') 1273 1274 self.assertRaises(antlr3.tree.RewriteCardinalityException, 1275 self.execParser, grammar, "a", "a b 3 4 5") 1276 1277 1278 def testCardinality2(self): 1279 grammar = textwrap.dedent( 1280 r''' 1281 grammar T; 1282 options {language=Python3;output=AST;} 1283 a : ID+ -> ID ID ID ; // only 2 input IDs 1284 op : '+'|'-' ; 1285 ID : 'a'..'z'+ ; 1286 INT : '0'..'9'+; 1287 WS : (' '|'\n') {$channel=HIDDEN} ; 1288 ''') 1289 1290 self.assertRaises(antlr3.tree.RewriteCardinalityException, 1291 self.execParser, grammar, "a", "a b") 1292 1293 1294 def testCardinality3(self): 1295 grammar = textwrap.dedent( 1296 r''' 1297 grammar T; 1298 options {language=Python3;output=AST;} 1299 a : ID? INT -> ID INT ; 1300 op : '+'|'-' ; 1301 ID : 'a'..'z'+ ; 1302 INT : '0'..'9'+; 1303 WS : (' '|'\n') {$channel=HIDDEN} ; 1304 ''') 1305 1306 self.assertRaises(antlr3.tree.RewriteEmptyStreamException, 1307 self.execParser, grammar, "a", "3") 1308 1309 1310 def testLoopCardinality(self): 1311 grammar = textwrap.dedent( 1312 r''' 1313 grammar T; 1314 options {language=Python3;output=AST;} 1315 a : ID? INT -> ID+ INT ; 1316 op : '+'|'-' ; 1317 ID : 'a'..'z'+ ; 1318 INT : '0'..'9'+; 1319 WS : (' '|'\n') {$channel=HIDDEN} ; 1320 ''') 1321 1322 self.assertRaises(antlr3.tree.RewriteEarlyExitException, 1323 self.execParser, grammar, "a", "3") 1324 1325 1326 def testWildcard(self): 1327 grammar = textwrap.dedent( 1328 r''' 1329 grammar T; 1330 options {language=Python3;output=AST;} 1331 a : ID c=. -> $c; 1332 ID : 'a'..'z'+ ; 1333 INT : '0'..'9'+; 1334 WS : (' '|'\n') {$channel=HIDDEN} ; 1335 ''') 1336 1337 found = self.execParser(grammar, "a", "abc 34") 1338 self.assertEqual("34", found) 1339 1340 1341 # E R R O R S 1342 1343 def testExtraTokenInSimpleDecl(self): 1344 grammar = textwrap.dedent( 1345 r''' 1346 grammar foo; 1347 options {language=Python3;output=AST;} 1348 tokens {EXPR;} 1349 decl : type ID '=' INT ';' -> ^(EXPR type ID INT) ; 1350 type : 'int' | 'float' ; 1351 ID : 'a'..'z'+ ; 1352 INT : '0'..'9'+; 1353 WS : (' '|'\n') {$channel=HIDDEN} ; 1354 ''') 1355 1356 found, errors = self.execParser(grammar, "decl", "int 34 x=1;", 1357 expectErrors=True) 1358 self.assertEqual(["line 1:4 extraneous input '34' expecting ID"], 1359 errors) 1360 self.assertEqual("(EXPR int x 1)", found) # tree gets correct x and 1 tokens 1361 1362 1363 #@testbase.broken("FIXME", AssertionError) 1364 def testMissingIDInSimpleDecl(self): 1365 grammar = textwrap.dedent( 1366 r''' 1367 grammar foo; 1368 options {language=Python3;output=AST;} 1369 tokens {EXPR;} 1370 decl : type ID '=' INT ';' -> ^(EXPR type ID INT) ; 1371 type : 'int' | 'float' ; 1372 ID : 'a'..'z'+ ; 1373 INT : '0'..'9'+; 1374 WS : (' '|'\n') {$channel=HIDDEN} ; 1375 ''') 1376 1377 found, errors = self.execParser(grammar, "decl", "int =1;", 1378 expectErrors=True) 1379 self.assertEqual(["line 1:4 missing ID at '='"], errors) 1380 self.assertEqual("(EXPR int <missing ID> 1)", found) # tree gets invented ID token 1381 1382 1383 def testMissingSetInSimpleDecl(self): 1384 grammar = textwrap.dedent( 1385 r''' 1386 grammar foo; 1387 options {language=Python3;output=AST;} 1388 tokens {EXPR;} 1389 decl : type ID '=' INT ';' -> ^(EXPR type ID INT) ; 1390 type : 'int' | 'float' ; 1391 ID : 'a'..'z'+ ; 1392 INT : '0'..'9'+; 1393 WS : (' '|'\n') {$channel=HIDDEN} ; 1394 ''') 1395 1396 found, errors = self.execParser(grammar, "decl", "x=1;", 1397 expectErrors=True) 1398 self.assertEqual(["line 1:0 mismatched input 'x' expecting set None"], 1399 errors); 1400 self.assertEqual("(EXPR <error: x> x 1)", found) # tree gets invented ID token 1401 1402 1403 def testMissingTokenGivesErrorNode(self): 1404 grammar = textwrap.dedent( 1405 r''' 1406 grammar foo; 1407 options {language=Python3;output=AST;} 1408 a : ID INT -> ID INT ; 1409 ID : 'a'..'z'+ ; 1410 INT : '0'..'9'+; 1411 WS : (' '|'\n') {$channel=HIDDEN} ; 1412 ''') 1413 1414 found, errors = self.execParser(grammar, "a", "abc", 1415 expectErrors=True) 1416 self.assertEqual(["line 1:3 missing INT at '<EOF>'"], errors) 1417 # doesn't do in-line recovery for sets (yet?) 1418 self.assertEqual("abc <missing INT>", found) 1419 1420 1421 def testExtraTokenGivesErrorNode(self): 1422 grammar = textwrap.dedent( 1423 r''' 1424 grammar foo; 1425 options {language=Python3;output=AST;} 1426 a : b c -> b c; 1427 b : ID -> ID ; 1428 c : INT -> INT ; 1429 ID : 'a'..'z'+ ; 1430 INT : '0'..'9'+; 1431 WS : (' '|'\n') {$channel=HIDDEN} ; 1432 ''') 1433 1434 found, errors = self.execParser(grammar, "a", "abc ick 34", 1435 expectErrors=True) 1436 self.assertEqual(["line 1:4 extraneous input 'ick' expecting INT"], 1437 errors) 1438 self.assertEqual("abc 34", found) 1439 1440 1441 #@testbase.broken("FIXME", AssertionError) 1442 def testMissingFirstTokenGivesErrorNode(self): 1443 grammar = textwrap.dedent( 1444 r''' 1445 grammar foo; 1446 options {language=Python3;output=AST;} 1447 a : ID INT -> ID INT ; 1448 ID : 'a'..'z'+ ; 1449 INT : '0'..'9'+; 1450 WS : (' '|'\n') {$channel=HIDDEN} ; 1451 ''') 1452 1453 found, errors = self.execParser(grammar, "a", "34", expectErrors=True) 1454 self.assertEqual(["line 1:0 missing ID at '34'"], errors) 1455 self.assertEqual("<missing ID> 34", found) 1456 1457 1458 #@testbase.broken("FIXME", AssertionError) 1459 def testMissingFirstTokenGivesErrorNode2(self): 1460 grammar = textwrap.dedent( 1461 r''' 1462 grammar foo; 1463 options {language=Python3;output=AST;} 1464 a : b c -> b c; 1465 b : ID -> ID ; 1466 c : INT -> INT ; 1467 ID : 'a'..'z'+ ; 1468 INT : '0'..'9'+; 1469 WS : (' '|'\n') {$channel=HIDDEN} ; 1470 ''') 1471 1472 found, errors = self.execParser(grammar, "a", "34", expectErrors=True) 1473 # finds an error at the first token, 34, and re-syncs. 1474 # re-synchronizing does not consume a token because 34 follows 1475 # ref to rule b (start of c). It then matches 34 in c. 1476 self.assertEqual(["line 1:0 missing ID at '34'"], errors) 1477 self.assertEqual("<missing ID> 34", found) 1478 1479 1480 def testNoViableAltGivesErrorNode(self): 1481 grammar = textwrap.dedent( 1482 r''' 1483 grammar foo; 1484 options {language=Python3;output=AST;} 1485 a : b -> b | c -> c; 1486 b : ID -> ID ; 1487 c : INT -> INT ; 1488 ID : 'a'..'z'+ ; 1489 S : '*' ; 1490 INT : '0'..'9'+; 1491 WS : (' '|'\n') {$channel=HIDDEN} ; 1492 ''') 1493 1494 found, errors = self.execParser(grammar, "a", "*", expectErrors=True) 1495 # finds an error at the first token, 34, and re-syncs. 1496 # re-synchronizing does not consume a token because 34 follows 1497 # ref to rule b (start of c). It then matches 34 in c. 1498 self.assertEqual(["line 1:0 no viable alternative at input '*'"], 1499 errors); 1500 self.assertEqual("<unexpected: [@0,0:0='*',<S>,1:0], resync=*>", 1501 found) 1502 1503 1504if __name__ == '__main__': 1505 unittest.main() 1506