Home | History | Annotate | Download | only in test
      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  */
     28 package org.antlr.test;
     29 
     30 import org.antlr.Tool;
     31 import org.antlr.codegen.CodeGenerator;
     32 import org.antlr.grammar.v3.ANTLRParser;
     33 import org.antlr.grammar.v3.ActionTranslator;
     34 import org.antlr.runtime.CommonToken;
     35 import org.stringtemplate.v4.ST;
     36 import org.stringtemplate.v4.STGroup;
     37 import org.antlr.tool.ErrorManager;
     38 import org.antlr.tool.Grammar;
     39 import org.antlr.tool.GrammarSemanticsMessage;
     40 import org.antlr.tool.Message;
     41 import org.junit.Test;
     42 
     43 /** Test templates in actions; %... shorthands */
     44 public class TestTemplates extends BaseTest {
     45 	private static final String LINE_SEP = System.getProperty("line.separator");
     46 
     47 	@Test
     48     public void testTemplateConstructor() throws Exception {
     49 		String action = "x = %foo(name={$ID.text});";
     50 		String expecting = "x = templateLib.getInstanceOf(\"foo\"," +
     51 			"new STAttrMap().put(\"name\", (ID1!=null?ID1.getText():null)));";
     52 
     53 		ErrorQueue equeue = new ErrorQueue();
     54 		ErrorManager.setErrorListener(equeue);
     55 		Grammar g = new Grammar(
     56 			"grammar t;\n" +
     57 			"options {\n" +
     58 			"    output=template;\n" +
     59 			"}\n" +
     60 			"\n" +
     61 			"a : ID {"+action+"}\n" +
     62 			"  ;\n" +
     63 			"\n" +
     64 			"ID : 'a';\n");
     65 		Tool antlr = newTool();
     66 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
     67 		g.setCodeGenerator(generator);
     68 		generator.genRecognizer(); // forces load of templates
     69 		ActionTranslator translator =
     70 			new ActionTranslator(generator,
     71 										"a",
     72 										new CommonToken(ANTLRParser.ACTION,action),1);
     73 		String rawTranslation =
     74 			translator.translate();
     75 		STGroup templates =
     76 			new STGroup();
     77 		ST actionST = new ST(templates, rawTranslation);
     78 		String found = actionST.render();
     79 
     80 		assertNoErrors(equeue);
     81 
     82 		assertEquals(expecting, found);
     83 	}
     84 
     85 	@Test
     86     public void testTemplateConstructorNoArgs() throws Exception {
     87 		String action = "x = %foo();";
     88 		String expecting = "x = templateLib.getInstanceOf(\"foo\");";
     89 
     90 		ErrorQueue equeue = new ErrorQueue();
     91 		ErrorManager.setErrorListener(equeue);
     92 		Grammar g = new Grammar(
     93 			"grammar t;\n" +
     94 			"options {\n" +
     95 			"    output=template;\n" +
     96 			"}\n" +
     97 			"\n" +
     98 			"a : ID {"+action+"}\n" +
     99 			"  ;\n" +
    100 			"\n" +
    101 			"ID : 'a';\n");
    102 		Tool antlr = newTool();
    103 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    104 		g.setCodeGenerator(generator);
    105 		generator.genRecognizer(); // forces load of templates
    106 		ActionTranslator translator =
    107 			new ActionTranslator(generator,
    108 										"a",
    109 										new CommonToken(ANTLRParser.ACTION,action),1);
    110 		String rawTranslation =
    111 			translator.translate();
    112 		STGroup templates =
    113 			new STGroup();
    114 		ST actionST = new ST(templates, rawTranslation);
    115 		String found = actionST.render();
    116 
    117 		assertNoErrors(equeue);
    118 
    119 		assertEquals(expecting, found);
    120 	}
    121 
    122 	@Test
    123     public void testIndirectTemplateConstructor() throws Exception {
    124 		String action = "x = %({\"foo\"})(name={$ID.text});";
    125 		String expecting = "x = templateLib.getInstanceOf(\"foo\"," +
    126 			"new STAttrMap().put(\"name\", (ID1!=null?ID1.getText():null)));";
    127 
    128 		ErrorQueue equeue = new ErrorQueue();
    129 		ErrorManager.setErrorListener(equeue);
    130 		Grammar g = new Grammar(
    131 			"grammar t;\n" +
    132 			"options {\n" +
    133 			"    output=template;\n" +
    134 			"}\n" +
    135 			"\n" +
    136 			"a : ID {"+action+"}\n" +
    137 			"  ;\n" +
    138 			"\n" +
    139 			"ID : 'a';\n");
    140 		Tool antlr = newTool();
    141 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    142 		g.setCodeGenerator(generator);
    143 		generator.genRecognizer(); // forces load of templates
    144 		ActionTranslator translator =
    145 			new ActionTranslator(generator,
    146 										"a",
    147 										new CommonToken(ANTLRParser.ACTION,action),1);
    148 		String rawTranslation =
    149 			translator.translate();
    150 		STGroup templates =
    151 			new STGroup();
    152 		ST actionST = new ST(templates, rawTranslation);
    153 		String found = actionST.render();
    154 
    155 		assertNoErrors(equeue);
    156 
    157 		assertEquals(expecting, found);
    158 	}
    159 
    160 	@Test public void testStringConstructor() throws Exception {
    161 		String action = "x = %{$ID.text};";
    162 		String expecting = "x = new StringTemplate(templateLib,(ID1!=null?ID1.getText():null));";
    163 
    164 		ErrorQueue equeue = new ErrorQueue();
    165 		ErrorManager.setErrorListener(equeue);
    166 		Grammar g = new Grammar(
    167 			"grammar t;\n" +
    168 			"options {\n" +
    169 			"    output=template;\n" +
    170 			"}\n" +
    171 			"\n" +
    172 			"a : ID {"+action+"}\n" +
    173 			"  ;\n" +
    174 			"\n" +
    175 			"ID : 'a';\n");
    176 		Tool antlr = newTool();
    177 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    178 		g.setCodeGenerator(generator);
    179 		generator.genRecognizer(); // forces load of templates
    180 		ActionTranslator translator = new ActionTranslator(generator,
    181 																	 "a",
    182 																	 new CommonToken(ANTLRParser.ACTION,action),1);
    183 		String rawTranslation =
    184 			translator.translate();
    185 		STGroup templates =
    186 			new STGroup();
    187 		ST actionST = new ST(templates, rawTranslation);
    188 		String found = actionST.render();
    189 
    190 		assertNoErrors(equeue);
    191 
    192 		assertEquals(expecting, found);
    193 	}
    194 
    195 	@Test public void testSetAttr() throws Exception {
    196 		String action = "%x.y = z;";
    197 		String expecting = "(x).setAttribute(\"y\", z);";
    198 
    199 		ErrorQueue equeue = new ErrorQueue();
    200 		ErrorManager.setErrorListener(equeue);
    201 		Grammar g = new Grammar(
    202 			"grammar t;\n" +
    203 			"options {\n" +
    204 			"    output=template;\n" +
    205 			"}\n" +
    206 			"\n" +
    207 			"a : ID {"+action+"}\n" +
    208 			"  ;\n" +
    209 			"\n" +
    210 			"ID : 'a';\n");
    211 		Tool antlr = newTool();
    212 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    213 		g.setCodeGenerator(generator);
    214 		generator.genRecognizer(); // forces load of templates
    215 		ActionTranslator translator =
    216 			new ActionTranslator(generator,
    217 										"a",
    218 										new CommonToken(ANTLRParser.ACTION,action),1);
    219 		String rawTranslation =
    220 			translator.translate();
    221 		STGroup templates =
    222 			new STGroup();
    223 		ST actionST = new ST(templates, rawTranslation);
    224 		String found = actionST.render();
    225 
    226 		assertNoErrors(equeue);
    227 
    228 		assertEquals(expecting, found);
    229 	}
    230 
    231 	@Test public void testSetAttrOfExpr() throws Exception {
    232 		String action = "%{foo($ID.text).getST()}.y = z;";
    233 		String expecting = "(foo((ID1!=null?ID1.getText():null)).getST()).setAttribute(\"y\", z);";
    234 
    235 		ErrorQueue equeue = new ErrorQueue();
    236 		ErrorManager.setErrorListener(equeue);
    237 		Grammar g = new Grammar(
    238 			"grammar t;\n" +
    239 			"options {\n" +
    240 			"    output=template;\n" +
    241 			"}\n" +
    242 			"\n" +
    243 			"a : ID {"+action+"}\n" +
    244 			"  ;\n" +
    245 			"\n" +
    246 			"ID : 'a';\n");
    247 		Tool antlr = newTool();
    248 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    249 		g.setCodeGenerator(generator);
    250 		generator.genRecognizer(); // forces load of templates
    251 		ActionTranslator translator = new ActionTranslator(generator,
    252 																	 "a",
    253 																	 new CommonToken(ANTLRParser.ACTION,action),1);
    254 		String rawTranslation =
    255 			translator.translate();
    256 		STGroup templates =
    257 			new STGroup();
    258 		ST actionST = new ST(templates, rawTranslation);
    259 		String found = actionST.render();
    260 
    261 		assertNoErrors(equeue);
    262 
    263 		assertEquals(expecting, found);
    264 	}
    265 
    266 	@Test public void testSetAttrOfExprInMembers() throws Exception {
    267 		ErrorQueue equeue = new ErrorQueue();
    268 		ErrorManager.setErrorListener(equeue);
    269 		Grammar g = new Grammar(
    270 			"grammar t;\n" +
    271 			"options {\n" +
    272 			"    output=template;\n" +
    273 			"}\n" +
    274 			"@members {\n" +
    275 			"%code.instr = o;" + // must not get null ptr!
    276 			"}\n" +
    277 			"a : ID\n" +
    278 			"  ;\n" +
    279 			"\n" +
    280 			"ID : 'a';\n");
    281 		Tool antlr = newTool();
    282 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    283 		g.setCodeGenerator(generator);
    284 		generator.genRecognizer(); // forces load of templates
    285 
    286 		assertNoErrors(equeue);
    287 	}
    288 
    289 	@Test public void testCannotHaveSpaceBeforeDot() throws Exception {
    290 		String action = "%x .y = z;";
    291 		String expecting = null;
    292 
    293 		ErrorQueue equeue = new ErrorQueue();
    294 		ErrorManager.setErrorListener(equeue);
    295 		Grammar g = new Grammar(
    296 			"grammar t;\n" +
    297 			"options {\n" +
    298 			"    output=template;\n" +
    299 			"}\n" +
    300 			"\n" +
    301 			"a : ID {"+action+"}\n" +
    302 			"  ;\n" +
    303 			"\n" +
    304 			"ID : 'a';\n");
    305 		Tool antlr = newTool();
    306 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    307 		g.setCodeGenerator(generator);
    308 		generator.genRecognizer(); // forces load of templates
    309 
    310 		int expectedMsgID = ErrorManager.MSG_INVALID_TEMPLATE_ACTION;
    311 		Object expectedArg = "%x";
    312 		GrammarSemanticsMessage expectedMessage =
    313 			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
    314 		checkError(equeue, expectedMessage);
    315 	}
    316 
    317 	@Test public void testCannotHaveSpaceAfterDot() throws Exception {
    318 		String action = "%x. y = z;";
    319 		String expecting = null;
    320 
    321 		ErrorQueue equeue = new ErrorQueue();
    322 		ErrorManager.setErrorListener(equeue);
    323 		Grammar g = new Grammar(
    324 			"grammar t;\n" +
    325 			"options {\n" +
    326 			"    output=template;\n" +
    327 			"}\n" +
    328 			"\n" +
    329 			"a : ID {"+action+"}\n" +
    330 			"  ;\n" +
    331 			"\n" +
    332 			"ID : 'a';\n");
    333 		Tool antlr = newTool();
    334 		CodeGenerator generator = new CodeGenerator(antlr, g, "Java");
    335 		g.setCodeGenerator(generator);
    336 		generator.genRecognizer(); // forces load of templates
    337 
    338 		int expectedMsgID = ErrorManager.MSG_INVALID_TEMPLATE_ACTION;
    339 		Object expectedArg = "%x.";
    340 		GrammarSemanticsMessage expectedMessage =
    341 			new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
    342 		checkError(equeue, expectedMessage);
    343 	}
    344 
    345 	protected void checkError(ErrorQueue equeue,
    346 							  GrammarSemanticsMessage expectedMessage)
    347 		throws Exception
    348 	{
    349 		/*
    350 		System.out.println(equeue.infos);
    351 		System.out.println(equeue.warnings);
    352 		System.out.println(equeue.errors);
    353 		*/
    354 		Message foundMsg = null;
    355 		for (int i = 0; i < equeue.errors.size(); i++) {
    356 			Message m = (Message)equeue.errors.get(i);
    357 			if (m.msgID==expectedMessage.msgID ) {
    358 				foundMsg = m;
    359 			}
    360 		}
    361 		assertTrue("no error; "+expectedMessage.msgID+" expected", equeue.errors.size()>0);
    362 		assertTrue("too many errors; "+equeue.errors, equeue.errors.size()<=1);
    363 		assertTrue("couldn't find expected error: "+expectedMessage.msgID, foundMsg!=null);
    364 		assertTrue("error is not a GrammarSemanticsMessage",
    365 				   foundMsg instanceof GrammarSemanticsMessage);
    366 		assertEquals(expectedMessage.arg, foundMsg.arg);
    367 		assertEquals(expectedMessage.arg2, foundMsg.arg2);
    368 	}
    369 
    370 	// S U P P O R T
    371 	private void assertNoErrors(ErrorQueue equeue) {
    372 		assertTrue("unexpected errors: "+equeue, equeue.errors.size()==0);
    373 	}
    374 }
    375