diff --git a/tool/resources/org/antlr/v4/tool/templates/messages/languages/en.stg b/tool/resources/org/antlr/v4/tool/templates/messages/languages/en.stg index 7ad4c47c8..fc321e086 100644 --- a/tool/resources/org/antlr/v4/tool/templates/messages/languages/en.stg +++ b/tool/resources/org/antlr/v4/tool/templates/messages/languages/en.stg @@ -122,7 +122,7 @@ UNKNOWN_RULE_ATTRIBUTE(arg,arg2,arg3) ::= "unknown attribute for rule in " UNKNOWN_SIMPLE_ATTRIBUTE(arg,arg2) ::= "unknown attribute reference in " -ISOLATED_RULE_SCOPE(arg,arg2) ::= +ISOLATED_RULE_REF(arg,arg2) ::= "missing attribute access on rule reference in " INVALID_RULE_PARAMETER_REF(arg,arg2) ::= "cannot access rule 's parameter: " diff --git a/tool/src/org/antlr/v4/semantics/AttributeChecks.java b/tool/src/org/antlr/v4/semantics/AttributeChecks.java index 0ea700f20..d69817f22 100644 --- a/tool/src/org/antlr/v4/semantics/AttributeChecks.java +++ b/tool/src/org/antlr/v4/semantics/AttributeChecks.java @@ -71,19 +71,18 @@ public class AttributeChecks implements ActionSplitterListener { // $x.y public void qualifiedAttr(String expr, Token x, Token y) { if ( node.resolver.resolveToAttribute(x.getText(), y.getText(), node)==null ) { - Rule r = node.resolver.resolveToRule(x.getText(), node); - if ( r!=null ) { - Rule rref = g.getRule(x.getText()); + Rule rref = isolatedRuleRef(x.getText()); + if ( rref!=null ) { if ( rref!=null && rref.args!=null && rref.args.get(y.getText())!=null ) { ErrorManager.grammarError(ErrorType.INVALID_RULE_PARAMETER_REF, g.fileName, y, y.getText(), expr); } else { ErrorManager.grammarError(ErrorType.UNKNOWN_RULE_ATTRIBUTE, - g.fileName, y, y.getText(), r.name, expr); + g.fileName, y, y.getText(), rref.name, expr); } } - else if ( !node.resolver.resolvesToAttributeDict(x.getText(), node) ) { + else if ( !resolvesToAttributeDict(x.getText()) ) { ErrorManager.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE, g.fileName, x, x.getText(), expr); } @@ -107,8 +106,8 @@ public class AttributeChecks implements ActionSplitterListener { if ( node.resolver.resolveToDynamicScope(x.getText(), node)!=null ) { return; // $S for scope S is ok } - if ( node.resolver.resolveToRule(x.getText(), node)!=null ) { - ErrorManager.grammarError(ErrorType.ISOLATED_RULE_SCOPE, + if ( isolatedRuleRef(x.getText())!=null ) { + ErrorManager.grammarError(ErrorType.ISOLATED_RULE_REF, g.fileName, x, x.getText(), expr); return; } @@ -174,4 +173,53 @@ public class AttributeChecks implements ActionSplitterListener { public void setExprAttribute(String expr) { } public void setAttribute(String expr) { } public void templateExpr(String expr) { } + + // SUPPORT + + public Rule isolatedRuleRef(String x) { + if ( node.resolver instanceof Grammar ) return null; + + if ( x.equals(r.name) ) return r; + List labels = null; + if ( node.resolver instanceof Rule ) { + labels = r.getLabelDefs().get(x); + } + else if ( node.resolver instanceof Alternative ) { + labels = ((Alternative)node.resolver).labelDefs.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()); + } + } + if ( node.resolver instanceof Alternative ) { + if ( ((Alternative)node.resolver).ruleRefs.get(x)!=null ) { + return g.getRule(x); + } + } + return null; + } + + public boolean resolvesToAttributeDict(String x) { + if ( node.resolver instanceof Grammar ) return g.scopes.get(x)!=null; + + List labels = null; + if ( node.resolver instanceof Rule ) { + labels = r.getLabelDefs().get(x); + } + else if ( node.resolver instanceof Alternative ) { + labels = ((Alternative)node.resolver).labelDefs.get(x); + } + if ( labels!=null ) { // it's a label ref. is it a token label? + LabelElementPair anyLabelDef = labels.get(0); + if ( anyLabelDef.type==LabelType.TOKEN_LABEL ) return true; + } + if ( x.equals(r.name) ) return true; // $r for action in rule r, $r is a dict + Rule r = g.getRule(x); + if ( r!=null && r.scope!=null ) return true; + if ( g.scopes.get(x)!=null ) return true; + return false; + } + } diff --git a/tool/src/org/antlr/v4/tool/Alternative.java b/tool/src/org/antlr/v4/tool/Alternative.java index 75df31996..f1c9273d5 100644 --- a/tool/src/org/antlr/v4/tool/Alternative.java +++ b/tool/src/org/antlr/v4/tool/Alternative.java @@ -33,8 +33,6 @@ public class Alternative implements AttributeResolver { public Alternative(Rule r) { this.rule = r; } - private AttributeResolver getParent() { return rule; } - /** $x Attribute: rule arguments, return values, predefined rule prop. */ public Attribute resolveToAttribute(String x, ActionAST node) { @@ -70,56 +68,13 @@ public class Alternative implements AttributeResolver { return null; } - /** $x AttributeDict: references to tokens and token labels in the - * current alt (including any elements within subrules contained - * in that outermost alt). x can be rule with scope or a global scope. - * - * x can also be surrounding rule since we use for error checking. - */ - public boolean resolvesToAttributeDict(String x, ActionAST node) { - if ( tokenRefs.get(x)!=null ) return true; - List labels = labelDefs.get(x); - if ( labels!=null ) { // it's a label ref. is it a token label? - LabelElementPair anyLabelDef = labels.get(0); - if ( anyLabelDef.type==LabelType.TOKEN_LABEL ) return true; - } - if ( x.equals(rule.name) ) return true; // $r for action in rule r, $r is a dict - Rule r = rule.g.getRule(x); - if ( r!=null && r.scope!=null ) return true; - if ( rule.g.scopes.get(x)!=null ) return true; - return false; - } - - // 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 AttributeDict resolveToDynamicScope(String x, ActionAST node) { Rule r = resolveToRule(x, node); if ( r!=null && r.scope !=null ) return r.scope; - return getParent().resolveToDynamicScope(x, node); + return rule.resolveToDynamicScope(x, node); } + /** x can be ruleref or rule label. */ public Rule resolveToRule(String x, ActionAST node) { if ( ruleRefs.get(x)!=null ) return rule.g.getRule(x); List labels = labelDefs.get(x); @@ -129,6 +84,7 @@ public class Alternative implements AttributeResolver { return rule.g.getRule(anyLabelDef.element.getText()); } } - return getParent().resolveToRule(x, node); + if ( x.equals(rule.name) ) return rule; + return null; } } diff --git a/tool/src/org/antlr/v4/tool/AttributeResolver.java b/tool/src/org/antlr/v4/tool/AttributeResolver.java index 673804213..57abc9a6b 100644 --- a/tool/src/org/antlr/v4/tool/AttributeResolver.java +++ b/tool/src/org/antlr/v4/tool/AttributeResolver.java @@ -30,10 +30,5 @@ package org.antlr.v4.tool; public interface AttributeResolver { public Attribute resolveToAttribute(String x, ActionAST node); public Attribute resolveToAttribute(String x, String y, ActionAST node); - /** Error checking when $x.y is not attribute. We ask if $x is a dict. */ - public boolean resolvesToAttributeDict(String x, ActionAST node); public AttributeDict resolveToDynamicScope(String x, ActionAST node); - //public Attribute resolveToDynamicScopeAttribute(String x, String y, 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/ErrorType.java b/tool/src/org/antlr/v4/tool/ErrorType.java index 7dc1ef4f7..271ba227c 100644 --- a/tool/src/org/antlr/v4/tool/ErrorType.java +++ b/tool/src/org/antlr/v4/tool/ErrorType.java @@ -80,7 +80,7 @@ public enum ErrorType { INVALID_RULE_PARAMETER_REF(ErrorSeverity.ERROR, true, true), UNKNOWN_RULE_ATTRIBUTE(ErrorSeverity.ERROR, true, true), UNKNOWN_ATTRIBUTE_IN_SCOPE(ErrorSeverity.ERROR, true, true), - ISOLATED_RULE_SCOPE(ErrorSeverity.ERROR, true, true), + ISOLATED_RULE_REF(ErrorSeverity.ERROR, true, true), SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE(ErrorSeverity.ERROR, true, true), LABEL_CONFLICTS_WITH_RULE(ErrorSeverity.ERROR, true, true), LABEL_CONFLICTS_WITH_TOKEN(ErrorSeverity.ERROR, true, true), @@ -130,7 +130,7 @@ public enum ErrorType { AST_OP_IN_ALT_WITH_REWRITE(ErrorSeverity.ERROR, true, true), WILDCARD_AS_ROOT(ErrorSeverity.ERROR, true, true), CONFLICTING_OPTION_IN_TREE_FILTER(ErrorSeverity.ERROR, true, true), - /** Documentation comment is unterminated */ + /** Documentation comment is unterminated */ //UNTERMINATED_DOC_COMMENT(ErrorSeverity.ERROR, true, true), // Dependency sorting errors diff --git a/tool/src/org/antlr/v4/tool/Grammar.java b/tool/src/org/antlr/v4/tool/Grammar.java index aefc48d9a..551b33d77 100644 --- a/tool/src/org/antlr/v4/tool/Grammar.java +++ b/tool/src/org/antlr/v4/tool/Grammar.java @@ -222,19 +222,8 @@ public class Grammar implements AttributeResolver { return null; } - /** $s AttributeDict: s is a global scope */ - public boolean resolvesToAttributeDict(String x, ActionAST node) { - return scopes.get(x)!=null; - } - public AttributeDict resolveToDynamicScope(String x, ActionAST node) { - AttributeDict s = scopes.get(x); - if ( s !=null ) return s; - if ( node.resolver != this ) { // if not member action, can ref rule - Rule r = rules.get(x); - if ( r!=null ) return r.scope; - } - return null; + return scopes.get(x); } // /** $x in grammar action can only be scope name */ @@ -247,9 +236,6 @@ public class Grammar implements AttributeResolver { // */ // public boolean resolves(String x, String y, ActionAST node) { return false; } - /** Can't be a rule ref in grammar named action */ - 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 * default scope should be "parser". diff --git a/tool/src/org/antlr/v4/tool/Rule.java b/tool/src/org/antlr/v4/tool/Rule.java index 0ae170e00..16a6fba44 100644 --- a/tool/src/org/antlr/v4/tool/Rule.java +++ b/tool/src/org/antlr/v4/tool/Rule.java @@ -135,8 +135,6 @@ public class Rule implements AttributeResolver { return defs; } - private AttributeResolver getParent() { return g; } - /** $x Attribute: rule arguments, return values, predefined rule prop. */ public Attribute resolveToAttribute(String x, ActionAST node) { Attribute a = args.get(x); if ( a!=null ) return a; @@ -163,93 +161,23 @@ public class Rule implements AttributeResolver { } - /** $x AttributeDict: references to token labels in *any* alt. x can - * be any rule with scope or global scope or surrounding rule x. - */ - public boolean resolvesToAttributeDict(String x, ActionAST node) { - List labels = getLabelDefs().get(x); - if ( labels!=null ) { // it's a label ref. is it a token label? - LabelElementPair anyLabelDef = labels.get(0); - if ( anyLabelDef.type==LabelType.TOKEN_LABEL ) return true; - } - if ( x.equals(this.name) ) return true; // $r for action in rule r, $r is a dict - Rule r = g.getRule(x); - if ( r!=null && r.scope!=null ) return true; - if ( g.scopes.get(x)!=null ) return true; - return false; - } - public AttributeDict resolveToDynamicScope(String x, ActionAST node) { - Rule r = resolveToRule(x, node); - if ( r!=null && r.scope !=null ) return r.scope; - return getParent().resolveToDynamicScope(x, node); + Rule r = resolveToRule(x); + if ( r!=null && r.scope!=null ) return r.scope; + return g.scopes.get(x); } - 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) + public Rule resolveToRule(String x) { + if ( x.equals(this.name) ) return this; + 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 g.getRule(x); } - - /** 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) { -// 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; -// -// //alt[currentAlt].tokenRefs -// // not here? look in grammar for global scope -// return null; -// } - - /** Resolve x in $x.y to - */ -// public AttributeScope resolveScope(String name, Alternative alt) { -// AttributeScope s = null; -// if ( this.name.equals(name) ) { // $r ref in rule r -// s = resolveLocalAttributeScope(name); -// if ( s!=null ) return s; -// } -// -// if ( alt.tokenRefs.get(name)!=null ) { // token ref in this alt? -// return getPredefinedScope(LabelType.TOKEN_LABEL); -// } -// if ( alt.ruleRefs.get(name)!=null ) { // rule ref in this alt? -// s = getLocalAttributeScope(name); -// if ( s!=null ) return s; -// } -// List labels = alt.labelDefs.get(name); // label -// if ( labels!=null ) { -// // it's a label ref, compute scope from label type and grammar type -// LabelElementPair anyLabelDef = labels.get(0); -// return getPredefinedScope(anyLabelDef.type); -// } -// return null; -// } -// -// /** Look for name in the arg, return value, predefined property, -// * or dynamic scope attribute list for this rule. -// */ -// public AttributeScope resolveLocalAttributeScope(String name) { -// if ( args.get(name)!=null ) return args; -// if ( retvals.get(name)!=null ) return retvals; -// AttributeScope s = getPredefinedScope(LabelType.RULE_LABEL); -// if ( s.get(name)!=null ) return s; -// if ( scope!=null && scope.get(name)!=null ) return scope; -// return null; -// } public AttributeDict getPredefinedScope(LabelType ltype) { String grammarLabelKey = g.getTypeString() + ":" + ltype; diff --git a/tool/test/org/antlr/v4/test/TestAttributeChecks.java b/tool/test/org/antlr/v4/test/TestAttributeChecks.java index 2d4e2c571..33604e38e 100644 --- a/tool/test/org/antlr/v4/test/TestAttributeChecks.java +++ b/tool/test/org/antlr/v4/test/TestAttributeChecks.java @@ -73,7 +73,7 @@ public class TestAttributeChecks extends BaseTest { "$a.ick = 3;", "error(31): A.g:6:6: unknown attribute ick for rule a in $a.ick = 3;", "$b.d", "error(30): A.g:6:6: cannot access rule d's parameter: $b.d", // can't see rule ref's arg "$d.text", "error(29): A.g:6:4: unknown attribute reference d in $d.text", // valid rule, but no ref - "$lab.d", "error(31): A.g:6:8: unknown attribute d for rule b in $lab.d", + "$lab.d", "error(30): A.g:6:8: cannot access rule d's parameter: $lab.d", }; String[] finallyChecks = { @@ -91,7 +91,7 @@ public class TestAttributeChecks extends BaseTest { "$b", "error(29): A.g:9:14: unknown attribute reference b in $b", "$b.d", "error(29): A.g:9:14: unknown attribute reference b in $b.d", "$c.text", "error(29): A.g:9:14: unknown attribute reference c in $c.text", - "$lab.d", "error(31): A.g:9:18: unknown attribute d for rule b in $lab.d", + "$lab.d", "error(30): A.g:9:18: cannot access rule d's parameter: $lab.d", }; String[] dynMembersChecks = {