forked from jasder/antlr
Merge pull request #650 from parrt/null-ptr-unknown-target
add new panic() method, though not yet used. revert to java target if ca...
This commit is contained in:
commit
163ec98afc
|
@ -41,6 +41,7 @@ import org.antlr.v4.automata.ATNFactory;
|
|||
import org.antlr.v4.automata.LexerATNFactory;
|
||||
import org.antlr.v4.automata.ParserATNFactory;
|
||||
import org.antlr.v4.codegen.CodeGenPipeline;
|
||||
import org.antlr.v4.codegen.CodeGenerator;
|
||||
import org.antlr.v4.misc.Graph;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.parse.GrammarASTAdaptor;
|
||||
|
@ -398,6 +399,12 @@ public class Tool {
|
|||
SemanticPipeline sem = new SemanticPipeline(g);
|
||||
sem.process();
|
||||
|
||||
String language = g.getOptionString("language");
|
||||
if ( !CodeGenerator.targetExists(language) ) {
|
||||
errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR, language);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( errMgr.getNumErrors()>prevErrors ) return;
|
||||
|
||||
// BUILD ATN FROM AST
|
||||
|
|
|
@ -48,8 +48,9 @@ public class CodeGenPipeline {
|
|||
}
|
||||
|
||||
public void process() {
|
||||
CodeGenerator gen = new CodeGenerator(g);
|
||||
if ( !CodeGenerator.targetExists(g.getOptionString("language")) ) return;
|
||||
|
||||
CodeGenerator gen = new CodeGenerator(g);
|
||||
IntervalSet idTypes = new IntervalSet();
|
||||
idTypes.add(ANTLRParser.ID);
|
||||
idTypes.add(ANTLRParser.RULE_REF);
|
||||
|
@ -63,8 +64,6 @@ public class CodeGenPipeline {
|
|||
}
|
||||
}
|
||||
|
||||
if ( gen.getTemplates()==null ) return;
|
||||
|
||||
if ( g.isLexer() ) {
|
||||
ST lexer = gen.generateLexer();
|
||||
writeRecognizer(lexer, gen);
|
||||
|
@ -74,13 +73,15 @@ public class CodeGenPipeline {
|
|||
writeRecognizer(parser, gen);
|
||||
if ( g.tool.gen_listener ) {
|
||||
gen.writeListener(gen.generateListener());
|
||||
if (gen.getTarget().wantsBaseListener())
|
||||
if (gen.getTarget().wantsBaseListener()) {
|
||||
gen.writeBaseListener(gen.generateBaseListener());
|
||||
}
|
||||
}
|
||||
if ( g.tool.gen_visitor ) {
|
||||
gen.writeVisitor(gen.generateVisitor());
|
||||
if (gen.getTarget().wantsBaseVisitor())
|
||||
if (gen.getTarget().wantsBaseVisitor()) {
|
||||
gen.writeBaseVisitor(gen.generateBaseVisitor());
|
||||
}
|
||||
}
|
||||
gen.writeHeaderFile();
|
||||
}
|
||||
|
@ -93,7 +94,9 @@ public class CodeGenPipeline {
|
|||
if (g.tool.ST_inspector_wait_for_close) {
|
||||
try {
|
||||
viz.waitForClose();
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,17 +34,18 @@ import org.antlr.v4.Tool;
|
|||
import org.antlr.v4.codegen.model.OutputModelObject;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.misc.NotNull;
|
||||
import org.antlr.v4.runtime.misc.Nullable;
|
||||
import org.antlr.v4.tool.ErrorType;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
import org.stringtemplate.v4.AutoIndentWriter;
|
||||
import org.stringtemplate.v4.ST;
|
||||
import org.stringtemplate.v4.STGroup;
|
||||
import org.stringtemplate.v4.STGroupFile;
|
||||
import org.stringtemplate.v4.STWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -54,7 +55,7 @@ public class CodeGenerator {
|
|||
public static final String TEMPLATE_ROOT = "org/antlr/v4/tool/templates/codegen";
|
||||
public static final String VOCAB_FILE_EXTENSION = ".tokens";
|
||||
public static final String DEFAULT_LANGUAGE = "Java";
|
||||
public final static String vocabFilePattern =
|
||||
public static final String vocabFilePattern =
|
||||
"<tokens.keys:{t | <t>=<tokens.(t)>\n}>" +
|
||||
"<literals.keys:{t | <t>=<literals.(t)>\n}>";
|
||||
|
||||
|
@ -69,6 +70,12 @@ public class CodeGenerator {
|
|||
|
||||
public int lineWidth = 72;
|
||||
|
||||
private CodeGenerator(String language) {
|
||||
this.g = null;
|
||||
this.tool = null;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public CodeGenerator(@NotNull Grammar g) {
|
||||
this(g.tool, g, g.getOptionString("language"));
|
||||
}
|
||||
|
@ -79,16 +86,32 @@ public class CodeGenerator {
|
|||
this.language = language != null ? language : DEFAULT_LANGUAGE;
|
||||
}
|
||||
|
||||
public static boolean targetExists(String language) {
|
||||
String targetName = "org.antlr.v4.codegen."+language+"Target";
|
||||
try {
|
||||
Class<? extends Target> c = Class.forName(targetName).asSubclass(Target.class);
|
||||
Constructor<? extends Target> ctor = c.getConstructor(CodeGenerator.class);
|
||||
CodeGenerator gen = new CodeGenerator(language);
|
||||
Target target = ctor.newInstance(gen);
|
||||
return target.templatesExist();
|
||||
}
|
||||
catch (Exception e) { // ignore errors; we're detecting presence only
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Target getTarget() {
|
||||
if (target == null) {
|
||||
if ( target == null && targetExists(language) ) {
|
||||
loadLanguageTarget(language);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public STGroup getTemplates() {
|
||||
return getTarget().getTemplates();
|
||||
Target t = getTarget();
|
||||
return t==null ? null : t.getTemplates();
|
||||
}
|
||||
|
||||
protected void loadLanguageTarget(String language) {
|
||||
|
@ -98,29 +121,9 @@ public class CodeGenerator {
|
|||
Constructor<? extends Target> ctor = c.getConstructor(CodeGenerator.class);
|
||||
target = ctor.newInstance(this);
|
||||
}
|
||||
catch (ClassNotFoundException cnfe) {
|
||||
catch (Exception e) {
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
cnfe,
|
||||
targetName);
|
||||
}
|
||||
catch (NoSuchMethodException nsme) {
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
nsme,
|
||||
targetName);
|
||||
}
|
||||
catch (InvocationTargetException ite) {
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
ite,
|
||||
targetName);
|
||||
}
|
||||
catch (InstantiationException ie) {
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
ie,
|
||||
targetName);
|
||||
}
|
||||
catch (IllegalAccessException cnfe) {
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
cnfe,
|
||||
e,
|
||||
targetName);
|
||||
}
|
||||
}
|
||||
|
@ -183,19 +186,19 @@ public class CodeGenerator {
|
|||
}
|
||||
|
||||
public void writeListener(ST outputFileST) {
|
||||
getTarget().genFile(g,outputFileST, getListenerFileName());
|
||||
getTarget().genFile(g, outputFileST, getListenerFileName());
|
||||
}
|
||||
|
||||
public void writeBaseListener(ST outputFileST) {
|
||||
getTarget().genFile(g,outputFileST, getBaseListenerFileName());
|
||||
getTarget().genFile(g, outputFileST, getBaseListenerFileName());
|
||||
}
|
||||
|
||||
public void writeVisitor(ST outputFileST) {
|
||||
getTarget().genFile(g,outputFileST, getVisitorFileName());
|
||||
getTarget().genFile(g, outputFileST, getVisitorFileName());
|
||||
}
|
||||
|
||||
public void writeBaseVisitor(ST outputFileST) {
|
||||
getTarget().genFile(g,outputFileST, getBaseVisitorFileName());
|
||||
getTarget().genFile(g, outputFileST, getBaseVisitorFileName());
|
||||
}
|
||||
|
||||
public void writeHeaderFile() {
|
||||
|
@ -205,7 +208,7 @@ public class CodeGenerator {
|
|||
ST extST = getTemplates().getInstanceOf("headerFileExtension");
|
||||
ST headerFileST = null;
|
||||
// TODO: don't hide this header file generation here!
|
||||
getTarget().genRecognizerHeaderFile(g,headerFileST,extST.render(lineWidth));
|
||||
getTarget().genRecognizerHeaderFile(g, headerFileST, extST.render(lineWidth));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,4 +301,5 @@ public class CodeGenerator {
|
|||
String recognizerName = g.getRecognizerName();
|
||||
return recognizerName+extST.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.antlr.v4.misc.Utils;
|
|||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.runtime.RuntimeMetaData;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.misc.Nullable;
|
||||
import org.antlr.v4.tool.ErrorType;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
|
@ -99,6 +100,7 @@ public abstract class Target {
|
|||
*/
|
||||
public abstract String getVersion();
|
||||
|
||||
@Nullable
|
||||
public STGroup getTemplates() {
|
||||
if (templates == null) {
|
||||
String version = getVersion();
|
||||
|
@ -348,8 +350,31 @@ public abstract class Target {
|
|||
|
||||
protected abstract boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode);
|
||||
|
||||
public boolean templatesExist() {
|
||||
String groupFileName = CodeGenerator.TEMPLATE_ROOT + "/" + getLanguage() + "/" + getLanguage() + STGroup.GROUP_FILE_EXTENSION;
|
||||
STGroup result = null;
|
||||
try {
|
||||
result = new STGroupFile(groupFileName);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
result = null;
|
||||
}
|
||||
return result!=null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected STGroup loadTemplates() {
|
||||
STGroup result = new STGroupFile(CodeGenerator.TEMPLATE_ROOT+"/"+getLanguage()+"/"+getLanguage()+STGroup.GROUP_FILE_EXTENSION);
|
||||
String groupFileName = CodeGenerator.TEMPLATE_ROOT + "/" + getLanguage() + "/" + getLanguage() + STGroup.GROUP_FILE_EXTENSION;
|
||||
STGroup result = null;
|
||||
try {
|
||||
result = new STGroupFile(groupFileName);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
gen.tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
iae,
|
||||
language);
|
||||
}
|
||||
if ( result==null ) return null;
|
||||
result.registerRenderer(Integer.class, new NumberRenderer());
|
||||
result.registerRenderer(String.class, new StringRenderer());
|
||||
result.setListener(new STErrorListener() {
|
||||
|
|
|
@ -318,6 +318,16 @@ public class ErrorManager {
|
|||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
public void panic(ErrorType errorType, Object... args) {
|
||||
ToolMessage msg = new ToolMessage(errorType, args);
|
||||
ST msgST = getMessageTemplate(msg);
|
||||
String outputMsg = msgST.render();
|
||||
if ( formatWantsSingleLineMessage() ) {
|
||||
outputMsg = outputMsg.replace('\n', ' ');
|
||||
}
|
||||
panic(outputMsg);
|
||||
}
|
||||
|
||||
public static void panic(String msg) {
|
||||
rawError(msg);
|
||||
panic();
|
||||
|
|
|
@ -147,7 +147,7 @@ public enum ErrorType {
|
|||
* ANTLR cannot generate '<em>language</em>' code as of version
|
||||
* <em>version</em></p>
|
||||
*/
|
||||
CANNOT_CREATE_TARGET_GENERATOR(31, "ANTLR cannot generate '<arg>' code as of version "+ Tool.VERSION, ErrorSeverity.ERROR),
|
||||
CANNOT_CREATE_TARGET_GENERATOR(31, "ANTLR cannot generate '<arg>' code as of version "+ Tool.VERSION, ErrorSeverity.ERROR_ONE_OFF),
|
||||
/**
|
||||
* Compiler Error 32.
|
||||
*
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
package org.antlr.v4.test;
|
||||
|
||||
import org.antlr.v4.Tool;
|
||||
import org.antlr.v4.tool.ErrorType;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -325,7 +326,7 @@ public class TestToolSyntaxErrors extends BaseTest {
|
|||
grammar,
|
||||
expected
|
||||
};
|
||||
|
||||
|
||||
super.testErrors(pair, true);
|
||||
}
|
||||
|
||||
|
@ -373,7 +374,7 @@ public class TestToolSyntaxErrors extends BaseTest {
|
|||
"WS : [ \\r\\t\\n]+ -> skip ;\n";
|
||||
String expected =
|
||||
"";
|
||||
|
||||
|
||||
String[] pair = new String[] { grammar, expected };
|
||||
super.testErrors(pair, true);
|
||||
}
|
||||
|
@ -523,4 +524,47 @@ public class TestToolSyntaxErrors extends BaseTest {
|
|||
|
||||
super.testErrors(pair, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a regression test for antlr/antlr4#649 "unknown target causes
|
||||
* null ptr exception.".
|
||||
* https://github.com/antlr/antlr4/issues/649
|
||||
* Stops before processing the lexer
|
||||
*/
|
||||
@Test public void testInvalidLanguageInGrammarWithLexerCommand() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options { language=Foo; }\n" +
|
||||
"start : 'T' EOF;\n" +
|
||||
"Something : 'something' -> channel(CUSTOM);";
|
||||
String expected =
|
||||
"error(" + ErrorType.CANNOT_CREATE_TARGET_GENERATOR.code + "): ANTLR cannot generate 'Foo' code as of version " + Tool.VERSION + "\n";
|
||||
String[] pair = new String[] {
|
||||
grammar,
|
||||
expected
|
||||
};
|
||||
|
||||
super.testErrors(pair, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a regression test for antlr/antlr4#649 "unknown target causes
|
||||
* null ptr exception.".
|
||||
* https://github.com/antlr/antlr4/issues/649
|
||||
*/
|
||||
@Test public void testInvalidLanguageInGrammar() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"options { language=Foo; }\n" +
|
||||
"start : 'T' EOF;\n";
|
||||
String expected =
|
||||
"error(" + ErrorType.CANNOT_CREATE_TARGET_GENERATOR.code + "): ANTLR cannot generate 'Foo' code as of version " + Tool.VERSION + "\n";
|
||||
|
||||
String[] pair = new String[] {
|
||||
grammar,
|
||||
expected
|
||||
};
|
||||
|
||||
super.testErrors(pair, true);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue