Merge pull request #662 from parrt/fix-661

Fix 661
This commit is contained in:
Terence Parr 2014-07-11 12:10:41 -07:00
commit f86fc71128
11 changed files with 292 additions and 183 deletions

52
bild.py
View File

@ -4,6 +4,7 @@ import string
# bootstrap by downloading bilder.py if not found
import urllib
import os
if not os.path.exists("bilder.py"):
print "bootstrapping; downloading bilder.py"
@ -34,25 +35,25 @@ TARGETS = {"Java":uniformpath(JAVA_TARGET),
"CSharp":uniformpath(CSHARP_TARGET)}
def parsers():
antlr3("tool/src/org/antlr/v4/parse", "gen", package="org.antlr.v4.parse")
antlr3("tool/src/org/antlr/v4/codegen", "gen", package="org.antlr.v4.codegen", args=["-lib","tool/src/org/antlr/v4/parse"])
antlr4("runtime/Java/src/org/antlr/v4/runtime/tree/xpath", "gen", package="org.antlr.v4.runtime.tree.xpath")
antlr3("tool/src/org/antlr/v4/parse", "gen3", package="org.antlr.v4.parse")
antlr3("tool/src/org/antlr/v4/codegen", "gen3", package="org.antlr.v4.codegen", args=["-lib",uniformpath("gen3/org/antlr/v4/parse")])
antlr4("runtime/Java/src/org/antlr/v4/runtime/tree/xpath", "gen4", package="org.antlr.v4.runtime.tree.xpath")
def compile():
require(parsers)
cp = uniformpath("out")+os.pathsep+ \
os.path.join(JARCACHE,"antlr-3.5.1-complete.jar")+os.pathsep+ \
"runtime/Java/lib/org.abego.treelayout.core.jar"
args = ["-Xlint", "-Xlint:-serial", "-g"]
javac("runtime/JavaAnnotations/src/", "out", version="1.6", cp=cp, args=args)
javac("runtime/Java/src", "out", version="1.6", cp=cp, args=args)
javac("tool/src", "out", version="1.6", cp=cp, args=args)
javac("gen", "out", version="1.6", cp=cp, args=args)
"runtime/Java/lib/org.abego.treelayout.core.jar"+os.pathsep+ \
JARCACHE+"/antlr-4.4-complete.jar"
srcpath = ["gen3", "gen4", "runtime/JavaAnnotations/src", "runtime/Java/src", "tool/src"]
args = ["-Xlint", "-Xlint:-serial", "-g", "-sourcepath", string.join(srcpath, os.pathsep)]
for sp in srcpath:
javac(sp, "out", version="1.6", cp=cp, args=args)
# pull in targets
for t in TARGETS:
javac(TARGETS[t]+"/tool/src", "out", version="1.6", cp=cp, args=args)
def mkjar():
def mkjar_complete():
require(compile)
copytree(src="tool/resources", trg="out") # messages, Java code gen, etc...
manifest = \
@ -73,17 +74,19 @@ Created-By: http://www.bildtool.org
mkdir(trgdir)
copyfile(TARGETS[t]+"/tool/resources/org/antlr/v4/tool/templates/codegen/"+t+"/"+t+".stg",
trgdir)
jar("dist/antlr-"+VERSION+"-complete.jar", srcdir="out", manifest=manifest)
jarfile = "dist/antlr-"+VERSION+"-complete.jar"
jar(jarfile, srcdir="out", manifest=manifest)
print "Generated "+jarfile
mkruntimejar()
def mkruntimejar():
def mkjar_runtime():
# out/... dir is full of tool-related stuff, make special dir out/runtime
cp = uniformpath("out/runtime")+os.pathsep+ \
"runtime/Java/lib/org.abego.treelayout.core.jar"
args = ["-Xlint", "-Xlint:-serial", "-g"]
javac("runtime/JavaAnnotations/src/", "out/runtime", version="1.6", cp=cp, args=args)
javac("runtime/Java/src", "out/runtime", version="1.6", cp=cp, args=args)
srcpath = ["runtime/JavaAnnotations/src", "runtime/Java/src"]
args = ["-Xlint", "-Xlint:-serial", "-g", "-sourcepath", string.join(srcpath, os.pathsep)]
for sp in srcpath:
javac(sp, "out", version="1.6", cp=cp, args=args)
manifest = \
"""Implementation-Vendor: ANTLR
Implementation-Title: ANTLR 4 Runtime
@ -94,8 +97,20 @@ Created-By: http://www.bildtool.org
""" % (VERSION,os.getlogin())
# unjar required library
unjar("runtime/Java/lib/org.abego.treelayout.core.jar", trgdir="out/runtime")
jar("dist/antlr-runtime-"+VERSION+".jar", srcdir="out/runtime", manifest=manifest)
jarfile = "dist/antlr-runtime-" + VERSION + ".jar"
jar(jarfile, srcdir="out/runtime", manifest=manifest)
print "Generated "+jarfile
def mkjar():
mkjar_complete()
# put it in JARCARCHE too so bild can find it during antlr4()
copyfile(src="dist/antlr-4.4-complete.jar", trg=JARCACHE)
# rebuild/bootstrap XPath with 4.4 so it can use 4.4 runtime (gen'd with 4.3 at this point)
rmdir("gen4/org/antlr/v4/runtime/tree/xpath") # kill 4.3-generated version
antlr4("runtime/Java/src/org/antlr/v4/runtime/tree/xpath", "gen4", version="4.4", package="org.antlr.v4.runtime.tree.xpath")
compile()
mkjar_complete() # make it again with up to date XPath lexer
mkjar_runtime() # now build the runtime jar
def tests():
require(mkjar)
@ -119,7 +134,8 @@ def all():
def clean():
rmdir("out")
rmdir("gen")
rmdir("gen3")
rmdir("gen4")
rmdir("doc")
def mkdoc():

