Merge pull request #1458 from KvanTTT/mixed_type_labels_1409
Check labels for tokens with different types
This commit is contained in:
commit
11117e02d4
|
@ -285,4 +285,39 @@ public class TestSymbolIssues extends BaseJavaToolTest {
|
|||
|
||||
testErrors(test, false);
|
||||
}
|
||||
|
||||
// https://github.com/antlr/antlr4/issues/1409
|
||||
@Test public void testLabelsForTokensWithMixedTypes() {
|
||||
String[] test = {
|
||||
"grammar L;\n" +
|
||||
"\n" +
|
||||
"rule1 // Correct (Alternatives)\n" +
|
||||
" : t1 = a #aLabel\n" +
|
||||
" | t1 = b #bLabel\n" +
|
||||
" ;\n" +
|
||||
"rule2 //Incorrect type casting in generated code (RULE_LABEL)\n" +
|
||||
" : t2 = a | t2 = b\n" +
|
||||
" ;\n" +
|
||||
"rule3\n" +
|
||||
" : t3 += a+ b t3 += c+ //Incorrect type casting in generated code (RULE_LIST_LABEL)\n" +
|
||||
" ;\n" +
|
||||
"rule4\n" +
|
||||
" : a t4 = A b t4 = B c // Correct (TOKEN_LABEL)\n" +
|
||||
" ;\n" +
|
||||
"rule5\n" +
|
||||
" : a t5 += A b t5 += B c // Correct (TOKEN_LIST_LABEL)\n" +
|
||||
" ;\n" +
|
||||
"a: A;\n" +
|
||||
"b: B;\n" +
|
||||
"c: C;\n" +
|
||||
"A: 'a';\n" +
|
||||
"B: 'b';\n" +
|
||||
"C: 'c';\n",
|
||||
|
||||
"error(" + ErrorType.LABEL_TYPE_CONFLICT.code + "): L.g4:8:15: label t2=b type mismatch with previous definition: t2=a\n" +
|
||||
"error(" + ErrorType.LABEL_TYPE_CONFLICT.code + "): L.g4:11:17: label t3+=c type mismatch with previous definition: t3+=a\n"
|
||||
};
|
||||
|
||||
testErrors(test, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.antlr.v4.tool.LabelElementPair;
|
|||
import org.antlr.v4.tool.LexerGrammar;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
import org.antlr.v4.tool.ast.GrammarAST;
|
||||
import org.antlr.v4.tool.LabelType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -70,10 +71,10 @@ public class SymbolChecks {
|
|||
}
|
||||
|
||||
public void process() {
|
||||
// methods affect fields, but no side-effects outside this object
|
||||
// methods affect fields, but no side-effects outside this object
|
||||
// So, call order sensitive
|
||||
// First collect all rules for later use in checkForLabelConflict()
|
||||
if ( g.rules!=null ) {
|
||||
if (g.rules != null) {
|
||||
for (Rule r : g.rules.values()) nameToRuleMap.put(r.name, r);
|
||||
}
|
||||
checkReservedNames(g.rules.values());
|
||||
|
@ -83,41 +84,39 @@ public class SymbolChecks {
|
|||
}
|
||||
|
||||
public void checkActionRedefinitions(List<GrammarAST> actions) {
|
||||
if ( actions==null ) return;
|
||||
if (actions == null) return;
|
||||
String scope = g.getDefaultActionScope();
|
||||
String name;
|
||||
GrammarAST nameNode;
|
||||
for (GrammarAST ampersandAST : actions) {
|
||||
nameNode = (GrammarAST)ampersandAST.getChild(0);
|
||||
if ( ampersandAST.getChildCount()==2 ) {
|
||||
nameNode = (GrammarAST) ampersandAST.getChild(0);
|
||||
if (ampersandAST.getChildCount() == 2) {
|
||||
name = nameNode.getText();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
scope = nameNode.getText();
|
||||
name = ampersandAST.getChild(1).getText();
|
||||
}
|
||||
Set<String> scopeActions = actionScopeToActionNames.get(scope);
|
||||
if ( scopeActions==null ) { // init scope
|
||||
scopeActions = new HashSet<String>();
|
||||
actionScopeToActionNames.put(scope, scopeActions);
|
||||
}
|
||||
if ( !scopeActions.contains(name) ) {
|
||||
scopeActions.add(name);
|
||||
}
|
||||
else {
|
||||
errMgr.grammarError(ErrorType.ACTION_REDEFINITION,
|
||||
g.fileName, nameNode.token, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
name = ampersandAST.getChild(1).getText();
|
||||
}
|
||||
Set<String> scopeActions = actionScopeToActionNames.get(scope);
|
||||
if (scopeActions == null) { // init scope
|
||||
scopeActions = new HashSet<String>();
|
||||
actionScopeToActionNames.put(scope, scopeActions);
|
||||
}
|
||||
if (!scopeActions.contains(name)) {
|
||||
scopeActions.add(name);
|
||||
} else {
|
||||
errMgr.grammarError(ErrorType.ACTION_REDEFINITION,
|
||||
g.fileName, nameNode.token, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkForTokenConflicts(List<GrammarAST> tokenIDRefs) {
|
||||
public void checkForTokenConflicts(List<GrammarAST> tokenIDRefs) {
|
||||
// for (GrammarAST a : tokenIDRefs) {
|
||||
// Token t = a.token;
|
||||
// String ID = t.getText();
|
||||
// tokenIDs.add(ID);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/** Make sure a label doesn't conflict with another symbol.
|
||||
* Labels must not conflict with: rules, tokens, scope names,
|
||||
|
@ -126,43 +125,54 @@ public class SymbolChecks {
|
|||
* for repeated defs.
|
||||
*/
|
||||
public void checkForLabelConflicts(Collection<Rule> rules) {
|
||||
for (Rule r : rules) {
|
||||
checkForAttributeConflicts(r);
|
||||
Map<String, LabelElementPair> labelNameSpace =
|
||||
new HashMap<String, LabelElementPair>();
|
||||
for (int i=1; i<=r.numberOfAlts; i++) {
|
||||
for (Rule r : rules) {
|
||||
checkForAttributeConflicts(r);
|
||||
Map<String, LabelElementPair> labelNameSpace =
|
||||
new HashMap<String, LabelElementPair>();
|
||||
for (int i = 1; i <= r.numberOfAlts; i++) {
|
||||
if (r.hasAltSpecificContexts()) {
|
||||
labelNameSpace.clear();
|
||||
}
|
||||
|
||||
Alternative a = r.alt[i];
|
||||
for (List<LabelElementPair> pairs : a.labelDefs.values() ) {
|
||||
for (LabelElementPair p : pairs) {
|
||||
checkForLabelConflict(r, p.label);
|
||||
String name = p.label.getText();
|
||||
LabelElementPair prev = labelNameSpace.get(name);
|
||||
if ( prev==null ) labelNameSpace.put(name, p);
|
||||
else checkForTypeMismatch(prev, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Alternative a = r.alt[i];
|
||||
for (List<LabelElementPair> pairs : a.labelDefs.values()) {
|
||||
for (LabelElementPair p : pairs) {
|
||||
checkForLabelConflict(r, p.label);
|
||||
String name = p.label.getText();
|
||||
LabelElementPair prev = labelNameSpace.get(name);
|
||||
if (prev == null) labelNameSpace.put(name, p);
|
||||
else checkForTypeMismatch(prev, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkForTypeMismatch(LabelElementPair prevLabelPair,
|
||||
LabelElementPair labelPair)
|
||||
{
|
||||
// label already defined; if same type, no problem
|
||||
if ( prevLabelPair.type != labelPair.type ) {
|
||||
String typeMismatchExpr = labelPair.type+"!="+prevLabelPair.type;
|
||||
errMgr.grammarError(
|
||||
ErrorType.LABEL_TYPE_CONFLICT,
|
||||
g.fileName,
|
||||
labelPair.label.token,
|
||||
labelPair.label.getText(),
|
||||
typeMismatchExpr);
|
||||
}
|
||||
}
|
||||
void checkForTypeMismatch(LabelElementPair prevLabelPair, LabelElementPair labelPair) {
|
||||
// label already defined; if same type, no problem
|
||||
if (prevLabelPair.type != labelPair.type) {
|
||||
String typeMismatchExpr = labelPair.type + "!=" + prevLabelPair.type;
|
||||
errMgr.grammarError(
|
||||
ErrorType.LABEL_TYPE_CONFLICT,
|
||||
g.fileName,
|
||||
labelPair.label.token,
|
||||
labelPair.label.getText(),
|
||||
typeMismatchExpr);
|
||||
}
|
||||
if (!prevLabelPair.element.getText().equals(labelPair.element.getText()) &&
|
||||
(prevLabelPair.type.equals(LabelType.RULE_LABEL) || prevLabelPair.type.equals(LabelType.RULE_LIST_LABEL)) &&
|
||||
(labelPair.type.equals(LabelType.RULE_LABEL) || labelPair.type.equals(LabelType.RULE_LIST_LABEL))) {
|
||||
|
||||
String prevLabelOp = prevLabelPair.type.equals(LabelType.RULE_LIST_LABEL) ? "+=" : "=";
|
||||
String labelOp = labelPair.type.equals(LabelType.RULE_LIST_LABEL) ? "+=" : "=";
|
||||
errMgr.grammarError(
|
||||
ErrorType.LABEL_TYPE_CONFLICT,
|
||||
g.fileName,
|
||||
labelPair.label.token,
|
||||
labelPair.label.getText() + labelOp + labelPair.element.getText(),
|
||||
prevLabelPair.label.getText() + prevLabelOp + prevLabelPair.element.getText());
|
||||
}
|
||||
}
|
||||
|
||||
public void checkForLabelConflict(Rule r, GrammarAST labelID) {
|
||||
String name = labelID.getText();
|
||||
|
|
|
@ -12,10 +12,5 @@ public enum LabelType {
|
|||
TOKEN_LABEL,
|
||||
RULE_LIST_LABEL,
|
||||
TOKEN_LIST_LABEL,
|
||||
LEXER_STRING_LABEL, // used in lexer for x='a'
|
||||
SUBRULE_LABEL, // x=(...)
|
||||
SUBRULE_LIST_LABEL, // x+=(...)
|
||||
WILDCARD_TREE_LABEL, // Used in tree grammar x=.
|
||||
WILDCARD_TREE_LIST_LABEL // Used in tree grammar x+=.
|
||||
;
|
||||
LEXER_STRING_LABEL; // used in lexer for x='a'
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue