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:
Terence Parr 2014-06-30 15:40:37 -07:00
commit 163ec98afc
7 changed files with 135 additions and 42 deletions

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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() {

View File

@ -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();

View File

@ -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.
*

View File

@ -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);
}
}