View File

@ -434,7 +434,8 @@ public class Tool {
* Important enough to avoid multiple definitions that we do very early,
* right after AST construction. Also check for undefined rules in
* parser/lexer to avoid exceptions later. Return true if we find multiple
* definitions of the same rule or a reference to an undefined rule.
* definitions of the same rule or a reference to an undefined rule or
* parser rule ref in lexer rule.
*/
public boolean checkForRuleIssues(final Grammar g) {
// check for redefined rules
@ -466,7 +467,7 @@ public class Tool {
// check for undefined rules
class UndefChecker extends GrammarTreeVisitor {
public boolean undefined = false;
public boolean badref = false;
@Override
public void tokenRef(TerminalAST ref) {
if ("EOF".equals(ref.getText())) {
@ -480,18 +481,28 @@ public class Tool {
@Override
public void ruleRef(GrammarAST ref, ActionAST arg) {
RuleAST ruleAST = ruleToAST.get(ref.getText());
if ( ruleAST==null ) {
undefined = true;
if (Character.isUpperCase(currentRuleName.charAt(0)) &&
Character.isLowerCase(ref.getText().charAt(0)))
{
badref = true;
String fileName = ref.getToken().getInputStream().getSourceName();
errMgr.grammarError(ErrorType.PARSER_RULE_REF_IN_LEXER_RULE,
fileName, ref.getToken(), ref.getText(), currentRuleName);
}
else if ( ruleAST==null ) {
badref = true;
errMgr.grammarError(ErrorType.UNDEFINED_RULE_REF,
g.fileName, ref.token, ref.getText());
}
}
@Override
public ErrorManager getErrorManager() { return errMgr; }
}
UndefChecker chk = new UndefChecker();
chk.visitGrammar(g.ast);
return redefinition || chk.undefined;
return redefinition || chk.badref;
}
public List<GrammarRootAST> sortGrammarByTokenVocab(List<String> fileNames) {

View File

@ -0,0 +1,166 @@
package org.antlr.v4.codegen.model;
import org.antlr.runtime.tree.TreeNodeStream;
import org.antlr.v4.misc.FrequencySet;
import org.antlr.v4.misc.MutableInt;
import org.antlr.v4.parse.GrammarTreeVisitor;
import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.TerminalAST;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;
public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
final Deque<FrequencySet<String>> frequencies;
public ElementFrequenciesVisitor(TreeNodeStream input) {
super(input);
frequencies = new ArrayDeque<FrequencySet<String>>();
frequencies.push(new FrequencySet<String>());
}
/** During code gen, we can assume tree is in good shape */
@Override
public ErrorManager getErrorManager() { return super.getErrorManager(); }
/*
* Common
*/
/**
* Generate a frequency set as the union of two input sets. If an
* element is contained in both sets, the value for the output will be
* the maximum of the two input values.
*
* @param a The first set.
* @param b The second set.
* @return The union of the two sets, with the maximum value chosen
* whenever both sets contain the same key.
*/
protected static FrequencySet<String> combineMax(FrequencySet<String> a, FrequencySet<String> b) {
FrequencySet<String> result = combineAndClip(a, b, 1);
for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
result.get(entry.getKey()).v = entry.getValue().v;
}
for (Map.Entry<String, MutableInt> entry : b.entrySet()) {
MutableInt slot = result.get(entry.getKey());
slot.v = Math.max(slot.v, entry.getValue().v);
}
return result;
}
/**
* Generate a frequency set as the union of two input sets, with the
* values clipped to a specified maximum value. If an element is
* contained in both sets, the value for the output, prior to clipping,
* will be the sum of the two input values.
*
* @param a The first set.
* @param b The second set.
* @param clip The maximum value to allow for any output.
* @return The sum of the two sets, with the individual elements clipped
* to the maximum value gived by {@code clip}.
*/
protected static FrequencySet<String> combineAndClip(FrequencySet<String> a, FrequencySet<String> b, int clip) {
FrequencySet<String> result = new FrequencySet<String>();
for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
for (int i = 0; i < entry.getValue().v; i++) {
result.add(entry.getKey());
}
}
for (Map.Entry<String, MutableInt> entry : b.entrySet()) {
for (int i = 0; i < entry.getValue().v; i++) {
result.add(entry.getKey());
}
}
for (Map.Entry<String, MutableInt> entry : result.entrySet()) {
entry.getValue().v = Math.min(entry.getValue().v, clip);
}
return result;
}
@Override
public void tokenRef(TerminalAST ref) {
frequencies.peek().add(ref.getText());
}
@Override
public void ruleRef(GrammarAST ref, ActionAST arg) {
frequencies.peek().add(ref.getText());
}
/*
* Parser rules
*/
@Override
protected void enterAlternative(AltAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitAlternative(AltAST tree) {
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
}
@Override
protected void enterElement(GrammarAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitElement(GrammarAST tree) {
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
}
@Override
protected void exitSubrule(GrammarAST tree) {
if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
entry.getValue().v = 2;
}
}
}
/*
* Lexer rules
*/
@Override
protected void enterLexerAlternative(GrammarAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitLexerAlternative(GrammarAST tree) {
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
}
@Override
protected void enterLexerElement(GrammarAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitLexerElement(GrammarAST tree) {
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
}
@Override
protected void exitLexerSubrule(GrammarAST tree) {
if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
entry.getValue().v = 2;
}
}
}
}

View File

@ -32,7 +32,6 @@ package org.antlr.v4.codegen.model;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.runtime.tree.TreeNodeStream;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.decl.AltLabelStructDecl;
import org.antlr.v4.codegen.model.decl.AttributeDecl;
@ -45,10 +44,8 @@ import org.antlr.v4.codegen.model.decl.ContextTokenListIndexedGetterDecl;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.misc.FrequencySet;
import org.antlr.v4.misc.MutableInt;
import org.antlr.v4.misc.Utils;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.parse.GrammarTreeVisitor;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.OrderedHashSet;
@ -59,12 +56,9 @@ import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.TerminalAST;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -292,151 +286,4 @@ public class RuleFunction extends OutputModelObject {
}
ruleCtx.addDecl(d); // stick in overall rule's ctx
}
protected static class ElementFrequenciesVisitor extends GrammarTreeVisitor {
final Deque<FrequencySet<String>> frequencies;
public ElementFrequenciesVisitor(TreeNodeStream input) {
super(input);
frequencies = new ArrayDeque<FrequencySet<String>>();
frequencies.push(new FrequencySet<String>());
}
/*
* Common
*/
/**
* Generate a frequency set as the union of two input sets. If an
* element is contained in both sets, the value for the output will be
* the maximum of the two input values.
*
* @param a The first set.
* @param b The second set.
* @return The union of the two sets, with the maximum value chosen
* whenever both sets contain the same key.
*/
protected static FrequencySet<String> combineMax(FrequencySet<String> a, FrequencySet<String> b) {
FrequencySet<String> result = combineAndClip(a, b, 1);
for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
result.get(entry.getKey()).v = entry.getValue().v;
}
for (Map.Entry<String, MutableInt> entry : b.entrySet()) {
MutableInt slot = result.get(entry.getKey());
slot.v = Math.max(slot.v, entry.getValue().v);
}
return result;
}
/**
* Generate a frequency set as the union of two input sets, with the
* values clipped to a specified maximum value. If an element is
* contained in both sets, the value for the output, prior to clipping,
* will be the sum of the two input values.
*
* @param a The first set.
* @param b The second set.
* @param clip The maximum value to allow for any output.
* @return The sum of the two sets, with the individual elements clipped
* to the maximum value gived by {@code clip}.
*/
protected static FrequencySet<String> combineAndClip(FrequencySet<String> a, FrequencySet<String> b, int clip) {
FrequencySet<String> result = new FrequencySet<String>();
for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
for (int i = 0; i < entry.getValue().v; i++) {
result.add(entry.getKey());
}
}
for (Map.Entry<String, MutableInt> entry : b.entrySet()) {
for (int i = 0; i < entry.getValue().v; i++) {
result.add(entry.getKey());
}
}
for (Map.Entry<String, MutableInt> entry : result.entrySet()) {
entry.getValue().v = Math.min(entry.getValue().v, clip);
}
return result;
}
@Override
public void tokenRef(TerminalAST ref) {
frequencies.peek().add(ref.getText());
}
@Override
public void ruleRef(GrammarAST ref, ActionAST arg) {
frequencies.peek().add(ref.getText());
}
/*
* Parser rules
*/
@Override
protected void enterAlternative(AltAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitAlternative(AltAST tree) {
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
}
@Override
protected void enterElement(GrammarAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitElement(GrammarAST tree) {
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
}
@Override
protected void exitSubrule(GrammarAST tree) {
if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
entry.getValue().v = 2;
}
}
}
/*
* Lexer rules
*/
@Override
protected void enterLexerAlternative(GrammarAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitLexerAlternative(GrammarAST tree) {
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
}
@Override
protected void enterLexerElement(GrammarAST tree) {
frequencies.push(new FrequencySet<String>());
}
@Override
protected void exitLexerElement(GrammarAST tree) {
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
}
@Override
protected void exitLexerSubrule(GrammarAST tree) {
if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
entry.getValue().v = 2;
}
}
}
}
}

