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