summaryrefslogtreecommitdiff
path: root/antlr4-maven-plugin/src
diff options
context:
space:
mode:
Diffstat (limited to 'antlr4-maven-plugin/src')
-rw-r--r--antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4ErrorLog.java31
-rw-r--r--antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java182
-rw-r--r--antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/GrammarDependencies.java314
-rw-r--r--antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/MojoUtils.java79
-rw-r--r--antlr4-maven-plugin/src/site/site.xml8
-rw-r--r--antlr4-maven-plugin/src/test/java/org/antlr/mojo/antlr4/Antlr4MojoTest.java361
-rw-r--r--antlr4-maven-plugin/src/test/projects/dependencyRemoved/pom.xml33
-rw-r--r--antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/imports/HelloBase.g416
-rw-r--r--antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/test/Hello.g47
-rw-r--r--antlr4-maven-plugin/src/test/projects/importTokens/pom.xml33
-rw-r--r--antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/imports/SimpleLexer.tokens3
-rw-r--r--antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/test/SimpleParser.g48
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsCustom/pom.xml48
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/Hello.g44
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestLexer.g46
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestParser.g45
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/imports/TestBaseLexer.g416
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsStandard/pom.xml33
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/imports/TestBaseLexer.g416
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/Hello.g44
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestLexer.g46
-rw-r--r--antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestParser.g45
22 files changed, 1116 insertions, 102 deletions
diff --git a/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4ErrorLog.java b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4ErrorLog.java
index b251878..92d2377 100644
--- a/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4ErrorLog.java
+++ b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4ErrorLog.java
@@ -1,31 +1,8 @@
/*
- [The "BSD license"]
- Copyright (c) 2012 Terence Parr
- Copyright (c) 2012 Sam Harwell
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ * Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
package org.antlr.mojo.antlr4;
import org.antlr.v4.Tool;
diff --git a/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java
index d8712ee..0afe54f 100644
--- a/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java
+++ b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java
@@ -1,31 +1,8 @@
/*
- [The "BSD license"]
- Copyright (c) 2012 Terence Parr
- Copyright (c) 2012 Sam Harwell
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ * Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
package org.antlr.mojo.antlr4;
@@ -59,6 +36,7 @@ import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -95,7 +73,13 @@ public class Antlr4Mojo extends AbstractMojo {
* specify grammar file encoding; e.g., euc-jp
*/
@Parameter(property = "project.build.sourceEncoding")
- protected String encoding;
+ protected String inputEncoding;
+
+ /**
+ * specify output file encoding; defaults to source encoding
+ */
+ @Parameter(property = "project.build.sourceEncoding")
+ protected String outputEncoding;
/**
* Generate parse tree listener interface and base class.
@@ -184,6 +168,12 @@ public class Antlr4Mojo extends AbstractMojo {
@Parameter(defaultValue = "${basedir}/src/main/antlr4/imports")
private File libDirectory;
+ /**
+ * The directory where build status information is located.
+ */
+ @Parameter(defaultValue = "${project.build.directory}/maven-status/antlr4", readonly=true)
+ private File statusDirectory;
+
@Component
private BuildContext buildContext;
@@ -222,6 +212,8 @@ public class Antlr4Mojo extends AbstractMojo {
Log log = getLog();
+ outputEncoding = validateEncoding(outputEncoding);
+
if (log.isDebugEnabled()) {
for (String e : excludes) {
log.debug("ANTLR: Exclude: " + e);
@@ -249,16 +241,22 @@ public class Antlr4Mojo extends AbstractMojo {
outputDir.mkdirs();
}
+ GrammarDependencies dependencies = new GrammarDependencies(sourceDirectory, libDirectory, arguments, getDependenciesStatusFile(), getLog());
+
// Now pick up all the files and process them with the Tool
//
List<List<String>> argumentSets;
+ Set<File> grammarFiles;
+ Set<File> importGrammarFiles;
try {
List<String> args = getCommandArguments();
- argumentSets = processGrammarFiles(args, sourceDirectory);
- } catch (InclusionScanException ie) {
- log.error(ie);
- throw new MojoExecutionException("Fatal error occured while evaluating the names of the grammar files to analyze", ie);
+ grammarFiles = getGrammarFiles(sourceDirectory);
+ importGrammarFiles = getImportFiles(sourceDirectory);
+ argumentSets = processGrammarFiles(args, grammarFiles, dependencies, sourceDirectory);
+ } catch (Exception e) {
+ log.error(e);
+ throw new MojoExecutionException("Fatal error occured while evaluating the names of the grammar files to analyze", e);
}
log.debug("Output directory base will be " + outputDirectory.getAbsolutePath());
@@ -272,6 +270,14 @@ public class Antlr4Mojo extends AbstractMojo {
throw new MojoFailureException("Error creating an instanceof the ANTLR tool.", e);
}
+ try {
+ dependencies.analyze(grammarFiles, importGrammarFiles, tool);
+ } catch (Exception e) {
+ log.error("Dependency analysis failed, see exception report for details",
+ e);
+ throw new MojoFailureException("Dependency analysis failed.", e);
+ }
+
// Set working directory for ANTLR to be the base source directory
tool.inputDirectory = sourceDirectory;
@@ -288,6 +294,12 @@ public class Antlr4Mojo extends AbstractMojo {
// Tell Maven that there are some new source files underneath the output directory.
addSourceRoot(this.getOutputDirectory());
}
+
+ try {
+ dependencies.save();
+ } catch (IOException ex) {
+ log.warn("Could not save grammar dependency status", ex);
+ }
}
private List<String> getCommandArguments() {
@@ -310,9 +322,10 @@ public class Antlr4Mojo extends AbstractMojo {
args.add("-atn");
}
- if (encoding != null && !encoding.isEmpty()) {
+ if ( inputEncoding!=null && !inputEncoding.isEmpty()) {
args.add("-encoding");
- args.add(encoding);
+ outputEncoding = inputEncoding;
+ args.add(inputEncoding);
}
if (listener) {
@@ -355,22 +368,11 @@ public class Antlr4Mojo extends AbstractMojo {
* @param sourceDirectory
* @exception InclusionScanException
*/
-
- private List<List<String>> processGrammarFiles(List<String> args, File sourceDirectory) throws InclusionScanException {
- // Which files under the source set should we be looking for as grammar files
- SourceMapping mapping = new SuffixMapping("g4", Collections.<String>emptySet());
-
- // What are the sets of includes (defaulted or otherwise).
- Set<String> includes = getIncludesPatterns();
-
- // Now, to the excludes, we need to add the imports directory
- // as this is autoscanned for imported grammars and so is auto-excluded from the
- // set of grammar fields we should be analyzing.
- excludes.add("imports/**");
-
- SourceInclusionScanner scan = new SimpleSourceInclusionScanner(includes, excludes);
- scan.addSourceMapping(mapping);
- Set<File> grammarFiles = scan.getIncludedSources(sourceDirectory, null);
+ private List<List<String>> processGrammarFiles(
+ List<String> args,
+ Set<File> grammarFiles,
+ GrammarDependencies dependencies,
+ File sourceDirectory) throws InclusionScanException, IOException {
// We don't want the plugin to run for every grammar, regardless of whether
// it's changed since the last compilation. Check the mtime of the tokens vs
@@ -381,7 +383,8 @@ public class Antlr4Mojo extends AbstractMojo {
String tokensFileName = grammarFile.getName().split("\\.")[0] + ".tokens";
File outputFile = new File(outputDirectory, tokensFileName);
if ( (! outputFile.exists()) ||
- outputFile.lastModified() < grammarFile.lastModified() ) {
+ outputFile.lastModified() < grammarFile.lastModified() ||
+ dependencies.isDependencyChanged(grammarFile)) {
grammarFilesToProcess.add(grammarFile);
}
}
@@ -405,7 +408,7 @@ public class Antlr4Mojo extends AbstractMojo {
getLog().debug("Grammar file '" + grammarFile.getPath() + "' detected.");
- String relPathBase = findSourceSubdir(sourceDirectory, grammarFile.getPath());
+ String relPathBase = MojoUtils.findSourceSubdir(sourceDirectory, grammarFile);
String relPath = relPathBase + grammarFile.getName();
getLog().debug(" ... relative path is: " + relPath);
@@ -430,6 +433,39 @@ public class Antlr4Mojo extends AbstractMojo {
return result;
}
+ private Set<File> getImportFiles(File sourceDirectory) throws InclusionScanException {
+ if (!libDirectory.exists()) return Collections.emptySet();
+
+ Set<String> includes = new HashSet<String>();
+ includes.add("*.g4");
+ includes.add("*.tokens");
+
+ SourceInclusionScanner scan = new SimpleSourceInclusionScanner(includes,
+ Collections.<String>emptySet());
+ scan.addSourceMapping(new SuffixMapping("G4", "g4"));
+
+ return scan.getIncludedSources(libDirectory, null);
+ }
+
+ private Set<File> getGrammarFiles(File sourceDirectory) throws InclusionScanException
+ {
+ // Which files under the source set should we be looking for as grammar files
+ SourceMapping mapping = new SuffixMapping("g4", Collections.<String>emptySet());
+
+ // What are the sets of includes (defaulted or otherwise).
+ Set<String> includes = getIncludesPatterns();
+
+ // Now, to the excludes, we need to add the imports directory
+ // as this is autoscanned for imported grammars and so is auto-excluded from the
+ // set of grammar fields we should be analyzing.
+ excludes.add("imports/**");
+
+ SourceInclusionScanner scan = new SimpleSourceInclusionScanner(includes, excludes);
+ scan.addSourceMapping(mapping);
+
+ return scan.getIncludedSources(sourceDirectory, null);
+ }
+
private static String getPackageName(String relativeFolderPath) {
if (relativeFolderPath.contains("..")) {
throw new UnsupportedOperationException("Cannot handle relative paths containing '..'");
@@ -450,30 +486,14 @@ public class Antlr4Mojo extends AbstractMojo {
return includes;
}
- /**
- * Given the source directory File object and the full PATH to a grammar,
- * produce the path to the named grammar file in relative terms to the
- * {@code sourceDirectory}. This will then allow ANTLR to produce output
- * relative to the base of the output directory and reflect the input
- * organization of the grammar files.
- *
- * @param sourceDirectory The source directory {@link File} object
- * @param grammarFileName The full path to the input grammar file
- * @return The path to the grammar file relative to the source directory
- */
- private String findSourceSubdir(File sourceDirectory, String grammarFileName) {
- String srcPath = sourceDirectory.getPath() + File.separator;
+ private File getDependenciesStatusFile() {
+ File statusFile = new File(statusDirectory, "dependencies.ser");
- if (!grammarFileName.startsWith(srcPath)) {
- throw new IllegalArgumentException("expected " + grammarFileName + " to be prefixed with " + sourceDirectory);
+ if (!statusFile.getParentFile().exists()) {
+ statusFile.getParentFile().mkdirs();
}
- File unprefixedGrammarFileName = new File(grammarFileName.substring(srcPath.length()));
- if (unprefixedGrammarFileName.getParent() == null) {
- return "";
- }
-
- return unprefixedGrammarFileName.getParent() + File.separator;
+ return statusFile;
}
private final class CustomTool extends Tool {
@@ -515,7 +535,21 @@ public class Antlr4Mojo extends AbstractMojo {
URI relativePath = project.getBasedir().toURI().relativize(outputFile.toURI());
getLog().debug(" Writing file: " + relativePath);
OutputStream outputStream = buildContext.newFileOutputStream(outputFile);
- return new BufferedWriter(new OutputStreamWriter(outputStream));
+ if ( outputEncoding!=null && !outputEncoding.isEmpty()) {
+ return new BufferedWriter(new OutputStreamWriter(outputStream, outputEncoding));
+ }
+ else {
+ return new BufferedWriter(new OutputStreamWriter(outputStream));
+ }
}
}
+
+ /**
+ * Validates the given encoding.
+ *
+ * @return the validated encoding. If {@code null} was provided, returns the platform default encoding.
+ */
+ private String validateEncoding(String encoding) {
+ return (encoding == null) ? Charset.defaultCharset().name() : Charset.forName(encoding.trim()).name();
+ }
}
diff --git a/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/GrammarDependencies.java b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/GrammarDependencies.java
new file mode 100644
index 0000000..f8ebb1e
--- /dev/null
+++ b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/GrammarDependencies.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.antlr.mojo.antlr4;
+
+import org.antlr.runtime.tree.Tree;
+import org.antlr.v4.Tool;
+import org.antlr.v4.misc.Graph;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarRootAST;
+import org.apache.maven.plugin.logging.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+class GrammarDependencies {
+ private final Graph<String> graph = new Graph<String>();
+ private final File sourceDirectory;
+ private final File libDirectory;
+ private final File statusFile;
+ private final String packageName;
+
+ /** Map grammars to their checksum and references. */
+ private final Map<File, Map.Entry<byte[], Collection<String>>> grammars;
+ private final Log log;
+
+ public GrammarDependencies(File sourceDirectory, File libDirectory,
+ List<String> arguments, File status, Log log) {
+ this.log = log;
+ this.sourceDirectory = sourceDirectory;
+ this.libDirectory = libDirectory;
+ this.statusFile = status;
+ this.grammars = loadStatus(status);
+ this.packageName = getPackage(arguments);
+ }
+
+ /**
+ * Determines the package to use.
+ *
+ * @param arguments the tool arguments.
+ *
+ * @return the package. Returns {@code null} to indicate that no package should be
+ * used.
+ */
+ private String getPackage(List<String> arguments) {
+ int index = (arguments != null) ? arguments.indexOf("-package") : -1;
+
+ return (index > -1)
+ ? (arguments.get(index + 1).replace('.', File.separatorChar) +
+ File.separatorChar)
+ : null;
+ }
+
+ public void save() throws IOException {
+ if (!grammars.isEmpty()) {
+ log.debug("Persisting grammars dependency status: " + statusFile);
+
+ ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
+ statusFile));
+
+ try {
+ out.writeObject(grammars);
+ } finally {
+ out.close();
+ }
+ }
+ }
+
+ /**
+ * Performs dependency analysis for the given grammar files.
+ *
+ * @param grammarFiles the grammar files.
+ * @param importGrammarFiles the import grammar files.
+ * @param tool the tool to use.
+ *
+ * @return self-reference.
+ */
+ public GrammarDependencies analyze(Set<File> grammarFiles,
+ Set<File> importGrammarFiles, Tool tool) throws IOException {
+ log.debug("Analysing grammar dependencies " + sourceDirectory);
+
+ // for dependency analysis we require all grammars
+ Collection<File> grammarsAndTokens = new HashSet<File>();
+ grammarsAndTokens.addAll(importGrammarFiles);
+ grammarsAndTokens.addAll(grammarFiles);
+
+ for (File grammarFile : grammarsAndTokens) {
+ // .tokens files must not be parsed, they can just be referenced
+ if (!grammarFile.getName().endsWith(".tokens"))
+ analyse(grammarFile, grammarsAndTokens, tool);
+ }
+
+ for (File grammarFile : grammarFiles) {
+ Collection<String> usages = findUsages(getRelativePath(grammarFile));
+
+ if (!usages.isEmpty()) {
+ grammars.put(grammarFile,
+ new AbstractMap.SimpleImmutableEntry<byte[], Collection<String>>(
+ MojoUtils.checksum(grammarFile), usages));
+
+ log.debug(" " + getRelativePath(grammarFile) + " used by " + usages);
+ }
+ }
+
+ for (File grammarFile : importGrammarFiles) {
+ // imported files are not allowed to be qualified
+ Collection<String> usages = findUsages(grammarFile.getName());
+
+ if (!usages.isEmpty()) {
+ grammars.put(grammarFile,
+ new AbstractMap.SimpleImmutableEntry<byte[], Collection<String>>(
+ MojoUtils.checksum(grammarFile), usages));
+
+ log.debug(" " + grammarFile.getName() + " imported by " + usages);
+ }
+ }
+
+ return this;
+ }
+
+
+ /**
+ * Determines whether a grammar used by the given grammar was modified since the last
+ * build.
+ *
+ * @param grammarFile the grammar.
+ *
+ * @return {@code true} if a grammar used by the given grammar has been modified.
+ */
+ public boolean isDependencyChanged(File grammarFile) throws IOException {
+ String grammarPath = getRelativePath(grammarFile);
+
+ for (Map.Entry<File, Map.Entry<byte[], Collection<String>>> e : grammars.entrySet()) {
+ File depGrammarFile = e.getKey();
+ byte[] checksum = e.getValue().getKey();
+ Collection<String> usages = e.getValue().getValue();
+
+ if (usages.contains(grammarPath)) {
+ if (!depGrammarFile.exists() || !Arrays.equals(MojoUtils.checksum(depGrammarFile), checksum)) {
+ log.debug(" " + grammarPath + ": dependency " +
+ depGrammarFile.getName() + " changed");
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines the relative target path of the given grammar file.
+ *
+ * @param grammarFile the grammar file.
+ *
+ * @return the relative path.
+ */
+ private String getRelativePath(File grammarFile) {
+ // the library directory does not allow sub-directories
+ if (grammarFile.getPath().startsWith(libDirectory.getPath()))
+ return grammarFile.getName();
+
+ // if a package is given, we have to use it
+ if (packageName != null)
+ return packageName + grammarFile.getName();
+
+ // otherwise resolve the path relative to the source directory
+ String path = MojoUtils.findSourceSubdir(sourceDirectory, grammarFile);
+
+ return path + grammarFile.getName();
+ }
+
+ /**
+ * Returns the grammar file names that directly or indirectly use the given grammar.
+ *
+ * @param grammarFileName the grammar file name.
+ *
+ * @return the grammar file names that use the given grammar file.
+ */
+ private Collection<String> findUsages(String grammarFileName) {
+ Collection<String> result = new ArrayList<String>();
+ explore(grammarFileName, result);
+
+ return result;
+ }
+
+ private void explore(String grammarName, Collection<String> result) {
+ for (Graph.Node<String> node : graph.getNode(grammarName).edges) {
+ result.add(node.payload);
+ explore(node.payload, result);
+ }
+ }
+
+ private void analyse(File grammarFile, Collection<File> grammarFiles, Tool tool) {
+ GrammarRootAST grammar = tool.parseGrammar(grammarFile.getAbsolutePath());
+
+ if (grammar == null)
+ return;
+
+ for (GrammarAST importDecl : grammar.getAllChildrenWithType(ANTLRParser.IMPORT)) {
+ Tree id = importDecl.getFirstChildWithType(ANTLRParser.ID);
+
+ // missing id is not valid, but we don't want to prevent the root cause from
+ // being reported by the ANTLR tool
+ if (id != null) {
+ String grammarPath = getRelativePath(grammarFile);
+
+ graph.addEdge(id.getText() + ".g4", grammarPath);
+ }
+ }
+
+ for (GrammarAST options : grammar.getAllChildrenWithType(ANTLRParser.OPTIONS)) {
+ for (int i = 0, count = options.getChildCount(); i < count; i++) {
+ Tree option = options.getChild(i);
+
+ if (option.getType() == ANTLRParser.ASSIGN) {
+ String key = option.getChild(0).getText();
+ String value = option.getChild(1).getText();
+
+ if ("tokenVocab".equals(key)) {
+ String name = stripQuotes(value);
+ // the grammar name may be qualified, but we resolve the path anyway
+ String grammarName = stripPath(name);
+ String grammarPath = MojoUtils.findSourceSubdir(sourceDirectory,
+ grammarFile);
+ File depGrammarFile = resolve(grammarName, grammarPath);
+
+ // if a package has been given, we use it instead of the file directory path
+ // (files probably reside in the root directory anyway with such a configuration )
+ if (packageName != null)
+ grammarPath = packageName;
+
+ graph.addEdge(getRelativePath(depGrammarFile),
+ grammarPath + grammarFile.getName());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Resolves the given grammar name.
+ *
+ * @param name the name.
+ * @param path the relative path.
+ *
+ * @return the grammar file.
+ */
+ private File resolve(String name, String path) {
+ File file = new File(sourceDirectory, path + name + ".g4");
+
+ if (file.exists())
+ return file;
+
+ file = new File(libDirectory, name + ".g4");
+
+ if (file.exists())
+ return file;
+
+ return new File(libDirectory, name + ".tokens");
+ }
+
+ private Map<File, Map.Entry<byte[], Collection<String>>> loadStatus(File statusFile) {
+ if (statusFile.exists()) {
+ log.debug("Load grammars dependency status: " + statusFile);
+
+ try {
+ ObjectInputStream in = new ObjectInputStream(new FileInputStream(
+ statusFile));
+
+ try {
+ @SuppressWarnings("unchecked")
+ Map<File, Map.Entry<byte[], Collection<String>>> data =
+ (Map<File, Map.Entry<byte[], Collection<String>>>)
+ in.readObject();
+
+ return data;
+ } finally {
+ in.close();
+ }
+ } catch (Exception ex) {
+ log.warn("Could not load grammar dependency status information", ex);
+ }
+ }
+
+ return new HashMap<File, Map.Entry<byte[], Collection<String>>>();
+ }
+
+ private String stripPath(String str) {
+ return str.replaceAll("^.*[/\\\\]", "");
+ }
+
+ private String stripQuotes(String str) {
+ return str.replaceAll("\\A'|'\\Z", "");
+ }
+}
diff --git a/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/MojoUtils.java b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/MojoUtils.java
new file mode 100644
index 0000000..56da59b
--- /dev/null
+++ b/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/MojoUtils.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.antlr.mojo.antlr4;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
+class MojoUtils {
+ /**
+ * Creates the MD5 checksum for the given file.
+ *
+ * @param file the file.
+ *
+ * @return the checksum.
+ */
+ public static byte[] checksum(File file) throws IOException {
+ try {
+ InputStream in = new FileInputStream(file);
+ byte[] buffer = new byte[2048];
+ MessageDigest complete = MessageDigest.getInstance("MD5");
+
+ try {
+ int n;
+
+ do {
+ n = in.read(buffer);
+
+ if (n > 0) {
+ complete.update(buffer, 0, n);
+ }
+ } while (n != -1);
+ } finally {
+ in.close();
+ }
+
+ return complete.digest();
+ } catch (NoSuchAlgorithmException ex) {
+ throw new IOException("Could not create checksum " + file, ex);
+ }
+ }
+
+ /**
+ * Given the source directory File object and the full PATH to a grammar, produce the
+ * path to the named grammar file in relative terms to the {@code sourceDirectory}.
+ * This will then allow ANTLR to produce output relative to the base of the output
+ * directory and reflect the input organization of the grammar files.
+ *
+ * @param sourceDirectory The source directory {@link File} object
+ * @param grammarFileName The full path to the input grammar file
+ *
+ * @return The path to the grammar file relative to the source directory
+ */
+ public static String findSourceSubdir(File sourceDirectory, File grammarFile) {
+ String srcPath = sourceDirectory.getPath() + File.separator;
+ String path = grammarFile.getPath();
+
+ if (!path.startsWith(srcPath)) {
+ throw new IllegalArgumentException("expected " + path +
+ " to be prefixed with " + sourceDirectory);
+ }
+
+ File unprefixedGrammarFileName = new File(path.substring(srcPath.length()));
+
+ if (unprefixedGrammarFileName.getParent() == null) {
+ return "";
+ }
+
+ return unprefixedGrammarFileName.getParent() + File.separator;
+ }
+}
diff --git a/antlr4-maven-plugin/src/site/site.xml b/antlr4-maven-plugin/src/site/site.xml
index 0cf1aa2..23cd29c 100644
--- a/antlr4-maven-plugin/src/site/site.xml
+++ b/antlr4-maven-plugin/src/site/site.xml
@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ ~ Use of this file is governed by the BSD 3-clause license that
+ ~ can be found in the LICENSE.txt file in the project root.
+ -->
+
<project name="ANTLR v4 Maven plugin">
<publishDate position="left"/>
@@ -7,7 +13,7 @@
<poweredBy>
<logo name="ANTLR Web Site" href="http://antlr.org/"
- img="http://www.antlr.org/wiki/download/attachments/292/ANTLR4"/>
+ img="http://www.antlr.org/images/antlr-logo.png"/>
</poweredBy>
<body>
diff --git a/antlr4-maven-plugin/src/test/java/org/antlr/mojo/antlr4/Antlr4MojoTest.java b/antlr4-maven-plugin/src/test/java/org/antlr/mojo/antlr4/Antlr4MojoTest.java
new file mode 100644
index 0000000..12c45cd
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/java/org/antlr/mojo/antlr4/Antlr4MojoTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.antlr.mojo.antlr4;
+
+import io.takari.maven.testing.TestMavenRuntime;
+import io.takari.maven.testing.TestResources;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+public class Antlr4MojoTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Rule
+ public final TestResources resources = new TestResources();
+
+ @Rule
+ public final TestMavenRuntime maven = new TestMavenRuntime();
+
+ @Test
+ public void importTokens() throws Exception {
+ Path baseDir = resources.getBasedir("importTokens").toPath();
+ Path antlrDir = baseDir.resolve("src/main/antlr4");
+ Path generatedSources = baseDir.resolve("target/generated-sources/antlr4");
+
+ Path genParser = generatedSources.resolve("test/SimpleParser.java");
+ Path tokens = antlrDir.resolve("imports/SimpleLexer.tokens");
+
+ MavenProject project = maven.readMavenProject(baseDir.toFile());
+ MavenSession session = maven.newMavenSession(project);
+ MojoExecution exec = maven.newMojoExecution("antlr4");
+
+ ////////////////////////////////////////////////////////////////////////
+ // 1st - all grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ assertFalse(Files.exists(genParser));
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Files.exists(genParser));
+
+ ////////////////////////////////////////////////////////////////////////
+ // 2nd - nothing has been modified, no grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ {
+ byte[] sum = checksum(genParser);
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Arrays.equals(sum, checksum(genParser)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // 3rd - the imported grammar changed, every dependency has to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ try(Change change = Change.of(tokens, "DOT=4")) {
+ byte[] sum = checksum(genParser);
+
+ maven.executeMojo(session, project, exec);
+
+ assertFalse(Arrays.equals(sum, checksum(genParser)));
+ }
+ }
+
+ @Test
+ public void importsCustomLayout() throws Exception {
+ Path baseDir = resources.getBasedir("importsCustom").toPath();
+ Path antlrDir = baseDir.resolve("src/main/antlr4");
+ Path generatedSources = baseDir.resolve("src/main/java");
+
+ Path genTestLexer = generatedSources.resolve("foo/TestLexer.java");
+ Path genTestParser = generatedSources.resolve("foo/TestParser.java");
+ Path genHello = generatedSources.resolve("foo/HelloParser.java");
+
+ Path baseGrammar = antlrDir.resolve("imports/TestBaseLexer.g4");
+ Path lexerGrammar = antlrDir.resolve("TestLexer.g4");
+ Path parserGrammar = antlrDir.resolve("TestParser.g4");
+
+ Xpp3Dom outputDirectory = TestMavenRuntime.newParameter("outputDirectory",
+ "src/main/java/foo");
+ Xpp3Dom arguments = new Xpp3Dom("arguments");
+ arguments.addChild(TestMavenRuntime.newParameter("argument", "-package"));
+ arguments.addChild(TestMavenRuntime.newParameter("argument", "foo"));
+
+ MavenProject project = maven.readMavenProject(baseDir.toFile());
+ MavenSession session = maven.newMavenSession(project);
+ MojoExecution exec = maven.newMojoExecution("antlr4", outputDirectory, arguments);
+
+ ////////////////////////////////////////////////////////////////////////
+ // 1st - all grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ assertFalse(Files.exists(genHello));
+ assertFalse(Files.exists(genTestParser));
+ assertFalse(Files.exists(genTestLexer));
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Files.exists(genHello));
+ assertTrue(Files.exists(genTestParser));
+ assertTrue(Files.exists(genTestLexer));
+
+ ////////////////////////////////////////////////////////////////////////
+ // 2nd - nothing has been modified, no grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertTrue(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // 3rd - the imported grammar changed, every dependency has to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ // modify the grammar to make checksum comparison detect a change
+ try(Change change = Change.of(baseGrammar, "DOT: '.' ;")) {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertFalse(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // 4th - the lexer grammar changed, the parser grammar has to be processed as well
+ ////////////////////////////////////////////////////////////////////////
+
+ // modify the grammar to make checksum comparison detect a change
+ try(Change change = Change.of(lexerGrammar, "fragment DOT : '.';")) {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertFalse(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // 5th - the parser grammar changed, no other grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ // modify the grammar to make checksum comparison detect a change
+ try(Change change = Change.of(parserGrammar, " t : WS* ;")) {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertFalse(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+ }
+
+ @Test
+ public void importsStandardLayout() throws Exception {
+ Path baseDir = resources.getBasedir("importsStandard").toPath();
+ Path antlrDir = baseDir.resolve("src/main/antlr4");
+ Path generatedSources = baseDir.resolve("target/generated-sources/antlr4");
+
+ Path genTestLexer = generatedSources.resolve("test/TestLexer.java");
+ Path genTestParser = generatedSources.resolve("test/TestParser.java");
+ Path genHello = generatedSources.resolve("test/HelloParser.java");
+
+ Path baseGrammar = antlrDir.resolve("imports/TestBaseLexer.g4");
+ Path lexerGrammar = antlrDir.resolve("test/TestLexer.g4");
+ Path parserGrammar = antlrDir.resolve("test/TestParser.g4");
+
+ MavenProject project = maven.readMavenProject(baseDir.toFile());
+ MavenSession session = maven.newMavenSession(project);
+ MojoExecution exec = maven.newMojoExecution("antlr4");
+
+ ////////////////////////////////////////////////////////////////////////
+ // 1st - all grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ assertFalse(Files.exists(genHello));
+ assertFalse(Files.exists(genTestParser));
+ assertFalse(Files.exists(genTestLexer));
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Files.exists(genHello));
+ assertTrue(Files.exists(genTestParser));
+ assertTrue(Files.exists(genTestLexer));
+
+ ////////////////////////////////////////////////////////////////////////
+ // 2nd - nothing has been modified, no grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertTrue(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // 3rd - the imported grammar changed, every dependency has to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ // modify the grammar to make checksum comparison detect a change
+ try(Change change = Change.of(baseGrammar, "DOT: '.' ;")) {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertFalse(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // 4th - the lexer grammar changed, the parser grammar has to be processed as well
+ ////////////////////////////////////////////////////////////////////////
+
+ // modify the grammar to make checksum comparison detect a change
+ try(Change change = Change.of(lexerGrammar)) {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertFalse(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // 5th - the parser grammar changed, no other grammars have to be processed
+ ////////////////////////////////////////////////////////////////////////
+
+ // modify the grammar to make checksum comparison detect a change
+ try(Change change = Change.of(parserGrammar, " t : WS* ;")) {
+ byte[] testLexerSum = checksum(genTestLexer);
+ byte[] testParserSum = checksum(genTestParser);
+ byte[] helloSum = checksum(genHello);
+
+ maven.executeMojo(session, project, exec);
+
+ assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer)));
+ assertFalse(Arrays.equals(testParserSum, checksum(genTestParser)));
+ assertTrue(Arrays.equals(helloSum, checksum(genHello)));
+ }
+ }
+
+ @Test
+ public void processWhenDependencyRemoved() throws Exception {
+ Path baseDir = resources.getBasedir("dependencyRemoved").toPath();
+ Path antlrDir = baseDir.resolve("src/main/antlr4");
+
+ Path baseGrammar = antlrDir.resolve("imports/HelloBase.g4");
+
+ MavenProject project = maven.readMavenProject(baseDir.toFile());
+ MavenSession session = maven.newMavenSession(project);
+ MojoExecution exec = maven.newMojoExecution("antlr4");
+
+ maven.executeMojo(session, project, exec);
+
+ try(Change temp = Change.of(baseGrammar)) {
+ // if the base grammar no longer exists, processing must be performed
+ Files.delete(baseGrammar);
+
+ thrown.expect(MojoExecutionException.class);
+ thrown.expectMessage("ANTLR 4 caught 1 build errors.");
+
+ maven.executeMojo(session, project, exec);
+ }
+ }
+
+ private byte[] checksum(Path path) throws IOException {
+ return MojoUtils.checksum(path.toFile());
+ }
+
+ private static class Change implements AutoCloseable {
+ final Path file;
+ final byte[] original;
+
+ public Change(Path file, String change) {
+ this.file = file;
+
+ try {
+ original = Files.readAllBytes(file);
+ } catch (IOException ex) {
+ throw new RuntimeException("Could not read file " + file);
+ }
+
+ String text = new String(original, StandardCharsets.UTF_8) + change;
+
+ write(file, text.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private void write(Path file, byte[] data) {
+ try {
+ Files.write(file, data);
+ } catch (IOException ex) {
+ throw new RuntimeException("Could not write file " + file);
+ }
+ }
+
+ public static Change of(Path file, String change) {
+ return new Change(file, change);
+ }
+
+ public static Change of(Path file) {
+ return new Change(file, "\n");
+ }
+
+ @Override
+ public void close() {
+ write(file, original);
+ }
+ }
+}
diff --git a/antlr4-maven-plugin/src/test/projects/dependencyRemoved/pom.xml b/antlr4-maven-plugin/src/test/projects/dependencyRemoved/pom.xml
new file mode 100644
index 0000000..3163b81
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/dependencyRemoved/pom.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ ~ Use of this file is governed by the BSD 3-clause license that
+ ~ can be found in the LICENSE.txt file in the project root.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>deps.removed</groupId>
+ <artifactId>depRemoved</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Test processing after dependency removed</name>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>antlr4-maven-plugin</artifactId>
+ <configuration>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/imports/HelloBase.g4 b/antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/imports/HelloBase.g4
new file mode 100644
index 0000000..5fcc6d3
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/imports/HelloBase.g4
@@ -0,0 +1,16 @@
+lexer grammar TestBaseLexer;
+
+tokens { Name }
+
+// Default "mode": Everything OUTSIDE of a tag
+Comment : '<!--' .*? '-->' ;
+CDSect : '<![CDATA[' .*? ']]>' ;
+
+fragment
+Whitespace : ' ' | '\n' | '\t' | '\r' ;
+
+fragment
+Hexdigit : [a-fA-F0-9] ;
+
+fragment
+Digit : [0-9] ;
diff --git a/antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/test/Hello.g4 b/antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/test/Hello.g4
new file mode 100644
index 0000000..54f998c
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/dependencyRemoved/src/main/antlr4/test/Hello.g4
@@ -0,0 +1,7 @@
+grammar Hello;
+
+import HelloBase;
+
+r : 'hello' ID ;
+ID : [a-z]+ ;
+WS : [ \r\t\n]+ -> skip ;
diff --git a/antlr4-maven-plugin/src/test/projects/importTokens/pom.xml b/antlr4-maven-plugin/src/test/projects/importTokens/pom.xml
new file mode 100644
index 0000000..478b517
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importTokens/pom.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ ~ Use of this file is governed by the BSD 3-clause license that
+ ~ can be found in the LICENSE.txt file in the project root.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>import.tokens</groupId>
+ <artifactId>importTokens</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Test importing tokens file</name>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>antlr4-maven-plugin</artifactId>
+ <configuration>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/imports/SimpleLexer.tokens b/antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/imports/SimpleLexer.tokens
new file mode 100644
index 0000000..4637d6e
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/imports/SimpleLexer.tokens
@@ -0,0 +1,3 @@
+ID=1
+INT=2
+SEMI=3
diff --git a/antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/test/SimpleParser.g4 b/antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/test/SimpleParser.g4
new file mode 100644
index 0000000..bbd8274
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importTokens/src/main/antlr4/test/SimpleParser.g4
@@ -0,0 +1,8 @@
+parser grammar SimpleParser;
+options {
+ // get token types from SimpleLexer.tokens; don't name it
+ // SimpleParser.tokens as ANTLR will overwrite!
+ tokenVocab=SimpleLexer;
+}
+
+s : ( ID | INT )* SEMI ;
diff --git a/antlr4-maven-plugin/src/test/projects/importsCustom/pom.xml b/antlr4-maven-plugin/src/test/projects/importsCustom/pom.xml
new file mode 100644
index 0000000..a5826bc
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsCustom/pom.xml
@@ -0,0 +1,48 @@
+<!--
+ ~ Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ ~ Use of this file is governed by the BSD 3-clause license that
+ ~ can be found in the LICENSE.txt file in the project root.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>imports.custom</groupId>
+ <artifactId>importsCustom</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Test importing, custom layout</name>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>antlr4-maven-plugin</artifactId>
+ <configuration>
+ <outputDirectory>${basedir}/src/main/java/com/foo</outputDirectory>
+ <arguments>
+ <argument>-visitor</argument>
+ <argument>-no-listener</argument>
+ <argument>-Xlog</argument>
+ <argument>-package</argument>
+ <argument>com.foo</argument>
+ </arguments>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>antlr4</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/Hello.g4 b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/Hello.g4
new file mode 100644
index 0000000..e38ac87
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/Hello.g4
@@ -0,0 +1,4 @@
+grammar Hello;
+r : 'hello' ID ;
+ID : [a-z]+ ;
+WS : [ \r\t\n]+ -> skip ; \ No newline at end of file
diff --git a/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestLexer.g4 b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestLexer.g4
new file mode 100644
index 0000000..668b764
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestLexer.g4
@@ -0,0 +1,6 @@
+lexer grammar TestLexer;
+
+import TestBaseLexer;
+
+WS : Whitespace+ -> skip;
+TEXT : ~[<&]+ ; // match any 16 bit char other than < and & \ No newline at end of file
diff --git a/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestParser.g4 b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestParser.g4
new file mode 100644
index 0000000..5c25961
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/TestParser.g4
@@ -0,0 +1,5 @@
+parser grammar TestParser;
+
+options { tokenVocab=TestLexer; }
+
+document : (Comment | Name) EOF ; \ No newline at end of file
diff --git a/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/imports/TestBaseLexer.g4 b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/imports/TestBaseLexer.g4
new file mode 100644
index 0000000..5fcc6d3
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsCustom/src/main/antlr4/imports/TestBaseLexer.g4
@@ -0,0 +1,16 @@
+lexer grammar TestBaseLexer;
+
+tokens { Name }
+
+// Default "mode": Everything OUTSIDE of a tag
+Comment : '<!--' .*? '-->' ;
+CDSect : '<![CDATA[' .*? ']]>' ;
+
+fragment
+Whitespace : ' ' | '\n' | '\t' | '\r' ;
+
+fragment
+Hexdigit : [a-fA-F0-9] ;
+
+fragment
+Digit : [0-9] ;
diff --git a/antlr4-maven-plugin/src/test/projects/importsStandard/pom.xml b/antlr4-maven-plugin/src/test/projects/importsStandard/pom.xml
new file mode 100644
index 0000000..77f63a2
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsStandard/pom.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
+ ~ Use of this file is governed by the BSD 3-clause license that
+ ~ can be found in the LICENSE.txt file in the project root.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>imports.standard</groupId>
+ <artifactId>importsStandard</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Test importing, standard layout</name>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>antlr4-maven-plugin</artifactId>
+ <configuration>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/imports/TestBaseLexer.g4 b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/imports/TestBaseLexer.g4
new file mode 100644
index 0000000..5fcc6d3
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/imports/TestBaseLexer.g4
@@ -0,0 +1,16 @@
+lexer grammar TestBaseLexer;
+
+tokens { Name }
+
+// Default "mode": Everything OUTSIDE of a tag
+Comment : '<!--' .*? '-->' ;
+CDSect : '<![CDATA[' .*? ']]>' ;
+
+fragment
+Whitespace : ' ' | '\n' | '\t' | '\r' ;
+
+fragment
+Hexdigit : [a-fA-F0-9] ;
+
+fragment
+Digit : [0-9] ;
diff --git a/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/Hello.g4 b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/Hello.g4
new file mode 100644
index 0000000..e38ac87
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/Hello.g4
@@ -0,0 +1,4 @@
+grammar Hello;
+r : 'hello' ID ;
+ID : [a-z]+ ;
+WS : [ \r\t\n]+ -> skip ; \ No newline at end of file
diff --git a/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestLexer.g4 b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestLexer.g4
new file mode 100644
index 0000000..668b764
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestLexer.g4
@@ -0,0 +1,6 @@
+lexer grammar TestLexer;
+
+import TestBaseLexer;
+
+WS : Whitespace+ -> skip;
+TEXT : ~[<&]+ ; // match any 16 bit char other than < and & \ No newline at end of file
diff --git a/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestParser.g4 b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestParser.g4
new file mode 100644
index 0000000..5c25961
--- /dev/null
+++ b/antlr4-maven-plugin/src/test/projects/importsStandard/src/main/antlr4/test/TestParser.g4
@@ -0,0 +1,5 @@
+parser grammar TestParser;
+
+options { tokenVocab=TestLexer; }
+
+document : (Comment | Name) EOF ; \ No newline at end of file