forked from jasder/antlr
Restrict certain token, channel, mode names. fixed #1015
Clear error (can not use or declare mode with reserved name) instead of "Serialized ATN data element out of range." exception from #967.
This commit is contained in:
parent
935c25b110
commit
a7a9804ecd
|
@ -184,4 +184,43 @@ public class TestSymbolIssues extends BaseTest {
|
|||
|
||||
testErrors(test, false);
|
||||
}
|
||||
|
||||
@Test public void testTokensModesChannelsDeclarationConflictsWithReserved() throws Exception {
|
||||
String[] test = {
|
||||
"lexer grammar L;\n" +
|
||||
"channels { SKIP, HIDDEN, channel0 }\n" +
|
||||
"A: 'a';\n" +
|
||||
"mode MAX_CHAR_VALUE;\n" +
|
||||
"MIN_CHAR_VALUE: 'a';\n" +
|
||||
"mode DEFAULT_MODE;\n" +
|
||||
"B: 'b';\n" +
|
||||
"mode M;\n" +
|
||||
"C: 'c';",
|
||||
|
||||
"error(" + ErrorType.RESERVED_RULE_NAME.code + "): L.g4:5:0: cannot declare a rule with reserved name MIN_CHAR_VALUE\n" +
|
||||
"error(" + ErrorType.MODE_CONFLICTS_WITH_COMMON_CONSTANTS.code + "): L.g4:4:0: can not use or declare mode with reserved name MAX_CHAR_VALUE\n" +
|
||||
"error(" + ErrorType.CHANNEL_CONFLICTS_WITH_COMMON_CONSTANTS.code + "): L.g4:2:11: can not use or declare channel with reserved name SKIP\n" +
|
||||
"error(" + ErrorType.CHANNEL_CONFLICTS_WITH_COMMON_CONSTANTS.code + "): L.g4:2:17: can not use or declare channel with reserved name HIDDEN\n"
|
||||
};
|
||||
|
||||
testErrors(test, false);
|
||||
}
|
||||
|
||||
@Test public void testTokensModesChannelsUsingConflictsWithReserved() throws Exception {
|
||||
String[] test = {
|
||||
"lexer grammar L;\n" +
|
||||
"A: 'a' -> channel(SKIP);\n" +
|
||||
"B: 'b' -> type(MORE);\n" +
|
||||
"C: 'c' -> mode(SKIP);\n" +
|
||||
"D: 'd' -> channel(HIDDEN);\n" +
|
||||
"E: 'e' -> type(EOF);\n" +
|
||||
"F: 'f' -> pushMode(DEFAULT_MODE);",
|
||||
|
||||
"error(" + ErrorType.CHANNEL_CONFLICTS_WITH_COMMON_CONSTANTS.code + "): L.g4:2:18: can not use or declare channel with reserved name SKIP\n" +
|
||||
"error(" + ErrorType.TOKEN_CONFLICTS_WITH_COMMON_CONSTANTS.code + "): L.g4:3:15: can not use or declare token with reserved name MORE\n" +
|
||||
"error(" + ErrorType.MODE_CONFLICTS_WITH_COMMON_CONSTANTS.code + "): L.g4:4:15: can not use or declare mode with reserved name SKIP\n"
|
||||
};
|
||||
|
||||
testErrors(test, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,6 +112,10 @@ public class LexerATNFactory extends ParserATNFactory {
|
|||
codegenTemplates = gen.getTemplates();
|
||||
}
|
||||
|
||||
public static Set<String> getCommonConstants() {
|
||||
return COMMON_CONSTANTS.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ATN createATN() {
|
||||
// BUILD ALL START STATES (ONE PER MODE)
|
||||
|
@ -243,8 +247,8 @@ public class LexerATNFactory extends ParserATNFactory {
|
|||
|
||||
// fall back to standard action generation for the command
|
||||
ST cmdST = codegenTemplates.getInstanceOf("Lexer" +
|
||||
CharSupport.capitalize(ID.getText())+
|
||||
"Command");
|
||||
CharSupport.capitalize(ID.getText()) +
|
||||
"Command");
|
||||
if (cmdST == null) {
|
||||
g.tool.errMgr.grammarError(ErrorType.INVALID_LEXER_COMMAND, g.fileName, ID.token, ID.getText());
|
||||
return epsilon(ID);
|
||||
|
@ -407,6 +411,7 @@ public class LexerATNFactory extends ParserATNFactory {
|
|||
}
|
||||
else if ("mode".equals(command) && arg != null) {
|
||||
String modeName = arg.getText();
|
||||
checkMode(modeName, arg.token);
|
||||
Integer mode = getConstantValue(modeName, arg.getToken());
|
||||
if (mode == null) {
|
||||
return null;
|
||||
|
@ -416,6 +421,7 @@ public class LexerATNFactory extends ParserATNFactory {
|
|||
}
|
||||
else if ("pushMode".equals(command) && arg != null) {
|
||||
String modeName = arg.getText();
|
||||
checkMode(modeName, arg.token);
|
||||
Integer mode = getConstantValue(modeName, arg.getToken());
|
||||
if (mode == null) {
|
||||
return null;
|
||||
|
@ -425,6 +431,7 @@ public class LexerATNFactory extends ParserATNFactory {
|
|||
}
|
||||
else if ("type".equals(command) && arg != null) {
|
||||
String typeName = arg.getText();
|
||||
checkToken(typeName, arg.token);
|
||||
Integer type = getConstantValue(typeName, arg.getToken());
|
||||
if (type == null) {
|
||||
return null;
|
||||
|
@ -434,6 +441,7 @@ public class LexerATNFactory extends ParserATNFactory {
|
|||
}
|
||||
else if ("channel".equals(command) && arg != null) {
|
||||
String channelName = arg.getText();
|
||||
checkChannel(channelName, arg.token);
|
||||
Integer channel = getConstantValue(channelName, arg.getToken());
|
||||
if (channel == null) {
|
||||
return null;
|
||||
|
@ -446,6 +454,23 @@ public class LexerATNFactory extends ParserATNFactory {
|
|||
}
|
||||
}
|
||||
|
||||
protected void checkMode(String modeName, Token token) {
|
||||
if (!modeName.equals("DEFAULT_MODE") && COMMON_CONSTANTS.containsKey(modeName)) {
|
||||
g.tool.errMgr.grammarError(ErrorType.MODE_CONFLICTS_WITH_COMMON_CONSTANTS, g.fileName, token, token.getText());
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkToken(String tokenName, Token token) {
|
||||
if (!tokenName.equals("EOF") && COMMON_CONSTANTS.containsKey(tokenName)) {
|
||||
g.tool.errMgr.grammarError(ErrorType.TOKEN_CONFLICTS_WITH_COMMON_CONSTANTS, g.fileName, token, token.getText());
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkChannel(String channelName, Token token) {
|
||||
if (!channelName.equals("HIDDEN") && !channelName.equals("DEFAULT_TOKEN_CHANNEL") && COMMON_CONSTANTS.containsKey(channelName)) {
|
||||
g.tool.errMgr.grammarError(ErrorType.CHANNEL_CONFLICTS_WITH_COMMON_CONSTANTS, g.fileName, token, token.getText());
|
||||
}
|
||||
}
|
||||
|
||||
protected Integer getConstantValue(String name, Token token) {
|
||||
if (name == null) {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
package org.antlr.v4.semantics;
|
||||
|
||||
import org.antlr.v4.analysis.LeftRecursiveRuleTransformer;
|
||||
import org.antlr.v4.automata.LexerATNFactory;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.misc.Pair;
|
||||
|
@ -68,6 +69,11 @@ import java.util.Set;
|
|||
* tokens and rules from the imported grammars into a single collection.
|
||||
*/
|
||||
public class SemanticPipeline {
|
||||
protected final Set<String> reservedNames = new HashSet<String>();
|
||||
{
|
||||
reservedNames.addAll(LexerATNFactory.getCommonConstants());
|
||||
}
|
||||
|
||||
public Grammar g;
|
||||
|
||||
public SemanticPipeline(Grammar g) {
|
||||
|
@ -289,6 +295,10 @@ public class SemanticPipeline {
|
|||
g.tool.errMgr.grammarError(ErrorType.CHANNEL_CONFLICTS_WITH_TOKEN, g.fileName, channel.token, channelName);
|
||||
}
|
||||
|
||||
if (reservedNames.contains(channelName)) {
|
||||
g.tool.errMgr.grammarError(ErrorType.CHANNEL_CONFLICTS_WITH_COMMON_CONSTANTS, g.fileName, channel.token, channelName);
|
||||
}
|
||||
|
||||
if (outermost instanceof LexerGrammar) {
|
||||
LexerGrammar lexerGrammar = (LexerGrammar)outermost;
|
||||
if (lexerGrammar.modes.containsKey(channelName)) {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
package org.antlr.v4.semantics;
|
||||
|
||||
import org.antlr.v4.automata.LexerATNFactory;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.tool.Alternative;
|
||||
|
@ -69,7 +70,7 @@ public class SymbolChecks {
|
|||
|
||||
protected final Set<String> reservedNames = new HashSet<String>();
|
||||
{
|
||||
reservedNames.add("EOF");
|
||||
reservedNames.addAll(LexerATNFactory.getCommonConstants());
|
||||
}
|
||||
|
||||
public SymbolChecks(Grammar g, SymbolCollector collector) {
|
||||
|
@ -275,6 +276,11 @@ public class SymbolChecks {
|
|||
if (g.isLexer()) {
|
||||
LexerGrammar lexerGrammar = (LexerGrammar)g;
|
||||
for (String modeName : lexerGrammar.modes.keySet()) {
|
||||
if (!modeName.equals("DEFAULT_MODE") && reservedNames.contains(modeName)) {
|
||||
Rule rule = ((Collection<Rule>)lexerGrammar.modes.get(modeName)).iterator().next();
|
||||
g.tool.errMgr.grammarError(ErrorType.MODE_CONFLICTS_WITH_COMMON_CONSTANTS, g.fileName, rule.ast.parent.getToken(), modeName);
|
||||
}
|
||||
|
||||
if (g.getTokenType(modeName) != Token.INVALID_TYPE) {
|
||||
Rule rule = ((Collection<Rule>)lexerGrammar.modes.get(modeName)).iterator().next();
|
||||
g.tool.errMgr.grammarError(ErrorType.MODE_CONFLICTS_WITH_TOKEN, g.fileName, rule.ast.parent.getToken(), modeName);
|
||||
|
|
|
@ -971,6 +971,36 @@ public enum ErrorType {
|
|||
* <p>mode <em>name</em> conflicts with token with same name</p>
|
||||
*/
|
||||
MODE_CONFLICTS_WITH_TOKEN(170, "mode <arg> conflicts with token with same name", ErrorSeverity.ERROR),
|
||||
/**
|
||||
* Compiler Error 171.
|
||||
*
|
||||
* <p>can not use or declare token with reserved name</p>
|
||||
*
|
||||
* <p>Reserved names: HIDDEN, DEFAULT_TOKEN_CHANNEL, SKIP, MORE, EOF, MAX_CHAR_VALUE, MIN_CHAR_VALUE.
|
||||
*
|
||||
* <p>Can be used but can not be declared: EOF</p>
|
||||
*/
|
||||
TOKEN_CONFLICTS_WITH_COMMON_CONSTANTS(171, "can not use or declare token with reserved name <arg>", ErrorSeverity.ERROR),
|
||||
/**
|
||||
* Compiler Error 172.
|
||||
*
|
||||
* <p>can not use or declare token with reserved name</p>
|
||||
*
|
||||
* <p>Reserved names: DEFAULT_MODE, SKIP, MORE, EOF, MAX_CHAR_VALUE, MIN_CHAR_VALUE.
|
||||
*
|
||||
* <p>Can be used but can not be declared: HIDDEN, DEFAULT_TOKEN_CHANNEL</p>
|
||||
*/
|
||||
CHANNEL_CONFLICTS_WITH_COMMON_CONSTANTS(172, "can not use or declare channel with reserved name <arg>", ErrorSeverity.ERROR),
|
||||
/**
|
||||
* Compiler Error 173.
|
||||
*
|
||||
* <p>can not use or declare token with reserved name</p>
|
||||
*
|
||||
* <p>Reserved names: HIDDEN, DEFAULT_TOKEN_CHANNEL, DEFAULT_MODE, SKIP, MORE, MAX_CHAR_VALUE, MIN_CHAR_VALUE.
|
||||
*
|
||||
* <p>Can be used and can be declared: DEFAULT_MODE</p>
|
||||
*/
|
||||
MODE_CONFLICTS_WITH_COMMON_CONSTANTS(173, "can not use or declare mode with reserved name <arg>", ErrorSeverity.ERROR),
|
||||
|
||||
/*
|
||||
* Backward incompatibility errors
|
||||
|
|
Loading…
Reference in New Issue