diff --git a/tool/src/org/antlr/v4/semantics/AttributeChecks.java b/tool/src/org/antlr/v4/semantics/AttributeChecks.java index 576c48cf3..dc934da36 100644 --- a/tool/src/org/antlr/v4/semantics/AttributeChecks.java +++ b/tool/src/org/antlr/v4/semantics/AttributeChecks.java @@ -68,16 +68,15 @@ public class AttributeChecks implements ActionSplitterListener { new AttributeChecks(g, r, alt, node, rhs).examineAction(); } - public void qualifiedAttr(String expr, Token x, Token y) { - if ( !node.resolver.resolves(x.getText(), y.getText(), node) ) { - if ( !node.resolver.resolves(x.getText(), node) && - (r==null || !r.name.equals(x.getText())) ) - { - ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, - g.fileName, x, x.getText(), expr); - return; - } - if ( node.resolver.resolveRefToRule(x.getText(), node)!=null ) { + public void qualifiedAttr(String expr, Token x, Token y) { + if ( node.resolver.resolveToScope(x.getText(), node)==null ) { + ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, + g.fileName, x, x.getText(), expr); + return; + } + + if ( node.resolver.resolveToAttribute(x.getText(), y.getText(), node)==null ) { + if ( node.resolver.resolveToRule(x.getText(), node)!=null ) { Rule rref = g.getRule(x.getText()); if ( rref!=null && rref.args!=null && rref.args.get(y.getText())!=null ) { ErrorManager.grammarError(ErrorType.INVALID_RULE_PARAMETER_REF, @@ -95,7 +94,7 @@ public class AttributeChecks implements ActionSplitterListener { } public void setAttr(String expr, Token x, Token rhs) { - if ( !node.resolver.resolves(x.getText(), node) ) { + if ( node.resolver.resolveToAttribute(x.getText(), node)==null ) { ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, g.fileName, x, x.getText(), expr); } @@ -103,15 +102,15 @@ public class AttributeChecks implements ActionSplitterListener { } public void attr(String expr, Token x) { // arg, retval, predefined, token ref, rule ref, current rule - if ( node.resolver.resolveRefToRule(x.getText(), node)!=null ) { // or in rule and is rule ref - ErrorManager.grammarError(ErrorType.ISOLATED_RULE_SCOPE, - g.fileName, x, x.getText(), expr); - return; - } - if ( !node.resolver.resolves(x.getText(), node) ) { - ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, - g.fileName, x, x.getText(), expr); - } + if ( node.resolver.resolveToAttribute(x.getText(), node)==null ) { + if ( node.resolver.resolveToRule(x.getText(), node)!=null ) { // or in rule and is rule ref + ErrorManager.grammarError(ErrorType.ISOLATED_RULE_SCOPE, + g.fileName, x, x.getText(), expr); + return; + } + ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, + g.fileName, x, x.getText(), expr); + } } public void setDynamicScopeAttr(String expr, Token x, Token y, Token rhs) { @@ -120,18 +119,18 @@ public class AttributeChecks implements ActionSplitterListener { public void dynamicScopeAttr(String expr, Token x, Token y) { System.out.println(x+" :: "+y); - if ( !node.resolver.resolves(x.getText(), y.getText(), node) ) { - if ( !node.resolver.resolves(x.getText(), node) && - (r==null || !r.name.equals(x.getText())) ) - { - ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, - g.fileName, x, x.getText(), expr); - } - else { - ErrorManager.grammarError(ErrorType.UNKNOWN_DYNAMIC_SCOPE_ATTRIBUTE, - g.fileName, y, x.getText(), y.getText(), expr); - } - } +// if ( !node.resolver.resolves(x.getText(), y.getText(), node) ) { +// if ( !node.resolver.resolves(x.getText(), node) && +// (r==null || !r.name.equals(x.getText())) ) +// { +// ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, +// g.fileName, x, x.getText(), expr); +// } +// else { +// ErrorManager.grammarError(ErrorType.UNKNOWN_DYNAMIC_SCOPE_ATTRIBUTE, +// g.fileName, y, x.getText(), y.getText(), expr); +// } +// } } public void setDynamicNegativeIndexedScopeAttr(String expr, Token x, Token y, diff --git a/tool/src/org/antlr/v4/tool/Alternative.java b/tool/src/org/antlr/v4/tool/Alternative.java index 02c8abf29..d676f988f 100644 --- a/tool/src/org/antlr/v4/tool/Alternative.java +++ b/tool/src/org/antlr/v4/tool/Alternative.java @@ -35,39 +35,54 @@ public class Alternative implements AttributeResolver { public AttributeResolver getParent() { return rule; } - /** Is isolated x a token/rule/label ref? */ - public boolean resolves(String x, ActionAST node) { - boolean inAlt = - tokenRefs.get(x)!=null|| - ruleRefs.get(x)!=null || - labelDefs.get(x)!=null; - if ( inAlt ) return inAlt; - return getParent().resolves(x, node); - } - - /** Find x as token/rule/label ref then find y in properties list. */ - public boolean resolves(String x, String y, ActionAST node) { - if ( tokenRefs.get(x)!=null ) { // token ref in this alt? - return rule.getPredefinedScope(LabelType.TOKEN_LABEL).get(y)!=null; - } - if ( ruleRefs.get(x)!=null ) { // rule ref in this alt? - // look up rule, ask it to resolve y (must be retval or predefined) - return rule.g.getRule(x).resolvesAsRetvalOrProperty(y); - } - Rule r = resolveRefToRule(x, node); - if ( r!=null ) return r.resolvesAsRetvalOrProperty(y); - return getParent().resolves(x, y, node); - } - - public boolean dynScopeResolves(String x, ActionAST node) { - return getParent().dynScopeResolves(x,node); + // only rules have attr, not alts + public Attribute resolveToAttribute(String x, ActionAST node) { + return getParent().resolveToAttribute(x, node); } - public boolean dynScopeResolves(String x, String y, ActionAST node) { - return getParent().dynScopeResolves(x,y,node); + public Attribute resolveToAttribute(String x, String y, ActionAST node) { + AttributeScope s = resolveToScope(x, node); + return s.get(y); +// if ( s.get(y)!=null ) return s.get(y); +// return getParent().resolveToAttribute(x, y, node); } - public Rule resolveRefToRule(String x, ActionAST node) { + /** Is isolated x a token/rule/label ref? */ + public AttributeScope resolveToScope(String x, ActionAST node) { + if ( tokenRefs.get(x)!=null ) return AttributeScope.predefinedTokenScope; + if ( ruleRefs.get(x)!=null ) return AttributeScope.predefinedTokenScope; + List labels = labelDefs.get(x); + if ( labels !=null ) { + LabelElementPair anyLabelDef = labels.get(0); + return rule.getPredefinedScope(anyLabelDef.type); + } + return getParent().resolveToScope(x, node); + } + + // public boolean resolves(String x, ActionAST node) { +// boolean inAlt = +// tokenRefs.get(x)!=null|| +// ruleRefs.get(x)!=null || +// labelDefs.get(x)!=null; +// if ( inAlt ) return inAlt; +// return getParent().resolves(x, node); +// } +// +// /** Find x as token/rule/label ref then find y in properties list. */ +// public boolean resolves(String x, String y, ActionAST node) { +// if ( tokenRefs.get(x)!=null ) { // token ref in this alt? +// return rule.getPredefinedScope(LabelType.TOKEN_LABEL).get(y)!=null; +// } +// if ( ruleRefs.get(x)!=null ) { // rule ref in this alt? +// // look up rule, ask it to resolve y (must be retval or predefined) +// return rule.g.getRule(x).resolvesAsRetvalOrProperty(y); +// } +// Rule r = resolveRule(x, node); +// if ( r!=null ) return r.resolvesAsRetvalOrProperty(y); +// return getParent().resolves(x, y, node); +// } + + public Rule resolveToRule(String x, ActionAST node) { if ( ruleRefs.get(x)!=null ) return rule.g.getRule(x); List labels = labelDefs.get(x); if ( labels!=null ) { // it's a label ref. is it a rule label? @@ -76,6 +91,6 @@ public class Alternative implements AttributeResolver { return rule.g.getRule(anyLabelDef.element.getText()); } } - return getParent().resolveRefToRule(x, node); + return getParent().resolveToRule(x, node); } } diff --git a/tool/src/org/antlr/v4/tool/AttributeResolver.java b/tool/src/org/antlr/v4/tool/AttributeResolver.java index e52ff04c2..f1b427034 100644 --- a/tool/src/org/antlr/v4/tool/AttributeResolver.java +++ b/tool/src/org/antlr/v4/tool/AttributeResolver.java @@ -7,9 +7,9 @@ package org.antlr.v4.tool; */ public interface AttributeResolver { public AttributeResolver getParent(); - public boolean resolves(String x, ActionAST node); - public boolean resolves(String x, String y, ActionAST node); - public boolean dynScopeResolves(String x, ActionAST node); - public boolean dynScopeResolves(String x, String y, ActionAST node); - public Rule resolveRefToRule(String x, ActionAST node); + public Attribute resolveToAttribute(String x, ActionAST node); + public Attribute resolveToAttribute(String x, String y, ActionAST node); + public AttributeScope resolveToScope(String x, ActionAST node); + /** Resolve to surrounding rule, rule ref/label if in alt, or other rule */ + public Rule resolveToRule(String x, ActionAST node); } diff --git a/tool/src/org/antlr/v4/tool/AttributeScope.java b/tool/src/org/antlr/v4/tool/AttributeScope.java index 14ae2afc2..58a1a6050 100644 --- a/tool/src/org/antlr/v4/tool/AttributeScope.java +++ b/tool/src/org/antlr/v4/tool/AttributeScope.java @@ -13,8 +13,9 @@ import java.util.Set; */ public class AttributeScope { /** The scope name */ - protected String name; + public String name; public GrammarAST ast; +// public Type type; /** All token scopes (token labels) share the same fixed scope of * of predefined attributes. I keep this out of the runtime.Token diff --git a/tool/src/org/antlr/v4/tool/Grammar.java b/tool/src/org/antlr/v4/tool/Grammar.java index 731c8db04..26e8cb1f1 100644 --- a/tool/src/org/antlr/v4/tool/Grammar.java +++ b/tool/src/org/antlr/v4/tool/Grammar.java @@ -214,33 +214,35 @@ public class Grammar implements AttributeResolver { public AttributeResolver getParent() { return null; } - /** $x in grammar action can only be scope name */ - public boolean resolves(String x, ActionAST node) { - return scopes.get(x)!=null; - } - - /** $x.y makes no sense in grammar action; Rule.resolves() - * shouldn't call this. - */ - public boolean resolves(String x, String y, ActionAST node) { return false; } - - public boolean dynScopeResolves(String x, ActionAST node) { - if ( scopes.get(x)!=null ) return true; - // resolve inside of a rule? x can be any rule ref - if ( !(node.resolver instanceof Grammar) ) { - Rule r = getRule(x); - if ( r!=null && r.scope!=null ) return true; - } - return false; + // no isolated attr at grammar action level + public Attribute resolveToAttribute(String x, ActionAST node) { + return null; } - public boolean dynScopeResolves(String x, String y, ActionAST node) { + public Attribute resolveToAttribute(String x, String y, ActionAST node) { + AttributeScope s = resolveToScope(x, node); + return s.get(y); + } + + // $x can be scope (but not rule with scope) + public AttributeScope resolveToScope(String x, ActionAST node) { AttributeScope s = scopes.get(x); - return s.get(y)!=null; + if ( s!=null ) return s; + return null; } + // /** $x in grammar action can only be scope name */ +// public boolean resolves(String x, ActionAST node) { +// return scopes.get(x)!=null; +// } +// +// /** $x.y makes no sense in grammar action; Rule.resolves() +// * shouldn't call this. +// */ +// public boolean resolves(String x, String y, ActionAST node) { return false; } + /** Can't be a rule ref in grammar named action */ - public Rule resolveRefToRule(String x, ActionAST node) { return null; } + public Rule resolveToRule(String x, ActionAST node) { return null; } /** Given a grammar type, what should be the default action scope? * If I say @members in a COMBINED grammar, for example, the diff --git a/tool/src/org/antlr/v4/tool/Rule.java b/tool/src/org/antlr/v4/tool/Rule.java index c18ec1d1a..b2fccd527 100644 --- a/tool/src/org/antlr/v4/tool/Rule.java +++ b/tool/src/org/antlr/v4/tool/Rule.java @@ -79,49 +79,25 @@ public class Rule implements AttributeResolver { for (int i=1; i<=numberOfAlts; i++) alt[i] = new Alternative(this); } - public AttributeResolver getParent() { return g; } - /** Is isolated x an arg, retval, predefined prop? */ - public boolean resolves(String x, ActionAST node) { - if ( resolvesAsRetvalOrProperty(x) ) return true; - if ( args.get(x)!=null ) return true; - // resolve outside of an alt? - if ( node.resolver instanceof Alternative ) return getParent().resolves(x, node); - if ( getLabelNames().contains(x) ) return true; // can see all labels if not in alt - return getParent().resolves(x, node); - } - - /** For $x.y, is x an arg, retval, predefined prop, token/rule/label ref? - * If so, make sure y resolves within that perspective. - * For $x::y, is x this rule or another? If so, is y in that scope? - */ - public boolean resolves(String x, String y, ActionAST node) { - Rule r = resolveRefToRule(x, node); - if ( r!=null ) return r.resolvesAsRetvalOrProperty(y); - return getParent().resolves(x,y,node); - } - - public boolean dynScopeResolves(String x, ActionAST node) { - return x.equals(this.name); - } - - public boolean dynScopeResolves(String x, String y, ActionAST node) { - return x.equals(this.name) && scope.get(y)!=null; - } - - public Rule resolveRefToRule(String x, ActionAST node) { - if ( x.equals(this.name) ) return this; - if ( node.resolver == this ) { // action not in alt (attr space is this rule) - List labels = getLabelDefs().get(x); - if ( labels!=null ) { // it's a label ref. is it a rule label? - LabelElementPair anyLabelDef = labels.get(0); - if ( anyLabelDef.type==LabelType.RULE_LABEL ) { - return g.getRule(anyLabelDef.element.getText()); - } - } - } - return null; // don't look for general rule (not one ref'd in this rule) - } +// public boolean resolves(String x, ActionAST node) { +// if ( resolvesAsRetvalOrProperty(x) ) return true; +// if ( args.get(x)!=null ) return true; +// // resolve outside of an alt? +// if ( node.resolver instanceof Alternative ) return getParent().resolves(x, node); +// if ( getLabelNames().contains(x) ) return true; // can see all labels if not in alt +// return getParent().resolves(x, node); +// } +// +// /** For $x.y, is x an arg, retval, predefined prop, token/rule/label ref? +// * If so, make sure y resolves within that perspective. +// * For $x::y, is x this rule or another? If so, is y in that scope? +// */ +// public boolean resolves(String x, String y, ActionAST node) { +// Rule r = resolveRule(x, node); +// if ( r!=null ) return r.resolvesAsRetvalOrProperty(y); +// return getParent().resolves(x,y,node); +// } public boolean resolvesAsRetvalOrProperty(String y) { if ( retvals.get(y)!=null ) return true; @@ -156,7 +132,56 @@ public class Rule implements AttributeResolver { return defs; } - /** Look up name from context of this rule and an alternative. + public AttributeResolver getParent() { return g; } + + public Attribute resolveToAttribute(String x, ActionAST node) { + Attribute a = args.get(name); if ( a!=null ) return a; + a = retvals.get(name); if ( a!=null ) return a; + AttributeScope properties = getPredefinedScope(LabelType.RULE_LABEL); + a = properties.get(name); + if ( a!=null ) return a; + // not here? look in grammar for global scope + return getParent().resolveToAttribute(x, node); + } + + public Attribute resolveToAttribute(String x, String y, ActionAST node) { + AttributeScope s = resolveToScope(x, node); + return s.get(y); + } + + /** $r ref in rule r? if not, look for x in grammar's perspective + */ + public AttributeScope resolveToScope(String x, ActionAST node) { + if ( this.name.equals(x) ) { + return getPredefinedScope(LabelType.RULE_LABEL); + } + if ( node.resolver == this ) { // action not in alt (attr space is this rule) + List labels = getLabelDefs().get(x); + if ( labels!=null ) { // it's a label ref. is it a rule label? + LabelElementPair anyLabelDef = labels.get(0); + if ( anyLabelDef.type==LabelType.RULE_LABEL ) { + return getPredefinedScope(LabelType.RULE_LABEL); + } + } + } + return getParent().resolveToScope(x, node); + } + + public Rule resolveToRule(String x, ActionAST node) { + if ( x.equals(this.name) ) return this; + if ( node.resolver == this ) { // action not in alt (attr space is this rule) + List labels = getLabelDefs().get(x); + if ( labels!=null ) { // it's a label ref. is it a rule label? + LabelElementPair anyLabelDef = labels.get(0); + if ( anyLabelDef.type==LabelType.RULE_LABEL ) { + return g.getRule(anyLabelDef.element.getText()); + } + } + } + return null; // don't look for general rule (not one ref'd in this rule) + } + + /** Look up name from context of this rule and an alternative. * Find an arg, retval, predefined property, or label/rule/token ref. */ // public Attribute resolve(String name) {