hydraql.shaded.org.antlr.v4.tool.Rule Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2012-2017 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 hydraql.shaded.org.antlr.v4.tool;
import hydraql.shaded.org.antlr.v4.runtime.misc.Pair;
import hydraql.shaded.org.antlr.v4.tool.ast.ActionAST;
import hydraql.shaded.org.antlr.v4.tool.ast.AltAST;
import hydraql.shaded.org.antlr.v4.tool.ast.GrammarAST;
import hydraql.shaded.org.antlr.v4.tool.ast.PredAST;
import hydraql.shaded.org.antlr.v4.tool.ast.RuleAST;
import hydraql.shaded.org.stringtemplate.v4.misc.MultiMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Rule implements AttributeResolver {
/** Rule refs have a predefined set of attributes as well as
* the return values and args.
*
* These must be consistent with ActionTranslator.rulePropToModelMap, ...
*/
public static final AttributeDict predefinedRulePropertiesDict =
new AttributeDict(AttributeDict.DictType.PREDEFINED_RULE);
static {
predefinedRulePropertiesDict.add(new Attribute("parser"));
predefinedRulePropertiesDict.add(new Attribute("text"));
predefinedRulePropertiesDict.add(new Attribute("start"));
predefinedRulePropertiesDict.add(new Attribute("stop"));
predefinedRulePropertiesDict.add(new Attribute("ctx"));
}
public static final Set validLexerCommands = new HashSet();
static {
// CALLS
validLexerCommands.add("mode");
validLexerCommands.add("pushMode");
validLexerCommands.add("type");
validLexerCommands.add("channel");
// ACTIONS
validLexerCommands.add("popMode");
validLexerCommands.add("skip");
validLexerCommands.add("more");
}
public final String name;
public List modifiers;
public RuleAST ast;
public AttributeDict args;
public AttributeDict retvals;
public AttributeDict locals;
/** In which grammar does this rule live? */
public final Grammar g;
/** If we're in a lexer grammar, we might be in a mode */
public final String mode;
/** If null then use value from global option that is false by default */
public final boolean caseInsensitive;
/** Map a name to an action for this rule like @init {...}.
* The code generator will use this to fill holes in the rule template.
* I track the AST node for the action in case I need the line number
* for errors.
*/
public Map namedActions =
new HashMap();
/** Track exception handlers; points at "catch" node of (catch exception action)
* don't track finally action
*/
public List exceptions = new ArrayList();
/** Track all executable actions other than named actions like @init
* and catch/finally (not in an alt). Also tracks predicates, rewrite actions.
* We need to examine these actions before code generation so
* that we can detect refs to $rule.attr etc...
*
* This tracks per rule; Alternative objs also track per alt.
*/
public List actions = new ArrayList();
public ActionAST finallyAction;
public final int numberOfAlts;
public boolean isStartRule = true; // nobody calls us
/** 1..n alts */
public Alternative[] alt;
/** All rules have unique index 0..n-1 */
public int index;
public int actionIndex = -1; // if lexer; 0..n-1 for n actions in a rule
public Rule(Grammar g, String name, RuleAST ast, int numberOfAlts) {
this(g, name, ast, numberOfAlts, null, false);
}
public Rule(Grammar g, String name, RuleAST ast, int numberOfAlts, String lexerMode, boolean caseInsensitive) {
this.g = g;
this.name = name;
this.ast = ast;
this.numberOfAlts = numberOfAlts;
alt = new Alternative[numberOfAlts+1]; // 1..n
for (int i=1; i<=numberOfAlts; i++) alt[i] = new Alternative(this, i);
this.mode = lexerMode;
this.caseInsensitive = caseInsensitive;
}
public void defineActionInAlt(int currentAlt, ActionAST actionAST) {
actions.add(actionAST);
alt[currentAlt].actions.add(actionAST);
if ( g.isLexer() ) {
defineLexerAction(actionAST);
}
}
/** Lexer actions are numbered across rules 0..n-1 */
public void defineLexerAction(ActionAST actionAST) {
actionIndex = g.lexerActions.size();
if ( g.lexerActions.get(actionAST)==null ) {
g.lexerActions.put(actionAST, actionIndex);
}
}
public void definePredicateInAlt(int currentAlt, PredAST predAST) {
actions.add(predAST);
alt[currentAlt].actions.add(predAST);
if ( g.sempreds.get(predAST)==null ) {
g.sempreds.put(predAST, g.sempreds.size());
}
}
public Attribute resolveRetvalOrProperty(String y) {
if ( retvals!=null ) {
Attribute a = retvals.get(y);
if ( a!=null ) return a;
}
AttributeDict d = getPredefinedScope(LabelType.RULE_LABEL);
return d.get(y);
}
public Set getTokenRefs() {
Set refs = new HashSet();
for (int i=1; i<=numberOfAlts; i++) {
refs.addAll(alt[i].tokenRefs.keySet());
}
return refs;
}
public Set getElementLabelNames() {
Set refs = new HashSet();
for (int i=1; i<=numberOfAlts; i++) {
refs.addAll(alt[i].labelDefs.keySet());
}
if ( refs.isEmpty() ) return null;
return refs;
}
public MultiMap getElementLabelDefs() {
MultiMap defs =
new MultiMap();
for (int i=1; i<=numberOfAlts; i++) {
for (List pairs : alt[i].labelDefs.values()) {
for (LabelElementPair p : pairs) {
defs.map(p.label.getText(), p);
}
}
}
return defs;
}
public boolean hasAltSpecificContexts() {
return getAltLabels()!=null;
}
/** Used for recursive rules (subclass), which have 1 alt, but many original alts */
public int getOriginalNumberOfAlts() {
return numberOfAlts;
}
/**
* Get {@code #} labels. The keys of the map are the labels applied to outer
* alternatives of a lexer rule, and the values are collections of pairs
* (alternative number and {@link AltAST}) identifying the alternatives with
* this label. Unlabeled alternatives are not included in the result.
*/
public Map>> getAltLabels() {
Map>> labels = new LinkedHashMap>>();
for (int i=1; i<=numberOfAlts; i++) {
GrammarAST altLabel = alt[i].ast.altLabel;
if ( altLabel!=null ) {
List> list = labels.get(altLabel.getText());
if (list == null) {
list = new ArrayList>();
labels.put(altLabel.getText(), list);
}
list.add(new Pair(i, alt[i].ast));
}
}
if ( labels.isEmpty() ) return null;
return labels;
}
public List getUnlabeledAltASTs() {
List alts = new ArrayList();
for (int i=1; i<=numberOfAlts; i++) {
GrammarAST altLabel = alt[i].ast.altLabel;
if ( altLabel==null ) alts.add(alt[i].ast);
}
if ( alts.isEmpty() ) return null;
return alts;
}
/** $x Attribute: rule arguments, return values, predefined rule prop.
*/
@Override
public Attribute resolveToAttribute(String x, ActionAST node) {
if ( args!=null ) {
Attribute a = args.get(x); if ( a!=null ) return a;
}
if ( retvals!=null ) {
Attribute a = retvals.get(x); if ( a!=null ) return a;
}
if ( locals!=null ) {
Attribute a = locals.get(x); if ( a!=null ) return a;
}
AttributeDict properties = getPredefinedScope(LabelType.RULE_LABEL);
return properties.get(x);
}
/** $x.y Attribute: x is surrounding rule, label ref (in any alts) */
@Override
public Attribute resolveToAttribute(String x, String y, ActionAST node) {
LabelElementPair anyLabelDef = getAnyLabelDef(x);
if ( anyLabelDef!=null ) {
if ( anyLabelDef.type==LabelType.RULE_LABEL ) {
return g.getRule(anyLabelDef.element.getText()).resolveRetvalOrProperty(y);
}
else {
AttributeDict scope = getPredefinedScope(anyLabelDef.type);
if (scope == null) {
return null;
}
return scope.get(y);
}
}
return null;
}
@Override
public boolean resolvesToLabel(String x, ActionAST node) {
LabelElementPair anyLabelDef = getAnyLabelDef(x);
return anyLabelDef!=null &&
(anyLabelDef.type==LabelType.RULE_LABEL ||
anyLabelDef.type==LabelType.TOKEN_LABEL);
}
@Override
public boolean resolvesToListLabel(String x, ActionAST node) {
LabelElementPair anyLabelDef = getAnyLabelDef(x);
return anyLabelDef!=null &&
(anyLabelDef.type==LabelType.RULE_LIST_LABEL ||
anyLabelDef.type==LabelType.TOKEN_LIST_LABEL);
}
@Override
public boolean resolvesToToken(String x, ActionAST node) {
LabelElementPair anyLabelDef = getAnyLabelDef(x);
if ( anyLabelDef!=null && anyLabelDef.type==LabelType.TOKEN_LABEL ) return true;
return false;
}
@Override
public boolean resolvesToAttributeDict(String x, ActionAST node) {
if ( resolvesToToken(x, node) ) return true;
return false;
}
public Rule resolveToRule(String x) {
if ( x.equals(this.name) ) return this;
LabelElementPair anyLabelDef = getAnyLabelDef(x);
if ( anyLabelDef!=null && anyLabelDef.type==LabelType.RULE_LABEL ) {
return g.getRule(anyLabelDef.element.getText());
}
return g.getRule(x);
}
public LabelElementPair getAnyLabelDef(String x) {
List labels = getElementLabelDefs().get(x);
if ( labels!=null ) return labels.get(0);
return null;
}
public AttributeDict getPredefinedScope(LabelType ltype) {
String grammarLabelKey = g.getTypeString() + ":" + ltype;
return Grammar.grammarAndLabelRefTypeToScope.get(grammarLabelKey);
}
public boolean isFragment() {
if ( modifiers==null ) return false;
for (GrammarAST a : modifiers) {
if ( a.getText().equals("fragment") ) return true;
}
return false;
}
@Override
public int hashCode() { return name.hashCode(); }
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Rule)) {
return false;
}
return name.equals(((Rule)obj).name);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("Rule{name=").append(name);
if ( args!=null ) buf.append(", args=").append(args);
if ( retvals!=null ) buf.append(", retvals=").append(retvals);
buf.append("}");
return buf.toString();
}
}