View File

@ -76,6 +76,7 @@ options {
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.parse;
import org.antlr.v4.Tool;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
import java.lang.reflect.Method;
@ -86,13 +87,14 @@ public String grammarName;
public GrammarAST currentRuleAST;
public String currentModeName = LexerGrammar.DEFAULT_MODE_NAME;
public String currentRuleName;
//public GrammarAST currentRuleBlock;
public GrammarAST currentOuterAltRoot;
public int currentOuterAltNumber = 1; // 1..n
public int rewriteEBNFLevel = 0;
public GrammarTreeVisitor() { this(null); }
// Should be abstract but can't make gen'd parser abstract;
// subclasses should implement else everything goes to stderr!
public ErrorManager getErrorManager() { return null; }
public void visitGrammar(GrammarAST t) { visit(t, "grammarSpec"); }
@ -742,6 +744,7 @@ lexerAtom
| WILDCARD
| LEXER_CHAR_SET
| range
| ruleref
;
actionElement

View File

@ -130,6 +130,9 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
this.errMgr = g.tool.errMgr;
}
@Override
public ErrorManager getErrorManager() { return errMgr; }
public void process() { visitGrammar(g.ast); }
// Routines to route visitor traffic to the checking routines
@ -376,8 +379,8 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
void checkInvalidRuleRef(Token ruleID) {
String fileName = ruleID.getInputStream().getSourceName();
if ( g.isLexer() && Character.isLowerCase(ruleID.getText().charAt(0)) ) {
g.tool.errMgr.grammarError(ErrorType.PARSER_RULES_NOT_ALLOWED,
fileName, ruleID, ruleID.getText());
g.tool.errMgr.grammarError(ErrorType.PARSER_RULE_REF_IN_LEXER_RULE,
fileName, ruleID, ruleID.getText(), currentRuleName);
}
}

