1 /*
2  * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3  * Use of this file is governed by the BSD 3-clause license that
4  * can be found in the LICENSE.txt file in the project root.
5  */
6 package org.antlr.v4.test.tool;
7 
8 import org.antlr.runtime.RecognitionException;
9 import org.antlr.v4.automata.ATNFactory;
10 import org.antlr.v4.automata.LexerATNFactory;
11 import org.antlr.v4.automata.ParserATNFactory;
12 import org.antlr.v4.codegen.CodeGenerator;
13 import org.antlr.v4.semantics.SemanticPipeline;
14 import org.antlr.v4.test.runtime.ErrorQueue;
15 import org.antlr.v4.tool.Grammar;
16 import org.antlr.v4.tool.LexerGrammar;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.stringtemplate.v4.AutoIndentWriter;
20 import org.stringtemplate.v4.InstanceScope;
21 import org.stringtemplate.v4.Interpreter;
22 import org.stringtemplate.v4.ST;
23 import org.stringtemplate.v4.STGroup;
24 import org.stringtemplate.v4.STWriter;
25 import org.stringtemplate.v4.misc.ErrorManager;
26 import org.stringtemplate.v4.misc.ErrorType;
27 
28 import java.io.IOException;
29 import java.io.StringWriter;
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 import static org.junit.Assert.assertFalse;
34 import static org.junit.Assert.assertNotEquals;
35 
36 public class TestCodeGeneration extends BaseJavaToolTest {
37 	@Before
38 	@Override
testSetUp()39 	public void testSetUp() throws Exception {
40 		super.testSetUp();
41 	}
42 
testArgDecl()43 	@Test public void testArgDecl() throws Exception { // should use template not string
44 		/*ErrorQueue equeue = */new ErrorQueue();
45 		String g =
46 				"grammar T;\n" +
47 				"a[int xyz] : 'a' ;\n";
48 		List<String> evals = getEvalInfoForString(g, "int xyz");
49 		System.out.println(evals);
50 		for (int i = 0; i < evals.size(); i++) {
51 			String eval = evals.get(i);
52 			assertFalse("eval should not be POJO: "+eval, eval.startsWith("<pojo:"));
53 		}
54 	}
55 
AssignTokenNamesToStringLiteralsInGeneratedParserRuleContexts()56 	@Test public void AssignTokenNamesToStringLiteralsInGeneratedParserRuleContexts() throws Exception {
57 		String g =
58 			"grammar T;\n" +
59 			"root: 't1';\n" +
60 			"Token: 't1';";
61 		List<String> evals = getEvalInfoForString(g, "() { return getToken(");
62 		assertNotEquals(0, evals.size());
63 	}
64 
AssignTokenNamesToStringLiteralArraysInGeneratedParserRuleContexts()65 	@Test public void AssignTokenNamesToStringLiteralArraysInGeneratedParserRuleContexts() throws Exception {
66 		String g =
67 			"grammar T;\n" +
68 				"root: 't1' 't1';\n" +
69 				"Token: 't1';";
70 		List<String> evals = getEvalInfoForString(g, "() { return getTokens(");
71 		assertNotEquals(0, evals.size());
72 	}
73 
74 	/** Add tags around each attribute/template/value write */
75 	public static class DebugInterpreter extends Interpreter {
76 		List<String> evals = new ArrayList<String>();
77 		ErrorManager myErrMgrCopy;
78 		int tab = 0;
DebugInterpreter(STGroup group, ErrorManager errMgr, boolean debug)79 		public DebugInterpreter(STGroup group, ErrorManager errMgr, boolean debug) {
80 			super(group, errMgr, debug);
81 			myErrMgrCopy = errMgr;
82 		}
83 
84 		@Override
writeObject(STWriter out, InstanceScope scope, Object o, String[] options)85 		protected int writeObject(STWriter out, InstanceScope scope, Object o, String[] options) {
86 			if ( o instanceof ST ) {
87 				String name = ((ST)o).getName();
88 				name = name.substring(1);
89 				if ( !name.startsWith("_sub") ) {
90 					try {
91 						out.write("<ST:" + name + ">");
92 						evals.add("<ST:" + name + ">");
93 						int r = super.writeObject(out, scope, o, options);
94 						out.write("</ST:" + name + ">");
95 						evals.add("</ST:" + name + ">");
96 						return r;
97 					} catch (IOException ioe) {
98 						myErrMgrCopy.IOError(scope.st, ErrorType.WRITE_IO_ERROR, ioe);
99 					}
100 				}
101 			}
102 			return super.writeObject(out, scope, o, options);
103 		}
104 
105 		@Override
writePOJO(STWriter out, InstanceScope scope, Object o, String[] options)106 		protected int writePOJO(STWriter out, InstanceScope scope, Object o, String[] options) throws IOException {
107 			Class<?> type = o.getClass();
108 			String name = type.getSimpleName();
109 			out.write("<pojo:"+name+">"+o.toString()+"</pojo:"+name+">");
110 			evals.add("<pojo:" + name + ">" + o.toString() + "</pojo:" + name + ">");
111 			return super.writePOJO(out, scope, o, options);
112 		}
113 
indent(STWriter out)114 		public void indent(STWriter out) throws IOException {
115 			for (int i=1; i<=tab; i++) {
116 				out.write("\t");
117 			}
118 		}
119 	}
120 
getEvalInfoForString(String grammarString, String pattern)121 	public List<String> getEvalInfoForString(String grammarString, String pattern) throws RecognitionException {
122 		ErrorQueue equeue = new ErrorQueue();
123 		Grammar g = new Grammar(grammarString);
124 		List<String> evals = new ArrayList<String>();
125 		if ( g.ast!=null && !g.ast.hasErrors ) {
126 			SemanticPipeline sem = new SemanticPipeline(g);
127 			sem.process();
128 
129 			ATNFactory factory = new ParserATNFactory(g);
130 			if (g.isLexer()) factory = new LexerATNFactory((LexerGrammar) g);
131 			g.atn = factory.createATN();
132 
133 			CodeGenerator gen = new CodeGenerator(g);
134 			ST outputFileST = gen.generateParser();
135 
136 //			STViz viz = outputFileST.inspect();
137 //			try {
138 //				viz.waitForClose();
139 //			}
140 //			catch (Exception e) {
141 //				e.printStackTrace();
142 //			}
143 
144 			boolean debug = false;
145 			DebugInterpreter interp =
146 					new DebugInterpreter(outputFileST.groupThatCreatedThisInstance,
147 							outputFileST.impl.nativeGroup.errMgr,
148 							debug);
149 			InstanceScope scope = new InstanceScope(null, outputFileST);
150 			StringWriter sw = new StringWriter();
151 			AutoIndentWriter out = new AutoIndentWriter(sw);
152 			interp.exec(out, scope);
153 
154 			for (String e : interp.evals) {
155 				if (e.contains(pattern)) {
156 					evals.add(e);
157 				}
158 			}
159 		}
160 		if ( equeue.size()>0 ) {
161 			System.err.println(equeue.toString());
162 		}
163 		return evals;
164 	}
165 }
166