TestAttributes.java revision 324c4644fee44b9898524c09511bd33c3f12e2df
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.antlr.Tool;
31import org.antlr.codegen.CodeGenerator;
32import org.antlr.grammar.v3.ANTLRParser;
33import org.antlr.grammar.v3.ActionTranslator;
34import org.antlr.runtime.CommonToken;
35import org.stringtemplate.v4.ST;
36import org.stringtemplate.v4.STGroup;
37import org.antlr.tool.*;
38import org.junit.Test;
39
40import java.io.StringReader;
41import java.util.ArrayList;
42import java.util.List;
43
44/** Check the $x, $x.y attributes.  For checking the actual
45 *  translation, assume the Java target.  This is still a great test
46 *  for the semantics of the $x.y stuff regardless of the target.
47 */
48public class TestAttributes extends BaseTest {
49
50	/** Public default constructor used by TestRig */
51	public TestAttributes() {
52	}
53
54	@Test public void testEscapedLessThanInAction() throws Exception {
55		Grammar g = new Grammar();
56		Tool antlr = newTool();
57		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
58		String action = "i<3; '<xmltag>'";
59		ActionTranslator translator = new ActionTranslator(generator,"a",
60			new CommonToken(ANTLRParser.ACTION,action),0);
61		String expecting = action;
62		String rawTranslation =
63			translator.translate();
64		STGroup templates =
65			new STGroup();
66		ST actionST = new ST(templates, "<action>");
67		actionST.add("action", rawTranslation);
68		String found = actionST.render();
69		assertEquals(expecting, found);
70	}
71
72	@Test public void testEscaped$InAction() throws Exception {
73		String action = "int \\$n; \"\\$in string\\$\"";
74		String expecting = "int $n; \"$in string$\"";
75		Grammar g = new Grammar(
76			"parser grammar t;\n"+
77				"@members {"+action+"}\n"+
78				"a[User u, int i]\n" +
79				"        : {"+action+"}\n" +
80				"        ;");
81		Tool antlr = newTool();
82		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
83		g.setCodeGenerator(generator);
84		generator.genRecognizer(); // forces load of templates
85		ActionTranslator translator =
86			new ActionTranslator(generator,
87				"a",
88				new CommonToken(ANTLRParser.ACTION,action),0);
89		String found = translator.translate();		assertEquals(expecting, found);
90	}
91
92	@Test public void testArguments() throws Exception {
93		String action = "$i; $i.x; $u; $u.x";
94		String expecting = "i; i.x; u; u.x";
95
96		ErrorQueue equeue = new ErrorQueue();
97		ErrorManager.setErrorListener(equeue);
98		Grammar g = new Grammar(
99			"parser grammar t;\n"+
100				"a[User u, int i]\n" +
101				"        : {"+action+"}\n" +
102				"        ;");
103		Tool antlr = newTool();
104		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
105		g.setCodeGenerator(generator);
106		generator.genRecognizer(); // forces load of templates
107		ActionTranslator translator = new ActionTranslator(generator,"a",
108			new CommonToken(ANTLRParser.ACTION,action),1);
109		String found = translator.translate();		assertEquals(expecting, found);
110
111		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
112	}
113
114	@Test public void testComplicatedArgParsing() throws Exception {
115		String action = "x, (*a).foo(21,33), 3.2+1, '\\n', "+
116			"\"a,oo\\nick\", {bl, \"fdkj\"eck}";
117		String expecting = "x, (*a).foo(21,33), 3.2+1, '\\n', \"a,oo\\nick\", {bl, \"fdkj\"eck}";
118
119		ErrorQueue equeue = new ErrorQueue();
120		ErrorManager.setErrorListener(equeue);
121
122		// now check in actual grammar.
123		Grammar g = new Grammar(
124			"parser grammar t;\n"+
125				"a[User u, int i]\n" +
126				"        : A a["+action+"] B\n" +
127				"        ;");
128		Tool antlr = newTool();
129		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
130		g.setCodeGenerator(generator);
131		generator.genRecognizer(); // forces load of templates
132		ActionTranslator translator = new ActionTranslator(generator,"a",
133			new CommonToken(ANTLRParser.ACTION,action),1);
134		String rawTranslation =	translator.translate();
135		assertEquals(expecting, rawTranslation);
136
137		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
138	}
139
140	@Test public void testBracketArgParsing() throws Exception {
141		ErrorQueue equeue = new ErrorQueue();
142		ErrorManager.setErrorListener(equeue);
143
144		// now check in actual grammar.
145		Grammar g = new Grammar(
146			"parser grammar t;\n"+
147				"a[String[\\] ick, int i]\n" +
148				"        : A \n"+
149				"        ;");
150		Tool antlr = newTool();
151		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
152		g.setCodeGenerator(generator);
153		generator.genRecognizer(); // forces load of templates
154		Rule r = g.getRule("a");
155		AttributeScope parameters = r.parameterScope;
156		List<Attribute> attrs = parameters.getAttributes();
157		assertEquals("attribute mismatch","String[] ick",attrs.get(0).decl.toString());
158		assertEquals("parameter name mismatch","ick",attrs.get(0).name);
159		assertEquals("declarator mismatch", "String[]", attrs.get(0).type);
160
161		assertEquals("attribute mismatch","int i",attrs.get(1).decl.toString());
162		assertEquals("parameter name mismatch","i",attrs.get(1).name);
163		assertEquals("declarator mismatch", "int", attrs.get(1).type);
164
165		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
166	}
167
168	@Test public void testStringArgParsing() throws Exception {
169		String action = "34, '{', \"it's<\", '\"', \"\\\"\", 19";
170		String expecting = "34, '{', \"it's<\", '\"', \"\\\"\", 19";
171
172		ErrorQueue equeue = new ErrorQueue();
173		ErrorManager.setErrorListener(equeue);
174
175		// now check in actual grammar.
176		Grammar g = new Grammar(
177			"parser grammar t;\n"+
178				"a[User u, int i]\n" +
179				"        : A a["+action+"] B\n" +
180				"        ;");
181		Tool antlr = newTool();
182		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
183		g.setCodeGenerator(generator);
184		generator.genRecognizer(); // forces load of templates
185		ActionTranslator translator = new ActionTranslator(generator,"a",
186			new CommonToken(ANTLRParser.ACTION,action),1);
187		String rawTranslation =	translator.translate();
188		assertEquals(expecting, rawTranslation);
189
190		List<String> expectArgs = new ArrayList<String>() {
191			{add("34");}
192			{add("'{'");}
193			{add("\"it's<\"");}
194			{add("'\"'");}
195			{add("\"\\\"\"");} // that's "\""
196			{add("19");}
197		};
198		List<String> actualArgs = CodeGenerator.getListOfArgumentsFromAction(action, ',');
199		assertEquals("args mismatch", expectArgs, actualArgs);
200
201		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
202	}
203
204	@Test public void testComplicatedSingleArgParsing() throws Exception {
205		String action = "(*a).foo(21,33,\",\")";
206		String expecting = "(*a).foo(21,33,\",\")";
207
208		ErrorQueue equeue = new ErrorQueue();
209		ErrorManager.setErrorListener(equeue);
210
211		// now check in actual grammar.
212		Grammar g = new Grammar(
213			"parser grammar t;\n"+
214				"a[User u, int i]\n" +
215				"        : A a["+action+"] B\n" +
216				"        ;");
217		Tool antlr = newTool();
218		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
219		g.setCodeGenerator(generator);
220		generator.genRecognizer(); // forces load of templates
221		ActionTranslator translator = new ActionTranslator(generator,"a",
222			new CommonToken(ANTLRParser.ACTION,action),1);
223		String rawTranslation =	translator.translate();
224		assertEquals(expecting, rawTranslation);
225
226		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
227	}
228
229	@Test public void testArgWithLT() throws Exception {
230		String action = "34<50";
231		String expecting = "34<50";
232
233		ErrorQueue equeue = new ErrorQueue();
234		ErrorManager.setErrorListener(equeue);
235
236		// now check in actual grammar.
237		Grammar g = new Grammar(
238			"parser grammar t;\n"+
239				"a[boolean b]\n" +
240				"        : A a["+action+"] B\n" +
241				"        ;");
242		Tool antlr = newTool();
243		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
244		g.setCodeGenerator(generator);
245		generator.genRecognizer(); // forces load of templates
246		ActionTranslator translator = new ActionTranslator(generator,"a",
247			new CommonToken(ANTLRParser.ACTION,action),1);
248		String rawTranslation =
249			translator.translate();
250		assertEquals(expecting, rawTranslation);
251
252		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
253	}
254
255	@Test public void testGenericsAsArgumentDefinition() throws Exception {
256		String action = "$foo.get(\"ick\");";
257		String expecting = "foo.get(\"ick\");";
258
259		ErrorQueue equeue = new ErrorQueue();
260		ErrorManager.setErrorListener(equeue);
261		String grammar =
262			"parser grammar T;\n"+
263				"a[HashMap<String,String> foo]\n" +
264				"        : {"+action+"}\n" +
265				"        ;";
266		Grammar g = new Grammar(grammar);
267		Rule ra = g.getRule("a");
268		List<Attribute> attrs = ra.parameterScope.getAttributes();
269		assertEquals("attribute mismatch","HashMap<String,String> foo",attrs.get(0).decl.toString());
270		assertEquals("parameter name mismatch","foo",attrs.get(0).name);
271		assertEquals("declarator mismatch", "HashMap<String,String>", attrs.get(0).type);
272
273		Tool antlr = newTool();
274		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
275		g.setCodeGenerator(generator);
276		generator.genRecognizer(); // forces load of templates
277		ActionTranslator translator = new ActionTranslator(generator,"a",
278			new CommonToken(ANTLRParser.ACTION,action),1);
279		String found = translator.translate();		assertEquals(expecting, found);
280
281		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
282	}
283
284	@Test public void testGenericsAsArgumentDefinition2() throws Exception {
285		String action = "$foo.get(\"ick\"); x=3;";
286		String expecting = "foo.get(\"ick\"); x=3;";
287
288		ErrorQueue equeue = new ErrorQueue();
289		ErrorManager.setErrorListener(equeue);
290		String grammar =
291			"parser grammar T;\n"+
292				"a[HashMap<String,String> foo, int x, List<String> duh]\n" +
293				"        : {"+action+"}\n" +
294				"        ;";
295		Grammar g = new Grammar(grammar);
296		Rule ra = g.getRule("a");
297		List<Attribute> attrs = ra.parameterScope.getAttributes();
298
299		assertEquals("attribute mismatch","HashMap<String,String> foo",attrs.get(0).decl.toString().trim());
300		assertEquals("parameter name mismatch","foo",attrs.get(0).name);
301		assertEquals("declarator mismatch", "HashMap<String,String>", attrs.get(0).type);
302
303		assertEquals("attribute mismatch","int x",attrs.get(1).decl.toString().trim());
304		assertEquals("parameter name mismatch","x",attrs.get(1).name);
305		assertEquals("declarator mismatch", "int", attrs.get(1).type);
306
307		assertEquals("attribute mismatch","List<String> duh",attrs.get(2).decl.toString().trim());
308		assertEquals("parameter name mismatch","duh",attrs.get(2).name);
309		assertEquals("declarator mismatch", "List<String>", attrs.get(2).type);
310
311		Tool antlr = newTool();
312		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
313		g.setCodeGenerator(generator);
314		generator.genRecognizer(); // forces load of templates
315		ActionTranslator translator = new ActionTranslator(generator,"a",
316			new CommonToken(ANTLRParser.ACTION,action),1);
317		String found = translator.translate();		assertEquals(expecting, found);
318
319		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
320	}
321
322	@Test public void testGenericsAsReturnValue() throws Exception {
323		ErrorQueue equeue = new ErrorQueue();
324		ErrorManager.setErrorListener(equeue);
325		String grammar =
326			"parser grammar T;\n"+
327				"a returns [HashMap<String,String> foo] : ;\n";
328		Grammar g = new Grammar(grammar);
329		Rule ra = g.getRule("a");
330		List<Attribute> attrs = ra.returnScope.getAttributes();
331		assertEquals("attribute mismatch","HashMap<String,String> foo",attrs.get(0).decl.toString());
332		assertEquals("parameter name mismatch","foo",attrs.get(0).name);
333		assertEquals("declarator mismatch", "HashMap<String,String>", attrs.get(0).type);
334
335		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
336	}
337
338	@Test public void testComplicatedArgParsingWithTranslation() throws Exception {
339		String action = "x, $A.text+\"3242\", (*$A).foo(21,33), 3.2+1, '\\n', "+
340			"\"a,oo\\nick\", {bl, \"fdkj\"eck}";
341		String expecting = "x, (A1!=null?A1.getText():null)+\"3242\", (*A1).foo(21,33), 3.2+1, '\\n', \"a,oo\\nick\", {bl, \"fdkj\"eck}";
342
343		ErrorQueue equeue = new ErrorQueue();
344		ErrorManager.setErrorListener(equeue);
345
346		// now check in actual grammar.
347		Grammar g = new Grammar(
348			"parser grammar t;\n"+
349				"a[User u, int i]\n" +
350				"        : A a["+action+"] B\n" +
351				"        ;");
352		Tool antlr = newTool();
353		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
354		g.setCodeGenerator(generator);
355		generator.genRecognizer(); // forces load of templates
356		ActionTranslator translator = new ActionTranslator(generator,"a",
357			new CommonToken(ANTLRParser.ACTION,action),1);
358		String found = translator.translate();		assertEquals(expecting, found);
359
360		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
361	}
362
363	/** $x.start refs are checked during translation not before so ANTLR misses
364	 the fact that rule r has refs to predefined attributes if the ref is after
365	 the def of the method or self-referential.  Actually would be ok if I didn't
366	 convert actions to strings; keep as templates.
367	 June 9, 2006: made action translation leave templates not strings
368	 */
369	@Test public void testRefToReturnValueBeforeRefToPredefinedAttr() throws Exception {
370		String action = "$x.foo";
371		String expecting = "(x!=null?x.foo:0)";
372
373		ErrorQueue equeue = new ErrorQueue();
374		ErrorManager.setErrorListener(equeue);
375		Grammar g = new Grammar(
376			"parser grammar t;\n"+
377				"a : x=b {"+action+"} ;\n" +
378				"b returns [int foo] : B {$b.start} ;\n");
379		Tool antlr = newTool();
380		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
381		g.setCodeGenerator(generator);
382		generator.genRecognizer(); // forces load of templates
383		ActionTranslator translator = new ActionTranslator(generator,"a",
384			new CommonToken(ANTLRParser.ACTION,action),1);
385		String found = translator.translate();
386		assertEquals(expecting, found);
387
388		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
389	}
390
391	@Test public void testRuleLabelBeforeRefToPredefinedAttr() throws Exception {
392		// As of Mar 2007, I'm removing unused labels.  Unfortunately,
393		// the action is not seen until code gen.  Can't see $x.text
394		// before stripping unused labels.  We really need to translate
395		// actions first so code gen logic can use info.
396		String action = "$x.text";
397		String expecting = "(x!=null?input.toString(x.start,x.stop):null)";
398
399		ErrorQueue equeue = new ErrorQueue();
400		ErrorManager.setErrorListener(equeue);
401		Grammar g = new Grammar(
402			"parser grammar t;\n"+
403				"a : x=b {###"+action+"!!!} ;\n" +
404				"b : B ;\n");
405		Tool antlr = newTool();
406
407		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
408		g.setCodeGenerator(generator);
409		generator.genRecognizer(); // codegen phase sets some vars we need
410		ST codeST = generator.getRecognizerST();
411		String code = codeST.render();
412		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
413		assertEquals(expecting, found);
414		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
415	}
416
417	@Test public void testInvalidArguments() throws Exception {
418		String action = "$x";
419		String expecting = action;
420
421		ErrorQueue equeue = new ErrorQueue();
422		ErrorManager.setErrorListener(equeue);
423		Grammar g = new Grammar(
424			"parser grammar t;\n"+
425				"a[User u, int i]\n" +
426				"        : {"+action+"}\n" +
427				"        ;");
428		Tool antlr = newTool();
429		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
430		ActionTranslator translator = new ActionTranslator(generator,
431			"a",
432			new CommonToken(ANTLRParser.ACTION,action),1);
433		String found = translator.translate();
434		assertEquals(expecting, found);
435
436		int expectedMsgID = ErrorManager.MSG_UNKNOWN_SIMPLE_ATTRIBUTE;
437		Object expectedArg = "x";
438		GrammarSemanticsMessage expectedMessage =
439			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
440		checkError(equeue, expectedMessage);
441	}
442
443	@Test public void testReturnValue() throws Exception {
444		String action = "$x.i";
445		String expecting = "x";
446
447		ErrorQueue equeue = new ErrorQueue();
448		ErrorManager.setErrorListener(equeue);
449		Grammar g = new Grammar(
450			"grammar t;\n"+
451				"a returns [int i]\n" +
452				"        : 'a'\n" +
453				"        ;\n" +
454				"b : x=a {"+action+"} ;\n");
455		Tool antlr = newTool();
456		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
457		g.setCodeGenerator(generator);
458		generator.genRecognizer(); // forces load of templates
459		ActionTranslator translator =
460			new ActionTranslator(generator,
461				"b",
462				new CommonToken(ANTLRParser.ACTION,action),1);
463		String found =	translator.translate();
464		assertEquals(expecting, found);
465
466		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
467	}
468
469	@Test public void testActionNotMovedToSynPred() throws Exception {
470		String action = "$b = true;";
471		String expecting = "retval.b = true;";
472
473		ErrorQueue equeue = new ErrorQueue();
474		ErrorManager.setErrorListener(equeue);
475		Grammar g = new Grammar(
476			"grammar t;\n"+
477			"options {output=AST;}\n" + // push b into retval struct
478			"a returns [boolean b]\n" +
479			"options {backtrack=true;}\n" +
480			"   : 'a' {"+action+"}\n" +
481			"   | 'a'\n" +
482			"   ;\n");
483		Tool antlr = newTool();
484		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
485		g.setCodeGenerator(generator);
486		generator.genRecognizer(); // forces load of templates
487		ActionTranslator translator =
488			new ActionTranslator(generator,
489				"a",
490				new CommonToken(ANTLRParser.ACTION,action),1);
491		String found =	translator.translate();
492		assertEquals(expecting, found);
493
494		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
495	}
496
497	@Test public void testReturnValueWithNumber() throws Exception {
498		String action = "$x.i1";
499		String expecting = "x";
500
501		ErrorQueue equeue = new ErrorQueue();
502		ErrorManager.setErrorListener(equeue);
503		Grammar g = new Grammar(
504			"grammar t;\n"+
505				"a returns [int i1]\n" +
506				"        : 'a'\n" +
507				"        ;\n" +
508				"b : x=a {"+action+"} ;\n");
509		Tool antlr = newTool();
510		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
511		g.setCodeGenerator(generator);
512		generator.genRecognizer(); // forces load of templates
513		ActionTranslator translator =
514			new ActionTranslator(generator,
515				"b",
516				new CommonToken(ANTLRParser.ACTION,action),1);
517		String found = translator.translate();
518		assertEquals(expecting, found);
519
520		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
521	}
522
523	@Test public void testReturnValues() throws Exception {
524		String action = "$i; $i.x; $u; $u.x";
525		String expecting = "retval.i; retval.i.x; retval.u; retval.u.x";
526
527		ErrorQueue equeue = new ErrorQueue();
528		ErrorManager.setErrorListener(equeue);
529		Grammar g = new Grammar(
530			"parser grammar t;\n"+
531				"a returns [User u, int i]\n" +
532				"        : {"+action+"}\n" +
533				"        ;");
534		Tool antlr = newTool();
535		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
536		g.setCodeGenerator(generator);
537		generator.genRecognizer(); // forces load of templates
538		ActionTranslator translator = new ActionTranslator(generator,"a",
539			new CommonToken(ANTLRParser.ACTION,action),1);
540		String found = translator.translate();
541		assertEquals(expecting, found);
542
543		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
544	}
545
546	/* regression test for ANTLR-46 */
547	@Test public void testReturnWithMultipleRuleRefs() throws Exception {
548		String action1 = "$obj = $rule2.obj;";
549		String action2 = "$obj = $rule3.obj;";
550		String expecting1 = "obj = rule21;";
551		String expecting2 = "obj = rule32;";
552
553		ErrorQueue equeue = new ErrorQueue();
554		ErrorManager.setErrorListener(equeue);
555		Grammar g = new Grammar(
556			"grammar t;\n" +
557				"rule1 returns [ Object obj ]\n" +
558				":	rule2 { "+action1+" }\n" +
559				"|	rule3 { "+action2+" }\n" +
560				";\n"+
561				"rule2 returns [ Object obj ]\n"+
562				":	foo='foo' { $obj = $foo.text; }\n"+
563				";\n"+
564				"rule3 returns [ Object obj ]\n"+
565				":	bar='bar' { $obj = $bar.text; }\n"+
566				";");
567		Tool antlr = newTool();
568		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
569		g.setCodeGenerator(generator);
570		generator.genRecognizer(); // forces load of templates
571		int i = 0;
572		String action = action1;
573		String expecting = expecting1;
574		do {
575			ActionTranslator translator = new ActionTranslator(generator,"rule1",
576				new CommonToken(ANTLRParser.ACTION,action),i+1);
577			String found = translator.translate();
578			assertEquals(expecting, found);
579			action = action2;
580			expecting = expecting2;
581		} while (i++ < 1);
582		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
583	}
584
585	@Test public void testInvalidReturnValues() throws Exception {
586		String action = "$x";
587		String expecting = action;
588
589		ErrorQueue equeue = new ErrorQueue();
590		ErrorManager.setErrorListener(equeue);
591		Grammar g = new Grammar(
592			"parser grammar t;\n"+
593				"a returns [User u, int i]\n" +
594				"        : {"+action+"}\n" +
595				"        ;");
596		Tool antlr = newTool();
597		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
598		ActionTranslator translator = new ActionTranslator(generator,"a",
599			new CommonToken(ANTLRParser.ACTION,action),1);
600		String found = translator.translate();
601		assertEquals(expecting, found);
602
603		int expectedMsgID = ErrorManager.MSG_UNKNOWN_SIMPLE_ATTRIBUTE;
604		Object expectedArg = "x";
605		GrammarSemanticsMessage expectedMessage =
606			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
607		checkError(equeue, expectedMessage);
608	}
609
610	@Test public void testTokenLabels() throws Exception {
611		String action = "$id; $f; $id.text; $id.getText(); $id.dork " +
612			"$id.type; $id.line; $id.pos; " +
613			"$id.channel; $id.index;";
614		String expecting = "id; f; (id!=null?id.getText():null); id.getText(); id.dork (id!=null?id.getType():0); (id!=null?id.getLine():0); (id!=null?id.getCharPositionInLine():0); (id!=null?id.getChannel():0); (id!=null?id.getTokenIndex():0);";
615
616		ErrorQueue equeue = new ErrorQueue();
617		ErrorManager.setErrorListener(equeue);
618		Grammar g = new Grammar(
619			"parser grammar t;\n"+
620				"a : id=ID f=FLOAT {"+action+"}\n" +
621				"  ;");
622		Tool antlr = newTool();
623		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
624		g.setCodeGenerator(generator);
625		generator.genRecognizer(); // forces load of templates
626		ActionTranslator translator = new ActionTranslator(generator,"a",
627			new CommonToken(ANTLRParser.ACTION,action),1);
628		String found = translator.translate();
629		assertEquals(expecting, found);
630
631		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
632	}
633
634	@Test public void testRuleLabels() throws Exception {
635		String action = "$r.x; $r.start;\n $r.stop;\n $r.tree; $a.x; $a.stop;";
636		String expecting = "(r!=null?r.x:0); (r!=null?((Token)r.start):null);" + newline +
637			"             (r!=null?((Token)r.stop):null);" + newline +
638			"             (r!=null?((Object)r.tree):null); (r!=null?r.x:0); (r!=null?((Token)r.stop):null);";
639
640		ErrorQueue equeue = new ErrorQueue();
641		ErrorManager.setErrorListener(equeue);
642		Grammar g = new Grammar(
643			"parser grammar t;\n"+
644				"a returns [int x]\n" +
645				"  :\n" +
646				"  ;\n"+
647				"b : r=a {###"+action+"!!!}\n" +
648				"  ;");
649		Tool antlr = newTool();
650		antlr.setOutputDirectory(null); // write to /dev/null
651		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
652		g.setCodeGenerator(generator);
653		generator.genRecognizer(); // codegen phase sets some vars we need
654		ST codeST = generator.getRecognizerST();
655		String code = codeST.render();
656		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
657		assertEquals(expecting, found);
658
659		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
660	}
661
662	@Test public void testAmbiguRuleRef() throws Exception {
663		ErrorQueue equeue = new ErrorQueue();
664		ErrorManager.setErrorListener(equeue);
665		Grammar g = new Grammar(
666			"parser grammar t;\n"+
667				"a : A a {$a.text} | B ;");
668		Tool antlr = newTool();
669		antlr.setOutputDirectory(null); // write to /dev/null
670		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
671		g.setCodeGenerator(generator);
672		generator.genRecognizer();
673
674		// error(132): <string>:2:9: reference $a is ambiguous; rule a is enclosing rule and referenced in the production
675		assertEquals("unexpected errors: "+equeue, 1, equeue.errors.size());
676	}
677
678	@Test public void testRuleLabelsWithSpecialToken() throws Exception {
679		String action = "$r.x; $r.start; $r.stop; $r.tree; $a.x; $a.stop;";
680		String expecting = "(r!=null?r.x:0); (r!=null?((MYTOKEN)r.start):null); (r!=null?((MYTOKEN)r.stop):null); (r!=null?((Object)r.tree):null); (r!=null?r.x:0); (r!=null?((MYTOKEN)r.stop):null);";
681
682		ErrorQueue equeue = new ErrorQueue();
683		ErrorManager.setErrorListener(equeue);
684		Grammar g = new Grammar(
685			"parser grammar t;\n"+
686				"options {TokenLabelType=MYTOKEN;}\n"+
687				"a returns [int x]\n" +
688				"  :\n" +
689				"  ;\n"+
690				"b : r=a {###"+action+"!!!}\n" +
691				"  ;");
692		Tool antlr = newTool();
693		antlr.setOutputDirectory(null); // write to /dev/null
694		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
695		g.setCodeGenerator(generator);
696		generator.genRecognizer(); // codegen phase sets some vars we need
697
698		ST codeST = generator.getRecognizerST();
699		String code = codeST.render();
700		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
701		assertEquals(expecting, found);
702
703		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
704	}
705
706	@Test public void testForwardRefRuleLabels() throws Exception {
707		String action = "$r.x; $r.start; $r.stop; $r.tree; $a.x; $a.tree;";
708		String expecting = "(r!=null?r.x:0); (r!=null?((Token)r.start):null); (r!=null?((Token)r.stop):null); (r!=null?((Object)r.tree):null); (r!=null?r.x:0); (r!=null?((Object)r.tree):null);";
709
710		ErrorQueue equeue = new ErrorQueue();
711		ErrorManager.setErrorListener(equeue);
712		Grammar g = new Grammar(
713			"parser grammar t;\n"+
714				"b : r=a {###"+action+"!!!}\n" +
715				"  ;\n" +
716				"a returns [int x]\n" +
717				"  : ;\n");
718		Tool antlr = newTool();
719		antlr.setOutputDirectory(null); // write to /dev/null
720		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
721		g.setCodeGenerator(generator);
722		generator.genRecognizer(); // codegen phase sets some vars we need
723
724		ST codeST = generator.getRecognizerST();
725		String code = codeST.render();
726		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
727		assertEquals(expecting, found);
728
729		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
730	}
731
732	@Test public void testInvalidRuleLabelAccessesParameter() throws Exception {
733		String action = "$r.z";
734		String expecting = action;
735
736		ErrorQueue equeue = new ErrorQueue();
737		ErrorManager.setErrorListener(equeue);
738		Grammar g = new Grammar(
739			"parser grammar t;\n"+
740				"a[int z] returns [int x]\n" +
741				"  :\n" +
742				"  ;\n"+
743				"b : r=a[3] {"+action+"}\n" +
744				"  ;");
745		Tool antlr = newTool();
746		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
747		ActionTranslator translator = new ActionTranslator(generator, "b",
748			new CommonToken(ANTLRParser.ACTION,action),1);
749		String found = translator.translate();		assertEquals(expecting, found);
750
751		int expectedMsgID = ErrorManager.MSG_INVALID_RULE_PARAMETER_REF;
752		Object expectedArg = "a";
753		Object expectedArg2 = "z";
754		GrammarSemanticsMessage expectedMessage =
755			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
756		checkError(equeue, expectedMessage);
757	}
758
759	@Test public void testInvalidRuleLabelAccessesScopeAttribute() throws Exception {
760		String action = "$r.n";
761		String expecting = action;
762
763		ErrorQueue equeue = new ErrorQueue();
764		ErrorManager.setErrorListener(equeue);
765		Grammar g = new Grammar(
766			"parser grammar t;\n"+
767				"a\n" +
768				"scope { int n; }\n" +
769				"  :\n" +
770				"  ;\n"+
771				"b : r=a[3] {"+action+"}\n" +
772				"  ;");
773		Tool antlr = newTool();
774		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
775		ActionTranslator translator = new ActionTranslator(generator, "b",
776			new CommonToken(ANTLRParser.ACTION,action),1);
777		String found = translator.translate();
778		assertEquals(expecting, found);
779
780		int expectedMsgID = ErrorManager.MSG_INVALID_RULE_SCOPE_ATTRIBUTE_REF;
781		Object expectedArg = "a";
782		Object expectedArg2 = "n";
783		GrammarSemanticsMessage expectedMessage =
784			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
785		checkError(equeue, expectedMessage);
786	}
787
788	@Test public void testInvalidRuleAttribute() throws Exception {
789		String action = "$r.blort";
790		String expecting = action;
791
792		ErrorQueue equeue = new ErrorQueue();
793		ErrorManager.setErrorListener(equeue);
794		Grammar g = new Grammar(
795			"parser grammar t;\n"+
796				"a[int z] returns [int x]\n" +
797				"  :\n" +
798				"  ;\n"+
799				"b : r=a[3] {"+action+"}\n" +
800				"  ;");
801		Tool antlr = newTool();
802		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
803		ActionTranslator translator = new ActionTranslator(generator, "b",
804			new CommonToken(ANTLRParser.ACTION,action),1);
805		String found = translator.translate();
806		assertEquals(expecting, found);
807
808		int expectedMsgID = ErrorManager.MSG_UNKNOWN_RULE_ATTRIBUTE;
809		Object expectedArg = "a";
810		Object expectedArg2 = "blort";
811		GrammarSemanticsMessage expectedMessage =
812			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
813		checkError(equeue, expectedMessage);
814	}
815
816	@Test public void testMissingRuleAttribute() throws Exception {
817		String action = "$r";
818		String expecting = action;
819
820		ErrorQueue equeue = new ErrorQueue();
821		ErrorManager.setErrorListener(equeue);
822		Grammar g = new Grammar(
823			"parser grammar t;\n"+
824				"a[int z] returns [int x]\n" +
825				"  :\n" +
826				"  ;\n"+
827				"b : r=a[3] {"+action+"}\n" +
828				"  ;");
829		Tool antlr = newTool();
830		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
831		ActionTranslator translator = new ActionTranslator(generator, "b",
832			new CommonToken(ANTLRParser.ACTION,action),1);
833		String rawTranslation =
834			translator.translate();
835
836		int expectedMsgID = ErrorManager.MSG_ISOLATED_RULE_SCOPE;
837		Object expectedArg = "r";
838		Object expectedArg2 = null;
839		GrammarSemanticsMessage expectedMessage =
840			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
841		checkError(equeue, expectedMessage);
842	}
843
844	@Test public void testMissingUnlabeledRuleAttribute() throws Exception {
845		String action = "$a";
846		String expecting = action;
847
848		ErrorQueue equeue = new ErrorQueue();
849		ErrorManager.setErrorListener(equeue);
850		Grammar g = new Grammar(
851			"parser grammar t;\n"+
852				"a returns [int x]:\n" +
853				"  ;\n"+
854				"b : a {"+action+"}\n" +
855				"  ;");
856		Tool antlr = newTool();
857		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
858		ActionTranslator translator = new ActionTranslator(generator, "b",
859			new CommonToken(ANTLRParser.ACTION,action),1);
860		String rawTranslation =
861			translator.translate();
862
863		int expectedMsgID = ErrorManager.MSG_ISOLATED_RULE_SCOPE;
864		Object expectedArg = "a";
865		GrammarSemanticsMessage expectedMessage =
866			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
867		checkError(equeue, expectedMessage);
868	}
869
870	@Test public void testNonDynamicAttributeOutsideRule() throws Exception {
871		String action = "public void foo() { $x; }";
872		String expecting = action;
873
874		ErrorQueue equeue = new ErrorQueue();
875		ErrorManager.setErrorListener(equeue);
876		Grammar g = new Grammar(
877			"parser grammar t;\n"+
878				"@members {'+action+'}\n" +
879				"a : ;\n");
880		Tool antlr = newTool();
881		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
882		ActionTranslator translator = new ActionTranslator(generator,
883			null,
884			new CommonToken(ANTLRParser.ACTION,action),0);
885		String found = translator.translate();		assertEquals(expecting, found);
886
887		int expectedMsgID = ErrorManager.MSG_ATTRIBUTE_REF_NOT_IN_RULE;
888		Object expectedArg = "x";
889		GrammarSemanticsMessage expectedMessage =
890			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
891		checkError(equeue, expectedMessage);
892	}
893
894	@Test public void testNonDynamicAttributeOutsideRule2() throws Exception {
895		String action = "public void foo() { $x.y; }";
896		String expecting = action;
897
898		ErrorQueue equeue = new ErrorQueue();
899		ErrorManager.setErrorListener(equeue);
900		Grammar g = new Grammar(
901			"parser grammar t;\n"+
902				"@members {'+action+'}\n" +
903				"a : ;\n");
904		Tool antlr = newTool();
905		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
906		ActionTranslator translator = new ActionTranslator(generator,
907			null,
908			new CommonToken(ANTLRParser.ACTION,action),0);
909		String found = translator.translate();
910		assertEquals(expecting, found);
911
912		int expectedMsgID = ErrorManager.MSG_ATTRIBUTE_REF_NOT_IN_RULE;
913		Object expectedArg = "x";
914		Object expectedArg2 = "y";
915		GrammarSemanticsMessage expectedMessage =
916			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
917		checkError(equeue, expectedMessage);
918	}
919
920	// D Y N A M I C A L L Y  S C O P E D  A T T R I B U T E S
921
922	@Test public void testBasicGlobalScope() throws Exception {
923		String action = "$Symbols::names.add($id.text);";
924		String expecting = "((Symbols_scope)Symbols_stack.peek()).names.add((id!=null?id.getText():null));";
925
926		ErrorQueue equeue = new ErrorQueue();
927		ErrorManager.setErrorListener(equeue);
928		Grammar g = new Grammar(
929			"grammar t;\n"+
930				"scope Symbols {\n" +
931				"  int n;\n" +
932				"  List names;\n" +
933				"}\n" +
934				"a scope Symbols; : (id=ID ';' {"+action+"} )+\n" +
935				"  ;\n" +
936				"ID : 'a';\n");
937		Tool antlr = newTool();
938		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
939		g.setCodeGenerator(generator);
940		generator.genRecognizer(); // forces load of templates
941		ActionTranslator translator = new ActionTranslator(generator,"a",
942			new CommonToken(ANTLRParser.ACTION,action),1);
943		String found = translator.translate();
944		assertEquals(expecting, found);
945
946		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
947	}
948
949	@Test public void testUnknownGlobalScope() throws Exception {
950		String action = "$Symbols::names.add($id.text);";
951
952		ErrorQueue equeue = new ErrorQueue();
953		ErrorManager.setErrorListener(equeue);
954		Grammar g = new Grammar(
955			"grammar t;\n"+
956				"a scope Symbols; : (id=ID ';' {"+action+"} )+\n" +
957				"  ;\n" +
958				"ID : 'a';\n");
959		Tool antlr = newTool();
960		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
961		g.setCodeGenerator(generator);
962		generator.genRecognizer(); // forces load of templates
963		ActionTranslator translator = new ActionTranslator(generator,"a",
964			new CommonToken(ANTLRParser.ACTION,action),1);
965
966		assertEquals("unexpected errors: "+equeue, 2, equeue.errors.size());
967
968		int expectedMsgID = ErrorManager.MSG_UNKNOWN_DYNAMIC_SCOPE;
969		Object expectedArg = "Symbols";
970		GrammarSemanticsMessage expectedMessage =
971			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
972		checkError(equeue, expectedMessage);
973	}
974
975	@Test public void testIndexedGlobalScope() throws Exception {
976		String action = "$Symbols[-1]::names.add($id.text);";
977		String expecting =
978			"((Symbols_scope)Symbols_stack.elementAt(Symbols_stack.size()-1-1)).names.add((id!=null?id.getText():null));";
979
980		ErrorQueue equeue = new ErrorQueue();
981		ErrorManager.setErrorListener(equeue);
982		Grammar g = new Grammar(
983			"grammar t;\n"+
984				"scope Symbols {\n" +
985				"  int n;\n" +
986				"  List names;\n" +
987				"}\n" +
988				"a scope Symbols; : (id=ID ';' {"+action+"} )+\n" +
989				"  ;\n" +
990				"ID : 'a';\n");
991		Tool antlr = newTool();
992		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
993		g.setCodeGenerator(generator);
994		generator.genRecognizer(); // forces load of templates
995		ActionTranslator translator = new ActionTranslator(generator,"a",
996			new CommonToken(ANTLRParser.ACTION,action),1);
997		String found = translator.translate();
998		assertEquals(expecting, found);
999
1000		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1001	}
1002
1003	@Test public void test0IndexedGlobalScope() throws Exception {
1004		String action = "$Symbols[0]::names.add($id.text);";
1005		String expecting =
1006			"((Symbols_scope)Symbols_stack.elementAt(0)).names.add((id!=null?id.getText():null));";
1007
1008		ErrorQueue equeue = new ErrorQueue();
1009		ErrorManager.setErrorListener(equeue);
1010		Grammar g = new Grammar(
1011			"grammar t;\n"+
1012				"scope Symbols {\n" +
1013				"  int n;\n" +
1014				"  List names;\n" +
1015				"}\n" +
1016				"a scope Symbols; : (id=ID ';' {"+action+"} )+\n" +
1017				"  ;\n" +
1018				"ID : 'a';\n");
1019		Tool antlr = newTool();
1020		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1021		g.setCodeGenerator(generator);
1022		generator.genRecognizer(); // forces load of templates
1023		ActionTranslator translator = new ActionTranslator(generator,"a",
1024			new CommonToken(ANTLRParser.ACTION,action),1);
1025		String found = translator.translate();
1026		assertEquals(expecting, found);
1027
1028		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1029	}
1030
1031	@Test public void testAbsoluteIndexedGlobalScope() throws Exception {
1032		String action = "$Symbols[3]::names.add($id.text);";
1033		String expecting =
1034			"((Symbols_scope)Symbols_stack.elementAt(3)).names.add((id!=null?id.getText():null));";
1035
1036		ErrorQueue equeue = new ErrorQueue();
1037		ErrorManager.setErrorListener(equeue);
1038		Grammar g = new Grammar(
1039			"grammar t;\n"+
1040				"scope Symbols {\n" +
1041				"  int n;\n" +
1042				"  List names;\n" +
1043				"}\n" +
1044				"a scope Symbols; : (id=ID ';' {"+action+"} )+\n" +
1045				"  ;\n" +
1046				"ID : 'a';\n");
1047		Tool antlr = newTool();
1048		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1049		g.setCodeGenerator(generator);
1050		generator.genRecognizer(); // forces load of templates
1051		ActionTranslator translator = new ActionTranslator(generator,"a",
1052			new CommonToken(ANTLRParser.ACTION,action),1);
1053		String found = translator.translate();
1054		assertEquals(expecting, found);
1055
1056		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1057	}
1058
1059	@Test public void testScopeAndAttributeWithUnderscore() throws Exception {
1060		String action = "$foo_bar::a_b;";
1061		String expecting = "((foo_bar_scope)foo_bar_stack.peek()).a_b;";
1062
1063		ErrorQueue equeue = new ErrorQueue();
1064		ErrorManager.setErrorListener(equeue);
1065		Grammar g = new Grammar(
1066			"grammar t;\n"+
1067				"scope foo_bar {\n" +
1068				"  int a_b;\n" +
1069				"}\n" +
1070				"a scope foo_bar; : (ID {"+action+"} )+\n" +
1071				"  ;\n" +
1072				"ID : 'a';\n");
1073		Tool antlr = newTool();
1074		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1075		g.setCodeGenerator(generator);
1076		generator.genRecognizer(); // forces load of templates
1077		ActionTranslator translator = new ActionTranslator(generator,"a",
1078			new CommonToken(ANTLRParser.ACTION,action),1);
1079		String found = translator.translate();
1080		assertEquals(expecting, found);
1081
1082		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1083	}
1084
1085	@Test public void testSharedGlobalScope() throws Exception {
1086		String action = "$Symbols::x;";
1087		String expecting = "((Symbols_scope)Symbols_stack.peek()).x;";
1088
1089		ErrorQueue equeue = new ErrorQueue();
1090		ErrorManager.setErrorListener(equeue);
1091		Grammar g = new Grammar(
1092			"grammar t;\n"+
1093				"scope Symbols {\n" +
1094				"  String x;\n" +
1095				"}\n" +
1096				"a\n"+
1097				"scope { int y; }\n"+
1098				"scope Symbols;\n" +
1099				" : b {"+action+"}\n" +
1100				" ;\n" +
1101				"b : ID {$Symbols::x=$ID.text} ;\n" +
1102				"ID : 'a';\n");
1103		Tool antlr = newTool();
1104		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1105		g.setCodeGenerator(generator);
1106		generator.genRecognizer(); // forces load of templates
1107		ActionTranslator translator = new ActionTranslator(generator,"a",
1108			new CommonToken(ANTLRParser.ACTION,action),1);
1109		String found = translator.translate();
1110		assertEquals(expecting, found);
1111
1112		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1113	}
1114
1115	@Test public void testGlobalScopeOutsideRule() throws Exception {
1116		String action = "public void foo() {$Symbols::names.add('foo');}";
1117		String expecting = "public void foo() {((Symbols_scope)Symbols_stack.peek()).names.add('foo');}";
1118
1119		ErrorQueue equeue = new ErrorQueue();
1120		ErrorManager.setErrorListener(equeue);
1121		Grammar g = new Grammar(
1122			"grammar t;\n"+
1123				"scope Symbols {\n" +
1124				"  int n;\n" +
1125				"  List names;\n" +
1126				"}\n" +
1127				"@members {'+action+'}\n" +
1128				"a : \n" +
1129				"  ;\n");
1130		Tool antlr = newTool();
1131		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1132		g.setCodeGenerator(generator);
1133		generator.genRecognizer(); // forces load of templates
1134		ActionTranslator translator = new ActionTranslator(generator,"a",
1135			new CommonToken(ANTLRParser.ACTION,action),1);
1136		String found = translator.translate();
1137		assertEquals(expecting, found);
1138
1139		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1140	}
1141
1142	@Test public void testRuleScopeOutsideRule() throws Exception {
1143		String action = "public void foo() {$a::name;}";
1144		String expecting = "public void foo() {((a_scope)a_stack.peek()).name;}";
1145
1146		ErrorQueue equeue = new ErrorQueue();
1147		ErrorManager.setErrorListener(equeue);
1148		Grammar g = new Grammar(
1149			"grammar t;\n"+
1150				"@members {"+action+"}\n" +
1151				"a\n" +
1152				"scope { String name; }\n" +
1153				"  : {foo();}\n" +
1154				"  ;\n");
1155		Tool antlr = newTool();
1156		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1157		g.setCodeGenerator(generator);
1158		generator.genRecognizer(); // forces load of templates
1159		ActionTranslator translator = new ActionTranslator(generator,
1160			null,
1161			new CommonToken(ANTLRParser.ACTION,action),0);
1162		String found = translator.translate();		assertEquals(expecting, found);
1163
1164		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1165	}
1166
1167	@Test public void testBasicRuleScope() throws Exception {
1168		String action = "$a::n;";
1169		String expecting = "((a_scope)a_stack.peek()).n;";
1170
1171		ErrorQueue equeue = new ErrorQueue();
1172		ErrorManager.setErrorListener(equeue);
1173		Grammar g = new Grammar(
1174			"grammar t;\n"+
1175				"a\n" +
1176				"scope {\n" +
1177				"  int n;\n" +
1178				"} : {"+action+"}\n" +
1179				"  ;\n");
1180		Tool antlr = newTool();
1181		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1182		g.setCodeGenerator(generator);
1183		generator.genRecognizer(); // forces load of templates
1184		ActionTranslator translator = new ActionTranslator(generator,"a",
1185			new CommonToken(ANTLRParser.ACTION,action),1);
1186		String found = translator.translate();
1187		assertEquals(expecting, found);
1188
1189		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1190	}
1191
1192	@Test public void testUnqualifiedRuleScopeAccessInsideRule() throws Exception {
1193		String action = "$n;";
1194		String expecting = action;
1195
1196		ErrorQueue equeue = new ErrorQueue();
1197		ErrorManager.setErrorListener(equeue);
1198		Grammar g = new Grammar(
1199			"grammar t;\n"+
1200				"a\n" +
1201				"scope {\n" +
1202				"  int n;\n" +
1203				"} : {"+action+"}\n" +
1204				"  ;\n");
1205		Tool antlr = newTool();
1206		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1207		g.setCodeGenerator(generator);
1208		generator.genRecognizer(); // forces load of templates
1209
1210		int expectedMsgID = ErrorManager.MSG_ISOLATED_RULE_ATTRIBUTE;
1211		Object expectedArg = "n";
1212		Object expectedArg2 = null;
1213		GrammarSemanticsMessage expectedMessage =
1214			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg,
1215				expectedArg2);
1216		checkError(equeue, expectedMessage);
1217	}
1218
1219	@Test public void testIsolatedDynamicRuleScopeRef() throws Exception {
1220		String action = "$a;"; // refers to stack not top of stack
1221		String expecting = "a_stack;";
1222
1223		ErrorQueue equeue = new ErrorQueue();
1224		ErrorManager.setErrorListener(equeue);
1225		Grammar g = new Grammar(
1226			"grammar t;\n"+
1227				"a\n" +
1228				"scope {\n" +
1229				"  int n;\n" +
1230				"} : b ;\n" +
1231				"b : {"+action+"}\n" +
1232				"  ;\n");
1233		Tool antlr = newTool();
1234		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1235		g.setCodeGenerator(generator);
1236		generator.genRecognizer(); // forces load of templates
1237		ActionTranslator translator = new ActionTranslator(generator, "b",
1238			new CommonToken(ANTLRParser.ACTION,action),1);
1239		String found = translator.translate();
1240		assertEquals(expecting, found);
1241
1242		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1243	}
1244
1245	@Test public void testDynamicRuleScopeRefInSubrule() throws Exception {
1246		String action = "$a::n;";
1247		String expecting = "((a_scope)a_stack.peek()).n;";
1248
1249		ErrorQueue equeue = new ErrorQueue();
1250		ErrorManager.setErrorListener(equeue);
1251		Grammar g = new Grammar(
1252			"grammar t;\n"+
1253				"a\n" +
1254				"scope {\n" +
1255				"  float n;\n" +
1256				"} : b ;\n" +
1257				"b : {"+action+"}\n" +
1258				"  ;\n");
1259		Tool antlr = newTool();
1260		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1261		g.setCodeGenerator(generator);
1262		generator.genRecognizer(); // forces load of templates
1263		ActionTranslator translator = new ActionTranslator(generator, "b",
1264			new CommonToken(ANTLRParser.ACTION,action),1);
1265		String found = translator.translate();
1266		assertEquals(expecting, found);
1267
1268		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1269	}
1270
1271	@Test public void testIsolatedGlobalScopeRef() throws Exception {
1272		String action = "$Symbols;";
1273		String expecting = "Symbols_stack;";
1274
1275		ErrorQueue equeue = new ErrorQueue();
1276		ErrorManager.setErrorListener(equeue);
1277		Grammar g = new Grammar(
1278			"grammar t;\n"+
1279				"scope Symbols {\n" +
1280				"  String x;\n" +
1281				"}\n" +
1282				"a\n"+
1283				"scope { int y; }\n"+
1284				"scope Symbols;\n" +
1285				" : b {"+action+"}\n" +
1286				" ;\n" +
1287				"b : ID {$Symbols::x=$ID.text} ;\n" +
1288				"ID : 'a';\n");
1289		Tool antlr = newTool();
1290		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1291		g.setCodeGenerator(generator);
1292		generator.genRecognizer(); // forces load of templates
1293		ActionTranslator translator = new ActionTranslator(generator,"a",
1294			new CommonToken(ANTLRParser.ACTION,action),1);
1295		String found = translator.translate();
1296		assertEquals(expecting, found);
1297
1298		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1299	}
1300
1301	@Test public void testRuleScopeFromAnotherRule() throws Exception {
1302		String action = "$a::n;"; // must be qualified
1303		String expecting = "((a_scope)a_stack.peek()).n;";
1304
1305		ErrorQueue equeue = new ErrorQueue();
1306		ErrorManager.setErrorListener(equeue);
1307		Grammar g = new Grammar(
1308			"grammar t;\n"+
1309				"a\n" +
1310				"scope {\n" +
1311				"  boolean n;\n" +
1312				"} : b\n" +
1313				"  ;\n" +
1314				"b : {"+action+"}\n" +
1315				"  ;\n");
1316		Tool antlr = newTool();
1317		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1318		g.setCodeGenerator(generator);
1319		generator.genRecognizer(); // forces load of templates
1320		ActionTranslator translator = new ActionTranslator(generator, "b",
1321			new CommonToken(ANTLRParser.ACTION,action),1);
1322		String found = translator.translate();
1323		assertEquals(expecting, found);
1324
1325		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1326	}
1327
1328	@Test public void testFullyQualifiedRefToCurrentRuleParameter() throws Exception {
1329		String action = "$a.i;";
1330		String expecting = "i;";
1331
1332		ErrorQueue equeue = new ErrorQueue();
1333		ErrorManager.setErrorListener(equeue);
1334		Grammar g = new Grammar(
1335			"grammar t;\n"+
1336				"a[int i]: {"+action+"}\n" +
1337				"  ;\n");
1338		Tool antlr = newTool();
1339		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1340		g.setCodeGenerator(generator);
1341		generator.genRecognizer(); // forces load of templates
1342		ActionTranslator translator = new ActionTranslator(generator,"a",
1343			new CommonToken(ANTLRParser.ACTION,action),1);
1344		String found = translator.translate();		assertEquals(expecting, found);
1345
1346		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1347	}
1348
1349	@Test public void testFullyQualifiedRefToCurrentRuleRetVal() throws Exception {
1350		String action = "$a.i;";
1351		String expecting = "retval.i;";
1352
1353		ErrorQueue equeue = new ErrorQueue();
1354		ErrorManager.setErrorListener(equeue);
1355		Grammar g = new Grammar(
1356			"grammar t;\n"+
1357				"a returns [int i, int j]: {"+action+"}\n" +
1358				"  ;\n");
1359		Tool antlr = newTool();
1360		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1361		g.setCodeGenerator(generator);
1362		generator.genRecognizer(); // forces load of templates
1363		ActionTranslator translator = new ActionTranslator(generator,"a",
1364			new CommonToken(ANTLRParser.ACTION,action),1);
1365		String found = translator.translate();
1366		assertEquals(expecting, found);
1367
1368		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1369	}
1370
1371	@Test public void testSetFullyQualifiedRefToCurrentRuleRetVal() throws Exception {
1372		String action = "$a.i = 1;";
1373		String expecting = "retval.i = 1;";
1374
1375		ErrorQueue equeue = new ErrorQueue();
1376		ErrorManager.setErrorListener(equeue);
1377		Grammar g = new Grammar(
1378			"grammar t;\n"+
1379				"a returns [int i, int j]: {"+action+"}\n" +
1380				"  ;\n");
1381		Tool antlr = newTool();
1382		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1383		g.setCodeGenerator(generator);
1384		generator.genRecognizer(); // forces load of templates
1385		ActionTranslator translator = new ActionTranslator(generator,"a",
1386			new CommonToken(ANTLRParser.ACTION,action),1);
1387		String found = translator.translate();
1388		assertEquals(expecting, found);
1389
1390		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1391	}
1392
1393	@Test public void testIsolatedRefToCurrentRule() throws Exception {
1394		String action = "$a;";
1395		String expecting = "";
1396
1397		ErrorQueue equeue = new ErrorQueue();
1398		ErrorManager.setErrorListener(equeue);
1399		Grammar g = new Grammar(
1400			"grammar t;\n"+
1401				"a : 'a' {"+action+"}\n" +
1402				"  ;\n");
1403		Tool antlr = newTool();
1404		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1405		g.setCodeGenerator(generator);
1406		generator.genRecognizer(); // forces load of templates
1407
1408		int expectedMsgID = ErrorManager.MSG_ISOLATED_RULE_SCOPE;
1409		Object expectedArg = "a";
1410		Object expectedArg2 = null;
1411		GrammarSemanticsMessage expectedMessage =
1412			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg,
1413				expectedArg2);
1414		checkError(equeue, expectedMessage);
1415	}
1416
1417	@Test public void testIsolatedRefToRule() throws Exception {
1418		String action = "$x;";
1419
1420		ErrorQueue equeue = new ErrorQueue();
1421		ErrorManager.setErrorListener(equeue);
1422		Grammar g = new Grammar(
1423			"grammar t;\n"+
1424				"a : x=b {"+action+"}\n" +
1425				"  ;\n" +
1426				"b : 'b' ;\n");
1427		Tool antlr = newTool();
1428		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1429		g.setCodeGenerator(generator);
1430		generator.genRecognizer(); // forces load of templates
1431
1432		int expectedMsgID = ErrorManager.MSG_ISOLATED_RULE_SCOPE;
1433		Object expectedArg = "x";
1434		GrammarSemanticsMessage expectedMessage =
1435			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
1436		checkError(equeue, expectedMessage);
1437	}
1438
1439	/*  I think these have to be errors $a.x makes no sense.
1440	@Test public void testFullyQualifiedRefToLabelInCurrentRule() throws Exception {
1441			String action = "$a.x;";
1442			String expecting = "x;";
1443
1444			ErrorQueue equeue = new ErrorQueue();
1445			ErrorManager.setErrorListener(equeue);
1446			Grammar g = new Grammar(
1447				"grammar t;\n"+
1448					"a : x='a' {"+action+"}\n" +
1449					"  ;\n");
1450			Tool antlr = newTool();
1451			CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1452			g.setCodeGenerator(generator);
1453			generator.genRecognizer(); // forces load of templates
1454			ActionTranslator translator = new ActionTranslator(generator,"a",
1455															   new CommonToken(ANTLRParser.ACTION,action),1);
1456			String rawTranslation =
1457				translator.translate();
1458			STGroup templates =
1459				new STGroup();
1460			ST actionST = new ST(templates, rawTranslation);
1461			String found = actionST.render();
1462			assertEquals(expecting, found);
1463
1464			assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1465		}
1466
1467	@Test public void testFullyQualifiedRefToListLabelInCurrentRule() throws Exception {
1468		String action = "$a.x;"; // must be qualified
1469		String expecting = "list_x;";
1470
1471		ErrorQueue equeue = new ErrorQueue();
1472		ErrorManager.setErrorListener(equeue);
1473		Grammar g = new Grammar(
1474			"grammar t;\n"+
1475				"a : x+='a' {"+action+"}\n" +
1476				"  ;\n");
1477		Tool antlr = newTool();
1478		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1479		g.setCodeGenerator(generator);
1480		generator.genRecognizer(); // forces load of templates
1481		ActionTranslator translator = new ActionTranslator(generator,"a",
1482														   new CommonToken(ANTLRParser.ACTION,action),1);
1483		String found = translator.translate();		assertEquals(expecting, found);
1484
1485		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1486	}
1487*/
1488	@Test public void testFullyQualifiedRefToTemplateAttributeInCurrentRule() throws Exception {
1489		String action = "$a.st;"; // can be qualified
1490		String expecting = "retval.st;";
1491
1492		ErrorQueue equeue = new ErrorQueue();
1493		ErrorManager.setErrorListener(equeue);
1494		Grammar g = new Grammar(
1495			"parser grammar t;\n" +
1496				"options {output=template;}\n"+
1497				"a : (A->{$A.text}) {"+action+"}\n" +
1498				"  ;\n");
1499		Tool antlr = newTool();
1500		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1501		g.setCodeGenerator(generator);
1502		generator.genRecognizer(); // forces load of templates
1503		ActionTranslator translator = new ActionTranslator(generator,"a",
1504			new CommonToken(ANTLRParser.ACTION,action),1);
1505		String found = translator.translate();
1506		assertEquals(expecting, found);
1507
1508		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1509	}
1510
1511	@Test public void testRuleRefWhenRuleHasScope() throws Exception {
1512		String action = "$b.start;";
1513		String expecting = "(b1!=null?((Token)b1.start):null);";
1514
1515		ErrorQueue equeue = new ErrorQueue();
1516		ErrorManager.setErrorListener(equeue);
1517		Grammar g = new Grammar(
1518			"grammar t;\n" +
1519				"a : b {###"+action+"!!!} ;\n" +
1520				"b\n" +
1521				"scope {\n" +
1522				"  int n;\n" +
1523				"} : 'b' \n" +
1524				"  ;\n");
1525		Tool antlr = newTool();
1526		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1527		g.setCodeGenerator(generator);
1528		generator.genRecognizer(); // forces load of templates
1529
1530		ST codeST = generator.getRecognizerST();
1531		String code = codeST.render();
1532		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
1533		assertEquals(expecting, found);
1534
1535		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1536	}
1537
1538	@Test public void testDynamicScopeRefOkEvenThoughRuleRefExists() throws Exception {
1539		String action = "$b::n;";
1540		String expecting = "((b_scope)b_stack.peek()).n;";
1541
1542		ErrorQueue equeue = new ErrorQueue();
1543		ErrorManager.setErrorListener(equeue);
1544		Grammar g = new Grammar(
1545			"grammar t;\n" +
1546				"s : b ;\n"+
1547				"b\n" +
1548				"scope {\n" +
1549				"  int n;\n" +
1550				"} : '(' b ')' {"+action+"}\n" + // refers to current invocation's n
1551				"  ;\n");
1552		Tool antlr = newTool();
1553		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1554		g.setCodeGenerator(generator);
1555		generator.genRecognizer(); // forces load of templates
1556		ActionTranslator translator = new ActionTranslator(generator, "b",
1557			new CommonToken(ANTLRParser.ACTION,action),1);
1558		String found = translator.translate();		assertEquals(expecting, found);
1559
1560		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1561	}
1562
1563	@Test public void testRefToTemplateAttributeForCurrentRule() throws Exception {
1564		String action = "$st=null;";
1565		String expecting = "retval.st =null;";
1566
1567		ErrorQueue equeue = new ErrorQueue();
1568		ErrorManager.setErrorListener(equeue);
1569		Grammar g = new Grammar(
1570			"parser grammar t;\n" +
1571				"options {output=template;}\n"+
1572				"a : {"+action+"}\n" +
1573				"  ;\n");
1574		Tool antlr = newTool();
1575		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1576		g.setCodeGenerator(generator);
1577		generator.genRecognizer(); // forces load of templates
1578		ActionTranslator translator = new ActionTranslator(generator,"a",
1579			new CommonToken(ANTLRParser.ACTION,action),1);
1580		String found = translator.translate();		assertEquals(expecting, found);
1581
1582		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1583	}
1584
1585	@Test public void testRefToTextAttributeForCurrentRule() throws Exception {
1586		String action = "$text";
1587		String expecting = "input.toString(retval.start,input.LT(-1))";
1588
1589		ErrorQueue equeue = new ErrorQueue();
1590		ErrorManager.setErrorListener(equeue);
1591		Grammar g = new Grammar(
1592			"parser grammar t;\n" +
1593				"options {output=template;}\n"+
1594				"a : {###"+action+"!!!}\n" +
1595				"  ;\n");
1596		Tool antlr = newTool();
1597		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1598		g.setCodeGenerator(generator);
1599		generator.genRecognizer(); // codegen phase sets some vars we need
1600		ST codeST = generator.getRecognizerST();
1601		String code = codeST.render();
1602		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
1603		assertEquals(expecting, found);
1604
1605		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1606	}
1607
1608	@Test public void testRefToStartAttributeForCurrentRule() throws Exception {
1609		String action = "$start;";
1610		String expecting = "((Token)retval.start);";
1611
1612		ErrorQueue equeue = new ErrorQueue();
1613		ErrorManager.setErrorListener(equeue);
1614		Grammar g = new Grammar(
1615			"parser grammar t;\n" +
1616				"a : {###"+action+"!!!}\n" +
1617				"  ;\n");
1618		Tool antlr = newTool();
1619		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1620		g.setCodeGenerator(generator);
1621		generator.genRecognizer(); // forces load of templates
1622		ActionTranslator translator = new ActionTranslator(generator,"a",
1623			new CommonToken(ANTLRParser.ACTION,action),1);
1624		ST codeST = generator.getRecognizerST();
1625		String code = codeST.render();
1626		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
1627		assertEquals(expecting, found);
1628
1629		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1630	}
1631
1632	@Test public void testTokenLabelFromMultipleAlts() throws Exception {
1633		String action = "$ID.text;"; // must be qualified
1634		String action2 = "$INT.text;"; // must be qualified
1635		String expecting = "(ID1!=null?ID1.getText():null);";
1636		String expecting2 = "(INT2!=null?INT2.getText():null);";
1637
1638		ErrorQueue equeue = new ErrorQueue();
1639		ErrorManager.setErrorListener(equeue);
1640		Grammar g = new Grammar(
1641			"grammar t;\n"+
1642				"a : ID {"+action+"}\n" +
1643				"  | INT {"+action2+"}\n" +
1644				"  ;\n" +
1645				"ID : 'a';\n" +
1646				"INT : '0';\n");
1647		Tool antlr = newTool();
1648		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1649		g.setCodeGenerator(generator);
1650		generator.genRecognizer(); // forces load of templates
1651		ActionTranslator translator = new ActionTranslator(generator,"a",
1652			new CommonToken(ANTLRParser.ACTION,action),1);
1653		String found = translator.translate();		assertEquals(expecting, found);
1654
1655		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1656		translator = new ActionTranslator(generator,
1657			"a",
1658			new CommonToken(ANTLRParser.ACTION,action2),2);
1659		found = translator.translate();
1660		assertEquals(expecting2, found);
1661
1662		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1663	}
1664
1665	@Test public void testRuleLabelFromMultipleAlts() throws Exception {
1666		String action = "$b.text;"; // must be qualified
1667		String action2 = "$c.text;"; // must be qualified
1668		String expecting = "(b1!=null?input.toString(b1.start,b1.stop):null);";
1669		String expecting2 = "(c2!=null?input.toString(c2.start,c2.stop):null);";
1670
1671		ErrorQueue equeue = new ErrorQueue();
1672		ErrorManager.setErrorListener(equeue);
1673		Grammar g = new Grammar(
1674			"grammar t;\n"+
1675				"a : b {###"+action+"!!!}\n" +
1676				"  | c {^^^"+action2+"&&&}\n" +
1677				"  ;\n" +
1678				"b : 'a';\n" +
1679				"c : '0';\n");
1680		Tool antlr = newTool();
1681		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1682		g.setCodeGenerator(generator);
1683		generator.genRecognizer(); // codegen phase sets some vars we need
1684		ST codeST = generator.getRecognizerST();
1685		String code = codeST.render();
1686		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
1687		assertEquals(expecting, found);
1688		found = code.substring(code.indexOf("^^^")+3,code.indexOf("&&&"));
1689		assertEquals(expecting2, found);
1690
1691		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1692	}
1693
1694	@Test public void testUnknownDynamicAttribute() throws Exception {
1695		String action = "$a::x";
1696		String expecting = action;
1697
1698		ErrorQueue equeue = new ErrorQueue();
1699		ErrorManager.setErrorListener(equeue);
1700		Grammar g = new Grammar(
1701			"grammar t;\n"+
1702				"a\n" +
1703				"scope {\n" +
1704				"  int n;\n" +
1705				"} : {"+action+"}\n" +
1706				"  ;\n");
1707		Tool antlr = newTool();
1708		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1709		g.setCodeGenerator(generator);
1710		generator.genRecognizer(); // forces load of templates
1711		ActionTranslator translator =
1712			new ActionTranslator(generator,
1713				"a",
1714				new CommonToken(ANTLRParser.ACTION,action),1);
1715		String found = translator.translate();		assertEquals(expecting, found);
1716
1717		int expectedMsgID = ErrorManager.MSG_UNKNOWN_DYNAMIC_SCOPE_ATTRIBUTE;
1718		Object expectedArg = "a";
1719		Object expectedArg2 = "x";
1720		GrammarSemanticsMessage expectedMessage =
1721			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
1722		checkError(equeue, expectedMessage);
1723	}
1724
1725	@Test public void testUnknownGlobalDynamicAttribute() throws Exception {
1726		String action = "$Symbols::x";
1727		String expecting = action;
1728
1729		ErrorQueue equeue = new ErrorQueue();
1730		ErrorManager.setErrorListener(equeue);
1731		Grammar g = new Grammar(
1732			"grammar t;\n"+
1733				"scope Symbols {\n" +
1734				"  int n;\n" +
1735				"}\n" +
1736				"a : {'+action+'}\n" +
1737				"  ;\n");
1738		Tool antlr = newTool();
1739		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1740		g.setCodeGenerator(generator);
1741		generator.genRecognizer(); // forces load of templates
1742		ActionTranslator translator =
1743			new ActionTranslator(generator,
1744				"a",
1745				new CommonToken(ANTLRParser.ACTION,action),1);
1746		String found = translator.translate();		assertEquals(expecting, found);
1747
1748		int expectedMsgID = ErrorManager.MSG_UNKNOWN_DYNAMIC_SCOPE_ATTRIBUTE;
1749		Object expectedArg = "Symbols";
1750		Object expectedArg2 = "x";
1751		GrammarSemanticsMessage expectedMessage =
1752			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
1753		checkError(equeue, expectedMessage);
1754	}
1755
1756	@Test public void testUnqualifiedRuleScopeAttribute() throws Exception {
1757		String action = "$n;"; // must be qualified
1758		String expecting = "$n;";
1759
1760		ErrorQueue equeue = new ErrorQueue();
1761		ErrorManager.setErrorListener(equeue);
1762		Grammar g = new Grammar(
1763			"grammar t;\n"+
1764				"a\n" +
1765				"scope {\n" +
1766				"  int n;\n" +
1767				"} : b\n" +
1768				"  ;\n" +
1769				"b : {'+action+'}\n" +
1770				"  ;\n");
1771		Tool antlr = newTool();
1772		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1773		ActionTranslator translator =
1774			new ActionTranslator(generator,
1775				"b",
1776				new CommonToken(ANTLRParser.ACTION,action),1);
1777		String found = translator.translate();		assertEquals(expecting, found);
1778
1779		int expectedMsgID = ErrorManager.MSG_UNKNOWN_SIMPLE_ATTRIBUTE;
1780		Object expectedArg = "n";
1781		Object expectedArg2 = null;
1782		GrammarSemanticsMessage expectedMessage =
1783			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
1784		checkError(equeue, expectedMessage);
1785	}
1786
1787	@Test public void testRuleAndTokenLabelTypeMismatch() throws Exception {
1788		ErrorQueue equeue = new ErrorQueue();
1789		ErrorManager.setErrorListener(equeue);
1790		Grammar g = new Grammar(
1791			"grammar t;\n"+
1792				"a : id='foo' id=b\n" +
1793				"  ;\n" +
1794				"b : ;\n");
1795		int expectedMsgID = ErrorManager.MSG_LABEL_TYPE_CONFLICT;
1796		Object expectedArg = "id";
1797		Object expectedArg2 = "rule!=token";
1798		GrammarSemanticsMessage expectedMessage =
1799			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
1800		checkError(equeue, expectedMessage);
1801	}
1802
1803	@Test public void testListAndTokenLabelTypeMismatch() throws Exception {
1804		ErrorQueue equeue = new ErrorQueue();
1805		ErrorManager.setErrorListener(equeue);
1806		Grammar g = new Grammar(
1807			"grammar t;\n"+
1808				"a : ids+='a' ids='b'\n" +
1809				"  ;\n" +
1810				"b : ;\n");
1811		int expectedMsgID = ErrorManager.MSG_LABEL_TYPE_CONFLICT;
1812		Object expectedArg = "ids";
1813		Object expectedArg2 = "token!=token-list";
1814		GrammarSemanticsMessage expectedMessage =
1815			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
1816		checkError(equeue, expectedMessage);
1817	}
1818
1819	@Test public void testListAndRuleLabelTypeMismatch() throws Exception {
1820		ErrorQueue equeue = new ErrorQueue();
1821		ErrorManager.setErrorListener(equeue);
1822		Grammar g = new Grammar(
1823			"grammar t;\n" +
1824				"options {output=AST;}\n"+
1825				"a : bs+=b bs=b\n" +
1826				"  ;\n" +
1827				"b : 'b';\n");
1828		int expectedMsgID = ErrorManager.MSG_LABEL_TYPE_CONFLICT;
1829		Object expectedArg = "bs";
1830		Object expectedArg2 = "rule!=rule-list";
1831		GrammarSemanticsMessage expectedMessage =
1832			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
1833		checkError(equeue, expectedMessage);
1834	}
1835
1836	@Test public void testArgReturnValueMismatch() throws Exception {
1837		ErrorQueue equeue = new ErrorQueue();
1838		ErrorManager.setErrorListener(equeue);
1839		Grammar g = new Grammar(
1840			"grammar t;\n"+
1841				"a[int i] returns [int x, int i]\n" +
1842				"  : \n" +
1843				"  ;\n" +
1844				"b : ;\n");
1845		int expectedMsgID = ErrorManager.MSG_ARG_RETVAL_CONFLICT;
1846		Object expectedArg = "i";
1847		Object expectedArg2 = "a";
1848		GrammarSemanticsMessage expectedMessage =
1849			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
1850		checkError(equeue, expectedMessage);
1851	}
1852
1853	@Test public void testSimplePlusEqualLabel() throws Exception {
1854		String action = "$ids.size();"; // must be qualified
1855		String expecting = "list_ids.size();";
1856
1857		ErrorQueue equeue = new ErrorQueue();
1858		ErrorManager.setErrorListener(equeue);
1859		Grammar g = new Grammar(
1860			"parser grammar t;\n"+
1861				"a : ids+=ID ( COMMA ids+=ID {"+action+"})* ;\n");
1862		Tool antlr = newTool();
1863		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1864		g.setCodeGenerator(generator);
1865		generator.genRecognizer(); // forces load of templates
1866		ActionTranslator translator =
1867			new ActionTranslator(generator,
1868				"a",
1869				new CommonToken(ANTLRParser.ACTION,action),1);
1870		String found = translator.translate();
1871		assertEquals(expecting, found);
1872
1873		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1874	}
1875
1876	@Test public void testPlusEqualStringLabel() throws Exception {
1877		String action = "$ids.size();"; // must be qualified
1878		String expecting = "list_ids.size();";
1879
1880		ErrorQueue equeue = new ErrorQueue();
1881		ErrorManager.setErrorListener(equeue);
1882		Grammar g = new Grammar(
1883			"grammar t;\n"+
1884				"a : ids+='if' ( ',' ids+=ID {"+action+"})* ;" +
1885				"ID : 'a';\n");
1886		Tool antlr = newTool();
1887		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1888		g.setCodeGenerator(generator);
1889		generator.genRecognizer(); // forces load of templates
1890		ActionTranslator translator =
1891			new ActionTranslator(generator,
1892				"a",
1893				new CommonToken(ANTLRParser.ACTION,action),1);
1894		String found = translator.translate();
1895		assertEquals(expecting, found);
1896
1897		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1898	}
1899
1900	@Test public void testPlusEqualSetLabel() throws Exception {
1901		String action = "$ids.size();"; // must be qualified
1902		String expecting = "list_ids.size();";
1903
1904		ErrorQueue equeue = new ErrorQueue();
1905		ErrorManager.setErrorListener(equeue);
1906		Grammar g = new Grammar(
1907			"grammar t;\n"+
1908				"a : ids+=('a'|'b') ( ',' ids+=ID {"+action+"})* ;" +
1909				"ID : 'a';\n");
1910		Tool antlr = newTool();
1911		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1912		g.setCodeGenerator(generator);
1913		generator.genRecognizer(); // forces load of templates
1914		ActionTranslator translator =
1915			new ActionTranslator(generator,
1916				"a",
1917				new CommonToken(ANTLRParser.ACTION,action),1);
1918		String found = translator.translate();
1919		assertEquals(expecting, found);
1920
1921		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1922	}
1923
1924	@Test public void testPlusEqualWildcardLabel() throws Exception {
1925		String action = "$ids.size();"; // must be qualified
1926		String expecting = "list_ids.size();";
1927
1928		ErrorQueue equeue = new ErrorQueue();
1929		ErrorManager.setErrorListener(equeue);
1930		Grammar g = new Grammar(
1931			"grammar t;\n"+
1932				"a : ids+=. ( ',' ids+=ID {"+action+"})* ;" +
1933				"ID : 'a';\n");
1934		Tool antlr = newTool();
1935		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1936		ActionTranslator translator =
1937			new ActionTranslator(generator,
1938				"a",
1939				new CommonToken(ANTLRParser.ACTION,action),1);
1940		g.setCodeGenerator(generator);
1941		generator.genRecognizer(); // forces load of templates
1942		String found = translator.translate();
1943		assertEquals(expecting, found);
1944
1945		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1946	}
1947
1948	@Test public void testImplicitTokenLabel() throws Exception {
1949		String action = "$ID; $ID.text; $ID.getText()";
1950		String expecting = "ID1; (ID1!=null?ID1.getText():null); ID1.getText()";
1951
1952		ErrorQueue equeue = new ErrorQueue();
1953		ErrorManager.setErrorListener(equeue);
1954		Grammar g = new Grammar(
1955			"grammar t;\n"+
1956				"a : ID {"+action+"} ;" +
1957				"ID : 'a';\n");
1958		Tool antlr = newTool();
1959		antlr.setOutputDirectory(null); // write to /dev/null
1960		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1961
1962		ActionTranslator translator =
1963			new ActionTranslator(generator,
1964				"a",
1965				new CommonToken(ANTLRParser.ACTION,action),1);
1966		g.setCodeGenerator(generator);
1967		generator.genRecognizer(); // forces load of templates
1968		String found = translator.translate();
1969		assertEquals(expecting, found);
1970
1971		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1972	}
1973
1974	@Test public void testImplicitRuleLabel() throws Exception {
1975		String action = "$r.start;";
1976		String expecting = "(r1!=null?((Token)r1.start):null);";
1977
1978		ErrorQueue equeue = new ErrorQueue();
1979		ErrorManager.setErrorListener(equeue);
1980		Grammar g = new Grammar(
1981			"grammar t;\n"+
1982				"a : r {###"+action+"!!!} ;" +
1983				"r : 'a';\n");
1984		Tool antlr = newTool();
1985		antlr.setOutputDirectory(null); // write to /dev/null
1986		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
1987		g.setCodeGenerator(generator);
1988		generator.genRecognizer();
1989
1990		ST codeST = generator.getRecognizerST();
1991		String code = codeST.render();
1992		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
1993		assertEquals(expecting, found);
1994
1995		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
1996	}
1997
1998	@Test public void testReuseExistingLabelWithImplicitRuleLabel() throws Exception {
1999		String action = "$r.start;";
2000		String expecting = "(x!=null?((Token)x.start):null);";
2001
2002		ErrorQueue equeue = new ErrorQueue();
2003		ErrorManager.setErrorListener(equeue);
2004		Grammar g = new Grammar(
2005			"grammar t;\n"+
2006				"a : x=r {###"+action+"!!!} ;" +
2007				"r : 'a';\n");
2008		Tool antlr = newTool();
2009		antlr.setOutputDirectory(null); // write to /dev/null
2010		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2011		g.setCodeGenerator(generator);
2012		generator.genRecognizer();
2013
2014		ST codeST = generator.getRecognizerST();
2015		String code = codeST.render();
2016		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
2017		assertEquals(expecting, found);
2018
2019		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2020	}
2021
2022	@Test public void testReuseExistingListLabelWithImplicitRuleLabel() throws Exception {
2023		String action = "$r.start;";
2024		String expecting = "(x!=null?((Token)x.start):null);";
2025
2026		ErrorQueue equeue = new ErrorQueue();
2027		ErrorManager.setErrorListener(equeue);
2028		Grammar g = new Grammar(
2029			"grammar t;\n"+
2030				"options {output=AST;}\n" +
2031				"a : x+=r {###"+action+"!!!} ;" +
2032				"r : 'a';\n");
2033		Tool antlr = newTool();
2034		antlr.setOutputDirectory(null); // write to /dev/null
2035		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2036		g.setCodeGenerator(generator);
2037		generator.genRecognizer();
2038
2039		ST codeST = generator.getRecognizerST();
2040		String code = codeST.render();
2041		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
2042		assertEquals(expecting, found);
2043
2044		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2045	}
2046
2047	@Test public void testReuseExistingLabelWithImplicitTokenLabel() throws Exception {
2048		String action = "$ID.text;";
2049		String expecting = "(x!=null?x.getText():null);";
2050
2051		ErrorQueue equeue = new ErrorQueue();
2052		ErrorManager.setErrorListener(equeue);
2053		Grammar g = new Grammar(
2054			"grammar t;\n"+
2055				"a : x=ID {"+action+"} ;" +
2056				"ID : 'a';\n");
2057		Tool antlr = newTool();
2058		antlr.setOutputDirectory(null); // write to /dev/null
2059		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2060		g.setCodeGenerator(generator);
2061		generator.genRecognizer();
2062
2063		ActionTranslator translator = new ActionTranslator(generator,"a",
2064			new CommonToken(ANTLRParser.ACTION,action),1);
2065		String found = translator.translate();
2066		assertEquals(expecting, found);
2067
2068		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2069	}
2070
2071	@Test public void testReuseExistingListLabelWithImplicitTokenLabel() throws Exception {
2072		String action = "$ID.text;";
2073		String expecting = "(x!=null?x.getText():null);";
2074
2075		ErrorQueue equeue = new ErrorQueue();
2076		ErrorManager.setErrorListener(equeue);
2077		Grammar g = new Grammar(
2078			"grammar t;\n"+
2079				"a : x+=ID {"+action+"} ;" +
2080				"ID : 'a';\n");
2081		Tool antlr = newTool();
2082		antlr.setOutputDirectory(null); // write to /dev/null
2083		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2084		g.setCodeGenerator(generator);
2085		generator.genRecognizer();
2086
2087		ActionTranslator translator = new ActionTranslator(generator,"a",
2088			new CommonToken(ANTLRParser.ACTION,action),1);
2089		String found = translator.translate();
2090		assertEquals(expecting, found);
2091
2092		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2093	}
2094
2095	@Test public void testRuleLabelWithoutOutputOption() throws Exception {
2096		ErrorQueue equeue = new ErrorQueue();
2097		ErrorManager.setErrorListener(equeue);
2098		Grammar g = new Grammar(
2099			"grammar T;\n"+
2100				"s : x+=a ;" +
2101				"a : 'a';\n"+
2102				"b : 'b';\n"+
2103				"WS : ' '|'\n';\n");
2104		Tool antlr = newTool();
2105		antlr.setOutputDirectory(null); // write to /dev/null
2106		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2107		g.setCodeGenerator(generator);
2108		generator.genRecognizer();
2109
2110		int expectedMsgID = ErrorManager.MSG_LIST_LABEL_INVALID_UNLESS_RETVAL_STRUCT;
2111		Object expectedArg = "x";
2112		Object expectedArg2 = null;
2113		GrammarSemanticsMessage expectedMessage =
2114			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2115		checkError(equeue, expectedMessage);
2116	}
2117
2118	@Test public void testRuleLabelOnTwoDifferentRulesAST() throws Exception {
2119		String grammar =
2120			"grammar T;\n"+
2121				"options {output=AST;}\n"+
2122				"s : x+=a x+=b {System.out.println($x);} ;" +
2123				"a : 'a';\n"+
2124				"b : 'b';\n"+
2125				"WS : (' '|'\\n') {skip();};\n";
2126		String expecting = "[a, b]\na b\n";
2127		String found = execParser("T.g", grammar, "TParser", "TLexer",
2128			"s", "a b", false);
2129		assertEquals(expecting, found);
2130	}
2131
2132	@Test public void testRuleLabelOnTwoDifferentRulesTemplate() throws Exception {
2133		String grammar =
2134			"grammar T;\n"+
2135				"options {output=template;}\n"+
2136				"s : x+=a x+=b {System.out.println($x);} ;" +
2137				"a : 'a' -> {%{\"hi\"}} ;\n"+
2138				"b : 'b' -> {%{\"mom\"}} ;\n"+
2139				"WS : (' '|'\\n') {skip();};\n";
2140		String expecting = "[hi, mom]\n";
2141		String found = execParser("T.g", grammar, "TParser", "TLexer",
2142			"s", "a b", false);
2143		assertEquals(expecting, found);
2144	}
2145
2146	@Test public void testMissingArgs() throws Exception {
2147		ErrorQueue equeue = new ErrorQueue();
2148		ErrorManager.setErrorListener(equeue);
2149		Grammar g = new Grammar(
2150			"grammar t;\n"+
2151				"a : r ;" +
2152				"r[int i] : 'a';\n");
2153		Tool antlr = newTool();
2154		antlr.setOutputDirectory(null); // write to /dev/null
2155		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2156		g.setCodeGenerator(generator);
2157		generator.genRecognizer();
2158
2159		int expectedMsgID = ErrorManager.MSG_MISSING_RULE_ARGS;
2160		Object expectedArg = "r";
2161		Object expectedArg2 = null;
2162		GrammarSemanticsMessage expectedMessage =
2163			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2164		checkError(equeue, expectedMessage);
2165	}
2166
2167	@Test public void testArgsWhenNoneDefined() throws Exception {
2168		ErrorQueue equeue = new ErrorQueue();
2169		ErrorManager.setErrorListener(equeue);
2170		Grammar g = new Grammar(
2171			"grammar t;\n"+
2172				"a : r[32,34] ;" +
2173				"r : 'a';\n");
2174		Tool antlr = newTool();
2175		antlr.setOutputDirectory(null); // write to /dev/null
2176		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2177		g.setCodeGenerator(generator);
2178		generator.genRecognizer();
2179
2180		int expectedMsgID = ErrorManager.MSG_RULE_HAS_NO_ARGS;
2181		Object expectedArg = "r";
2182		Object expectedArg2 = null;
2183		GrammarSemanticsMessage expectedMessage =
2184			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2185		checkError(equeue, expectedMessage);
2186	}
2187
2188	@Test public void testReturnInitValue() throws Exception {
2189		ErrorQueue equeue = new ErrorQueue();
2190		ErrorManager.setErrorListener(equeue);
2191		Grammar g = new Grammar(
2192			"grammar t;\n"+
2193				"a : r ;\n" +
2194				"r returns [int x=0] : 'a' {$x = 4;} ;\n");
2195		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2196
2197		Rule r = g.getRule("r");
2198		AttributeScope retScope = r.returnScope;
2199		List parameters = retScope.getAttributes();
2200		assertNotNull("missing return action", parameters);
2201		assertEquals(1, parameters.size());
2202		String found = parameters.get(0).toString();
2203		String expecting = "int x=0";
2204		assertEquals(expecting, found);
2205	}
2206
2207	@Test public void testMultipleReturnInitValue() throws Exception {
2208		ErrorQueue equeue = new ErrorQueue();
2209		ErrorManager.setErrorListener(equeue);
2210		Grammar g = new Grammar(
2211			"grammar t;\n"+
2212				"a : r ;\n" +
2213				"r returns [int x=0, int y, String s=new String(\"foo\")] : 'a' {$x = 4;} ;\n");
2214		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2215
2216		Rule r = g.getRule("r");
2217		AttributeScope retScope = r.returnScope;
2218		List parameters = retScope.getAttributes();
2219		assertNotNull("missing return action", parameters);
2220		assertEquals(3, parameters.size());
2221		assertEquals("int x=0", parameters.get(0).toString());
2222		assertEquals("int y", parameters.get(1).toString());
2223		assertEquals("String s=new String(\"foo\")", parameters.get(2).toString());
2224	}
2225
2226	@Test public void testCStyleReturnInitValue() throws Exception {
2227		ErrorQueue equeue = new ErrorQueue();
2228		ErrorManager.setErrorListener(equeue);
2229		Grammar g = new Grammar(
2230			"grammar t;\n"+
2231				"a : r ;\n" +
2232				"r returns [int (*x)()=NULL] : 'a' ;\n");
2233		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2234
2235		Rule r = g.getRule("r");
2236		AttributeScope retScope = r.returnScope;
2237		List parameters = retScope.getAttributes();
2238		assertNotNull("missing return action", parameters);
2239		assertEquals(1, parameters.size());
2240		String found = parameters.get(0).toString();
2241		String expecting = "int (*)() x=NULL";
2242		assertEquals(expecting, found);
2243	}
2244
2245	@Test public void testArgsWithInitValues() throws Exception {
2246		ErrorQueue equeue = new ErrorQueue();
2247		ErrorManager.setErrorListener(equeue);
2248		Grammar g = new Grammar(
2249			"grammar t;\n"+
2250				"a : r[32,34] ;" +
2251				"r[int x, int y=3] : 'a';\n");
2252		Tool antlr = newTool();
2253		antlr.setOutputDirectory(null); // write to /dev/null
2254		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2255		g.setCodeGenerator(generator);
2256		generator.genRecognizer();
2257
2258		int expectedMsgID = ErrorManager.MSG_ARG_INIT_VALUES_ILLEGAL;
2259		Object expectedArg = "y";
2260		Object expectedArg2 = null;
2261		GrammarSemanticsMessage expectedMessage =
2262			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2263		checkError(equeue, expectedMessage);
2264	}
2265
2266	@Test public void testArgsOnToken() throws Exception {
2267		ErrorQueue equeue = new ErrorQueue();
2268		ErrorManager.setErrorListener(equeue);
2269		Grammar g = new Grammar(
2270			"grammar t;\n"+
2271				"a : ID[32,34] ;" +
2272				"ID : 'a';\n");
2273		Tool antlr = newTool();
2274		antlr.setOutputDirectory(null); // write to /dev/null
2275		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2276		g.setCodeGenerator(generator);
2277		generator.genRecognizer();
2278
2279		int expectedMsgID = ErrorManager.MSG_ARGS_ON_TOKEN_REF;
2280		Object expectedArg = "ID";
2281		Object expectedArg2 = null;
2282		GrammarSemanticsMessage expectedMessage =
2283			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2284		checkError(equeue, expectedMessage);
2285	}
2286
2287	@Test public void testArgsOnTokenInLexer() throws Exception {
2288		ErrorQueue equeue = new ErrorQueue();
2289		ErrorManager.setErrorListener(equeue);
2290		Grammar g = new Grammar(
2291			"lexer grammar t;\n"+
2292				"R : 'z' ID[32,34] ;" +
2293				"ID : 'a';\n");
2294		Tool antlr = newTool();
2295		antlr.setOutputDirectory(null); // write to /dev/null
2296		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2297		g.setCodeGenerator(generator);
2298		generator.genRecognizer();
2299
2300		int expectedMsgID = ErrorManager.MSG_RULE_HAS_NO_ARGS;
2301		Object expectedArg = "ID";
2302		Object expectedArg2 = null;
2303		GrammarSemanticsMessage expectedMessage =
2304			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2305		checkError(equeue, expectedMessage);
2306	}
2307
2308	@Test public void testLabelOnRuleRefInLexer() throws Exception {
2309		String action = "$i.text";
2310		String expecting = "(i!=null?i.getText():null)";
2311		ErrorQueue equeue = new ErrorQueue();
2312		ErrorManager.setErrorListener(equeue);
2313		Grammar g = new Grammar(
2314			"lexer grammar t;\n"+
2315				"R : 'z' i=ID {"+action+"};" +
2316				"fragment ID : 'a';\n");
2317		Tool antlr = newTool();
2318		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2319		g.setCodeGenerator(generator);
2320		generator.genRecognizer(); // forces load of templates
2321		ActionTranslator translator =
2322			new ActionTranslator(generator,
2323				"R",
2324				new CommonToken(ANTLRParser.ACTION,action),1);
2325		String found = translator.translate();
2326		assertEquals(expecting, found);
2327
2328		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2329	}
2330
2331	@Test public void testRefToRuleRefInLexer() throws Exception {
2332		String action = "$ID.text";
2333		String expecting = "(ID1!=null?ID1.getText():null)";
2334		ErrorQueue equeue = new ErrorQueue();
2335		ErrorManager.setErrorListener(equeue);
2336		Grammar g = new Grammar(
2337			"lexer grammar t;\n"+
2338				"R : 'z' ID {"+action+"};" +
2339				"ID : 'a';\n");
2340		Tool antlr = newTool();
2341		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2342		g.setCodeGenerator(generator);
2343		generator.genRecognizer(); // forces load of templates
2344		ActionTranslator translator =
2345			new ActionTranslator(generator,
2346				"R",
2347				new CommonToken(ANTLRParser.ACTION,action),1);
2348		String found = translator.translate();
2349		assertEquals(expecting, found);
2350
2351		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2352	}
2353
2354	@Test public void testRefToRuleRefInLexerNoAttribute() throws Exception {
2355		String action = "$ID";
2356		String expecting = "ID1";
2357		ErrorQueue equeue = new ErrorQueue();
2358		ErrorManager.setErrorListener(equeue);
2359		Grammar g = new Grammar(
2360			"lexer grammar t;\n"+
2361				"R : 'z' ID {"+action+"};" +
2362				"ID : 'a';\n");
2363		Tool antlr = newTool();
2364		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2365		g.setCodeGenerator(generator);
2366		generator.genRecognizer(); // forces load of templates
2367		ActionTranslator translator =
2368			new ActionTranslator(generator,
2369				"R",
2370				new CommonToken(ANTLRParser.ACTION,action),1);
2371		String found = translator.translate();
2372		assertEquals(expecting, found);
2373
2374		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2375	}
2376
2377	@Test public void testCharLabelInLexer() throws Exception {
2378		ErrorQueue equeue = new ErrorQueue();
2379		ErrorManager.setErrorListener(equeue);
2380		Grammar g = new Grammar(
2381			"lexer grammar t;\n"+
2382				"R : x='z' ;\n");
2383
2384		Tool antlr = newTool();
2385		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2386		g.setCodeGenerator(generator);
2387		generator.genRecognizer(); // forces load of templates
2388
2389		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2390	}
2391
2392	@Test public void testCharListLabelInLexer() throws Exception {
2393		ErrorQueue equeue = new ErrorQueue();
2394		ErrorManager.setErrorListener(equeue);
2395		Grammar g = new Grammar(
2396			"lexer grammar t;\n"+
2397				"R : x+='z' ;\n");
2398
2399		Tool antlr = newTool();
2400		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2401		g.setCodeGenerator(generator);
2402		generator.genRecognizer(); // forces load of templates
2403		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2404	}
2405
2406	@Test public void testWildcardCharLabelInLexer() throws Exception {
2407		ErrorQueue equeue = new ErrorQueue();
2408		ErrorManager.setErrorListener(equeue);
2409		Grammar g = new Grammar(
2410			"lexer grammar t;\n"+
2411				"R : x=. ;\n");
2412
2413		Tool antlr = newTool();
2414		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2415		g.setCodeGenerator(generator);
2416		generator.genRecognizer(); // forces load of templates
2417		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2418	}
2419
2420	@Test public void testWildcardCharListLabelInLexer() throws Exception {
2421		ErrorQueue equeue = new ErrorQueue();
2422		ErrorManager.setErrorListener(equeue);
2423		Grammar g = new Grammar(
2424			"lexer grammar t;\n"+
2425				"R : x+=. ;\n");
2426
2427		Tool antlr = newTool();
2428		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2429		g.setCodeGenerator(generator);
2430		generator.genRecognizer(); // forces load of templates
2431		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2432	}
2433
2434	@Test public void testMissingArgsInLexer() throws Exception {
2435		ErrorQueue equeue = new ErrorQueue();
2436		ErrorManager.setErrorListener(equeue);
2437		Grammar g = new Grammar(
2438			"lexer grammar t;\n"+
2439				"A : R ;" +
2440				"R[int i] : 'a';\n");
2441		Tool antlr = newTool();
2442		antlr.setOutputDirectory(null); // write to /dev/null
2443		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2444		g.setCodeGenerator(generator);
2445		generator.genRecognizer();
2446
2447		int expectedMsgID = ErrorManager.MSG_MISSING_RULE_ARGS;
2448		Object expectedArg = "R";
2449		Object expectedArg2 = null;
2450		// getting a second error @1:12, probably from nextToken
2451		GrammarSemanticsMessage expectedMessage =
2452			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2453		checkError(equeue, expectedMessage);
2454	}
2455
2456	@Test public void testLexerRulePropertyRefs() throws Exception {
2457		String action = "$text $type $line $pos $channel $index $start $stop";
2458		String expecting = "getText() _type state.tokenStartLine state.tokenStartCharPositionInLine _channel -1 state.tokenStartCharIndex (getCharIndex()-1)";
2459		ErrorQueue equeue = new ErrorQueue();
2460		ErrorManager.setErrorListener(equeue);
2461		Grammar g = new Grammar(
2462			"lexer grammar t;\n"+
2463				"R : 'r' {"+action+"};\n");
2464		Tool antlr = newTool();
2465		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2466		g.setCodeGenerator(generator);
2467		generator.genRecognizer(); // forces load of templates
2468		ActionTranslator translator =
2469			new ActionTranslator(generator,
2470				"R",
2471				new CommonToken(ANTLRParser.ACTION,action),1);
2472		String found = translator.translate();
2473		assertEquals(expecting, found);
2474
2475		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2476	}
2477
2478	@Test public void testLexerLabelRefs() throws Exception {
2479		String action = "$a $b.text $c $d.text";
2480		String expecting = "a (b!=null?b.getText():null) c (d!=null?d.getText():null)";
2481		ErrorQueue equeue = new ErrorQueue();
2482		ErrorManager.setErrorListener(equeue);
2483		Grammar g = new Grammar(
2484			"lexer grammar t;\n"+
2485				"R : a='c' b='hi' c=. d=DUH {"+action+"};\n" +
2486				"DUH : 'd' ;\n");
2487		Tool antlr = newTool();
2488		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2489		g.setCodeGenerator(generator);
2490		generator.genRecognizer(); // forces load of templates
2491		ActionTranslator translator =
2492			new ActionTranslator(generator,
2493				"R",
2494				new CommonToken(ANTLRParser.ACTION,action),1);
2495		String found = translator.translate();
2496		assertEquals(expecting, found);
2497
2498		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2499	}
2500
2501	@Test public void testSettingLexerRulePropertyRefs() throws Exception {
2502		String action = "$text $type=1 $line=1 $pos=1 $channel=1 $index";
2503		String expecting = "getText() _type=1 state.tokenStartLine=1 state.tokenStartCharPositionInLine=1 _channel=1 -1";
2504		ErrorQueue equeue = new ErrorQueue();
2505		ErrorManager.setErrorListener(equeue);
2506		Grammar g = new Grammar(
2507			"lexer grammar t;\n"+
2508				"R : 'r' {"+action+"};\n");
2509		Tool antlr = newTool();
2510		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2511		g.setCodeGenerator(generator);
2512		generator.genRecognizer(); // forces load of templates
2513		ActionTranslator translator =
2514			new ActionTranslator(generator,
2515				"R",
2516				new CommonToken(ANTLRParser.ACTION,action),1);
2517		String found = translator.translate();
2518		assertEquals(expecting, found);
2519
2520		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2521	}
2522
2523	@Test public void testArgsOnTokenInLexerRuleOfCombined() throws Exception {
2524		ErrorQueue equeue = new ErrorQueue();
2525		ErrorManager.setErrorListener(equeue);
2526		Grammar g = new Grammar(
2527			"grammar t;\n"+
2528				"a : R;\n" +
2529				"R : 'z' ID[32] ;\n" +
2530				"ID : 'a';\n");
2531
2532		String lexerGrammarStr = g.getLexerGrammar();
2533		StringReader sr = new StringReader(lexerGrammarStr);
2534		Grammar lexerGrammar = new Grammar();
2535		lexerGrammar.setFileName("<internally-generated-lexer>");
2536		lexerGrammar.importTokenVocabulary(g);
2537		lexerGrammar.parseAndBuildAST(sr);
2538		lexerGrammar.defineGrammarSymbols();
2539		lexerGrammar.checkNameSpaceAndActions();
2540		sr.close();
2541
2542		Tool antlr = newTool();
2543		antlr.setOutputDirectory(null); // write to /dev/null
2544		CodeGenerator generator = new CodeGenerator(antlr, lexerGrammar, "Java");
2545		lexerGrammar.setCodeGenerator(generator);
2546		generator.genRecognizer();
2547
2548		int expectedMsgID = ErrorManager.MSG_RULE_HAS_NO_ARGS;
2549		Object expectedArg = "ID";
2550		Object expectedArg2 = null;
2551		GrammarSemanticsMessage expectedMessage =
2552			new GrammarSemanticsMessage(expectedMsgID, lexerGrammar, null, expectedArg, expectedArg2);
2553		checkError(equeue, expectedMessage);
2554	}
2555
2556	@Test public void testMissingArgsOnTokenInLexerRuleOfCombined() throws Exception {
2557		ErrorQueue equeue = new ErrorQueue();
2558		ErrorManager.setErrorListener(equeue);
2559		Grammar g = new Grammar(
2560			"grammar t;\n"+
2561				"a : R;\n" +
2562				"R : 'z' ID ;\n" +
2563				"ID[int i] : 'a';\n");
2564
2565		String lexerGrammarStr = g.getLexerGrammar();
2566		StringReader sr = new StringReader(lexerGrammarStr);
2567		Grammar lexerGrammar = new Grammar();
2568		lexerGrammar.setFileName("<internally-generated-lexer>");
2569		lexerGrammar.importTokenVocabulary(g);
2570		lexerGrammar.parseAndBuildAST(sr);
2571		lexerGrammar.defineGrammarSymbols();
2572		lexerGrammar.checkNameSpaceAndActions();
2573		sr.close();
2574
2575		Tool antlr = newTool();
2576		antlr.setOutputDirectory(null); // write to /dev/null
2577		CodeGenerator generator = new CodeGenerator(antlr, lexerGrammar, "Java");
2578		lexerGrammar.setCodeGenerator(generator);
2579		generator.genRecognizer();
2580
2581		int expectedMsgID = ErrorManager.MSG_MISSING_RULE_ARGS;
2582		Object expectedArg = "ID";
2583		Object expectedArg2 = null;
2584		GrammarSemanticsMessage expectedMessage =
2585			new GrammarSemanticsMessage(expectedMsgID, lexerGrammar, null, expectedArg, expectedArg2);
2586		checkError(equeue, expectedMessage);
2587	}
2588
2589	// T R E E S
2590
2591	@Test public void testTokenLabelTreeProperty() throws Exception {
2592		String action = "$id.tree;";
2593		String expecting = "id_tree;";
2594
2595		ErrorQueue equeue = new ErrorQueue();
2596		ErrorManager.setErrorListener(equeue);
2597		Grammar g = new Grammar(
2598			"grammar t;\n"+
2599				"a : id=ID {"+action+"} ;\n" +
2600				"ID : 'a';\n");
2601
2602		Tool antlr = newTool();
2603		antlr.setOutputDirectory(null); // write to /dev/null
2604		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2605		ActionTranslator translator =
2606			new ActionTranslator(generator,
2607				"a",
2608				new CommonToken(ANTLRParser.ACTION,action),1);
2609		g.setCodeGenerator(generator);
2610		generator.genRecognizer(); // forces load of templates
2611		String found = translator.translate();
2612		assertEquals(expecting, found);
2613
2614		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2615	}
2616
2617	@Test public void testTokenRefTreeProperty() throws Exception {
2618		String action = "$ID.tree;";
2619		String expecting = "ID1_tree;";
2620
2621		ErrorQueue equeue = new ErrorQueue();
2622		ErrorManager.setErrorListener(equeue);
2623		Grammar g = new Grammar(
2624			"grammar t;\n"+
2625				"a : ID {"+action+"} ;" +
2626				"ID : 'a';\n");
2627		Tool antlr = newTool();
2628		antlr.setOutputDirectory(null); // write to /dev/null
2629		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2630		g.setCodeGenerator(generator);
2631		generator.genRecognizer();
2632
2633		ActionTranslator translator = new ActionTranslator(generator,"a",
2634			new CommonToken(ANTLRParser.ACTION,action),1);
2635		String found = translator.translate();
2636		assertEquals(expecting, found);
2637	}
2638
2639	@Test public void testAmbiguousTokenRef() throws Exception {
2640		String action = "$ID;";
2641		String expecting = "";
2642
2643		ErrorQueue equeue = new ErrorQueue();
2644		ErrorManager.setErrorListener(equeue);
2645		Grammar g = new Grammar(
2646			"grammar t;\n"+
2647				"a : ID ID {"+action+"};" +
2648				"ID : 'a';\n");
2649		Tool antlr = newTool();
2650		antlr.setOutputDirectory(null); // write to /dev/null
2651		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2652		g.setCodeGenerator(generator);
2653		generator.genRecognizer();
2654
2655		int expectedMsgID = ErrorManager.MSG_NONUNIQUE_REF;
2656		Object expectedArg = "ID";
2657		GrammarSemanticsMessage expectedMessage =
2658			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
2659		checkError(equeue, expectedMessage);
2660	}
2661
2662	@Test public void testAmbiguousTokenRefWithProp() throws Exception {
2663		String action = "$ID.text;";
2664		String expecting = "";
2665
2666		ErrorQueue equeue = new ErrorQueue();
2667		ErrorManager.setErrorListener(equeue);
2668		Grammar g = new Grammar(
2669			"grammar t;\n"+
2670				"a : ID ID {"+action+"};" +
2671				"ID : 'a';\n");
2672		Tool antlr = newTool();
2673		antlr.setOutputDirectory(null); // write to /dev/null
2674		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2675		g.setCodeGenerator(generator);
2676		generator.genRecognizer();
2677
2678		int expectedMsgID = ErrorManager.MSG_NONUNIQUE_REF;
2679		Object expectedArg = "ID";
2680		GrammarSemanticsMessage expectedMessage =
2681			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
2682		checkError(equeue, expectedMessage);
2683	}
2684
2685	@Test public void testRuleRefWithDynamicScope() throws Exception {
2686		String action = "$field::x = $field.st;";
2687		String expecting = "((field_scope)field_stack.peek()).x = retval.st;";
2688
2689		ErrorQueue equeue = new ErrorQueue();
2690		ErrorManager.setErrorListener(equeue);
2691		Grammar g = new Grammar(
2692			"grammar a;\n" +
2693				"field\n" +
2694				"scope { ST x; }\n" +
2695				"    :   'y' {"+action+"}\n" +
2696				"    ;\n");
2697		Tool antlr = newTool();
2698		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2699		g.setCodeGenerator(generator);
2700		generator.genRecognizer(); // forces load of templates
2701		ActionTranslator translator = new ActionTranslator(generator,
2702			"field",
2703			new CommonToken(ANTLRParser.ACTION,action),1);
2704		String found = translator.translate();
2705		assertEquals(expecting, found);
2706
2707		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2708	}
2709
2710	@Test public void testAssignToOwnRulenameAttr() throws Exception {
2711		String action = "$rule.tree = null;";
2712		String expecting = "retval.tree = null;";
2713		ErrorQueue equeue = new ErrorQueue();
2714		ErrorManager.setErrorListener(equeue);
2715		Grammar g = new Grammar(
2716			"grammar a;\n" +
2717				"rule\n" +
2718				"    : 'y' {" + action +"}\n" +
2719				"    ;");
2720		Tool antlr = newTool();
2721		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2722		g.setCodeGenerator(generator);
2723		generator.genRecognizer(); // forces load of templates
2724		ActionTranslator translator = new ActionTranslator(generator,
2725			"rule",
2726			new CommonToken(ANTLRParser.ACTION,action),1);
2727		String found = translator.translate();
2728		assertEquals(expecting, found);
2729
2730		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2731	}
2732
2733	@Test public void testAssignToOwnParamAttr() throws Exception {
2734		String action = "$rule.i = 42; $i = 23;";
2735		String expecting = "i = 42; i = 23;";
2736		ErrorQueue equeue = new ErrorQueue();
2737		ErrorManager.setErrorListener(equeue);
2738		Grammar g = new Grammar(
2739			"grammar a;\n" +
2740				"rule[int i]\n" +
2741				"    : 'y' {" + action +"}\n" +
2742				"    ;");
2743		Tool antlr = newTool();
2744		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2745		g.setCodeGenerator(generator);
2746		generator.genRecognizer(); // forces load of templates
2747		ActionTranslator translator = new ActionTranslator(generator,
2748			"rule",
2749			new CommonToken(ANTLRParser.ACTION,action),1);
2750		String found = translator.translate();
2751		assertEquals(expecting, found);
2752
2753		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2754	}
2755
2756	@Test public void testIllegalAssignToOwnRulenameAttr() throws Exception {
2757		String action = "$rule.stop = 0;";
2758		ErrorQueue equeue = new ErrorQueue();
2759		ErrorManager.setErrorListener(equeue);
2760		Grammar g = new Grammar(
2761			"grammar a;\n" +
2762				"rule\n" +
2763				"    : 'y' {" + action +"}\n" +
2764				"    ;");
2765		Tool antlr = newTool();
2766		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2767		g.setCodeGenerator(generator);
2768		generator.genRecognizer(); // forces load of templates
2769		ActionTranslator translator = new ActionTranslator(generator,
2770			"rule",
2771			new CommonToken(ANTLRParser.ACTION,action),1);
2772		String rawTranslation =
2773			translator.translate();
2774
2775		int expectedMsgID = ErrorManager.MSG_WRITE_TO_READONLY_ATTR;
2776		Object expectedArg = "rule";
2777		Object expectedArg2 = "stop";
2778		GrammarSemanticsMessage expectedMessage =
2779			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2780		checkError(equeue, expectedMessage);
2781	}
2782
2783	@Test public void testIllegalAssignToLocalAttr() throws Exception {
2784		String action = "$tree = null; $st = null; $start = 0; $stop = 0; $text = 0;";
2785		String expecting = "retval.tree = null; retval.st = null;   ";
2786		ErrorQueue equeue = new ErrorQueue();
2787		ErrorManager.setErrorListener(equeue);
2788		Grammar g = new Grammar(
2789			"grammar a;\n" +
2790				"rule\n" +
2791				"    : 'y' {" + action +"}\n" +
2792				"    ;");
2793		Tool antlr = newTool();
2794		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2795		g.setCodeGenerator(generator);
2796		generator.genRecognizer(); // forces load of templates
2797		ActionTranslator translator = new ActionTranslator(generator,
2798			"rule",
2799			new CommonToken(ANTLRParser.ACTION,action),1);
2800		String rawTranslation =
2801			translator.translate();
2802
2803		int expectedMsgID = ErrorManager.MSG_WRITE_TO_READONLY_ATTR;
2804		ArrayList expectedErrors = new ArrayList(3);
2805		GrammarSemanticsMessage expectedMessage =
2806			new GrammarSemanticsMessage(expectedMsgID, g, null, "start", "");
2807		expectedErrors.add(expectedMessage);
2808		GrammarSemanticsMessage expectedMessage2 =
2809			new GrammarSemanticsMessage(expectedMsgID, g, null, "stop", "");
2810		expectedErrors.add(expectedMessage2);
2811		GrammarSemanticsMessage expectedMessage3 =
2812			new GrammarSemanticsMessage(expectedMsgID, g, null, "text", "");
2813		expectedErrors.add(expectedMessage3);
2814		checkErrors(equeue, expectedErrors);
2815
2816		STGroup templates =
2817			new STGroup();
2818		ST actionST = new ST(templates, rawTranslation);
2819		String found = actionST.render();
2820		assertEquals(expecting, found);
2821	}
2822
2823	@Test public void testIllegalAssignRuleRefAttr() throws Exception {
2824		String action = "$other.tree = null;";
2825		ErrorQueue equeue = new ErrorQueue();
2826		ErrorManager.setErrorListener(equeue);
2827		Grammar g = new Grammar(
2828			"grammar a;\n" +
2829				"options { output = AST;}" +
2830				"otherrule\n" +
2831				"    : 'y' ;" +
2832				"rule\n" +
2833				"    : other=otherrule {" + action +"}\n" +
2834				"    ;");
2835		Tool antlr = newTool();
2836		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2837		g.setCodeGenerator(generator);
2838		generator.genRecognizer(); // forces load of templates
2839		ActionTranslator translator = new ActionTranslator(generator,
2840			"rule",
2841			new CommonToken(ANTLRParser.ACTION,action),1);
2842		String rawTranslation =
2843			translator.translate();
2844
2845		int expectedMsgID = ErrorManager.MSG_WRITE_TO_READONLY_ATTR;
2846		Object expectedArg = "other";
2847		Object expectedArg2 = "tree";
2848		GrammarSemanticsMessage expectedMessage =
2849			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2850		checkError(equeue, expectedMessage);
2851	}
2852
2853	@Test public void testIllegalAssignTokenRefAttr() throws Exception {
2854		String action = "$ID.text = \"test\";";
2855		ErrorQueue equeue = new ErrorQueue();
2856		ErrorManager.setErrorListener(equeue);
2857		Grammar g = new Grammar(
2858			"grammar a;\n" +
2859				"ID\n" +
2860				"    : 'y' ;" +
2861				"rule\n" +
2862				"    : ID {" + action +"}\n" +
2863				"    ;");
2864		Tool antlr = newTool();
2865		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2866		g.setCodeGenerator(generator);
2867		generator.genRecognizer(); // forces load of templates
2868		ActionTranslator translator = new ActionTranslator(generator,
2869			"rule",
2870			new CommonToken(ANTLRParser.ACTION,action),1);
2871		String rawTranslation =
2872			translator.translate();
2873
2874		int expectedMsgID = ErrorManager.MSG_WRITE_TO_READONLY_ATTR;
2875		Object expectedArg = "ID";
2876		Object expectedArg2 = "text";
2877		GrammarSemanticsMessage expectedMessage =
2878			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
2879		checkError(equeue, expectedMessage);
2880	}
2881
2882	@Test public void testAssignToTreeNodeAttribute() throws Exception {
2883		String action = "$tree.scope = localScope;";
2884		String expecting = "((Object)retval.tree).scope = localScope;";
2885		ErrorQueue equeue = new ErrorQueue();
2886		ErrorManager.setErrorListener(equeue);
2887		Grammar g = new Grammar(
2888			"grammar a;\n" +
2889				"options { output=AST; }" +
2890				"rule\n" +
2891				"@init {\n" +
2892				"   Scope localScope=null;\n" +
2893				"}\n" +
2894				"@after {\n" +
2895				"   ###$tree.scope = localScope;!!!\n" +
2896				"}\n" +
2897				"   : 'a' -> ^('a')\n" +
2898				";");
2899		Tool antlr = newTool();
2900
2901		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2902		g.setCodeGenerator(generator);
2903		generator.genRecognizer(); // codegen phase sets some vars we need
2904		ST codeST = generator.getRecognizerST();
2905		String code = codeST.render();
2906		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
2907		assertEquals(expecting, found);
2908
2909	}
2910
2911	@Test public void testDoNotTranslateAttributeCompare() throws Exception {
2912		String action = "$a.line == $b.line";
2913		String expecting = "(a!=null?a.getLine():0) == (b!=null?b.getLine():0)";
2914		ErrorQueue equeue = new ErrorQueue();
2915		ErrorManager.setErrorListener(equeue);
2916		Grammar g = new Grammar(
2917			"lexer grammar a;\n" +
2918				"RULE:\n" +
2919				"     a=ID b=ID {" + action + "}" +
2920				"    ;\n" +
2921				"ID : 'id';"
2922		);
2923		Tool antlr = newTool();
2924		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2925		g.setCodeGenerator(generator);
2926		generator.genRecognizer();
2927		ActionTranslator translator = new ActionTranslator(generator,
2928			"RULE",
2929			new CommonToken(ANTLRParser.ACTION,action),1);
2930		String found = translator.translate();
2931		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2932		assertEquals(expecting, found);
2933	}
2934
2935	@Test public void testDoNotTranslateScopeAttributeCompare() throws Exception {
2936		String action = "if ($rule::foo == \"foo\" || 1) { System.out.println(\"ouch\"); }";
2937		String expecting = "if (((rule_scope)rule_stack.peek()).foo == \"foo\" || 1) { System.out.println(\"ouch\"); }";
2938		ErrorQueue equeue = new ErrorQueue();
2939		ErrorManager.setErrorListener(equeue);
2940		Grammar g = new Grammar(
2941			"grammar a;\n" +
2942				"rule\n" +
2943				"scope {\n" +
2944				"   String foo;" +
2945				"} :\n" +
2946				"     twoIDs" +
2947				"    ;\n" +
2948				"twoIDs:\n" +
2949				"    ID ID {" + action + "}\n" +
2950				"    ;\n" +
2951				"ID : 'id';"
2952		);
2953		Tool antlr = newTool();
2954		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2955		g.setCodeGenerator(generator);
2956		generator.genRecognizer();
2957		ActionTranslator translator = new ActionTranslator(generator,
2958			"twoIDs",
2959			new CommonToken(ANTLRParser.ACTION,action),1);
2960		String rawTranslation =
2961			translator.translate();
2962		// check that we didn't use scopeSetAttributeRef int translation!
2963		boolean foundScopeSetAttributeRef = false;
2964		for (int i = 0; i < translator.chunks.size(); i++) {
2965			Object chunk = translator.chunks.get(i);
2966			if (chunk instanceof ST) {
2967				if (((ST)chunk).getName().equals("/scopeSetAttributeRef")) {
2968					foundScopeSetAttributeRef = true;
2969				}
2970			}
2971		}
2972		assertFalse("action translator used scopeSetAttributeRef template in comparison!", foundScopeSetAttributeRef);
2973		STGroup templates =
2974			new STGroup();
2975		ST actionST = new ST(templates, rawTranslation);
2976		String found = actionST.render();
2977		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
2978		assertEquals(expecting, found);
2979	}
2980
2981	@Test public void testTreeRuleStopAttributeIsInvalid() throws Exception {
2982		String action = "$r.x; $r.start; $r.stop";
2983		String expecting = "(r!=null?r.x:0); (r!=null?((CommonTree)r.start):null); $r.stop";
2984
2985		ErrorQueue equeue = new ErrorQueue();
2986		ErrorManager.setErrorListener(equeue);
2987		Grammar g = new Grammar(
2988			"tree grammar t;\n" +
2989				"options {ASTLabelType=CommonTree;}\n"+
2990				"a returns [int x]\n" +
2991				"  :\n" +
2992				"  ;\n"+
2993				"b : r=a {###"+action+"!!!}\n" +
2994				"  ;");
2995		System.out.println(g.toString());
2996		Tool antlr = newTool();
2997		antlr.setOutputDirectory(null); // write to /dev/null
2998		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
2999		g.setCodeGenerator(generator);
3000		generator.genRecognizer(); // codegen phase sets some vars we need
3001		ST codeST = generator.getRecognizerST();
3002		String code = codeST.render();
3003		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
3004		assertEquals(expecting, found);
3005
3006		int expectedMsgID = ErrorManager.MSG_UNKNOWN_RULE_ATTRIBUTE;
3007		Object expectedArg = "a";
3008		Object expectedArg2 = "stop";
3009		GrammarSemanticsMessage expectedMessage =
3010			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
3011		System.out.println("equeue:"+equeue);
3012		checkError(equeue, expectedMessage);
3013	}
3014
3015	@Test public void testRefToTextAttributeForCurrentTreeRule() throws Exception {
3016		String action = "$text";
3017		String expecting = "input.getTokenStream().toString(" +
3018			"input.getTreeAdaptor().getTokenStartIndex(retval.start)," +
3019			"input.getTreeAdaptor().getTokenStopIndex(retval.start))";
3020
3021		ErrorQueue equeue = new ErrorQueue();
3022		ErrorManager.setErrorListener(equeue);
3023		Grammar g = new Grammar(
3024			"tree grammar t;\n" +
3025				"options {ASTLabelType=CommonTree;}\n" +
3026				"a : {###"+action+"!!!}\n" +
3027				"  ;\n");
3028
3029		Tool antlr = newTool();
3030		antlr.setOutputDirectory(null); // write to /dev/null
3031		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
3032		g.setCodeGenerator(generator);
3033		generator.genRecognizer(); // codegen phase sets some vars we need
3034		ST codeST = generator.getRecognizerST();
3035		String code = codeST.render();
3036		String found = code.substring(code.indexOf("###")+3,code.indexOf("!!!"));
3037		assertEquals(expecting, found);
3038
3039		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
3040	}
3041
3042	@Test public void testTypeOfGuardedAttributeRefIsCorrect() throws Exception {
3043		String action = "int x = $b::n;";
3044		String expecting = "int x = ((b_scope)b_stack.peek()).n;";
3045
3046		ErrorQueue equeue = new ErrorQueue();
3047		ErrorManager.setErrorListener(equeue);
3048		Grammar g = new Grammar(
3049			"grammar t;\n" +
3050				"s : b ;\n"+
3051				"b\n" +
3052				"scope {\n" +
3053				"  int n;\n" +
3054				"} : '(' b ')' {"+action+"}\n" + // refers to current invocation's n
3055				"  ;\n");
3056		Tool antlr = newTool();
3057		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
3058		g.setCodeGenerator(generator);
3059		generator.genRecognizer(); // forces load of templates
3060		ActionTranslator translator = new ActionTranslator(generator, "b",
3061			new CommonToken(ANTLRParser.ACTION,action),1);
3062		String found = translator.translate();
3063		assertEquals(expecting, found);
3064
3065		assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
3066	}
3067
3068	// S U P P O R T
3069
3070	protected void checkError(ErrorQueue equeue,
3071							  GrammarSemanticsMessage expectedMessage)
3072		throws Exception
3073	{
3074		/*
3075		System.out.println(equeue.infos);
3076		System.out.println(equeue.warnings);
3077		System.out.println(equeue.errors);
3078		*/
3079		Message foundMsg = null;
3080		for (int i = 0; i < equeue.errors.size(); i++) {
3081			Message m = (Message)equeue.errors.get(i);
3082			if (m.msgID==expectedMessage.msgID ) {
3083				foundMsg = m;
3084			}
3085		}
3086		assertTrue("no error; "+expectedMessage.msgID+" expected", equeue.errors.size() > 0);
3087		assertNotNull("couldn't find expected error: "+expectedMessage.msgID+" in "+equeue, foundMsg);
3088		assertTrue("error is not a GrammarSemanticsMessage",
3089			foundMsg instanceof GrammarSemanticsMessage);
3090		assertEquals(expectedMessage.arg, foundMsg.arg);
3091		assertEquals(expectedMessage.arg2, foundMsg.arg2);
3092	}
3093
3094	/** Allow checking for multiple errors in one test */
3095	protected void checkErrors(ErrorQueue equeue,
3096							   ArrayList expectedMessages)
3097		throws Exception
3098	{
3099		ArrayList messageExpected = new ArrayList(equeue.errors.size());
3100		for (int i = 0; i < equeue.errors.size(); i++) {
3101			Message m = (Message)equeue.errors.get(i);
3102			boolean foundMsg = false;
3103			for (int j = 0; j < expectedMessages.size(); j++) {
3104				Message em = (Message)expectedMessages.get(j);
3105				if (m.msgID==em.msgID && m.arg.equals(em.arg) && m.arg2.equals(em.arg2)) {
3106					foundMsg = true;
3107				}
3108			}
3109			if (foundMsg) {
3110				messageExpected.add(i, Boolean.TRUE);
3111			} else
3112				messageExpected.add(i, Boolean.FALSE);
3113		}
3114		for (int i = 0; i < equeue.errors.size(); i++) {
3115			assertTrue("unexpected error:" + equeue.errors.get(i), ((Boolean)messageExpected.get(i)).booleanValue());
3116		}
3117	}
3118}
3119