Skip to content
Commits on Source (11)
Before submitting an issue to ANTLR, please check off these boxes:
- [ ] I am not submitting a question on how to use ANTLR; instead, go to [antlr4-discussion google group](https://groups.google.com/forum/#!forum/antlr-discussion) or ask at [stackoverflow](http://stackoverflow.com/questions/tagged/antlr4)
- [ ] I have done a search of the existing issues to make sure I'm not sending in a duplicate
[cut]
Please include information about the expected behavior, actual behavior, and the smallest grammar or code that reproduces the behavior. If appropriate, please indicate the code generation targets such as Java, C#, ... Pointers into offending code regions are also very welcome.
[/cut]
[cut]
Thank you for proposing a contribution to the ANTLR project. In order to accept changes from the outside world, all contributors must "sign" the [contributors.txt](https://github.com/antlr/antlr4/blob/master/contributors.txt) contributors certificate of origin. It's an unfortunate reality of today's fuzzy and bizarre world of open-source ownership.
Make sure you are already in the contributors.txt file or add a commit to this pull request with the appropriate change. Thanks!
[/cut]
[The "BSD license"]
Copyright (c) 2015 Terence Parr, Sam Harwell
All rights reserved.
[The "BSD 3-clause license"]
Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
......@@ -11,8 +10,9 @@ are met:
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.
3. Neither the name of the copyright holder nor the names of its contributors
may 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
......
# ANTLR v4
[![Build Travis-CI Status](https://travis-ci.org/antlr/antlr4.png?branch=master)](https://travis-ci.org/antlr/antlr4) [![Build AppVeyor Status](https://ci.appveyor.com/api/projects/status/5acpbx1pg7bhgh8v/branch/master?svg=true)](https://ci.appveyor.com/project/parrt/antlr4) [![Java 7+](https://img.shields.io/badge/java-7+-4c7e9f.svg)](http://java.oracle.com) [![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/antlr/antlr4/master/LICENSE.txt)
**ANTLR** (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files. It's widely used to build languages, tools, and frameworks. From a grammar, ANTLR generates a parser that can build parse trees and also generates a listener interface (or visitor) that makes it easy to respond to the recognition of phrases of interest.
*Given day-job constraints, my time working on this project is limited so I'll have to focus first on fixing bugs rather than changing/improving the feature set. Likely I'll do it in bursts every few months. Please do not be offended if your bug or pull request does not yield a response! --parrt*
[![Donate](https://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BF92STRXT8F8Q)
## Authors and major contributors
* [Terence Parr](http://www.cs.usfca.edu/~parrt/), parrt@cs.usfca.edu
......@@ -11,22 +15,29 @@ ANTLR project lead and supreme dictator for life
[University of San Francisco](http://www.usfca.edu/)
* [Sam Harwell](http://tunnelvisionlabs.com/) (Tool co-author, Java and C# target)
* Eric Vergnaud (Javascript, Python2, Python3 targets and significant work on C# target)
* [Peter Boyer](https://github.com/pboyer) (Go target)
* [Mike Lischke](http://www.soft-gems.net/) (C++ completed target)
* Dan McLaughlin (C++ initial target)
* David Sisson (C++ initial target and test)
* [Janyou](https://github.com/janyou) (Swift target)
* [Ewan Mellor](https://github.com/ewanmellor), [Hanzhou Shi](https://github.com/hanjoes) (Swift target merging)
## Useful information
* [Release notes](https://github.com/antlr/antlr4/releases)
* [Getting started with v4](https://raw.githubusercontent.com/antlr/antlr4/master/doc/getting-started.md)
* [Getting started with v4](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md)
* [Official site](http://www.antlr.org/)
* [Documentation](https://raw.githubusercontent.com/antlr/antlr4/master/doc/index.md)
* [FAQ](https://raw.githubusercontent.com/antlr/antlr4/master/doc/faq/index.md)
* [API](http://www.antlr.org/api/Java/index.html)
* [Documentation](https://github.com/antlr/antlr4/blob/master/doc/index.md)
* [FAQ](https://github.com/antlr/antlr4/blob/master/doc/faq/index.md)
* [ANTLR code generation targets](https://github.com/antlr/antlr4/blob/master/doc/targets.md)<br>(Currently: Java, C#, Python2|3, JavaScript, Go, C++, Swift)
* [Java API](http://www.antlr.org/api/Java/index.html)
* [ANTLR v3](http://www.antlr3.org/)
* [v3 to v4 Migration, differences](https://raw.githubusercontent.com/antlr/antlr4/master/doc/faq/general.md)
* [v3 to v4 Migration, differences](https://github.com/antlr/antlr4/blob/master/doc/faq/general.md)
You might also find the following pages useful, particularly if you want to mess around with the various target languages.
* [How to build ANTLR itself](https://raw.githubusercontent.com/antlr/antlr4/master/doc/building-antlr.md)
* [How we create and deploy an ANTLR release](https://raw.githubusercontent.com/antlr/antlr4/master/doc/releasing-antlr.md)
* [How to build ANTLR itself](https://github.com/antlr/antlr4/blob/master/doc/building-antlr.md)
* [How we create and deploy an ANTLR release](https://github.com/antlr/antlr4/blob/master/doc/releasing-antlr.md)
## The Definitive ANTLR 4 Reference
......@@ -40,8 +51,3 @@ You will find the [Book source code](http://pragprog.com/titles/tpantlr2/source_
[This repository](https://github.com/antlr/grammars-v4) is a collection of grammars without actions where the
root directory name is the all-lowercase name of the language parsed
by the grammar. For example, java, cpp, csharp, c, etc...
Travis Status
---------
<a href="https://travis-ci.org/antlr/antlr4"><img src="https://api.travis-ci.org/antlr/antlr4.png"></a>
<!--
[The "BSD license"]
ANTLR - Copyright (c) Terence Parr, Sam Harwell
Maven Plugin - Copyright (c) Jim Idle
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.
-->
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.antlr</groupId>
<artifactId>antlr4-master</artifactId>
<version>4.5.4-SNAPSHOT</version>
<version>4.6</version>
</parent>
<artifactId>antlr4-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
......@@ -48,6 +22,11 @@
<!-- Ancilliary information for completeness -->
<inceptionYear>2009</inceptionYear>
<properties>
<mavenVersion>3.3.9</mavenVersion>
<takariLifecycleVersion>1.11.12</takariLifecycleVersion>
</properties>
<!-- ============================================================================= -->
<!-- What are we depedent on for the Mojos to execute? We need the plugin
......@@ -63,11 +42,6 @@
<version>3.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-api</artifactId>
......@@ -90,13 +64,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
<version>1.1</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
......@@ -105,9 +73,49 @@
<version>3.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.takari.maven.plugins</groupId>
<artifactId>takari-plugin-testing</artifactId>
<version>2.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>${mavenVersion}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>${mavenVersion}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>3.0.15</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>resources</directory>
</resource>
</resources>
<testSourceDirectory>src/test</testSourceDirectory>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
......@@ -132,6 +140,21 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.takari.maven.plugins</groupId>
<artifactId>takari-lifecycle-plugin</artifactId>
<version>${takariLifecycleVersion}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>testProperties</id>
<phase>process-test-resources</phase>
<goals>
<goal>testProperties</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
......@@ -145,7 +168,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<version>2.10.4</version>
<configuration>
<quiet>true</quiet>
</configuration>
......@@ -153,7 +176,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.3</version>
<version>2.5</version>
</plugin>
</plugins>
</reporting>
......
<?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.
-->
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
......
/*
[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;
......
/*
[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;
if (!grammarFileName.startsWith(srcPath)) {
throw new IllegalArgumentException("expected " + grammarFileName + " to be prefixed with " + sourceDirectory);
}
private File getDependenciesStatusFile() {
File statusFile = new File(statusDirectory, "dependencies.ser");
File unprefixedGrammarFileName = new File(grammarFileName.substring(srcPath.length()));
if (unprefixedGrammarFileName.getParent() == null) {
return "";
if (!statusFile.getParentFile().exists()) {
statusFile.getParentFile().mkdirs();
}
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);
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();
}
}
/*
* 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", "");
}
}
/*
* 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;
}
}
<?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>
......
/*
* 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);
}
}
}
<!--
~ 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>
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] ;
grammar Hello;
import HelloBase;
r : 'hello' ID ;
ID : [a-z]+ ;
WS : [ \r\t\n]+ -> skip ;
<!--
~ 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>
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 ;
<!--
~ 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>
grammar Hello;
r : 'hello' ID ;
ID : [a-z]+ ;
WS : [ \r\t\n]+ -> skip ;
\ No newline at end of file