• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2import textwrap
3import antlr3
4import antlr3.tree
5import testbase
6import sys
7
8class TestAutoAST(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 testTokenList(self):
113        grammar = textwrap.dedent(
114            r'''
115            grammar foo;
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("abc 34", found);
125
126
127    def testTokenListInSingleAltBlock(self):
128        grammar = textwrap.dedent(
129            r'''
130            grammar foo;
131            options {language=Python3;output=AST;}
132            a : (ID INT) ;
133            ID : 'a'..'z'+ ;
134            INT : '0'..'9'+;
135            WS : (' '|'\n') {$channel=HIDDEN} ;
136            ''')
137
138        found = self.execParser(grammar,"a", "abc 34")
139        self.assertEqual("abc 34", found)
140
141
142    def testSimpleRootAtOuterLevel(self):
143        grammar = textwrap.dedent(
144            r'''
145            grammar foo;
146            options {language=Python3;output=AST;}
147            a : ID^ INT ;
148            ID : 'a'..'z'+ ;
149            INT : '0'..'9'+;
150            WS : (' '|'\n') {$channel=HIDDEN} ;
151            ''')
152
153        found = self.execParser(grammar, "a", "abc 34")
154        self.assertEqual("(abc 34)", found)
155
156
157    def testSimpleRootAtOuterLevelReverse(self):
158        grammar = textwrap.dedent(
159            r'''
160            grammar T;
161            options {language=Python3;output=AST;}
162            a : INT ID^ ;
163            ID : 'a'..'z'+ ;
164            INT : '0'..'9'+;
165            WS : (' '|'\n') {$channel=HIDDEN} ;
166            ''')
167
168        found = self.execParser(grammar, "a", "34 abc")
169        self.assertEqual("(abc 34)", found)
170
171
172    def testBang(self):
173        grammar = textwrap.dedent(
174            r'''
175            grammar T;
176            options {language=Python3;output=AST;}
177            a : ID INT! ID! INT ;
178            ID : 'a'..'z'+ ;
179            INT : '0'..'9'+;
180            WS : (' '|'\n') {$channel=HIDDEN} ;
181            ''')
182
183        found = self.execParser(grammar, "a", "abc 34 dag 4532")
184        self.assertEqual("abc 4532", found)
185
186
187    def testOptionalThenRoot(self):
188        grammar = textwrap.dedent(
189            r'''
190            grammar T;
191            options {language=Python3;output=AST;}
192            a : ( ID INT )? ID^ ;
193            ID : 'a'..'z'+ ;
194            INT : '0'..'9'+;
195            WS : (' '|'\n') {$channel=HIDDEN} ;
196            ''')
197
198        found = self.execParser(grammar, "a", "a 1 b")
199        self.assertEqual("(b a 1)", found)
200
201
202    def testLabeledStringRoot(self):
203        grammar = textwrap.dedent(
204            r'''
205            grammar T;
206            options {language=Python3;output=AST;}
207            a : v='void'^ ID ';' ;
208            ID : 'a'..'z'+ ;
209            INT : '0'..'9'+;
210            WS : (' '|'\n') {$channel=HIDDEN} ;
211            ''')
212
213        found = self.execParser(grammar, "a", "void foo;")
214        self.assertEqual("(void foo ;)", found)
215
216
217    def testWildcard(self):
218        grammar = textwrap.dedent(
219            r'''
220            grammar T;
221            options {language=Python3;output=AST;}
222            a : v='void'^ . ';' ;
223            ID : 'a'..'z'+ ;
224            INT : '0'..'9'+;
225            WS : (' '|'\n') {$channel=HIDDEN} ;
226            ''')
227
228        found = self.execParser(grammar, "a", "void foo;")
229        self.assertEqual("(void foo ;)", found)
230
231
232    def testWildcardRoot(self):
233        grammar = textwrap.dedent(
234            r'''
235            grammar T;
236            options {language=Python3;output=AST;}
237            a : v='void' .^ ';' ;
238            ID : 'a'..'z'+ ;
239            INT : '0'..'9'+;
240            WS : (' '|'\n') {$channel=HIDDEN} ;
241            ''')
242
243        found = self.execParser(grammar, "a", "void foo;")
244        self.assertEqual("(foo void ;)", found)
245
246
247    def testWildcardRootWithLabel(self):
248        grammar = textwrap.dedent(
249            r'''
250            grammar T;
251            options {language=Python3;output=AST;}
252            a : v='void' x=.^ ';' ;
253            ID : 'a'..'z'+ ;
254            INT : '0'..'9'+;
255            WS : (' '|'\n') {$channel=HIDDEN} ;
256            ''')
257
258        found = self.execParser(grammar, "a", "void foo;")
259        self.assertEqual("(foo void ;)", found)
260
261
262    def testWildcardRootWithListLabel(self):
263        grammar = textwrap.dedent(
264            r'''
265            grammar T;
266            options {language=Python3;output=AST;}
267            a : v='void' x=.^ ';' ;
268            ID : 'a'..'z'+ ;
269            INT : '0'..'9'+;
270            WS : (' '|'\n') {$channel=HIDDEN} ;
271            ''')
272
273        found = self.execParser(grammar, "a", "void foo;")
274        self.assertEqual("(foo void ;)", found)
275
276
277    def testWildcardBangWithListLabel(self):
278        grammar = textwrap.dedent(
279            r'''
280            grammar T;
281            options {language=Python3;output=AST;}
282            a : v='void' x=.! ';' ;
283            ID : 'a'..'z'+ ;
284            INT : '0'..'9'+;
285            WS : (' '|'\n') {$channel=HIDDEN} ;
286            ''')
287
288        found = self.execParser(grammar, "a", "void foo;")
289        self.assertEqual("void ;", found)
290
291
292    def testRootRoot(self):
293        grammar = textwrap.dedent(
294            r'''
295            grammar T;
296            options {language=Python3;output=AST;}
297            a : ID^ INT^ ID ;
298            ID : 'a'..'z'+ ;
299            INT : '0'..'9'+;
300            WS : (' '|'\n') {$channel=HIDDEN} ;
301            ''')
302
303        found = self.execParser(grammar, "a", "a 34 c")
304        self.assertEqual("(34 a c)", found)
305
306
307    def testRootRoot2(self):
308        grammar = textwrap.dedent(
309            r'''
310            grammar T;
311            options {language=Python3;output=AST;}
312            a : ID INT^ ID^ ;
313            ID : 'a'..'z'+ ;
314            INT : '0'..'9'+;
315            WS : (' '|'\n') {$channel=HIDDEN} ;
316            ''')
317
318        found = self.execParser(grammar, "a", "a 34 c")
319        self.assertEqual("(c (34 a))", found)
320
321
322    def testRootThenRootInLoop(self):
323        grammar = textwrap.dedent(
324            r'''
325            grammar T;
326            options {language=Python3;output=AST;}
327            a : ID^ (INT '*'^ ID)+ ;
328            ID  : 'a'..'z'+ ;
329            INT : '0'..'9'+;
330            WS : (' '|'\n') {$channel=HIDDEN} ;
331            ''')
332
333        found = self.execParser(grammar, "a", "a 34 * b 9 * c")
334        self.assertEqual("(* (* (a 34) b 9) c)", found)
335
336
337    def testNestedSubrule(self):
338        grammar = textwrap.dedent(
339            r'''
340            grammar T;
341            options {language=Python3;output=AST;}
342            a : 'void' (({pass}ID|INT) ID | 'null' ) ';' ;
343            ID : 'a'..'z'+ ;
344            INT : '0'..'9'+;
345            WS : (' '|'\n') {$channel=HIDDEN} ;
346            ''')
347
348        found = self.execParser(grammar, "a", "void a b;")
349        self.assertEqual("void a b ;", found)
350
351
352    def testInvokeRule(self):
353        grammar = textwrap.dedent(
354            r'''
355            grammar T;
356            options {language=Python3;output=AST;}
357            a  : type ID ;
358            type : {pass}'int' | 'float' ;
359            ID : 'a'..'z'+ ;
360            INT : '0'..'9'+;
361            WS : (' '|'\n') {$channel=HIDDEN} ;
362            ''')
363
364        found = self.execParser(grammar, "a", "int a")
365        self.assertEqual("int a", found)
366
367
368    def testInvokeRuleAsRoot(self):
369        grammar = textwrap.dedent(
370            r'''
371            grammar T;
372            options {language=Python3;output=AST;}
373            a  : type^ ID ;
374            type : {pass}'int' | 'float' ;
375            ID : 'a'..'z'+ ;
376            INT : '0'..'9'+;
377            WS : (' '|'\n') {$channel=HIDDEN} ;
378            ''')
379
380        found = self.execParser(grammar, "a", "int a")
381        self.assertEqual("(int a)", found)
382
383
384    def testInvokeRuleAsRootWithLabel(self):
385        grammar = textwrap.dedent(
386            r'''
387            grammar T;
388            options {language=Python3;output=AST;}
389            a  : x=type^ ID ;
390            type : {pass}'int' | 'float' ;
391            ID : 'a'..'z'+ ;
392            INT : '0'..'9'+;
393            WS : (' '|'\n') {$channel=HIDDEN} ;
394            ''')
395
396        found = self.execParser(grammar, "a", "int a")
397        self.assertEqual("(int a)", found)
398
399
400    def testInvokeRuleAsRootWithListLabel(self):
401        grammar = textwrap.dedent(
402            r'''
403            grammar T;
404            options {language=Python3;output=AST;}
405            a  : x+=type^ ID ;
406            type : {pass}'int' | 'float' ;
407            ID : 'a'..'z'+ ;
408            INT : '0'..'9'+;
409            WS : (' '|'\n') {$channel=HIDDEN} ;
410            ''')
411
412        found = self.execParser(grammar, "a", "int a")
413        self.assertEqual("(int a)", found)
414
415
416    def testRuleRootInLoop(self):
417        grammar = textwrap.dedent(
418            r'''
419            grammar T;
420            options {language=Python3;output=AST;}
421            a : ID ('+'^ ID)* ;
422            ID : 'a'..'z'+ ;
423            INT : '0'..'9'+;
424            WS : (' '|'\n') {$channel=HIDDEN} ;
425            ''')
426
427        found = self.execParser(grammar, "a", "a+b+c+d")
428        self.assertEqual("(+ (+ (+ a b) c) d)", found)
429
430
431    def testRuleInvocationRuleRootInLoop(self):
432        grammar = textwrap.dedent(
433            r'''
434            grammar T;
435            options {language=Python3;output=AST;}
436            a : ID (op^ ID)* ;
437            op : {pass}'+' | '-' ;
438            ID : 'a'..'z'+ ;
439            INT : '0'..'9'+;
440            WS : (' '|'\n') {$channel=HIDDEN} ;
441            ''')
442
443        found = self.execParser(grammar, "a", "a+b+c-d")
444        self.assertEqual("(- (+ (+ a b) c) d)", found)
445
446
447    def testTailRecursion(self):
448        grammar = textwrap.dedent(
449            r'''
450            grammar T;
451            options {language=Python3;output=AST;}
452            s : a ;
453            a : atom ('exp'^ a)? ;
454            atom : INT ;
455            ID : 'a'..'z'+ ;
456            INT : '0'..'9'+;
457            WS : (' '|'\n') {$channel=HIDDEN} ;
458            ''')
459
460        found = self.execParser(grammar, "s", "3 exp 4 exp 5")
461        self.assertEqual("(exp 3 (exp 4 5))", found)
462
463
464    def testSet(self):
465        grammar = textwrap.dedent(
466            r'''
467            grammar T;
468            options {language=Python3;output=AST;}
469            a : ID|INT ;
470            ID : 'a'..'z'+ ;
471            INT : '0'..'9'+;
472            WS : (' '|'\n') {$channel=HIDDEN} ;
473            ''')
474
475        found = self.execParser(grammar, "a", "abc")
476        self.assertEqual("abc", found)
477
478
479    def testSetRoot(self):
480        grammar = textwrap.dedent(
481        r'''
482            grammar T;
483            options {language=Python3;output=AST;}
484            a : ('+' | '-')^ ID ;
485            ID : 'a'..'z'+ ;
486            INT : '0'..'9'+;
487            WS : (' '|'\n') {$channel=HIDDEN} ;
488            ''')
489
490        found = self.execParser(grammar, "a", "+abc")
491        self.assertEqual("(+ abc)", found)
492
493
494    @testbase.broken(
495        "FAILS until antlr.g rebuilt in v3", testbase.GrammarCompileError)
496    def testSetRootWithLabel(self):
497        grammar = textwrap.dedent(
498            r'''
499            grammar T;
500            options {language=Python3;output=AST;}
501            a : x=('+' | '-')^ ID ;
502            ID : 'a'..'z'+ ;
503            INT : '0'..'9'+;
504            WS : (' '|'\n') {$channel=HIDDEN} ;
505            ''')
506
507        found = self.execParser(grammar, "a", "+abc")
508        self.assertEqual("(+ abc)", found)
509
510
511    def testSetAsRuleRootInLoop(self):
512        grammar = textwrap.dedent(
513            r'''
514            grammar T;
515            options {language=Python3;output=AST;}
516            a : ID (('+'|'-')^ ID)* ;
517            ID : 'a'..'z'+ ;
518            INT : '0'..'9'+;
519            WS : (' '|'\n') {$channel=HIDDEN} ;
520            ''')
521
522        found = self.execParser(grammar, "a", "a+b-c")
523        self.assertEqual("(- (+ a b) c)", found)
524
525
526    def testNotSet(self):
527        grammar = textwrap.dedent(
528            r'''
529            grammar T;
530            options {language=Python3;output=AST;}
531            a : ~ID '+' INT ;
532            ID : 'a'..'z'+ ;
533            INT : '0'..'9'+;
534            WS : (' '|'\n') {$channel=HIDDEN} ;
535            ''')
536
537        found = self.execParser(grammar, "a", "34+2")
538        self.assertEqual("34 + 2", found)
539
540
541    def testNotSetWithLabel(self):
542        grammar = textwrap.dedent(
543            r'''
544            grammar T;
545            options {language=Python3;output=AST;}
546            a : x=~ID '+' INT ;
547            ID : 'a'..'z'+ ;
548            INT : '0'..'9'+;
549            WS : (' '|'\n') {$channel=HIDDEN} ;
550            ''')
551
552        found = self.execParser(grammar, "a", "34+2")
553        self.assertEqual("34 + 2", found)
554
555
556    def testNotSetWithListLabel(self):
557        grammar = textwrap.dedent(
558            r'''
559            grammar T;
560            options {language=Python3;output=AST;}
561            a : x=~ID '+' INT ;
562            ID : 'a'..'z'+ ;
563            INT : '0'..'9'+;
564            WS : (' '|'\n') {$channel=HIDDEN} ;
565            ''')
566
567        found = self.execParser(grammar, "a", "34+2")
568        self.assertEqual("34 + 2", found)
569
570
571    def testNotSetRoot(self):
572        grammar = textwrap.dedent(
573            r'''
574            grammar T;
575            options {language=Python3;output=AST;}
576            a : ~'+'^ INT ;
577            ID : 'a'..'z'+ ;
578            INT : '0'..'9'+;
579            WS : (' '|'\n') {$channel=HIDDEN} ;
580            ''')
581
582        found = self.execParser(grammar, "a", "34 55")
583        self.assertEqual("(34 55)", found)
584
585
586    def testNotSetRootWithLabel(self):
587        grammar = textwrap.dedent(
588            r'''
589            grammar T;
590            options {language=Python3;output=AST;}
591            a : ~'+'^ INT ;
592            ID : 'a'..'z'+ ;
593            INT : '0'..'9'+;
594            WS : (' '|'\n') {$channel=HIDDEN} ;
595            ''')
596
597        found = self.execParser(grammar, "a", "34 55")
598        self.assertEqual("(34 55)", found)
599
600
601    def testNotSetRootWithListLabel(self):
602        grammar = textwrap.dedent(
603            r'''
604            grammar T;
605            options {language=Python3;output=AST;}
606            a : ~'+'^ INT ;
607            ID : 'a'..'z'+ ;
608            INT : '0'..'9'+;
609            WS : (' '|'\n') {$channel=HIDDEN} ;
610            ''')
611
612        found = self.execParser(grammar, "a", "34 55")
613        self.assertEqual("(34 55)", found)
614
615
616    def testNotSetRuleRootInLoop(self):
617        grammar = textwrap.dedent(
618            r'''
619            grammar T;
620            options {language=Python3;output=AST;}
621            a : INT (~INT^ INT)* ;
622            blort : '+' ;
623            ID : 'a'..'z'+ ;
624            INT : '0'..'9'+;
625            WS : (' '|'\n') {$channel=HIDDEN} ;
626            ''')
627
628        found = self.execParser(grammar, "a", "3+4+5")
629        self.assertEqual("(+ (+ 3 4) 5)", found)
630
631
632    @testbase.broken("FIXME: What happened to the semicolon?", AssertionError)
633    def testTokenLabelReuse(self):
634        # check for compilation problem due to multiple defines
635        grammar = textwrap.dedent(
636            r'''
637            grammar T;
638            options {language=Python3;output=AST;}
639            a returns [result] : id=ID id=ID {$result = "2nd id="+$id.text+";"} ;
640            ID : 'a'..'z'+ ;
641            INT : '0'..'9'+;
642            WS : (' '|'\n') {$channel=HIDDEN} ;
643            ''')
644
645        found = self.execParser(grammar, "a", "a b")
646        self.assertEqual("2nd id=b;a b", found)
647
648
649    def testTokenLabelReuse2(self):
650        # check for compilation problem due to multiple defines
651        grammar = textwrap.dedent(
652            r'''
653            grammar T;
654            options {language=Python3;output=AST;}
655            a returns [result]: id=ID id=ID^ {$result = "2nd id="+$id.text+','} ;
656            ID : 'a'..'z'+ ;
657            INT : '0'..'9'+;
658            WS : (' '|'\n') {$channel=HIDDEN} ;
659            ''')
660
661        found = self.execParser(grammar, "a", "a b")
662        self.assertEqual("2nd id=b,(b a)", found)
663
664
665    def testTokenListLabelReuse(self):
666        # check for compilation problem due to multiple defines
667        # make sure ids has both ID tokens
668        grammar = textwrap.dedent(
669            r'''
670            grammar T;
671            options {language=Python3;output=AST;}
672            a returns [result] : ids+=ID ids+=ID {$result = "id list=[{}],".format(",".join([t.text for t in $ids]))} ;
673            ID : 'a'..'z'+ ;
674            INT : '0'..'9'+;
675            WS : (' '|'\n') {$channel=HIDDEN} ;
676            ''')
677
678        found = self.execParser(grammar, "a", "a b")
679        expecting = "id list=[a,b],a b"
680        self.assertEqual(expecting, found)
681
682
683    def testTokenListLabelReuse2(self):
684        # check for compilation problem due to multiple defines
685        # make sure ids has both ID tokens
686        grammar = textwrap.dedent(
687            r'''
688            grammar T;
689            options {language=Python3;output=AST;}
690            a returns [result] : ids+=ID^ ids+=ID {$result = "id list=[{}],".format(",".join([t.text for t in $ids]))} ;
691            ID : 'a'..'z'+ ;
692            INT : '0'..'9'+;
693            WS : (' '|'\n') {$channel=HIDDEN} ;
694            ''')
695
696        found = self.execParser(grammar, "a", "a b")
697        expecting = "id list=[a,b],(a b)"
698        self.assertEqual(expecting, found)
699
700
701    def testTokenListLabelRuleRoot(self):
702        grammar = textwrap.dedent(
703            r'''
704            grammar T;
705            options {language=Python3;output=AST;}
706            a : id+=ID^ ;
707            ID : 'a'..'z'+ ;
708            INT : '0'..'9'+;
709            WS : (' '|'\n') {$channel=HIDDEN} ;
710            ''')
711
712        found = self.execParser(grammar, "a", "a")
713        self.assertEqual("a", found)
714
715
716    def testTokenListLabelBang(self):
717        grammar = textwrap.dedent(
718            r'''
719            grammar T;
720            options {language=Python3;output=AST;}
721            a : id+=ID! ;
722            ID : 'a'..'z'+ ;
723            INT : '0'..'9'+;
724            WS : (' '|'\n') {$channel=HIDDEN} ;
725            ''')
726
727        found = self.execParser(grammar, "a", "a")
728        self.assertEqual("", found)
729
730
731    def testRuleListLabel(self):
732        grammar = textwrap.dedent(
733            r'''
734            grammar T;
735            options {language=Python3;output=AST;}
736            a returns [result]: x+=b x+=b {
737            t=$x[1]
738            $result = "2nd x="+t.toStringTree()+',';
739            };
740            b : ID;
741            ID : 'a'..'z'+ ;
742            INT : '0'..'9'+;
743            WS : (' '|'\n') {$channel=HIDDEN} ;
744            ''')
745
746        found = self.execParser(grammar, "a", "a b")
747        self.assertEqual("2nd x=b,a b", found)
748
749
750    def testRuleListLabelRuleRoot(self):
751        grammar = textwrap.dedent(
752            r'''
753            grammar T;
754            options {language=Python3;output=AST;}
755            a returns [result] : ( x+=b^ )+ {
756            $result = "x="+$x[1].toStringTree()+',';
757            } ;
758            b : ID;
759            ID : 'a'..'z'+ ;
760            INT : '0'..'9'+;
761            WS : (' '|'\n') {$channel=HIDDEN} ;
762            ''')
763
764        found = self.execParser(grammar, "a", "a b")
765        self.assertEqual("x=(b a),(b a)", found)
766
767
768    def testRuleListLabelBang(self):
769        grammar = textwrap.dedent(
770            r'''
771            grammar T;
772            options {language=Python3;output=AST;}
773            a returns [result] : x+=b! x+=b {
774            $result = "1st x="+$x[0].toStringTree()+',';
775            } ;
776            b : ID;
777            ID : 'a'..'z'+ ;
778            INT : '0'..'9'+;
779            WS : (' '|'\n') {$channel=HIDDEN} ;
780            ''')
781
782        found = self.execParser(grammar, "a", "a b")
783        self.assertEqual("1st x=a,b", found)
784
785
786    def testComplicatedMelange(self):
787        # check for compilation problem
788        grammar = textwrap.dedent(
789            r'''
790            grammar T;
791            options {language=Python3;output=AST;}
792            a : A b=B b=B c+=C c+=C D {s = $D.text} ;
793            A : 'a' ;
794            B : 'b' ;
795            C : 'c' ;
796            D : 'd' ;
797            WS : (' '|'\n') {$channel=HIDDEN} ;
798            ''')
799
800        found = self.execParser(grammar, "a", "a b b c c d")
801        self.assertEqual("a b b c c d", found)
802
803
804    def testReturnValueWithAST(self):
805        grammar = textwrap.dedent(
806            r'''
807            grammar foo;
808            options {language=Python3;output=AST;}
809            a returns [result] : ID b { $result = str($b.i) + '\n';} ;
810            b returns [i] : INT {$i=int($INT.text);} ;
811            ID : 'a'..'z'+ ;
812            INT : '0'..'9'+;
813            WS : (' '|'\n') {$channel=HIDDEN} ;
814            ''')
815
816        found = self.execParser(grammar, "a", "abc 34")
817        self.assertEqual("34\nabc 34", found)
818
819
820    def testSetLoop(self):
821        grammar = textwrap.dedent(
822            r'''
823            grammar T;
824            options { language=Python3;output=AST; }
825            r : (INT|ID)+ ;
826            ID : 'a'..'z' + ;
827            INT : '0'..'9' +;
828            WS: (' ' | '\n' | '\\t')+ {$channel = HIDDEN};
829            ''')
830
831        found = self.execParser(grammar, "r", "abc 34 d")
832        self.assertEqual("abc 34 d", found)
833
834
835    def testExtraTokenInSimpleDecl(self):
836        grammar = textwrap.dedent(
837            r'''
838            grammar foo;
839            options {language=Python3;output=AST;}
840            decl : type^ ID '='! INT ';'! ;
841            type : 'int' | 'float' ;
842            ID : 'a'..'z'+ ;
843            INT : '0'..'9'+;
844            WS : (' '|'\n') {$channel=HIDDEN} ;
845            ''')
846
847        found, errors = self.execParser(grammar, "decl", "int 34 x=1;",
848                                        expectErrors=True)
849        self.assertEqual(["line 1:4 extraneous input '34' expecting ID"],
850                         errors)
851        self.assertEqual("(int x 1)", found) # tree gets correct x and 1 tokens
852
853
854    def testMissingIDInSimpleDecl(self):
855        grammar = textwrap.dedent(
856            r'''
857            grammar foo;
858            options {language=Python3;output=AST;}
859            tokens {EXPR;}
860            decl : type^ ID '='! INT ';'! ;
861            type : 'int' | 'float' ;
862            ID : 'a'..'z'+ ;
863            INT : '0'..'9'+;
864            WS : (' '|'\n') {$channel=HIDDEN} ;
865            ''')
866
867        found, errors = self.execParser(grammar, "decl", "int =1;",
868                                        expectErrors=True)
869        self.assertEqual(["line 1:4 missing ID at '='"], errors)
870        self.assertEqual("(int <missing ID> 1)", found) # tree gets invented ID token
871
872
873    def testMissingSetInSimpleDecl(self):
874        grammar = textwrap.dedent(
875            r'''
876            grammar foo;
877            options {language=Python3;output=AST;}
878            tokens {EXPR;}
879            decl : type^ ID '='! INT ';'! ;
880            type : 'int' | 'float' ;
881            ID : 'a'..'z'+ ;
882            INT : '0'..'9'+;
883            WS : (' '|'\n') {$channel=HIDDEN} ;
884            ''')
885
886        found, errors = self.execParser(grammar, "decl", "x=1;",
887                                        expectErrors=True)
888        self.assertEqual(["line 1:0 mismatched input 'x' expecting set None"], errors)
889        self.assertEqual("(<error: x> x 1)", found) # tree gets invented ID token
890
891
892    def testMissingTokenGivesErrorNode(self):
893        grammar = textwrap.dedent(
894            r'''
895            grammar foo;
896            options {language=Python3;output=AST;}
897            a : ID INT ; // follow is EOF
898            ID : 'a'..'z'+ ;
899            INT : '0'..'9'+;
900            WS : (' '|'\n') {$channel=HIDDEN} ;
901            ''')
902
903        found, errors = self.execParser(grammar, "a", "abc", expectErrors=True)
904        self.assertEqual(["line 1:3 missing INT at '<EOF>'"], errors)
905        self.assertEqual("abc <missing INT>", found)
906
907
908    def testMissingTokenGivesErrorNodeInInvokedRule(self):
909        grammar = textwrap.dedent(
910            r'''
911            grammar foo;
912            options {language=Python3;output=AST;}
913            a : b ;
914            b : ID INT ; // follow should see EOF
915            ID : 'a'..'z'+ ;
916            INT : '0'..'9'+;
917            WS : (' '|'\n') {$channel=HIDDEN} ;
918            ''')
919
920        found, errors = self.execParser(grammar, "a", "abc", expectErrors=True)
921        self.assertEqual(["line 1:3 mismatched input '<EOF>' expecting INT"], errors)
922        self.assertEqual("<mismatched token: <EOF>, resync=abc>", found)
923
924
925    def testExtraTokenGivesErrorNode(self):
926        grammar = textwrap.dedent(
927            r'''
928            grammar foo;
929            options {language=Python3;output=AST;}
930            a : b c ;
931            b : ID ;
932            c : INT ;
933            ID : 'a'..'z'+ ;
934            INT : '0'..'9'+;
935            WS : (' '|'\n') {$channel=HIDDEN} ;
936            ''')
937
938        found, errors = self.execParser(grammar, "a", "abc ick 34",
939                                        expectErrors=True)
940        self.assertEqual(["line 1:4 extraneous input 'ick' expecting INT"],
941                          errors)
942        self.assertEqual("abc 34", found)
943
944
945    def testMissingFirstTokenGivesErrorNode(self):
946        grammar = textwrap.dedent(
947            r'''
948            grammar foo;
949            options {language=Python3;output=AST;}
950            a : ID INT ;
951            ID : 'a'..'z'+ ;
952            INT : '0'..'9'+;
953            WS : (' '|'\n') {$channel=HIDDEN} ;
954            ''')
955
956        found, errors = self.execParser(grammar, "a", "34", expectErrors=True)
957        self.assertEqual(["line 1:0 missing ID at '34'"], errors)
958        self.assertEqual("<missing ID> 34", found)
959
960
961    def testMissingFirstTokenGivesErrorNode2(self):
962        grammar = textwrap.dedent(
963            r'''
964            grammar foo;
965            options {language=Python3;output=AST;}
966            a : b c ;
967            b : ID ;
968            c : INT ;
969            ID : 'a'..'z'+ ;
970            INT : '0'..'9'+;
971            WS : (' '|'\n') {$channel=HIDDEN} ;
972            ''')
973
974        found, errors = self.execParser(grammar, "a", "34", expectErrors=True)
975
976        # finds an error at the first token, 34, and re-syncs.
977        # re-synchronizing does not consume a token because 34 follows
978        # ref to rule b (start of c). It then matches 34 in c.
979        self.assertEqual(["line 1:0 missing ID at '34'"], errors)
980        self.assertEqual("<missing ID> 34", found)
981
982
983    def testNoViableAltGivesErrorNode(self):
984        grammar = textwrap.dedent(
985            r'''
986            grammar foo;
987            options {language=Python3;output=AST;}
988            a : b | c ;
989            b : ID ;
990            c : INT ;
991            ID : 'a'..'z'+ ;
992            S : '*' ;
993            INT : '0'..'9'+;
994            WS : (' '|'\n') {$channel=HIDDEN} ;
995            ''')
996
997        found, errors = self.execParser(grammar, "a", "*", expectErrors=True)
998        self.assertEqual(["line 1:0 no viable alternative at input '*'"],
999                         errors)
1000        self.assertEqual("<unexpected: [@0,0:0='*',<S>,1:0], resync=*>",
1001                         found)
1002
1003
1004if __name__ == '__main__':
1005    unittest.main()
1006