Merge pull request #713 from sharwell/fix-707
Improved support for recursive imports
This commit is contained in:
commit
f143495ab2
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue