got basic test harness for grammar errors

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 6659]
This commit is contained in:
parrt 2010-02-03 16:25:19 -08:00
parent 6829fc9e47
commit 81bcfe56dc
12 changed files with 250 additions and 123 deletions

View File

@ -1,10 +1,14 @@
package org.antlr.v4; package org.antlr.v4;
import org.antlr.runtime.*; import org.antlr.runtime.*;
import org.antlr.runtime.tree.*; import org.antlr.v4.parse.ANTLRLexer;
import org.antlr.v4.parse.*; import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.semantics.SemanticsPipeline; import org.antlr.v4.semantics.SemanticsPipeline;
import org.antlr.v4.tool.*; import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.GrammarRootAST;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -291,24 +295,34 @@ public class Tool {
} }
public Grammar load(String fileName) { public Grammar load(String fileName) {
Grammar g = null; ANTLRFileStream in = null;
try { try {
ANTLRFileStream in = new ANTLRFileStream(fileName); in = new ANTLRFileStream(fileName);
ANTLRLexer lexer = new ANTLRLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ANTLRParser p = new ANTLRParser(tokens);
p.setTreeAdaptor(new GrammarASTAdaptor(in));
ParserRuleReturnScope r = p.grammarSpec();
GrammarRootAST t = (GrammarRootAST) r.getTree();
if ( internalOption_PrintGrammarTree ) System.out.println(t.toStringTree());
g = new Grammar(this, t);
g.fileName = fileName;
grammars.put(g.name, g);
} }
catch (IOException ioe) { catch (IOException ioe) {
ErrorManager.toolError(ErrorType.CANNOT_OPEN_FILE, fileName, ioe); ErrorManager.toolError(ErrorType.CANNOT_OPEN_FILE, fileName, ioe);
} }
Grammar g = load(in);
g.fileName = fileName;
return g;
}
public Grammar loadFromString(String grammar) {
Grammar g = load(new ANTLRStringStream(grammar));
g.fileName = "<string>";
return g;
}
public Grammar load(CharStream in) {
Grammar g = null;
try {
ANTLRLexer lexer = new ANTLRLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ANTLRParser p = new ANTLRParser(tokens);
p.setTreeAdaptor(new GrammarASTAdaptor(in));
ParserRuleReturnScope r = p.grammarSpec();
g = new Grammar(this, (GrammarRootAST)r.getTree());
}
catch (RecognitionException re) { catch (RecognitionException re) {
// TODO: do we gen errors now? // TODO: do we gen errors now?
ErrorManager.internalError("can't generate this message at moment; antlr recovers"); ErrorManager.internalError("can't generate this message at moment; antlr recovers");
@ -319,7 +333,9 @@ public class Tool {
public void process() { public void process() {
// testing parser // testing parser
Grammar g = load(grammarFileNames.get(0)); Grammar g = load(grammarFileNames.get(0));
grammars.put(g.name, g);
g.loadImportedGrammars(); g.loadImportedGrammars();
if ( g.ast!=null && internalOption_PrintGrammarTree ) System.out.println(g.ast.toStringTree());
//g.ast.inspect(); //g.ast.inspect();
SemanticsPipeline sem = new SemanticsPipeline(); SemanticsPipeline sem = new SemanticsPipeline();
sem.process(g); sem.process(g);

View File

@ -1,5 +1,7 @@
package org.antlr.v4.misc; package org.antlr.v4.misc;
import java.util.Iterator;
/** */ /** */
public class Utils { public class Utils {
public static String stripFileExtension(String name) { public static String stripFileExtension(String name) {
@ -8,4 +10,16 @@ public class Utils {
if ( lastDot<0 ) return name; if ( lastDot<0 ) return name;
return name.substring(0, lastDot); return name.substring(0, lastDot);
} }
// Seriously: why isn't this built in to java? ugh!
public static String join(Iterator iter, String separator) {
StringBuilder buf = new StringBuilder();
while ( iter.hasNext() ) {
buf.append(iter.next());
if ( iter.hasNext() ) {
buf.append(separator);
}
}
return buf.toString();
}
} }

View File

@ -1,4 +1,4 @@
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 ANTLRLexer.g 2010-02-03 11:08:45 // $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 ANTLRLexer.g 2010-02-03 15:37:27
/* /*
[The "BSD licence"] [The "BSD licence"]
@ -31,11 +31,6 @@ package org.antlr.v4.parse;
import org.antlr.runtime.*; import org.antlr.runtime.*;
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
/** Read in an ANTLR grammar and build an AST. Try not to do /** Read in an ANTLR grammar and build an AST. Try not to do
* any actions, just build the tree. * any actions, just build the tree.
* *

View File

@ -1,4 +1,4 @@
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 ANTLRParser.g 2010-02-03 11:08:48 // $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 ANTLRParser.g 2010-02-03 15:37:30
/* /*
[The "BSD licence"] [The "BSD licence"]
@ -29,17 +29,12 @@
*/ */
package org.antlr.v4.parse; package org.antlr.v4.parse;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.v4.tool.*; import org.antlr.v4.tool.*;
import org.antlr.runtime.*;
import java.util.Stack;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.List;
import java.util.HashMap;
import org.antlr.runtime.tree.*;
/** The definitive ANTLR v3 grammar to parse ANTLR v4 grammars. /** The definitive ANTLR v3 grammar to parse ANTLR v4 grammars.
* The grammar builds ASTs that are sniffed by subsequent stages. * The grammar builds ASTs that are sniffed by subsequent stages.
@ -288,7 +283,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: id, rules, grammarType, prequelConstruct, DOC_COMMENT // elements: id, DOC_COMMENT, rules, prequelConstruct, grammarType
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -1127,7 +1122,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: delegateGrammar, IMPORT // elements: IMPORT, delegateGrammar
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -1408,7 +1403,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: TOKENS, tokenSpec // elements: tokenSpec, TOKENS
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -1563,7 +1558,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: STRING_LITERAL, ASSIGN, id // elements: id, STRING_LITERAL, ASSIGN
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -1703,7 +1698,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: ACTION, SCOPE, id // elements: id, SCOPE, ACTION
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -1857,7 +1852,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: ACTION, AT, id, actionScopeName // elements: actionScopeName, AT, ACTION, id
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -2357,7 +2352,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: ARG_ACTION, id, altListAsBlock, exceptionGroup, ruleReturns, DOC_COMMENT, rulePrequel, ruleModifiers // elements: altListAsBlock, ruleReturns, ARG_ACTION, id, ruleModifiers, DOC_COMMENT, exceptionGroup, rulePrequel
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -2583,7 +2578,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: CATCH, ARG_ACTION, ACTION // elements: ARG_ACTION, ACTION, CATCH
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -2666,7 +2661,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: FINALLY, ACTION // elements: ACTION, FINALLY
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -3288,7 +3283,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: AT, id, ACTION // elements: id, AT, ACTION
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -3804,7 +3799,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: elements, rewrite // elements: rewrite, elements
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -4948,7 +4943,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: block, blockSuffixe // elements: blockSuffixe, block
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -5454,7 +5449,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: id, ruleref, DOT // elements: DOT, id, ruleref
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -5512,7 +5507,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: DOT, terminal, id // elements: DOT, id, terminal
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -5711,7 +5706,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: notTerminal, NOT // elements: NOT, notTerminal
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -5754,7 +5749,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: NOT, block // elements: block, NOT
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -6018,7 +6013,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: altList, ACTION, optionsSpec, ra // elements: ra, ACTION, altList, optionsSpec
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -6199,7 +6194,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: RULE_REF, ARG_ACTION, op // elements: op, RULE_REF, ARG_ACTION
// token labels: op // token labels: op
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -6616,7 +6611,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: elementOptions, STRING_LITERAL // elements: STRING_LITERAL, elementOptions
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -7226,7 +7221,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: nakedRewrite, predicatedRewrite // elements: predicatedRewrite, nakedRewrite
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -7314,7 +7309,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: rewriteAlt, SEMPRED, SEMPRED, rewriteAlt // elements: rewriteAlt, SEMPRED, rewriteAlt, SEMPRED
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -8066,7 +8061,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: TOKEN_REF, ARG_ACTION // elements: ARG_ACTION, TOKEN_REF
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -8249,7 +8244,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: rewriteTreeAlt, ebnfSuffix // elements: ebnfSuffix, rewriteTreeAlt
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -8386,7 +8381,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: rewriteTreeElement, rewriteTreeAtom, TREE_BEGIN // elements: TREE_BEGIN, rewriteTreeElement, rewriteTreeAtom
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -8541,7 +8536,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: str, rewriteTemplateArgs, TEMPLATE // elements: str, TEMPLATE, rewriteTemplateArgs
// token labels: str // token labels: str
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -8802,7 +8797,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: rewriteTemplateArgs, ACTION // elements: ACTION, rewriteTemplateArgs
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:
@ -9048,7 +9043,7 @@ public class ANTLRParser extends Parser {
// AST REWRITE // AST REWRITE
// elements: ACTION, id // elements: id, ACTION
// token labels: // token labels:
// rule labels: retval // rule labels: retval
// token list labels: // token list labels:

View File

@ -1,4 +1,4 @@
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 ASTVerifier.g 2010-02-03 11:08:48 // $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 ASTVerifier.g 2010-02-03 15:37:30
/* /*
[The "BSD license"] [The "BSD license"]
@ -26,14 +26,15 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package org.antlr.v4.parse; package org.antlr.v4.parse;
import org.antlr.v4.tool.*;
import org.antlr.v4.runtime.tree.CommonTree; // use updated v4 one not v3
import org.antlr.runtime.*; import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;import java.util.Stack; import org.antlr.runtime.tree.TreeNodeStream;
import org.antlr.runtime.tree.TreeParser;
import org.antlr.runtime.tree.TreeRuleReturnScope;
import org.antlr.v4.runtime.tree.CommonTree;
import org.antlr.v4.tool.GrammarAST;
import java.util.List; import java.util.List;
import java.util.ArrayList;
/** The definitive ANTLR v3 tree grammar to parse ANTLR v4 grammars. /** The definitive ANTLR v3 tree grammar to parse ANTLR v4 grammars.
* Parses trees created in ANTLRParser.g. * Parses trees created in ANTLRParser.g.

View File

@ -2,17 +2,35 @@ package org.antlr.v4.semantics;
import org.antlr.misc.MultiMap; import org.antlr.misc.MultiMap;
import org.antlr.runtime.Token; import org.antlr.runtime.Token;
import org.antlr.tool.*;
import org.antlr.v4.misc.Utils; import org.antlr.v4.misc.Utils;
import org.antlr.v4.parse.ANTLRParser; import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.tool.*; import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.GrammarAST;
import java.io.File;
import java.util.*; import java.util.*;
/** No side-effects */ /** No side-effects; BasicSemanticTriggers.g invokes check rules for these:
*
* FILE_AND_GRAMMAR_NAME_DIFFER
* LEXER_RULES_NOT_ALLOWED
* PARSER_RULES_NOT_ALLOWED
* CANNOT_ALIAS_TOKENS_IN_LEXER
* ARGS_ON_TOKEN_REF
* ILLEGAL_OPTION
* REWRITE_OR_OP_WITH_NO_OUTPUT_OPTION
* NO_RULES
* REWRITE_FOR_MULTI_ELEMENT_ALT
* HETERO_ILLEGAL_IN_REWRITE_ALT
* AST_OP_WITH_NON_AST_OUTPUT_OPTION
* AST_OP_IN_ALT_WITH_REWRITE
* CONFLICTING_OPTION_IN_TREE_FILTER
* WILDCARD_AS_ROOT
* INVALID_IMPORT
* TOKEN_VOCAB_IN_DELEGATE
* IMPORT_NAME_CLASH
* REPEATED_PREQUEL
* TOKEN_NAMES_MUST_START_UPPER
*/
public class BasicSemanticChecks { public class BasicSemanticChecks {
public static final Set legalLexerOptions = public static final Set legalLexerOptions =
new HashSet() { new HashSet() {
@ -99,7 +117,9 @@ public class BasicSemanticChecks {
// TODO: track errors? // TODO: track errors?
protected static void checkGrammarName(Token nameToken) { protected static void checkGrammarName(Token nameToken) {
String fileName = nameToken.getInputStream().getSourceName(); String fullyQualifiedName = nameToken.getInputStream().getSourceName();
File f = new File(fullyQualifiedName);
String fileName = f.getName();
if ( !Utils.stripFileExtension(fileName).equals(nameToken.getText()) ) { if ( !Utils.stripFileExtension(fileName).equals(nameToken.getText()) ) {
ErrorManager.grammarError(ErrorType.FILE_AND_GRAMMAR_NAME_DIFFER, ErrorManager.grammarError(ErrorType.FILE_AND_GRAMMAR_NAME_DIFFER,
fileName, nameToken, nameToken.getText(), fileName); fileName, nameToken, nameToken.getText(), fileName);
@ -384,8 +404,4 @@ public class BasicSemanticChecks {
g, delegate); g, delegate);
} }
} }
protected static void checkFOO(int gtype, Token ID) {
}
} }

View File

@ -1,4 +1,4 @@
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 BasicSemanticTriggers.g 2010-02-03 13:08:25 // $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 BasicSemanticTriggers.g 2010-02-03 15:37:39
/* /*
[The "BSD license"] [The "BSD license"]
@ -26,15 +26,14 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package org.antlr.v4.semantics; package org.antlr.v4.semantics;
import org.antlr.v4.tool.*;
import org.antlr.runtime.*; import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;import java.util.Stack; import org.antlr.runtime.tree.TreeNodeStream;
import java.util.List; import org.antlr.runtime.tree.TreeRuleReturnScope;
import org.antlr.v4.tool.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.List;
import java.util.HashMap;
/** Triggers for the basic semantics of the input. Side-effects: /** Triggers for the basic semantics of the input. Side-effects:
* Set token, block, rule options in the tree. Load field option * Set token, block, rule options in the tree. Load field option
* with grammar options. Only legal options are set. * with grammar options. Only legal options are set.

View File

@ -1,18 +1,11 @@
package org.antlr.v4.semantics; package org.antlr.v4.semantics;
import org.antlr.runtime.RecognitionException; import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.BufferedTreeNodeStream; import org.antlr.runtime.tree.BufferedTreeNodeStream;
import org.antlr.runtime.tree.TreeVisitor;
import org.antlr.runtime.tree.TreeVisitorAction;
import org.antlr.v4.Tool;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.ASTVerifier; import org.antlr.v4.parse.ASTVerifier;
import org.antlr.v4.parse.GrammarASTAdaptor; import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.tool.ErrorManager; import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar; import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.GrammarASTWithOptions;
/** */ /** */
public class SemanticsPipeline { public class SemanticsPipeline {
@ -35,13 +28,17 @@ public class SemanticsPipeline {
BasicSemanticTriggers basics = new BasicSemanticTriggers(nodes,g); BasicSemanticTriggers basics = new BasicSemanticTriggers(nodes,g);
basics.downup(g.ast); basics.downup(g.ast);
// NOW DO DELEGATES (IF ANY) // NOW DO BASIC / EASY SEMANTIC CHECKS FOR DELEGATES (IF ANY)
if ( g.getImportedGrammars()!=null ) { if ( g.getImportedGrammars()!=null ) {
for (Grammar d : g.getImportedGrammars()) { for (Grammar d : g.getImportedGrammars()) {
process(d); process(d);
} }
} }
// DEFINE SYMBOLS
// ASSIGN TOKEN TYPES
/* dump options /* dump options
TreeVisitor v = new TreeVisitor(adaptor); TreeVisitor v = new TreeVisitor(adaptor);
v.visit(g.ast, v.visit(g.ast,

View File

@ -1,6 +1,5 @@
package org.antlr.v4.tool; package org.antlr.v4.tool;
import org.antlr.Tool;
import org.antlr.runtime.Token; import org.antlr.runtime.Token;
import org.stringtemplate.v4.ST; import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STErrorListener; import org.stringtemplate.v4.STErrorListener;
@ -57,10 +56,6 @@ public class ErrorManager {
private static Locale locale; private static Locale locale;
private static String formatName; private static String formatName;
// TODO: make thread local to hold this state
public static int errors;
public static int warnings;
static ANTLRErrorListener theDefaultErrorListener = new ANTLRErrorListener() { static ANTLRErrorListener theDefaultErrorListener = new ANTLRErrorListener() {
public void info(String msg) { public void info(String msg) {
if (formatWantsSingleLineMessage()) { if (formatWantsSingleLineMessage()) {
@ -109,8 +104,18 @@ public class ErrorManager {
public static final String FORMATS_DIR = "org/antlr/v4/tool/templates/messages/formats/"; public static final String FORMATS_DIR = "org/antlr/v4/tool/templates/messages/formats/";
public static final String MESSAGES_DIR = "org/antlr/v4/tool/templates/messages/languages/"; public static final String MESSAGES_DIR = "org/antlr/v4/tool/templates/messages/languages/";
private static class ErrorState {
public ANTLRErrorListener listener;
public int errors;
public int warnings;
}
private static ThreadLocal<ErrorState> state = new ThreadLocal<ErrorState>();
// make sure that this class is ready to use after loading // make sure that this class is ready to use after loading
static { static {
state.set(new ErrorState());
setErrorListener(theDefaultErrorListener);
org.stringtemplate.v4.misc.ErrorManager.setErrorListener(initSTListener); org.stringtemplate.v4.misc.ErrorManager.setErrorListener(initSTListener);
// it is inefficient to set the default locale here if another // it is inefficient to set the default locale here if another
// piece of code is going to set the locale, but that would // piece of code is going to set the locale, but that would
@ -123,9 +128,11 @@ public class ErrorManager {
setFormat("antlr"); setFormat("antlr");
org.stringtemplate.v4.misc.ErrorManager.setErrorListener(theDefaultSTListener); org.stringtemplate.v4.misc.ErrorManager.setErrorListener(theDefaultSTListener);
} }
public static ANTLRErrorListener getErrorListener() { public static ANTLRErrorListener getErrorListener() {
return theDefaultErrorListener; return state.get().listener;
} }
/** Return a StringTemplate that refers to the current format used for /** Return a StringTemplate that refers to the current format used for
@ -160,14 +167,14 @@ public class ErrorManager {
} }
public static void internalError(String error, Throwable e) { public static void internalError(String error, Throwable e) {
errors++; state.get().errors++;
StackTraceElement location = getLastNonErrorManagerCodeLocation(e); StackTraceElement location = getLastNonErrorManagerCodeLocation(e);
String msg = "Exception "+e+"@"+location+": "+error; String msg = "Exception "+e+"@"+location+": "+error;
System.err.println("internal error: "+msg); System.err.println("internal error: "+msg);
} }
public static void internalError(String error) { public static void internalError(String error) {
errors++; state.get().errors++;
StackTraceElement location = StackTraceElement location =
getLastNonErrorManagerCodeLocation(new Exception()); getLastNonErrorManagerCodeLocation(new Exception());
String msg = location+": "+error; String msg = location+": "+error;
@ -181,8 +188,8 @@ public class ErrorManager {
* @param args The arguments to pass to the StringTemplate * @param args The arguments to pass to the StringTemplate
*/ */
public static void toolError(ErrorType errorType, Object... args) { public static void toolError(ErrorType errorType, Object... args) {
errors++; state.get().errors++;
theDefaultErrorListener.error(new ToolMessage(errorType, args)); state.get().listener.error(new ToolMessage(errorType, args));
} }
/** /**
@ -217,9 +224,9 @@ public class ErrorManager {
Token token, Token token,
Object... args) Object... args)
{ {
errors++; state.get().errors++;
Message msg = new GrammarSemanticsMessage(etype,g,token,args); Message msg = new GrammarSemanticsMessage(etype,g,token,args);
theDefaultErrorListener.error(msg); state.get().listener.error(msg);
} }
public static void grammarError(ErrorType etype, public static void grammarError(ErrorType etype,
@ -227,9 +234,9 @@ public class ErrorManager {
Token token, Token token,
Object... args) Object... args)
{ {
errors++; state.get().errors++;
Message msg = new GrammarSemanticsMessage(etype,fileName,token,args); Message msg = new GrammarSemanticsMessage(etype,fileName,token,args);
theDefaultErrorListener.error(msg); state.get().listener.error(msg);
} }
public static void grammarWarning(ErrorType etype, public static void grammarWarning(ErrorType etype,
@ -237,9 +244,9 @@ public class ErrorManager {
Token token, Token token,
Object... args) Object... args)
{ {
warnings++; state.get().warnings++;
Message msg = new GrammarSemanticsMessage(etype,fileName,token,args); Message msg = new GrammarSemanticsMessage(etype,fileName,token,args);
theDefaultErrorListener.warning(msg); state.get().listener.warning(msg);
} }
/** Process a new message by sending it on to the error listener associated with the current thread /** Process a new message by sending it on to the error listener associated with the current thread
@ -249,7 +256,7 @@ public class ErrorManager {
} }
public static int getNumErrors() { public static int getNumErrors() {
return errors; return state.get().errors;
} }
/** Return first non ErrorManager code location for generating messages */ /** Return first non ErrorManager code location for generating messages */
@ -266,6 +273,17 @@ public class ErrorManager {
return location; return location;
} }
/** In general, you'll want all errors to go to a single spot.
* However, in a GUI, you might have two frames up with two
* different grammars. Two threads might launch to process the
* grammars--you would want errors to go to different objects
* depending on the thread. I store a single listener per
* thread.
*/
public static void setErrorListener(ANTLRErrorListener l) {
state.get().listener = l;
}
// S U P P O R T C O D E // S U P P O R T C O D E
/** We really only need a single locale for entire running ANTLR code /** We really only need a single locale for entire running ANTLR code

View File

@ -1,9 +1,13 @@
package org.antlr.v4.tool; package org.antlr.v4.tool;
import org.antlr.runtime.*; import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.ParserRuleReturnScope;
import org.antlr.runtime.RecognitionException;
import org.antlr.v4.Tool; import org.antlr.v4.Tool;
import org.antlr.v4.parse.ANTLRLexer; import org.antlr.v4.parse.ANTLRLexer;
import org.antlr.v4.parse.ANTLRParser; import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor;
import java.util.*; import java.util.*;
@ -41,15 +45,18 @@ public class Grammar {
} }
/** For testing */ /** For testing */
public Grammar(String grammarText) throws RecognitionException { public Grammar(String fileName, String grammarText) throws RecognitionException {
this.text = grammarText; this.text = grammarText;
ANTLRStringStream in = new ANTLRStringStream(grammarText); ANTLRStringStream in = new ANTLRStringStream(grammarText);
in.name = fileName;
ANTLRLexer lexer = new ANTLRLexer(in); ANTLRLexer lexer = new ANTLRLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer); CommonTokenStream tokens = new CommonTokenStream(lexer);
ANTLRParser p = new ANTLRParser(tokens); ANTLRParser p = new ANTLRParser(tokens);
p.setTreeAdaptor(new GrammarASTAdaptor(in));
ParserRuleReturnScope r = p.grammarSpec(); ParserRuleReturnScope r = p.grammarSpec();
ast = (GrammarRootAST) r.getTree(); ast = (GrammarRootAST)r.getTree();
System.out.println(ast.toStringTree()); this.name = ((GrammarAST)ast.getChild(0)).getText();
this.fileName = fileName;
} }
public void loadImportedGrammars() { public void loadImportedGrammars() {

View File

@ -27,17 +27,19 @@
*/ */
package org.antlr.v4.test; package org.antlr.v4.test;
import org.antlr.tool.ANTLRErrorListener; import org.antlr.v4.misc.Utils;
import org.antlr.tool.Message; import org.antlr.v4.tool.ANTLRErrorListener;
import org.antlr.tool.ToolMessage; import org.antlr.v4.tool.Message;
import org.antlr.v4.tool.ToolMessage;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.LinkedList;
public class ErrorQueue implements ANTLRErrorListener { public class ErrorQueue implements ANTLRErrorListener {
List infos = new LinkedList(); public List<String> infos = new ArrayList<String>();
List errors = new LinkedList(); public List<Message> errors = new ArrayList<Message>();
List warnings = new LinkedList(); public List<Message> warnings = new ArrayList<Message>();
public List<Message> all = new ArrayList<Message>();
public void info(String msg) { public void info(String msg) {
infos.add(msg); infos.add(msg);
@ -45,24 +47,23 @@ public class ErrorQueue implements ANTLRErrorListener {
public void error(Message msg) { public void error(Message msg) {
errors.add(msg); errors.add(msg);
all.add(msg);
} }
public void warning(Message msg) { public void warning(Message msg) {
warnings.add(msg); warnings.add(msg);
all.add(msg);
} }
public void error(ToolMessage msg) { public void error(ToolMessage msg) {
errors.add(msg); errors.add(msg);
all.add(msg);
} }
public int size() { public int size() {
return infos.size() + errors.size() + warnings.size(); return all.size() + infos.size();
} }
public String toString() { public String toString() { return Utils.join(all.iterator(), "\n"); }
return "infos: "+infos+
"errors: "+errors+
"warnings: "+warnings;
}
} }

View File

@ -0,0 +1,68 @@
package org.antlr.v4.test;
import org.antlr.runtime.RecognitionException;
import org.antlr.v4.semantics.SemanticsPipeline;
import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.Grammar;
import org.junit.Test;
public class TestBasicSemanticErrors extends BaseTest {
public static class InOutPair { String in, out; }
static String[] pairs = {
// INPUT
"grammar A;\n" +
"\n" +
"options {\n" +
" output=template;\n" +
"}\n" +
"\n" +
"a : ID<Foo> -> ID ;\n" +
"\n" +
"b : A^ | ((B!|C)) -> ICK;",
// YIELDS
"error(68): A.g:7:7: alts with rewrites can't use heterogeneous types left of ->\n" +
"error(77): A.g:9:4: AST operator with non-AST output option: ^\n" +
"error(77): A.g:9:11: AST operator with non-AST output option: !\n" +
"error(78): A.g:9:11: rule b alt 2 uses rewrite syntax and also an AST operator",
// INPUT
"tree grammar B;\n" +
"options {\n" +
"\tfilter=true;\n" +
"\tbacktrack=false;\n" +
"\toutput=template;\n" +
"}\n" +
"\n" +
"a : A;\n" +
"\n" +
"b : ^(. A) ;",
// YIELDS
"error(79): B.g:10:6: Wildcard invalid as root; wildcard can itself be a tree\n" +
"error(80): B.g:1:5: option backtrack=false conflicts with tree grammar filter mode\n" +
"error(80): B.g:1:5: option output=template conflicts with tree grammar filter mode",
};
@Test public void testErrors() {
for (int i = 0; i < pairs.length; i+=2) {
String input = pairs[i];
String expect = pairs[i+1];
ErrorQueue equeue = new ErrorQueue();
ErrorManager.setErrorListener(equeue);
try {
String[] lines = input.split("\n");
int lastSpace = lines[0].lastIndexOf(' ');
int semi = lines[0].lastIndexOf(';');
String fileName = lines[0].substring(lastSpace+1, semi)+".g";
Grammar g = new Grammar(fileName, input);
g.loadImportedGrammars();
SemanticsPipeline sem = new SemanticsPipeline();
sem.process(g);
}
catch (RecognitionException re) {
re.printStackTrace(System.err);
}
String actual = equeue.toString();
assertEquals(expect,actual);
}
}
}