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.
/*
* [The "BSD license"]
* Copyright (c) 2012 Terence Parr
* Copyright (c) 2012 Sam Harwell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
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
}
}