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 
7 package org.antlr.v4.codegen;
8 
9 import org.antlr.runtime.tree.CommonTreeNodeStream;
10 import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
11 import org.antlr.v4.codegen.model.Action;
12 import org.antlr.v4.codegen.model.AltBlock;
13 import org.antlr.v4.codegen.model.BaseListenerFile;
14 import org.antlr.v4.codegen.model.BaseVisitorFile;
15 import org.antlr.v4.codegen.model.Choice;
16 import org.antlr.v4.codegen.model.CodeBlockForAlt;
17 import org.antlr.v4.codegen.model.CodeBlockForOuterMostAlt;
18 import org.antlr.v4.codegen.model.LabeledOp;
19 import org.antlr.v4.codegen.model.LeftRecursiveRuleFunction;
20 import org.antlr.v4.codegen.model.Lexer;
21 import org.antlr.v4.codegen.model.LexerFile;
22 import org.antlr.v4.codegen.model.ListenerFile;
23 import org.antlr.v4.codegen.model.OutputModelObject;
24 import org.antlr.v4.codegen.model.Parser;
25 import org.antlr.v4.codegen.model.ParserFile;
26 import org.antlr.v4.codegen.model.RuleActionFunction;
27 import org.antlr.v4.codegen.model.RuleFunction;
28 import org.antlr.v4.codegen.model.RuleSempredFunction;
29 import org.antlr.v4.codegen.model.SrcOp;
30 import org.antlr.v4.codegen.model.StarBlock;
31 import org.antlr.v4.codegen.model.VisitorFile;
32 import org.antlr.v4.codegen.model.decl.CodeBlock;
33 import org.antlr.v4.misc.Utils;
34 import org.antlr.v4.parse.ANTLRParser;
35 import org.antlr.v4.parse.GrammarASTAdaptor;
36 import org.antlr.v4.tool.Alternative;
37 import org.antlr.v4.tool.ErrorType;
38 import org.antlr.v4.tool.Grammar;
39 import org.antlr.v4.tool.LeftRecursiveRule;
40 import org.antlr.v4.tool.Rule;
41 import org.antlr.v4.tool.ast.ActionAST;
42 import org.antlr.v4.tool.ast.BlockAST;
43 import org.antlr.v4.tool.ast.GrammarAST;
44 import org.antlr.v4.tool.ast.PredAST;
45 import org.stringtemplate.v4.ST;
46 import org.stringtemplate.v4.STGroup;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 import java.util.Stack;
51 
52 /** This receives events from SourceGenTriggers.g and asks factory to do work.
53  *  Then runs extensions in order on resulting SrcOps to get final list.
54  **/
55 public class OutputModelController {
56 	/** Who does the work? Doesn't have to be CoreOutputModelFactory. */
57 	public OutputModelFactory delegate;
58 
59 	/** Post-processing CodeGeneratorExtension objects; done in order given. */
60 	public List<CodeGeneratorExtension> extensions = new ArrayList<CodeGeneratorExtension>();
61 
62 	/** While walking code in rules, this is set to the tree walker that
63 	 *  triggers actions.
64 	 */
65 	public SourceGenTriggers walker;
66 
67 	/** Context set by the SourceGenTriggers.g */
68 	public int codeBlockLevel = -1;
69 	public int treeLevel = -1;
70 	public OutputModelObject root; // normally ParserFile, LexerFile, ...
71 	public Stack<RuleFunction> currentRule = new Stack<RuleFunction>();
72 	public Alternative currentOuterMostAlt;
73 	public CodeBlock currentBlock;
74 	public CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock;
75 
OutputModelController(OutputModelFactory factory)76 	public OutputModelController(OutputModelFactory factory) {
77 		this.delegate = factory;
78 	}
79 
addExtension(CodeGeneratorExtension ext)80 	public void addExtension(CodeGeneratorExtension ext) { extensions.add(ext); }
81 
82 	/** Build a file with a parser containing rule functions. Use the
83 	 *  controller as factory in SourceGenTriggers so it triggers codegen
84 	 *  extensions too, not just the factory functions in this factory.
85 	 */
buildParserOutputModel(boolean header)86 	public OutputModelObject buildParserOutputModel(boolean header) {
87 		CodeGenerator gen = delegate.getGenerator();
88 		ParserFile file = parserFile(gen.getRecognizerFileName(header));
89 		setRoot(file);
90 		file.parser = parser(file);
91 
92 		Grammar g = delegate.getGrammar();
93 		for (Rule r : g.rules.values()) {
94 			buildRuleFunction(file.parser, r);
95 		}
96 
97 		return file;
98 	}
99 
buildLexerOutputModel(boolean header)100 	public OutputModelObject buildLexerOutputModel(boolean header) {
101 		CodeGenerator gen = delegate.getGenerator();
102 		LexerFile file = lexerFile(gen.getRecognizerFileName(header));
103 		setRoot(file);
104 		file.lexer = lexer(file);
105 
106 		Grammar g = delegate.getGrammar();
107 		for (Rule r : g.rules.values()) {
108 			buildLexerRuleActions(file.lexer, r);
109 		}
110 
111 		return file;
112 	}
113 
buildListenerOutputModel(boolean header)114 	public OutputModelObject buildListenerOutputModel(boolean header) {
115 		CodeGenerator gen = delegate.getGenerator();
116 		return new ListenerFile(delegate, gen.getListenerFileName(header));
117 	}
118 
buildBaseListenerOutputModel(boolean header)119 	public OutputModelObject buildBaseListenerOutputModel(boolean header) {
120 		CodeGenerator gen = delegate.getGenerator();
121 		return new BaseListenerFile(delegate, gen.getBaseListenerFileName(header));
122 	}
123 
buildVisitorOutputModel(boolean header)124 	public OutputModelObject buildVisitorOutputModel(boolean header) {
125 		CodeGenerator gen = delegate.getGenerator();
126 		return new VisitorFile(delegate, gen.getVisitorFileName(header));
127 	}
128 
buildBaseVisitorOutputModel(boolean header)129 	public OutputModelObject buildBaseVisitorOutputModel(boolean header) {
130 		CodeGenerator gen = delegate.getGenerator();
131 		return new BaseVisitorFile(delegate, gen.getBaseVisitorFileName(header));
132 	}
133 
parserFile(String fileName)134 	public ParserFile parserFile(String fileName) {
135 		ParserFile f = delegate.parserFile(fileName);
136 		for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f);
137 		return f;
138 	}
139 
parser(ParserFile file)140 	public Parser parser(ParserFile file) {
141 		Parser p = delegate.parser(file);
142 		for (CodeGeneratorExtension ext : extensions) p = ext.parser(p);
143 		return p;
144 	}
145 
lexerFile(String fileName)146 	public LexerFile lexerFile(String fileName) {
147 		return new LexerFile(delegate, fileName);
148 	}
149 
lexer(LexerFile file)150 	public Lexer lexer(LexerFile file) {
151 		return new Lexer(delegate, file);
152 	}
153 
154 	/** Create RuleFunction per rule and update sempreds,actions of parser
155 	 *  output object with stuff found in r.
156 	 */
buildRuleFunction(Parser parser, Rule r)157 	public void buildRuleFunction(Parser parser, Rule r) {
158 		RuleFunction function = rule(r);
159 		parser.funcs.add(function);
160 		pushCurrentRule(function);
161 		function.fillNamedActions(delegate, r);
162 
163 		if ( r instanceof LeftRecursiveRule ) {
164 			buildLeftRecursiveRuleFunction((LeftRecursiveRule)r,
165 										   (LeftRecursiveRuleFunction)function);
166 		}
167 		else {
168 			buildNormalRuleFunction(r, function);
169 		}
170 
171 		Grammar g = getGrammar();
172 		for (ActionAST a : r.actions) {
173 			if ( a instanceof PredAST ) {
174 				PredAST p = (PredAST)a;
175 				RuleSempredFunction rsf = parser.sempredFuncs.get(r);
176 				if ( rsf==null ) {
177 					rsf = new RuleSempredFunction(delegate, r, function.ctxType);
178 					parser.sempredFuncs.put(r, rsf);
179 				}
180 				rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
181 			}
182 		}
183 
184 		popCurrentRule();
185 	}
186 
buildLeftRecursiveRuleFunction(LeftRecursiveRule r, LeftRecursiveRuleFunction function)187 	public void buildLeftRecursiveRuleFunction(LeftRecursiveRule r, LeftRecursiveRuleFunction function) {
188 		buildNormalRuleFunction(r, function);
189 
190 		// now inject code to start alts
191 		CodeGenerator gen = delegate.getGenerator();
192 		STGroup codegenTemplates = gen.getTemplates();
193 
194 		// pick out alt(s) for primaries
195 		CodeBlockForOuterMostAlt outerAlt = (CodeBlockForOuterMostAlt)function.code.get(0);
196 		List<CodeBlockForAlt> primaryAltsCode = new ArrayList<CodeBlockForAlt>();
197 		SrcOp primaryStuff = outerAlt.ops.get(0);
198 		if ( primaryStuff instanceof Choice ) {
199 			Choice primaryAltBlock = (Choice) primaryStuff;
200 			primaryAltsCode.addAll(primaryAltBlock.alts);
201 		}
202 		else { // just a single alt I guess; no block
203 			primaryAltsCode.add((CodeBlockForAlt)primaryStuff);
204 		}
205 
206 		// pick out alt(s) for op alts
207 		StarBlock opAltStarBlock = (StarBlock)outerAlt.ops.get(1);
208 		CodeBlockForAlt altForOpAltBlock = opAltStarBlock.alts.get(0);
209 		List<CodeBlockForAlt> opAltsCode = new ArrayList<CodeBlockForAlt>();
210 		SrcOp opStuff = altForOpAltBlock.ops.get(0);
211 		if ( opStuff instanceof AltBlock ) {
212 			AltBlock opAltBlock = (AltBlock)opStuff;
213 			opAltsCode.addAll(opAltBlock.alts);
214 		}
215 		else { // just a single alt I guess; no block
216 			opAltsCode.add((CodeBlockForAlt)opStuff);
217 		}
218 
219 		// Insert code in front of each primary alt to create specialized ctx if there was a label
220 		for (int i = 0; i < primaryAltsCode.size(); i++) {
221 			LeftRecursiveRuleAltInfo altInfo = r.recPrimaryAlts.get(i);
222 			if ( altInfo.altLabel==null ) continue;
223 			ST altActionST = codegenTemplates.getInstanceOf("recRuleReplaceContext");
224 			altActionST.add("ctxName", Utils.capitalize(altInfo.altLabel));
225 			Action altAction =
226 				new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
227 			CodeBlockForAlt alt = primaryAltsCode.get(i);
228 			alt.insertOp(0, altAction);
229 		}
230 
231 		// Insert code to set ctx.stop after primary block and before op * loop
232 		ST setStopTokenAST = codegenTemplates.getInstanceOf("recRuleSetStopToken");
233 		Action setStopTokenAction = new Action(delegate, function.ruleCtx, setStopTokenAST);
234 		outerAlt.insertOp(1, setStopTokenAction);
235 
236 		// Insert code to set _prevctx at start of * loop
237 		ST setPrevCtx = codegenTemplates.getInstanceOf("recRuleSetPrevCtx");
238 		Action setPrevCtxAction = new Action(delegate, function.ruleCtx, setPrevCtx);
239 		opAltStarBlock.addIterationOp(setPrevCtxAction);
240 
241 		// Insert code in front of each op alt to create specialized ctx if there was an alt label
242 		for (int i = 0; i < opAltsCode.size(); i++) {
243 			ST altActionST;
244 			LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i);
245 			String templateName;
246 			if ( altInfo.altLabel!=null ) {
247 				templateName = "recRuleLabeledAltStartAction";
248 				altActionST = codegenTemplates.getInstanceOf(templateName);
249 				altActionST.add("currentAltLabel", altInfo.altLabel);
250 			}
251 			else {
252 				templateName = "recRuleAltStartAction";
253 				altActionST = codegenTemplates.getInstanceOf(templateName);
254 				altActionST.add("ctxName", Utils.capitalize(r.name));
255 			}
256 			altActionST.add("ruleName", r.name);
257 			// add label of any lr ref we deleted
258 			altActionST.add("label", altInfo.leftRecursiveRuleRefLabel);
259 			if (altActionST.impl.formalArguments.containsKey("isListLabel")) {
260 				altActionST.add("isListLabel", altInfo.isListLabel);
261 			}
262 			else if (altInfo.isListLabel) {
263 				delegate.getGenerator().tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, "isListLabel");
264 			}
265 			Action altAction =
266 				new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
267 			CodeBlockForAlt alt = opAltsCode.get(i);
268 			alt.insertOp(0, altAction);
269 		}
270 	}
271 
buildNormalRuleFunction(Rule r, RuleFunction function)272 	public void buildNormalRuleFunction(Rule r, RuleFunction function) {
273 		CodeGenerator gen = delegate.getGenerator();
274 		// TRIGGER factory functions for rule alts, elements
275 		GrammarASTAdaptor adaptor = new GrammarASTAdaptor(r.ast.token.getInputStream());
276 		GrammarAST blk = (GrammarAST)r.ast.getFirstChildWithType(ANTLRParser.BLOCK);
277 		CommonTreeNodeStream nodes = new CommonTreeNodeStream(adaptor,blk);
278 		walker = new SourceGenTriggers(nodes, this);
279 		try {
280 			// walk AST of rule alts/elements
281 			function.code = DefaultOutputModelFactory.list(walker.block(null, null));
282 			function.hasLookaheadBlock = walker.hasLookaheadBlock;
283 		}
284 		catch (org.antlr.runtime.RecognitionException e){
285 			e.printStackTrace(System.err);
286 		}
287 
288 		function.ctxType = gen.getTarget().getRuleFunctionContextStructName(function);
289 
290 		function.postamble = rulePostamble(function, r);
291 	}
292 
buildLexerRuleActions(Lexer lexer, final Rule r)293 	public void buildLexerRuleActions(Lexer lexer, final Rule r) {
294 		if (r.actions.isEmpty()) {
295 			return;
296 		}
297 
298 		CodeGenerator gen = delegate.getGenerator();
299 		Grammar g = delegate.getGrammar();
300 		String ctxType = gen.getTarget().getRuleFunctionContextStructName(r);
301 		RuleActionFunction raf = lexer.actionFuncs.get(r);
302 		if ( raf==null ) {
303 			raf = new RuleActionFunction(delegate, r, ctxType);
304 		}
305 
306 		for (ActionAST a : r.actions) {
307 			if ( a instanceof PredAST ) {
308 				PredAST p = (PredAST)a;
309 				RuleSempredFunction rsf = lexer.sempredFuncs.get(r);
310 				if ( rsf==null ) {
311 					rsf = new RuleSempredFunction(delegate, r, ctxType);
312 					lexer.sempredFuncs.put(r, rsf);
313 				}
314 				rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
315 			}
316 			else if ( a.getType()== ANTLRParser.ACTION ) {
317 				raf.actions.put(g.lexerActions.get(a), new Action(delegate, a));
318 			}
319 		}
320 
321 		if (!raf.actions.isEmpty() && !lexer.actionFuncs.containsKey(r)) {
322 			// only add to lexer if the function actually contains actions
323 			lexer.actionFuncs.put(r, raf);
324 		}
325 	}
326 
rule(Rule r)327 	public RuleFunction rule(Rule r) {
328 		RuleFunction rf = delegate.rule(r);
329 		for (CodeGeneratorExtension ext : extensions) rf = ext.rule(rf);
330 		return rf;
331 	}
332 
rulePostamble(RuleFunction function, Rule r)333 	public List<SrcOp> rulePostamble(RuleFunction function, Rule r) {
334 		List<SrcOp> ops = delegate.rulePostamble(function, r);
335 		for (CodeGeneratorExtension ext : extensions) ops = ext.rulePostamble(ops);
336 		return ops;
337 	}
338 
getGrammar()339 	public Grammar getGrammar() { return delegate.getGrammar(); }
340 
getGenerator()341 	public CodeGenerator getGenerator() { return delegate.getGenerator(); }
342 
alternative(Alternative alt, boolean outerMost)343 	public CodeBlockForAlt alternative(Alternative alt, boolean outerMost) {
344 		CodeBlockForAlt blk = delegate.alternative(alt, outerMost);
345 		if ( outerMost ) {
346 			currentOuterMostAlternativeBlock = (CodeBlockForOuterMostAlt)blk;
347 		}
348 		for (CodeGeneratorExtension ext : extensions) blk = ext.alternative(blk, outerMost);
349 		return blk;
350 	}
351 
finishAlternative(CodeBlockForAlt blk, List<SrcOp> ops, boolean outerMost)352 	public CodeBlockForAlt finishAlternative(CodeBlockForAlt blk, List<SrcOp> ops,
353 											 boolean outerMost)
354 	{
355 		blk = delegate.finishAlternative(blk, ops);
356 		for (CodeGeneratorExtension ext : extensions) blk = ext.finishAlternative(blk, outerMost);
357 		return blk;
358 	}
359 
ruleRef(GrammarAST ID, GrammarAST label, GrammarAST args)360 	public List<SrcOp> ruleRef(GrammarAST ID, GrammarAST label, GrammarAST args) {
361 		List<SrcOp> ops = delegate.ruleRef(ID, label, args);
362 		for (CodeGeneratorExtension ext : extensions) {
363 			ops = ext.ruleRef(ops);
364 		}
365 		return ops;
366 	}
367 
tokenRef(GrammarAST ID, GrammarAST label, GrammarAST args)368 	public List<SrcOp> tokenRef(GrammarAST ID, GrammarAST label, GrammarAST args)
369 	{
370 		List<SrcOp> ops = delegate.tokenRef(ID, label, args);
371 		for (CodeGeneratorExtension ext : extensions) {
372 			ops = ext.tokenRef(ops);
373 		}
374 		return ops;
375 	}
376 
stringRef(GrammarAST ID, GrammarAST label)377 	public List<SrcOp> stringRef(GrammarAST ID, GrammarAST label) {
378 		List<SrcOp> ops = delegate.stringRef(ID, label);
379 		for (CodeGeneratorExtension ext : extensions) {
380 			ops = ext.stringRef(ops);
381 		}
382 		return ops;
383 	}
384 
385 	/** (A|B|C) possibly with ebnfRoot and label */
set(GrammarAST setAST, GrammarAST labelAST, boolean invert)386 	public List<SrcOp> set(GrammarAST setAST, GrammarAST labelAST, boolean invert) {
387 		List<SrcOp> ops = delegate.set(setAST, labelAST, invert);
388 		for (CodeGeneratorExtension ext : extensions) {
389 			ops = ext.set(ops);
390 		}
391 		return ops;
392 	}
393 
epsilon(Alternative alt, boolean outerMost)394 	public CodeBlockForAlt epsilon(Alternative alt, boolean outerMost) {
395 		CodeBlockForAlt blk = delegate.epsilon(alt, outerMost);
396 		for (CodeGeneratorExtension ext : extensions) blk = ext.epsilon(blk);
397 		return blk;
398 	}
399 
wildcard(GrammarAST ast, GrammarAST labelAST)400 	public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) {
401 		List<SrcOp> ops = delegate.wildcard(ast, labelAST);
402 		for (CodeGeneratorExtension ext : extensions) {
403 			ops = ext.wildcard(ops);
404 		}
405 		return ops;
406 	}
407 
action(ActionAST ast)408 	public List<SrcOp> action(ActionAST ast) {
409 		List<SrcOp> ops = delegate.action(ast);
410 		for (CodeGeneratorExtension ext : extensions) ops = ext.action(ops);
411 		return ops;
412 	}
413 
sempred(ActionAST ast)414 	public List<SrcOp> sempred(ActionAST ast) {
415 		List<SrcOp> ops = delegate.sempred(ast);
416 		for (CodeGeneratorExtension ext : extensions) ops = ext.sempred(ops);
417 		return ops;
418 	}
419 
getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label)420 	public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label) {
421 		Choice c = delegate.getChoiceBlock(blkAST, alts, label);
422 		for (CodeGeneratorExtension ext : extensions) c = ext.getChoiceBlock(c);
423 		return c;
424 	}
425 
getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts)426 	public Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
427 		Choice c = delegate.getEBNFBlock(ebnfRoot, alts);
428 		for (CodeGeneratorExtension ext : extensions) c = ext.getEBNFBlock(c);
429 		return c;
430 	}
431 
needsImplicitLabel(GrammarAST ID, LabeledOp op)432 	public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) {
433 		boolean needs = delegate.needsImplicitLabel(ID, op);
434 		for (CodeGeneratorExtension ext : extensions) needs |= ext.needsImplicitLabel(ID, op);
435 		return needs;
436 	}
437 
getRoot()438 	public OutputModelObject getRoot() { return root; }
439 
setRoot(OutputModelObject root)440 	public void setRoot(OutputModelObject root) { this.root = root; }
441 
getCurrentRuleFunction()442 	public RuleFunction getCurrentRuleFunction() {
443 		if ( !currentRule.isEmpty() )	return currentRule.peek();
444 		return null;
445 	}
446 
pushCurrentRule(RuleFunction r)447 	public void pushCurrentRule(RuleFunction r) { currentRule.push(r); }
448 
popCurrentRule()449 	public RuleFunction popCurrentRule() {
450 		if ( !currentRule.isEmpty() ) return currentRule.pop();
451 		return null;
452 	}
453 
getCurrentOuterMostAlt()454 	public Alternative getCurrentOuterMostAlt() { return currentOuterMostAlt; }
455 
setCurrentOuterMostAlt(Alternative currentOuterMostAlt)456 	public void setCurrentOuterMostAlt(Alternative currentOuterMostAlt) { this.currentOuterMostAlt = currentOuterMostAlt; }
457 
setCurrentBlock(CodeBlock blk)458 	public void setCurrentBlock(CodeBlock blk) {
459 		currentBlock = blk;
460 	}
461 
getCurrentBlock()462 	public CodeBlock getCurrentBlock() {
463 		return currentBlock;
464 	}
465 
setCurrentOuterMostAlternativeBlock(CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock)466 	public void setCurrentOuterMostAlternativeBlock(CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock) {
467 		this.currentOuterMostAlternativeBlock = currentOuterMostAlternativeBlock;
468 	}
469 
getCurrentOuterMostAlternativeBlock()470 	public CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock() {
471 		return currentOuterMostAlternativeBlock;
472 	}
473 
getCodeBlockLevel()474 	public int getCodeBlockLevel() { return codeBlockLevel; }
475 }
476