Merge pull request #713 from sharwell/fix-707

Improved support for recursive imports
This commit is contained in:
Terence Parr 2014-09-26 14:40:36 -07:00
commit f143495ab2
4 changed files with 98 additions and 31 deletions

View File

@ -608,6 +608,8 @@ public class Tool {
return g;
}
private final Map<String, Grammar> importedGrammars = new HashMap<String, Grammar>();
/**
* Try current dir then dir of g then lib dir
* @param g
@ -615,27 +617,34 @@ public class Tool {
*/
public Grammar loadImportedGrammar(Grammar g, GrammarAST nameNode) throws IOException {
String name = nameNode.getText();
g.tool.log("grammar", "load " + name + " from " + g.fileName);
File importedFile = null;
for (String extension : ALL_GRAMMAR_EXTENSIONS) {
importedFile = getImportedGrammarFile(g, name + extension);
if (importedFile != null) {
break;
Grammar imported = importedGrammars.get(name);
if (imported == null) {
g.tool.log("grammar", "load " + name + " from " + g.fileName);
File importedFile = null;
for (String extension : ALL_GRAMMAR_EXTENSIONS) {
importedFile = getImportedGrammarFile(g, name + extension);
if (importedFile != null) {
break;
}
}
if ( importedFile==null ) {
errMgr.grammarError(ErrorType.CANNOT_FIND_IMPORTED_GRAMMAR, g.fileName, nameNode.getToken(), name);
return null;
}
String absolutePath = importedFile.getAbsolutePath();
ANTLRFileStream in = new ANTLRFileStream(absolutePath, grammarEncoding);
GrammarRootAST root = parse(g.fileName, in);
if (root == null) {
return null;
}
imported = createGrammar(root);
imported.fileName = absolutePath;
importedGrammars.put(root.getGrammarName(), imported);
}
if ( importedFile==null ) {
errMgr.grammarError(ErrorType.CANNOT_FIND_IMPORTED_GRAMMAR, g.fileName, nameNode.getToken(), name);
return null;
}
ANTLRFileStream in = new ANTLRFileStream(importedFile.getAbsolutePath(), grammarEncoding);
GrammarRootAST root = parse(g.fileName, in);
if ( root==null ) {
return null;
}
Grammar imported = createGrammar(root);
imported.fileName = importedFile.getAbsolutePath();
return imported;
}

View File

@ -377,11 +377,9 @@ public class Grammar implements AttributeResolver {
if ( t.getType()==ANTLRParser.ASSIGN ) {
t = (GrammarAST)t.getChild(1);
importedGrammarName = t.getText();
tool.log("grammar", "import "+ importedGrammarName);
}
else if ( t.getType()==ANTLRParser.ID ) {
importedGrammarName = t.getText();
tool.log("grammar", "import " + t.getText());
}
Grammar g;
try {
@ -514,16 +512,24 @@ public class Grammar implements AttributeResolver {
* The grammars are in import tree preorder. Don't include ourselves
* in list as we're not a delegate of ourselves.
*/
public List<Grammar> getAllImportedGrammars() {
if ( importedGrammars==null ) return null;
List<Grammar> delegates = new ArrayList<Grammar>();
for (Grammar d : importedGrammars) {
delegates.add(d);
List<Grammar> ds = d.getAllImportedGrammars();
if (ds != null) delegates.addAll(ds);
public List<Grammar> getAllImportedGrammars() {
if (importedGrammars == null) {
return null;
}
return delegates;
}
LinkedHashMap<String, Grammar> delegates = new LinkedHashMap<String, Grammar>();
for (Grammar d : importedGrammars) {
delegates.put(d.fileName, d);
List<Grammar> ds = d.getAllImportedGrammars();
if (ds != null) {
for (Grammar imported : ds) {
delegates.put(imported.fileName, imported);
}
}
}
return new ArrayList<Grammar>(delegates.values());
}
public List<Grammar> getImportedGrammars() { return importedGrammars; }

View File

@ -289,8 +289,28 @@ public class GrammarTransformPipeline {
GrammarAST optionsRoot = (GrammarAST)imp.ast.getFirstChildWithType(ANTLRParser.OPTIONS);
if ( optionsRoot!=null ) {
rootGrammar.tool.errMgr.grammarError(ErrorType.OPTIONS_IN_DELEGATE,
optionsRoot.g.fileName, optionsRoot.token, imp.name);
// suppress the warning if the options match the options specified
// in the root grammar
// https://github.com/antlr/antlr4/issues/707
boolean hasNewOption = false;
for (Map.Entry<String, GrammarAST> option : imp.ast.getOptions().entrySet()) {
String importOption = imp.ast.getOptionString(option.getKey());
if (importOption == null) {
continue;
}
String rootOption = rootGrammar.ast.getOptionString(option.getKey());
if (!importOption.equals(rootOption)) {
hasNewOption = true;
break;
}
}
if (hasNewOption) {
rootGrammar.tool.errMgr.grammarError(ErrorType.OPTIONS_IN_DELEGATE,
optionsRoot.g.fileName, optionsRoot.token, imp.name);
}
}
}
rootGrammar.tool.log("grammar", "Grammar: "+rootGrammar.ast.toStringTree());

View File

@ -1998,4 +1998,36 @@ public class TestPerformance extends BaseTest {
Assert.assertEquals("", found);
Assert.assertEquals(null, stderrDuringParse);
}
@Test(timeout = 20000)
public void testExponentialInclude() {
String grammarFormat =
"parser grammar Level_%d_%d;\n" +
"\n" +
"%s import Level_%d_1, Level_%d_2;\n" +
"\n" +
"rule_%d_%d : EOF;\n";
System.out.println("dir "+tmpdir);
mkdir(tmpdir);
long startTime = System.nanoTime();
int levels = 20;
for (int level = 0; level < levels; level++) {
String leafPrefix = level == levels - 1 ? "//" : "";
String grammar1 = String.format(grammarFormat, level, 1, leafPrefix, level + 1, level + 1, level, 1);
writeFile(tmpdir, "Level_" + level + "_1.g4", grammar1);
if (level > 0) {
String grammar2 = String.format(grammarFormat, level, 2, leafPrefix, level + 1, level + 1, level, 1);
writeFile(tmpdir, "Level_" + level + "_2.g4", grammar2);
}
}
ErrorQueue equeue = antlr("Level_0_1.g4", false);
Assert.assertTrue(equeue.errors.isEmpty());
long endTime = System.nanoTime();
System.out.format("%s milliseconds.%n", (endTime - startTime) / 1000000.0);
}
}