1/*
2 * [The "BSD license"]
3 *  Copyright (c) 2010 Terence Parr
4 *  All rights reserved.
5 *
6 *  Redistribution and use in source and binary forms, with or without
7 *  modification, are permitted provided that the following conditions
8 *  are met:
9 *  1. Redistributions of source code must retain the above copyright
10 *      notice, this list of conditions and the following disclaimer.
11 *  2. Redistributions in binary form must reproduce the above copyright
12 *      notice, this list of conditions and the following disclaimer in the
13 *      documentation and/or other materials provided with the distribution.
14 *  3. The name of the author may not be used to endorse or promote products
15 *      derived from this software without specific prior written permission.
16 *
17 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28package org.antlr.test;
29
30import org.junit.Ignore;
31import org.junit.Test;
32
33public class TestAutoAST extends BaseTest {
34	protected boolean debug = false;
35
36	@Test public void testTokenList() throws Exception {
37		String grammar =
38			"grammar foo;\n" +
39			"options {output=AST;}\n" +
40			"a : ID INT ;\n" +
41			"ID : 'a'..'z'+ ;\n" +
42			"INT : '0'..'9'+;\n" +
43			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
44		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
45								  "a", "abc 34", debug);
46		assertEquals("abc 34\n", found);
47	}
48
49	@Test public void testTokenListInSingleAltBlock() throws Exception {
50		String grammar =
51			"grammar foo;\n" +
52			"options {output=AST;}\n" +
53			"a : (ID INT) ;\n" +
54			"ID : 'a'..'z'+ ;\n" +
55			"INT : '0'..'9'+;\n" +
56			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
57		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
58								  "a", "abc 34", debug);
59		assertEquals("abc 34\n", found);
60	}
61
62	@Test public void testSimpleRootAtOuterLevel() throws Exception {
63		String grammar =
64			"grammar foo;\n" +
65			"options {output=AST;}\n" +
66			"a : ID^ INT ;\n" +
67			"ID : 'a'..'z'+ ;\n" +
68			"INT : '0'..'9'+;\n" +
69			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
70		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
71								  "a", "abc 34", debug);
72		assertEquals("(abc 34)\n", found);
73	}
74
75	@Test public void testSimpleRootAtOuterLevelReverse() throws Exception {
76		String grammar =
77			"grammar T;\n" +
78			"options {output=AST;}\n" +
79			"a : INT ID^ ;\n" +
80			"ID : 'a'..'z'+ ;\n" +
81			"INT : '0'..'9'+;\n" +
82			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
83		String found = execParser("T.g", grammar, "TParser", "TLexer",
84								  "a", "34 abc", debug);
85		assertEquals("(abc 34)\n", found);
86	}
87
88	@Test public void testBang() throws Exception {
89		String grammar =
90			"grammar T;\n" +
91			"options {output=AST;}\n" +
92			"a : ID INT! ID! INT ;\n" +
93			"ID : 'a'..'z'+ ;\n" +
94			"INT : '0'..'9'+;\n" +
95			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
96		String found = execParser("T.g", grammar, "TParser", "TLexer",
97								  "a", "abc 34 dag 4532", debug);
98		assertEquals("abc 4532\n", found);
99	}
100
101	@Test public void testOptionalThenRoot() throws Exception {
102		String grammar =
103			"grammar T;\n" +
104			"options {output=AST;}\n" +
105			"a : ( ID INT )? ID^ ;\n" +
106			"ID : 'a'..'z'+ ;\n" +
107			"INT : '0'..'9'+;\n" +
108			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
109		String found = execParser("T.g", grammar, "TParser", "TLexer",
110								  "a", "a 1 b", debug);
111		assertEquals("(b a 1)\n", found);
112	}
113
114	@Test public void testLabeledStringRoot() throws Exception {
115		String grammar =
116			"grammar T;\n" +
117			"options {output=AST;}\n" +
118			"a : v='void'^ ID ';' ;\n" +
119			"ID : 'a'..'z'+ ;\n" +
120			"INT : '0'..'9'+;\n" +
121			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
122		String found = execParser("T.g", grammar, "TParser", "TLexer",
123								  "a", "void foo;", debug);
124		assertEquals("(void foo ;)\n", found);
125	}
126
127	@Test public void testWildcard() throws Exception {
128		String grammar =
129			"grammar T;\n" +
130			"options {output=AST;}\n" +
131			"a : v='void'^ . ';' ;\n" +
132			"ID : 'a'..'z'+ ;\n" +
133			"INT : '0'..'9'+;\n" +
134			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
135		String found = execParser("T.g", grammar, "TParser", "TLexer",
136								  "a", "void foo;", debug);
137		assertEquals("(void foo ;)\n", found);
138	}
139
140	@Test public void testWildcardRoot() throws Exception {
141		String grammar =
142			"grammar T;\n" +
143			"options {output=AST;}\n" +
144			"a : v='void' .^ ';' ;\n" +
145			"ID : 'a'..'z'+ ;\n" +
146			"INT : '0'..'9'+;\n" +
147			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
148		String found = execParser("T.g", grammar, "TParser", "TLexer",
149								  "a", "void foo;", debug);
150		assertEquals("(foo void ;)\n", found);
151	}
152
153	@Test public void testWildcardRootWithLabel() throws Exception {
154		String grammar =
155			"grammar T;\n" +
156			"options {output=AST;}\n" +
157			"a : v='void' x=.^ ';' ;\n" +
158			"ID : 'a'..'z'+ ;\n" +
159			"INT : '0'..'9'+;\n" +
160			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
161		String found = execParser("T.g", grammar, "TParser", "TLexer",
162								  "a", "void foo;", debug);
163		assertEquals("(foo void ;)\n", found);
164	}
165
166    @Test public void testWildcardRootWithListLabel() throws Exception {
167        String grammar =
168            "grammar T;\n" +
169            "options {output=AST;}\n" +
170            "a : v='void' x=.^ ';' ;\n" +
171            "ID : 'a'..'z'+ ;\n" +
172            "INT : '0'..'9'+;\n" +
173            "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
174        String found = execParser("T.g", grammar, "TParser", "TLexer",
175                                  "a", "void foo;", debug);
176        assertEquals("(foo void ;)\n", found);
177    }
178
179    @Test public void testWildcardBangWithListLabel() throws Exception {
180        String grammar =
181            "grammar T;\n" +
182            "options {output=AST;}\n" +
183            "a : v='void' x=.! ';' ;\n" +
184            "ID : 'a'..'z'+ ;\n" +
185            "INT : '0'..'9'+;\n" +
186            "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
187        String found = execParser("T.g", grammar, "TParser", "TLexer",
188                                  "a", "void foo;", debug);
189        assertEquals("void ;\n", found);
190    }
191
192	@Test public void testRootRoot() throws Exception {
193		String grammar =
194			"grammar T;\n" +
195			"options {output=AST;}\n" +
196			"a : ID^ INT^ ID ;\n" +
197			"ID : 'a'..'z'+ ;\n" +
198			"INT : '0'..'9'+;\n" +
199			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
200		String found = execParser("T.g", grammar, "TParser", "TLexer",
201								  "a", "a 34 c", debug);
202		assertEquals("(34 a c)\n", found);
203	}
204
205	@Test public void testRootRoot2() throws Exception {
206		String grammar =
207			"grammar T;\n" +
208			"options {output=AST;}\n" +
209			"a : ID INT^ ID^ ;\n" +
210			"ID : 'a'..'z'+ ;\n" +
211			"INT : '0'..'9'+;\n" +
212			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
213		String found = execParser("T.g", grammar, "TParser", "TLexer",
214								  "a", "a 34 c", debug);
215		assertEquals("(c (34 a))\n", found);
216	}
217
218	@Test public void testRootThenRootInLoop() throws Exception {
219		String grammar =
220			"grammar T;\n" +
221			"options {output=AST;}\n" +
222			"a : ID^ (INT '*'^ ID)+ ;\n" +
223			"ID  : 'a'..'z'+ ;\n" +
224			"INT : '0'..'9'+;\n" +
225			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
226		String found = execParser("T.g", grammar, "TParser", "TLexer",
227								  "a", "a 34 * b 9 * c", debug);
228		assertEquals("(* (* (a 34) b 9) c)\n", found);
229	}
230
231	@Test public void testNestedSubrule() throws Exception {
232		String grammar =
233			"grammar T;\n" +
234			"options {output=AST;}\n" +
235			"a : 'void' (({;}ID|INT) ID | 'null' ) ';' ;\n" +
236			"ID : 'a'..'z'+ ;\n" +
237			"INT : '0'..'9'+;\n" +
238			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
239		String found = execParser("T.g", grammar, "TParser", "TLexer",
240								  "a", "void a b;", debug);
241		assertEquals("void a b ;\n", found);
242	}
243
244	@Test public void testInvokeRule() throws Exception {
245		String grammar =
246			"grammar T;\n" +
247			"options {output=AST;}\n" +
248			"a  : type ID ;\n" +
249			"type : {;}'int' | 'float' ;\n" +
250			"ID : 'a'..'z'+ ;\n" +
251			"INT : '0'..'9'+;\n" +
252			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
253		String found = execParser("T.g", grammar, "TParser", "TLexer",
254								  "a", "int a", debug);
255		assertEquals("int a\n", found);
256	}
257
258	@Test public void testInvokeRuleAsRoot() throws Exception {
259		String grammar =
260			"grammar T;\n" +
261			"options {output=AST;}\n" +
262			"a  : type^ ID ;\n" +
263			"type : {;}'int' | 'float' ;\n" +
264			"ID : 'a'..'z'+ ;\n" +
265			"INT : '0'..'9'+;\n" +
266			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
267		String found = execParser("T.g", grammar, "TParser", "TLexer",
268								  "a", "int a", debug);
269		assertEquals("(int a)\n", found);
270	}
271
272	@Test public void testInvokeRuleAsRootWithLabel() throws Exception {
273		String grammar =
274			"grammar T;\n" +
275			"options {output=AST;}\n" +
276			"a  : x=type^ ID ;\n" +
277			"type : {;}'int' | 'float' ;\n" +
278			"ID : 'a'..'z'+ ;\n" +
279			"INT : '0'..'9'+;\n" +
280			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
281		String found = execParser("T.g", grammar, "TParser", "TLexer",
282								  "a", "int a", debug);
283		assertEquals("(int a)\n", found);
284	}
285
286	@Test public void testInvokeRuleAsRootWithListLabel() throws Exception {
287		String grammar =
288			"grammar T;\n" +
289			"options {output=AST;}\n" +
290			"a  : x+=type^ ID ;\n" +
291			"type : {;}'int' | 'float' ;\n" +
292			"ID : 'a'..'z'+ ;\n" +
293			"INT : '0'..'9'+;\n" +
294			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
295		String found = execParser("T.g", grammar, "TParser", "TLexer",
296								  "a", "int a", debug);
297		assertEquals("(int a)\n", found);
298	}
299
300	@Test public void testRuleRootInLoop() throws Exception {
301		String grammar =
302			"grammar T;\n" +
303			"options {output=AST;}\n" +
304			"a : ID ('+'^ ID)* ;\n" +
305			"ID : 'a'..'z'+ ;\n" +
306			"INT : '0'..'9'+;\n" +
307			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
308		String found = execParser("T.g", grammar, "TParser", "TLexer",
309								  "a", "a+b+c+d", debug);
310		assertEquals("(+ (+ (+ a b) c) d)\n", found);
311	}
312
313	@Test public void testRuleInvocationRuleRootInLoop() throws Exception {
314		String grammar =
315			"grammar T;\n" +
316			"options {output=AST;}\n" +
317			"a : ID (op^ ID)* ;\n" +
318			"op : {;}'+' | '-' ;\n" +
319			"ID : 'a'..'z'+ ;\n" +
320			"INT : '0'..'9'+;\n" +
321			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
322		String found = execParser("T.g", grammar, "TParser", "TLexer",
323								  "a", "a+b+c-d", debug);
324		assertEquals("(- (+ (+ a b) c) d)\n", found);
325	}
326
327	@Test public void testTailRecursion() throws Exception {
328		String grammar =
329			"grammar T;\n" +
330			"options {output=AST;}\n" +
331			"s : a ;\n" +
332			"a : atom ('exp'^ a)? ;\n" +
333			"atom : INT ;\n" +
334			"ID : 'a'..'z'+ ;\n" +
335			"INT : '0'..'9'+;\n" +
336			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
337		String found = execParser("T.g", grammar, "TParser", "TLexer",
338								  "s", "3 exp 4 exp 5", debug);
339		assertEquals("(exp 3 (exp 4 5))\n", found);
340	}
341
342	@Test public void testSet() throws Exception {
343		String grammar =
344			"grammar T;\n" +
345			"options {output=AST;}\n" +
346			"a : ID|INT ;\n" +
347			"ID : 'a'..'z'+ ;\n" +
348			"INT : '0'..'9'+;\n" +
349			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
350		String found = execParser("T.g", grammar, "TParser", "TLexer",
351								  "a", "abc", debug);
352		assertEquals("abc\n", found);
353	}
354
355	@Test public void testSetRoot() throws Exception {
356		String grammar =
357			"grammar T;\n" +
358			"options {output=AST;}\n" +
359			"a : ('+' | '-')^ ID ;\n" +
360			"ID : 'a'..'z'+ ;\n" +
361			"INT : '0'..'9'+;\n" +
362			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
363		String found = execParser("T.g", grammar, "TParser", "TLexer",
364								  "a", "+abc", debug);
365		assertEquals("(+ abc)\n", found);
366	}
367
368	@Ignore
369    // TODO: FAILS until I rebuild the antlr.g in v3
370    //
371    public void testSetRootWithLabel() throws Exception {
372
373		String grammar =
374			"grammar T;\n" +
375			"options {output=AST;}\n" +
376			"a : x=('+' | '-')^ ID ;\n" +
377			"ID : 'a'..'z'+ ;\n" +
378			"INT : '0'..'9'+;\n" +
379			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
380		String found = execParser("T.g", grammar, "TParser", "TLexer",
381								  "a", "+abc", debug);
382		assertEquals("(+ abc)\n", found);
383	}
384
385	@Test public void testSetAsRuleRootInLoop() throws Exception {
386		String grammar =
387			"grammar T;\n" +
388			"options {output=AST;}\n" +
389			"a : ID (('+'|'-')^ ID)* ;\n" +
390			"ID : 'a'..'z'+ ;\n" +
391			"INT : '0'..'9'+;\n" +
392			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
393		String found = execParser("T.g", grammar, "TParser", "TLexer",
394								  "a", "a+b-c", debug);
395		assertEquals("(- (+ a b) c)\n", found);
396	}
397
398	@Test public void testNotSet() throws Exception {
399		String grammar =
400			"grammar T;\n" +
401			"options {output=AST;}\n" +
402			"a : ~ID '+' INT ;\n" +
403			"ID : 'a'..'z'+ ;\n" +
404			"INT : '0'..'9'+;\n" +
405			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
406		String found = execParser("T.g", grammar, "TParser", "TLexer",
407								  "a", "34+2", debug);
408		assertEquals("34 + 2\n", found);
409	}
410
411	@Test public void testNotSetWithLabel() throws Exception {
412		String grammar =
413			"grammar T;\n" +
414			"options {output=AST;}\n" +
415			"a : x=~ID '+' INT ;\n" +
416			"ID : 'a'..'z'+ ;\n" +
417			"INT : '0'..'9'+;\n" +
418			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
419		String found = execParser("T.g", grammar, "TParser", "TLexer",
420								  "a", "34+2", debug);
421		assertEquals("34 + 2\n", found);
422	}
423
424	@Test public void testNotSetWithListLabel() throws Exception {
425		String grammar =
426			"grammar T;\n" +
427			"options {output=AST;}\n" +
428			"a : x=~ID '+' INT ;\n" +
429			"ID : 'a'..'z'+ ;\n" +
430			"INT : '0'..'9'+;\n" +
431			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
432		String found = execParser("T.g", grammar, "TParser", "TLexer",
433								  "a", "34+2", debug);
434		assertEquals("34 + 2\n", found);
435	}
436
437	@Test public void testNotSetRoot() throws Exception {
438		String grammar =
439			"grammar T;\n" +
440			"options {output=AST;}\n" +
441			"a : ~'+'^ INT ;\n" +
442			"ID : 'a'..'z'+ ;\n" +
443			"INT : '0'..'9'+;\n" +
444			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
445		String found = execParser("T.g", grammar, "TParser", "TLexer",
446								  "a", "34 55", debug);
447		assertEquals("(34 55)\n", found);
448	}
449
450	@Test public void testNotSetRootWithLabel() throws Exception {
451		String grammar =
452			"grammar T;\n" +
453			"options {output=AST;}\n" +
454			"a : ~'+'^ INT ;\n" +
455			"ID : 'a'..'z'+ ;\n" +
456			"INT : '0'..'9'+;\n" +
457			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
458		String found = execParser("T.g", grammar, "TParser", "TLexer",
459								  "a", "34 55", debug);
460		assertEquals("(34 55)\n", found);
461	}
462
463	@Test public void testNotSetRootWithListLabel() throws Exception {
464		String grammar =
465			"grammar T;\n" +
466			"options {output=AST;}\n" +
467			"a : ~'+'^ INT ;\n" +
468			"ID : 'a'..'z'+ ;\n" +
469			"INT : '0'..'9'+;\n" +
470			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
471		String found = execParser("T.g", grammar, "TParser", "TLexer",
472								  "a", "34 55", debug);
473		assertEquals("(34 55)\n", found);
474	}
475
476	@Test public void testNotSetRuleRootInLoop() throws Exception {
477		String grammar =
478			"grammar T;\n" +
479			"options {output=AST;}\n" +
480			"a : INT (~INT^ INT)* ;\n" +
481			"blort : '+' ;\n" +
482			"ID : 'a'..'z'+ ;\n" +
483			"INT : '0'..'9'+;\n" +
484			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
485		String found = execParser("T.g", grammar, "TParser", "TLexer",
486								  "a", "3+4+5", debug);
487		assertEquals("(+ (+ 3 4) 5)\n", found);
488	}
489
490	@Test public void testTokenLabelReuse() throws Exception {
491		// check for compilation problem due to multiple defines
492		String grammar =
493			"grammar T;\n" +
494			"options {output=AST;}\n" +
495			"a : id=ID id=ID {System.out.print(\"2nd id=\"+$id.text+';');} ;\n" +
496			"ID : 'a'..'z'+ ;\n" +
497			"INT : '0'..'9'+;\n" +
498			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
499		String found = execParser("T.g", grammar, "TParser", "TLexer",
500								  "a", "a b", debug);
501		assertEquals("2nd id=b;a b\n", found);
502	}
503
504	@Test public void testTokenLabelReuse2() throws Exception {
505		// check for compilation problem due to multiple defines
506		String grammar =
507			"grammar T;\n" +
508			"options {output=AST;}\n" +
509			"a : id=ID id=ID^ {System.out.print(\"2nd id=\"+$id.text+';');} ;\n" +
510			"ID : 'a'..'z'+ ;\n" +
511			"INT : '0'..'9'+;\n" +
512			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
513		String found = execParser("T.g", grammar, "TParser", "TLexer",
514								  "a", "a b", debug);
515		assertEquals("2nd id=b;(b a)\n", found);
516	}
517
518	@Test public void testTokenListLabelReuse() throws Exception {
519		// check for compilation problem due to multiple defines
520		// make sure ids has both ID tokens
521		String grammar =
522			"grammar T;\n" +
523			"options {output=AST;}\n" +
524			"a : ids+=ID ids+=ID {System.out.print(\"id list=\"+$ids+';');} ;\n" +
525			"ID : 'a'..'z'+ ;\n" +
526			"INT : '0'..'9'+;\n" +
527			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
528		String found = execParser("T.g", grammar, "TParser", "TLexer",
529								  "a", "a b", debug);
530		String expecting = "id list=[[@0,0:0='a',<4>,1:0], [@2,2:2='b',<4>,1:2]];a b\n";
531		assertEquals(expecting, found);
532	}
533
534	@Test public void testTokenListLabelReuse2() throws Exception {
535		// check for compilation problem due to multiple defines
536		// make sure ids has both ID tokens
537		String grammar =
538			"grammar T;\n" +
539			"options {output=AST;}\n" +
540			"a : ids+=ID^ ids+=ID {System.out.print(\"id list=\"+$ids+';');} ;\n" +
541			"ID : 'a'..'z'+ ;\n" +
542			"INT : '0'..'9'+;\n" +
543			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
544		String found = execParser("T.g", grammar, "TParser", "TLexer",
545								  "a", "a b", debug);
546		String expecting = "id list=[[@0,0:0='a',<4>,1:0], [@2,2:2='b',<4>,1:2]];(a b)\n";
547		assertEquals(expecting, found);
548	}
549
550	@Test public void testTokenListLabelRuleRoot() throws Exception {
551		String grammar =
552			"grammar T;\n" +
553			"options {output=AST;}\n" +
554			"a : id+=ID^ ;\n" +
555			"ID : 'a'..'z'+ ;\n" +
556			"INT : '0'..'9'+;\n" +
557			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
558		String found = execParser("T.g", grammar, "TParser", "TLexer",
559								  "a", "a", debug);
560		assertEquals("a\n", found);
561	}
562
563	@Test public void testTokenListLabelBang() throws Exception {
564		String grammar =
565			"grammar T;\n" +
566			"options {output=AST;}\n" +
567			"a : id+=ID! ;\n" +
568			"ID : 'a'..'z'+ ;\n" +
569			"INT : '0'..'9'+;\n" +
570			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
571		String found = execParser("T.g", grammar, "TParser", "TLexer",
572								  "a", "a", debug);
573		assertEquals("", found);
574	}
575
576	@Test public void testRuleListLabel() throws Exception {
577		String grammar =
578			"grammar T;\n" +
579			"options {output=AST;}\n" +
580			"a : x+=b x+=b {" +
581			"Tree t=(Tree)$x.get(1);" +
582			"System.out.print(\"2nd x=\"+t.toStringTree()+';');} ;\n" +
583			"b : ID;\n" +
584			"ID : 'a'..'z'+ ;\n" +
585			"INT : '0'..'9'+;\n" +
586			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
587		String found = execParser("T.g", grammar, "TParser", "TLexer",
588								  "a", "a b", debug);
589		assertEquals("2nd x=b;a b\n", found);
590	}
591
592	@Test public void testRuleListLabelRuleRoot() throws Exception {
593		String grammar =
594			"grammar T;\n" +
595			"options {output=AST;}\n" +
596			"a : ( x+=b^ )+ {" +
597			"System.out.print(\"x=\"+((CommonTree)$x.get(1)).toStringTree()+';');} ;\n" +
598			"b : ID;\n" +
599			"ID : 'a'..'z'+ ;\n" +
600			"INT : '0'..'9'+;\n" +
601			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
602		String found = execParser("T.g", grammar, "TParser", "TLexer",
603								  "a", "a b", debug);
604		assertEquals("x=(b a);(b a)\n", found);
605	}
606
607	@Test public void testRuleListLabelBang() throws Exception {
608		String grammar =
609			"grammar T;\n" +
610			"options {output=AST;}\n" +
611			"a : x+=b! x+=b {" +
612			"System.out.print(\"1st x=\"+((CommonTree)$x.get(0)).toStringTree()+';');} ;\n" +
613			"b : ID;\n" +
614			"ID : 'a'..'z'+ ;\n" +
615			"INT : '0'..'9'+;\n" +
616			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
617		String found = execParser("T.g", grammar, "TParser", "TLexer",
618								  "a", "a b", debug);
619		assertEquals("1st x=a;b\n", found);
620	}
621
622	@Test public void testComplicatedMelange() throws Exception {
623		// check for compilation problem
624		String grammar =
625			"grammar T;\n" +
626			"options {output=AST;}\n" +
627			"a : A b=B b=B c+=C c+=C D {String s = $D.text;} ;\n" +
628			"A : 'a' ;\n" +
629			"B : 'b' ;\n" +
630			"C : 'c' ;\n" +
631			"D : 'd' ;\n" +
632			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
633		String found = execParser("T.g", grammar, "TParser", "TLexer",
634								  "a", "a b b c c d", debug);
635		assertEquals("a b b c c d\n", found);
636	}
637
638	@Test public void testReturnValueWithAST() throws Exception {
639		String grammar =
640			"grammar foo;\n" +
641			"options {output=AST;}\n" +
642			"a : ID b {System.out.println($b.i);} ;\n" +
643			"b returns [int i] : INT {$i=Integer.parseInt($INT.text);} ;\n" +
644			"ID : 'a'..'z'+ ;\n" +
645			"INT : '0'..'9'+;\n" +
646			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
647		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
648								  "a", "abc 34", debug);
649		assertEquals("34\nabc 34\n", found);
650	}
651
652	@Test public void testSetLoop() throws Exception {
653		String grammar =
654			"grammar T;\n" +
655			"options { output=AST; }\n" +
656			"r : (INT|ID)+ ; \n" +
657			"ID : 'a'..'z' + ;\n" +
658			"INT : '0'..'9' +;\n" +
659			"WS: (' ' | '\\n' | '\\t')+ {$channel = HIDDEN;};\n";
660		String found = execParser("T.g", grammar, "TParser", "TLexer",
661								  "r", "abc 34 d", debug);
662		assertEquals("abc 34 d\n", found);
663	}
664
665	@Test public void testExtraTokenInSimpleDecl() throws Exception {
666		String grammar =
667			"grammar foo;\n" +
668			"options {output=AST;}\n" +
669			"decl : type^ ID '='! INT ';'! ;\n" +
670			"type : 'int' | 'float' ;\n" +
671			"ID : 'a'..'z'+ ;\n" +
672			"INT : '0'..'9'+;\n" +
673			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
674		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
675								  "decl", "int 34 x=1;", debug);
676		assertEquals("line 1:4 extraneous input '34' expecting ID\n", this.stderrDuringParse);
677		assertEquals("(int x 1)\n", found); // tree gets correct x and 1 tokens
678	}
679
680	@Test public void testMissingIDInSimpleDecl() throws Exception {
681		String grammar =
682			"grammar foo;\n" +
683			"options {output=AST;}\n" +
684			"tokens {EXPR;}\n" +
685			"decl : type^ ID '='! INT ';'! ;\n" +
686			"type : 'int' | 'float' ;\n" +
687			"ID : 'a'..'z'+ ;\n" +
688			"INT : '0'..'9'+;\n" +
689			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
690		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
691								  "decl", "int =1;", debug);
692		assertEquals("line 1:4 missing ID at '='\n", this.stderrDuringParse);
693		assertEquals("(int <missing ID> 1)\n", found); // tree gets invented ID token
694	}
695
696	@Test public void testMissingSetInSimpleDecl() throws Exception {
697		String grammar =
698			"grammar foo;\n" +
699			"options {output=AST;}\n" +
700			"tokens {EXPR;}\n" +
701			"decl : type^ ID '='! INT ';'! ;\n" +
702			"type : 'int' | 'float' ;\n" +
703			"ID : 'a'..'z'+ ;\n" +
704			"INT : '0'..'9'+;\n" +
705			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
706		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
707								  "decl", "x=1;", debug);
708		assertEquals("line 1:0 mismatched input 'x' expecting set null\n", this.stderrDuringParse);
709		assertEquals("(<error: x> x 1)\n", found); // tree gets invented ID token
710	}
711
712	@Test public void testMissingTokenGivesErrorNode() throws Exception {
713		String grammar =
714			"grammar foo;\n" +
715			"options {output=AST;}\n" +
716			"a : ID INT ;\n" + // follow is EOF
717			"ID : 'a'..'z'+ ;\n" +
718			"INT : '0'..'9'+;\n" +
719			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
720		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
721								  "a", "abc", debug);
722		assertEquals("line 1:3 missing INT at '<EOF>'\n", this.stderrDuringParse);
723		assertEquals("abc <missing INT>\n", found);
724	}
725
726	@Test public void testMissingTokenGivesErrorNodeInInvokedRule() throws Exception {
727		String grammar =
728			"grammar foo;\n" +
729			"options {output=AST;}\n" +
730			"a : b ;\n" +
731			"b : ID INT ;\n" + // follow should see EOF
732			"ID : 'a'..'z'+ ;\n" +
733			"INT : '0'..'9'+;\n" +
734			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
735		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
736								  "a", "abc", debug);
737		assertEquals("line 1:3 mismatched input '<EOF>' expecting INT\n", this.stderrDuringParse);
738		assertEquals("<mismatched token: [@1,3:3='<EOF>',<-1>,1:3], resync=abc>\n", found);
739	}
740
741	@Test public void testExtraTokenGivesErrorNode() throws Exception {
742		String grammar =
743			"grammar foo;\n" +
744			"options {output=AST;}\n" +
745			"a : b c ;\n" +
746			"b : ID ;\n" +
747			"c : INT ;\n" +
748			"ID : 'a'..'z'+ ;\n" +
749			"INT : '0'..'9'+;\n" +
750			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
751		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
752								  "a", "abc ick 34", debug);
753		assertEquals("line 1:4 extraneous input 'ick' expecting INT\n", this.stderrDuringParse);
754		assertEquals("abc 34\n", found);
755	}
756
757	@Test public void testMissingFirstTokenGivesErrorNode() throws Exception {
758		String grammar =
759			"grammar foo;\n" +
760			"options {output=AST;}\n" +
761			"a : ID INT ;\n" +
762			"ID : 'a'..'z'+ ;\n" +
763			"INT : '0'..'9'+;\n" +
764			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
765		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
766								  "a", "34", debug);
767		assertEquals("line 1:0 missing ID at '34'\n", this.stderrDuringParse);
768		assertEquals("<missing ID> 34\n", found);
769	}
770
771	@Test public void testMissingFirstTokenGivesErrorNode2() throws Exception {
772		String grammar =
773			"grammar foo;\n" +
774			"options {output=AST;}\n" +
775			"a : b c ;\n" +
776			"b : ID ;\n" +
777			"c : INT ;\n" +
778			"ID : 'a'..'z'+ ;\n" +
779			"INT : '0'..'9'+;\n" +
780			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
781		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
782								  "a", "34", debug);
783		// finds an error at the first token, 34, and re-syncs.
784		// re-synchronizing does not consume a token because 34 follows
785		// ref to rule b (start of c). It then matches 34 in c.
786		assertEquals("line 1:0 missing ID at '34'\n", this.stderrDuringParse);
787		assertEquals("<missing ID> 34\n", found);
788	}
789
790	@Test public void testNoViableAltGivesErrorNode() throws Exception {
791		String grammar =
792			"grammar foo;\n" +
793			"options {output=AST;}\n" +
794			"a : b | c ;\n" +
795			"b : ID ;\n" +
796			"c : INT ;\n" +
797			"ID : 'a'..'z'+ ;\n" +
798			"S : '*' ;\n" +
799			"INT : '0'..'9'+;\n" +
800			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
801		String found = execParser("foo.g", grammar, "fooParser", "fooLexer",
802								  "a", "*", debug);
803		assertEquals("line 1:0 no viable alternative at input '*'\n", this.stderrDuringParse);
804		assertEquals("<unexpected: [@0,0:0='*',<6>,1:0], resync=*>\n", found);
805	}
806
807
808	// S U P P O R T
809
810	public void _test() throws Exception {
811		String grammar =
812			"grammar T;\n" +
813			"options {output=AST;}\n" +
814			"a :  ;\n" +
815			"ID : 'a'..'z'+ ;\n" +
816			"INT : '0'..'9'+;\n" +
817			"WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
818		String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "abc 34", debug);
819		assertEquals("\n", found);
820	}
821
822}
823