View File

@ -36,6 +36,7 @@ import org.antlr.v4.misc.Utils;
import org.antlr.v4.parse.GrammarTreeVisitor;
import org.antlr.v4.parse.ScopeParser;
import org.antlr.v4.tool.AttributeDict;
import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.LeftRecursiveRule;
import org.antlr.v4.tool.Rule;
@ -52,13 +53,20 @@ import java.util.Map;
public class RuleCollector extends GrammarTreeVisitor {
/** which grammar are we checking */
public Grammar g;
public ErrorManager errMgr;
// stuff to collect. this is the output
public OrderedHashMap<String, Rule> rules = new OrderedHashMap<String, Rule>();
public MultiMap<String,GrammarAST> ruleToAltLabels = new MultiMap<String, GrammarAST>();
public Map<String,String> altLabelToRuleName = new HashMap<String, String>();
public RuleCollector(Grammar g) { this.g = g; }
public RuleCollector(Grammar g) {
this.g = g;
this.errMgr = g.tool.errMgr;
}
@Override
public ErrorManager getErrorManager() { return errMgr; }
public void process(GrammarAST ast) { visitGrammar(ast); }

View File

@ -31,6 +31,7 @@
package org.antlr.v4.semantics;
import org.antlr.v4.parse.GrammarTreeVisitor;
import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.LabelElementPair;
import org.antlr.v4.tool.Rule;
@ -68,10 +69,18 @@ public class SymbolCollector extends GrammarTreeVisitor {
/** Track action name node in @parser::members {...} or @members {...} */
List<GrammarAST> namedActions = new ArrayList<GrammarAST>();
public ErrorManager errMgr;
// context
public Rule currentRule;
public SymbolCollector(Grammar g) { this.g = g; }
public SymbolCollector(Grammar g) {
this.g = g;
this.errMgr = g.tool.errMgr;
}
@Override
public ErrorManager getErrorManager() { return errMgr; }
public void process(GrammarAST ast) { visitGrammar(ast); }

View File

@ -224,6 +224,12 @@ public enum ErrorType {
* <p>reference to undefined rule: <em>rule</em></p>
*/
UNDEFINED_RULE_REF(56, "reference to undefined rule: <arg>", ErrorSeverity.ERROR),
/**
* Compiler Error 160.
*
* <p>reference to undefined rule: <em>rule</em></p>
*/
PARSER_RULE_REF_IN_LEXER_RULE(160, "reference to parser rule <arg> in lexer rule <arg2>", ErrorSeverity.ERROR),
/**
* Compiler Error 57.
*

View File

@ -30,7 +30,6 @@
package org.antlr.v4.tool;
import org.antlr.runtime.tree.Tree;
import org.antlr.v4.Tool;
import org.antlr.v4.analysis.LeftRecursiveRuleTransformer;
import org.antlr.v4.misc.CharSupport;
@ -1063,6 +1062,8 @@ public class Grammar implements AttributeResolver {
public void stringRef(TerminalAST ref) {
strings.add(ref.getText());
}
@Override
public ErrorManager getErrorManager() { return tool.errMgr; }
};
collector.visitGrammar(ast);
return strings;

View File

@ -28,16 +28,23 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.test;
import org.antlr.v4.Tool;
import org.antlr.v4.automata.ATNPrinter;
import org.antlr.v4.automata.LexerATNFactory;
import org.antlr.v4.automata.ParserATNFactory;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.LexerGrammar;
import org.antlr.v4.tool.ast.GrammarRootAST;
import org.junit.Test;
import static org.junit.Assert.*;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class TestATNConstruction extends BaseTest {
@Test
@ -390,6 +397,38 @@ public class TestATNConstruction extends BaseTest {
"RuleStop_a_1-EOF->s8\n";
checkRuleATN(g, "a", expecting);
}
@Test public void testParserRuleRefInLexerRule() throws Exception {
boolean threwException = false;
ErrorQueue errorQueue = new ErrorQueue();
try {
String gstr =
"grammar U;\n"+
"a : A;\n"+
"A : a;\n";
Tool tool = new Tool();
tool.removeListeners();
tool.addListener(errorQueue);
assertEquals(0, errorQueue.size());
GrammarRootAST grammarRootAST = tool.parseGrammarFromString(gstr);
assertEquals(0, errorQueue.size());
Grammar g = tool.createGrammar(grammarRootAST);
assertEquals(0, errorQueue.size());
g.fileName = "<string>";
tool.process(g, false);
}
catch (Exception e) {
threwException = true;
e.printStackTrace();
}
System.out.println(errorQueue);
assertEquals(1, errorQueue.errors.size());
assertEquals(ErrorType.PARSER_RULE_REF_IN_LEXER_RULE, errorQueue.errors.get(0).getErrorType());
assertEquals("[a, A]", Arrays.toString(errorQueue.errors.get(0).getArgs()));
assertTrue(!threwException);
}
/*
@Test public void testMultiplePredicates() throws Exception {
Grammar g = new Grammar(