org.antlr.v4.codegen.model.RuleFunction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of antlr4 Show documentation
Show all versions of antlr4 Show documentation
The ANTLR 4 grammar compiler.
/*
* Copyright (c) 2012 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD-3-Clause license that
* can be found in the LICENSE.txt file in the project root.
*/
package org.antlr.v4.codegen.model;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.decl.AltLabelStructDecl;
import org.antlr.v4.codegen.model.decl.AttributeDecl;
import org.antlr.v4.codegen.model.decl.ContextRuleGetterDecl;
import org.antlr.v4.codegen.model.decl.ContextRuleListGetterDecl;
import org.antlr.v4.codegen.model.decl.ContextRuleListIndexedGetterDecl;
import org.antlr.v4.codegen.model.decl.ContextTokenGetterDecl;
import org.antlr.v4.codegen.model.decl.ContextTokenListGetterDecl;
import org.antlr.v4.codegen.model.decl.ContextTokenListIndexedGetterDecl;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.misc.FrequencySet;
import org.antlr.v4.misc.Utils;
import static org.antlr.v4.parse.ANTLRParser.RULE_REF;
import static org.antlr.v4.parse.ANTLRParser.TOKEN_REF;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.runtime.atn.ATNSimulator;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.runtime.misc.Tuple2;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.RuleAST;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** */
public class RuleFunction extends OutputModelObject {
public String name;
public List modifiers;
public String ctxType;
public Collection ruleLabels;
public Collection tokenLabels;
public ATNState startState;
public int index;
public Rule rule;
public boolean hasLookaheadBlock;
public String variantOf;
@ModelElement public List code;
@ModelElement public OrderedHashSet locals; // TODO: move into ctx?
@ModelElement public Collection args = null;
@ModelElement public StructDecl ruleCtx;
@ModelElement public Map altLabelCtxs;
@ModelElement public Map namedActions;
@ModelElement public Action finallyAction;
@ModelElement public List exceptions;
@ModelElement public List postamble;
public RuleFunction(OutputModelFactory factory, Rule r) {
super(factory);
this.name = r.name;
this.rule = r;
if ( r.modifiers!=null && !r.modifiers.isEmpty() ) {
this.modifiers = new ArrayList();
for (GrammarAST t : r.modifiers) modifiers.add(t.getText());
}
modifiers = Utils.nodesToStrings(r.modifiers);
index = r.index;
int lfIndex = name.indexOf(ATNSimulator.RULE_VARIANT_DELIMITER);
if (lfIndex >= 0) {
variantOf = name.substring(0, lfIndex);
}
if (r.name.equals(r.getBaseContext())) {
ruleCtx = new StructDecl(factory, r);
addContextGetters(factory, r.g.contextASTs.get(r.name));
if ( r.args!=null ) {
Collection decls = r.args.attributes.values();
if ( decls.size()>0 ) {
args = new ArrayList();
ruleCtx.addDecls(decls);
for (Attribute a : decls) {
args.add(new AttributeDecl(factory, a));
}
ruleCtx.ctorAttrs = args;
}
}
if ( r.retvals!=null ) {
ruleCtx.addDecls(r.retvals.attributes.values());
}
if ( r.locals!=null ) {
ruleCtx.addDecls(r.locals.attributes.values());
}
}
else {
if (r.args != null || r.retvals != null || r.locals != null) {
throw new UnsupportedOperationException("customized fields are not yet supported for customized context objects");
}
}
ruleLabels = r.getElementLabelNames();
tokenLabels = r.getTokenRefs();
if ( r.exceptions!=null ) {
exceptions = new ArrayList();
for (GrammarAST e : r.exceptions) {
ActionAST catchArg = (ActionAST)e.getChild(0);
ActionAST catchAction = (ActionAST)e.getChild(1);
exceptions.add(new ExceptionClause(factory, catchArg, catchAction));
}
}
startState = factory.getGrammar().atn.ruleToStartState[r.index];
}
public void addContextGetters(OutputModelFactory factory, Collection contextASTs) {
List unlabeledAlternatives = new ArrayList();
Map> labeledAlternatives = new HashMap>();
for (RuleAST ast : contextASTs) {
try {
unlabeledAlternatives.addAll(rule.g.getUnlabeledAlternatives(ast));
for (Map.Entry>> entry : rule.g.getLabeledAlternatives(ast).entrySet()) {
List list = labeledAlternatives.get(entry.getKey());
if (list == null) {
list = new ArrayList();
labeledAlternatives.put(entry.getKey(), list);
}
for (Tuple2 tuple : entry.getValue()) {
list.add(tuple.getItem2());
}
}
}
catch (RecognitionException ex) {
}
}
// Add ctx labels for elements in alts with no '#' label
if (!unlabeledAlternatives.isEmpty()) {
Set decls = getDeclsForAllElements(unlabeledAlternatives);
// put directly in base context
for (Decl decl : decls) {
ruleCtx.addDecl(decl);
}
}
// make structs for '#' labeled alts, define ctx labels for elements
altLabelCtxs = new HashMap();
if (!labeledAlternatives.isEmpty()) {
for (Map.Entry> entry : labeledAlternatives.entrySet()) {
AltLabelStructDecl labelDecl = new AltLabelStructDecl(factory, rule, entry.getKey());
altLabelCtxs.put(entry.getKey(), labelDecl);
Set decls = getDeclsForAllElements(entry.getValue());
for (Decl decl : decls) {
labelDecl.addDecl(decl);
}
}
}
}
public void fillNamedActions(OutputModelFactory factory, Rule r) {
if ( r.finallyAction!=null ) {
finallyAction = new Action(factory, r.finallyAction);
}
namedActions = new HashMap();
for (String name : r.namedActions.keySet()) {
ActionAST ast = r.namedActions.get(name);
namedActions.put(name, new Action(factory, ast));
}
}
/** for all alts, find which ref X or r needs List
Must see across alts. If any alt needs X or r as list, then
define as list.
*/
public Set getDeclsForAllElements(List altASTs) {
Set needsList = new HashSet();
Set suppress = new HashSet();
List allRefs = new ArrayList();
for (AltAST ast : altASTs) {
IntervalSet reftypes = new IntervalSet(RULE_REF, TOKEN_REF);
List refs = ast.getNodesWithType(reftypes);
allRefs.addAll(refs);
FrequencySet altFreq = getElementFrequenciesForAlt(ast);
for (GrammarAST t : refs) {
String refLabelName = getLabelName(rule.g, t);
if (altFreq.count(refLabelName)==0) {
suppress.add(refLabelName);
}
if ( altFreq.count(refLabelName)>1 ) {
needsList.add(refLabelName);
}
}
}
Set decls = new LinkedHashSet();
for (GrammarAST t : allRefs) {
String refLabelName = getLabelName(rule.g, t);
if (suppress.contains(refLabelName)) {
continue;
}
List d = getDeclForAltElement(t,
refLabelName,
needsList.contains(refLabelName));
decls.addAll(d);
}
return decls;
}
public static String getLabelName(Grammar g, GrammarAST t) {
String labelName = t.getText();
Rule referencedRule = g.rules.get(labelName);
if (referencedRule != null) {
labelName = referencedRule.getBaseContext();
}
return labelName;
}
/** Given list of X and r refs in alt, compute how many of each there are */
protected FrequencySet getElementFrequenciesForAlt(AltAST ast) {
try {
ElementFrequenciesVisitor visitor = new ElementFrequenciesVisitor(rule.g, new CommonTreeNodeStream(new GrammarASTAdaptor(), ast));
visitor.outerAlternative();
if (visitor.frequencies.size() != 1) {
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR);
return new FrequencySet();
}
return visitor.frequencies.peek();
}
catch (RecognitionException ex) {
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, ex);
return new FrequencySet();
}
}
public List getDeclForAltElement(GrammarAST t, String refLabelName, boolean needList) {
int lfIndex = refLabelName.indexOf(ATNSimulator.RULE_VARIANT_DELIMITER);
if (lfIndex >= 0) {
refLabelName = refLabelName.substring(0, lfIndex);
}
List decls = new ArrayList();
if ( t.getType()==RULE_REF ) {
Rule rref = factory.getGrammar().getRule(t.getText());
String ctxName = factory.getTarget()
.getRuleFunctionContextStructName(rref);
if ( needList) {
if(factory.getTarget().supportsOverloadedMethods())
decls.add( new ContextRuleListGetterDecl(factory, refLabelName, ctxName) );
decls.add( new ContextRuleListIndexedGetterDecl(factory, refLabelName, ctxName) );
}
else {
decls.add( new ContextRuleGetterDecl(factory, refLabelName, ctxName) );
}
}
else {
if ( needList ) {
if(factory.getTarget().supportsOverloadedMethods())
decls.add( new ContextTokenListGetterDecl(factory, refLabelName) );
decls.add( new ContextTokenListIndexedGetterDecl(factory, refLabelName) );
}
else {
decls.add( new ContextTokenGetterDecl(factory, refLabelName) );
}
}
return decls;
}
/** Add local var decl */
public void addLocalDecl(Decl d) {
if ( locals ==null ) locals = new OrderedHashSet();
locals.add(d);
d.isLocal = true;
}
/** Add decl to struct ctx for rule or alt if labeled */
public void addContextDecl(String altLabel, Decl d) {
CodeBlockForOuterMostAlt alt = d.getOuterMostAltCodeBlock();
// if we found code blk and might be alt label, try to add to that label ctx
if ( alt!=null && altLabelCtxs!=null ) {
// System.out.println(d.name+" lives in alt "+alt.alt.altNum);
AltLabelStructDecl altCtx = altLabelCtxs.get(altLabel);
if ( altCtx!=null ) { // we have an alt ctx
// System.out.println("ctx is "+ altCtx.name);
altCtx.addDecl(d);
return;
}
}
ruleCtx.addDecl(d); // stick in overall rule's ctx
}
}