Rewrite test generator as a Maven plugin that generates tests as part of the build

This commit only updates the "TestSets" collection of tests to use the new framework.
This commit is contained in:
Sam Harwell 2014-12-31 18:32:07 -06:00
parent 8cc929f942
commit 90763e5ae2
70 changed files with 1668 additions and 1028 deletions

View File

@ -88,7 +88,7 @@
<dependency> <dependency>
<groupId>org.codehaus.plexus</groupId> <groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-api</artifactId> <artifactId>plexus-compiler-api</artifactId>
<version>2.2</version> <version>2.4</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>
<org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>
<org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>
<org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>true</org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>
<org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>
<org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indentCasesFromSwitch>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indentCasesFromSwitch>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.continuationIndentSize>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.continuationIndentSize>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStarImport>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStarImport>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStaticStarImport>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStaticStarImport>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder>*;java</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder>
<netbeans.compile.on.save>test</netbeans.compile.on.save>
<org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.text-line-wrap>
<org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.indent-shift-width>
<org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.spaces-per-tab>
<org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.tab-size>
<org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.text-limit-width>
<org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.expand-tabs>false</org-netbeans-modules-editor-indent.text.x-stringtemplate4.CodeStyle.project.expand-tabs>
</properties>
</project-shared-configuration>

View File

@ -0,0 +1,210 @@
<!--
[The "BSD license"]
ANTLR - Copyright (c) 2005-2010 Terence Parr
Maven Plugin - Copyright (c) 2009 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.
-->
<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.4-SNAPSHOT</version>
</parent>
<artifactId>antlr4-testgen-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>ANTLR 4 Test Generator Maven plugin</name>
<description>Maven plugin for generating ANTLR 4 runtime tests</description>
<url>http://www.antlr.org</url>
<prerequisites>
<maven>3.0</maven>
</prerequisites>
<!-- Ancilliary information for completeness
-->
<inceptionYear>2009</inceptionYear>
<!-- ============================================================================= -->
<!--
What are we depedent on for the Mojos to execute? We need the
plugin API itself and of course we need the ANTLR Tool and runtime
and any of their dependencies, which we inherit. The Tool itself provides
us with all the dependencies, so we need only name it here.
-->
<dependencies>
<!--
The things we need to build the target language recognizer
-->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<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>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.sonatype.plexus</groupId>
<artifactId>plexus-build-api</artifactId>
<version>0.0.7</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>ST4</artifactId>
<version>4.0.8</version>
</dependency>
<!--
Testing requirements...
-->
<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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<resources>
<resource>
<directory>resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.3</version>
<configuration>
<!-- see http://jira.codehaus.org/browse/MNG-5346 -->
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
</configuration>
<executions>
<execution>
<id>mojo-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
</execution>
<execution>
<id>help-goal</id>
<goals>
<goal>helpmojo</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.7</version>
<configuration>
<dependencyLocationsEnabled>false</dependencyLocationsEnabled>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<configuration>
<quiet>true</quiet>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.3</version>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<goals>
<goal>antlr4</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnIncremental>true</runOnIncremental>
<runOnConfiguration>true</runOnConfiguration>
</execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>

View File

@ -0,0 +1,7 @@
//TestFolders ::= [
//]
TestTemplates ::= [
"LexerDelegatorInvokesDelegateRule": [],
"LexerDelegatorRuleOverridesDelegate": []
]

View File

@ -0,0 +1,31 @@
TestType() ::= "CompositeLexer"
Grammars ::= [
"M.g4": {<masterGrammar("M", "S")>},
"S.g4": {<slaveGrammar("S")>}
]
Input() ::= "abc"
Output() ::= <<
S.A
[@0,0:0='a',\<3>,1:0]
[@1,1:1='b',\<1>,1:1]
[@2,2:2='c',\<4>,1:2]
[@3,3:2='\<EOF>',\<-1>,1:3]<\n>
>>
Errors() ::= ""
masterGrammar(grammarName, slaveGrammarName) ::= <<
lexer grammar <grammarName>;
import <slaveGrammarName>;
B : 'b';
WS : (' '|'\n') -> skip ;
>>
slaveGrammar(grammarName) ::= <<
lexer grammar <grammarName>;
A : 'a' {<writeln("\"S.A\"")>};
C : 'c' ;
>>

View File

@ -0,0 +1,31 @@
TestType() ::= "CompositeLexer"
Grammars ::= [
"M.g4": {<masterGrammar("M", "S")>},
"S.g4": {<slaveGrammar("S")>}
]
Input() ::= "abc"
Output() ::= <<
S.A
[@0,0:0='a',\<3>,1:0]
[@1,1:1='b',\<1>,1:1]
[@2,2:2='c',\<4>,1:2]
[@3,3:2='\<EOF>',\<-1>,1:3]<\n>
>>
Errors() ::= ""
masterGrammar(grammarName, slaveGrammarName) ::= <<
lexer grammar <grammarName>;
import <slaveGrammarName>;
A : 'a' B {<writeln("\"M.A\"")>};
WS : (' '|'\n') -> skip ;
>>
slaveGrammar(grammarName) ::= <<
lexer grammar <grammarName>;
A : 'a' {<writeln("\"S.A\"")>};
B : 'b' {<writeln("\"S.B\"")>};
>>

View File

@ -0,0 +1,6 @@
TestFolders ::= [
"CompositeLexers": []
]
//TestTemplates ::= [
//]

View File

@ -0,0 +1,156 @@
/*
[The "BSD license"]
Copyright (c) 2014 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.
*/
package org.antlr.mojo.antlr4.testgen;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;
import org.stringtemplate.v4.gui.STViz;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@Mojo(
name = "antlr4.testgen",
defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES,
requiresDependencyResolution = ResolutionScope.TEST,
requiresProject = true)
public class Antlr4TestGeneratorMojo extends AbstractMojo {
// This project uses UTF-8, but the plugin might be used in another project
// which is not. Always load templates with UTF-8, but write using the
// specified encoding.
@Parameter(property = "project.build.sourceEncoding")
private String encoding;
@Parameter(property = "project", required = true, readonly = true)
private MavenProject project;
@Parameter(required = true)
private File runtimeTemplates;
@Parameter(defaultValue = "${project.build.directory}/generated-test-sources/antlr4-tests")
private File outputDirectory;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
STGroup targetGroup = new STGroupFile(runtimeTemplates.getPath());
targetGroup.registerModelAdaptor(STGroup.class, new STGroupModelAdaptor());
targetGroup.defineDictionary("escape", new JavaEscapeStringMap());
String rootFolder = "org/antlr4/runtime/test/templates";
STGroup index = new STGroupFile(rootFolder + "/Index.stg");
generateCodeForFolder(targetGroup, rootFolder, index);
project.addTestCompileSourceRoot(outputDirectory.getPath());
}
private void generateCodeForFolder(STGroup targetGroup, String folder, STGroup index) {
// make sure the index group is loaded since we call rawGetDictionary
index.load();
Map<String, Object> folders = index.rawGetDictionary("TestFolders");
if (folders != null) {
for (String key : folders.keySet()) {
String subfolder = folder + "/" + key;
STGroup subindex = new STGroupFile(subfolder + "/Index.stg");
generateCodeForFolder(targetGroup, folder + "/" + key, subindex);
}
}
Map<String, Object> templates = index.rawGetDictionary("TestTemplates");
if (templates != null && !templates.isEmpty()) {
generateTestFile(targetGroup, folder.substring(folder.lastIndexOf('/') + 1), folder, new ArrayList<String>(templates.keySet()));
}
}
private void generateTestFile(STGroup targetGroup, String testFile, String templateFolder, Collection<String> testTemplates) {
List<ST> templates = new ArrayList<ST>();
for (String template : testTemplates) {
STGroup testGroup = new STGroupFile(templateFolder + "/" + template + STGroup.GROUP_FILE_EXTENSION);
testGroup.importTemplates(targetGroup);
ST testType = testGroup.getInstanceOf("TestType");
if (testType == null) {
getLog().warn(String.format("Unable to generate tests for %s: no TestType specified.", template));
continue;
}
ST testMethodTemplate = targetGroup.getInstanceOf(testType.render() + "TestMethod");
if (testMethodTemplate == null) {
getLog().warn(String.format("Unable to generate tests for %s: TestType '%s' is not supported by the current runtime.", template, testType.render()));
continue;
}
testMethodTemplate.add(testMethodTemplate.impl.formalArguments.keySet().iterator().next(), testGroup);
templates.add(testMethodTemplate);
}
ST testFileTemplate = targetGroup.getInstanceOf("TestFile");
testFileTemplate.addAggr("file.{importErrorQueue,importGrammar,name,tests}", false, false, testFile, templates);
STViz viz = testFileTemplate.inspect();
try {
viz.waitForClose();
} catch (InterruptedException ex) {
}
File targetFolder = new File(outputDirectory, templateFolder.substring(0, templateFolder.indexOf("/templates")));
File targetFile = new File(targetFolder, "Test" + testFile + ".java");
try {
writeFile(targetFile, testFileTemplate.render());
} catch (IOException ex) {
getLog().error(String.format("Failed to write output file: %s", targetFile), ex);
}
}
public void writeFile(File file, String content) throws IOException {
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos, encoding != null ? encoding : "UTF-8");
try {
osw.write(content);
}
finally {
osw.close();
}
}
}

View File

@ -0,0 +1,63 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.antlr.mojo.antlr4.testgen;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.Set;
/**
*
* @author Sam Harwell
*/
public class JavaEscapeStringMap extends AbstractMap<String, Object> {
@Override
public Object get(Object key) {
if (key instanceof String) {
String str = (String)key;
StringBuilder builder = new StringBuilder(str.length());
for (int i = 0; i < str.length(); i++) {
switch (str.charAt(i)) {
case '\\':
builder.append("\\\\");
break;
case '\r':
// normalize \r\n to just \n
break;
case '\n':
builder.append("\\n");
break;
case '"':
builder.append("\\\"");
break;
default:
builder.append(str.charAt(i));
break;
}
}
return builder.toString();
}
return super.get(key);
}
@Override
public boolean containsKey(Object key) {
return key instanceof String;
}
@Override
public Set<Entry<String, Object>> entrySet() {
return Collections.emptySet();
}
}

View File

@ -0,0 +1,35 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.antlr.mojo.antlr4.testgen;
import org.stringtemplate.v4.Interpreter;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.misc.ObjectModelAdaptor;
import org.stringtemplate.v4.misc.STNoSuchPropertyException;
/**
*
* @author sam
*/
public class STGroupModelAdaptor extends ObjectModelAdaptor {
@Override
public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException {
STGroup group = (STGroup)o;
if (group.isDictionary(propertyName)) {
return group.rawGetDictionary(propertyName);
}
ST template = group.getInstanceOf(propertyName);
if (template != null) {
return template;
}
return super.getProperty(interp, self, o, property, propertyName);
}
}

View File

@ -0,0 +1,8 @@
Imported Grammar Files
In order to have the ANTLR plugin automatically locate and use grammars used
as imports in your main <<<.g4>>> files, you need to place the imported grammar
files in the <<<imports>>> directory beneath the root directory of your grammar
files (which is <<<src/main/antlr4>>> by default of course).
For a default layout, place your import grammars in the directory: <<<src/main/antlr4/imports>>>

View File

@ -0,0 +1,46 @@
Libraries
The introduction of the import directive in a grammar allows reuse of common grammar files
as well as the ability to divide up functional components of large grammars. However it has
caused some confusion in regard to the fact that generated vocabulary files (<<<*.tokens>>>) can also
be searched for with the <<<<libDirectory>>>> directive.
This has confused two separate functions and imposes a structure upon the layout of
your grammar files in certain cases. If you have grammars that both use the import
directive and also require the use of a vocabulary file then you will need to locate
the grammar that generates the <<<.tokens>>> file alongside the grammar that uses it. This
is because you will need to use the <<<<libDirectory>>>> directive to specify the
location of your imported grammars and ANTLR will not find any vocabulary files in
this directory.
The <<<.tokens>>> files for any grammars are generated within the same output directory structure
as the <<<.java>>> files. So, wherever the <<<.java>>> files are generated, you will also find the <<<.tokens>>>
files. ANTLR looks for <<<.tokens>>> files in both the <<<<libDirectory>>>> and the output directory
where it is placing the generated <<<.java>>> files. Hence when you locate the grammars that generate
<<<.tokens>>> files in the same source directory as the ones that use the <<<.tokens>>> files, then
the Maven plugin will find the expected <<<.tokens>>> files.
The <<<<libDirectory>>>> is specified like any other directory parameter in Maven. Here is an
example:
+--
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<configuration>
<goals>
<goal>antlr4</goal>
</goals>
<libDirectory>src/main/antlr4_imports</libDirectory>
</configuration>
</execution>
</executions>
</plugin>
+--

View File

@ -0,0 +1,40 @@
Simple configuration
If your grammar files are organized into the default locations as described in the {{{../index.html}introduction}},
then configuring the <<<pom.xml>>> file for your project is as simple as adding this to it
+--
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
+--
When the <<<mvn>>> command is executed all grammar files under <<<src/main/antlr4>>>, except any
import grammars under <<<src/main/antlr4/imports>>> will be analyzed and converted to
Java source code in the output directory <<<target/generated-sources/antlr4>>>.
Your input files under <<<antlr4>>> should be stored in sub directories that
reflect the package structure of your java parsers. If your grammar file <<<parser.g4>>> contains:
+---
@header {
package org.jimi.themuss;
}
+---
Then the <<<.g4>>> file should be stored in: <<<src/main/antlr4/org/jimi/themuss/parser.g4>>>. This way
the generated <<<.java>>> files will correctly reflect the package structure in which they will
finally rest as classes.

View File

@ -0,0 +1 @@
FAQ

View File

@ -0,0 +1,62 @@
-------------
ANTLR v4 Maven Plugin
-------------
Jim Idle
-------------
March 2009
-------------
ANTLR v4 Maven plugin
The ANTLR v4 Maven plugin is completely re-written as of version 4.0; if you are familiar
with prior versions, you should note that there are some behavioral differences that make
it worthwhile reading this documentation.
The job of the plugin is essentially to tell the standard ANTLR parser generator where the
input grammar files are and where the output files should be generated. As with all Maven
plugins, there are defaults, which you are advised to comply to, but are not forced to
comply to.
This version of the plugin allows full control over ANTLR and allows configuration of all
options that are useful for a build system. The code required to calculate dependencies,
check the build order, and otherwise work with your grammar files is built into the ANTLR
tool as of version 4.0 of ANTLR and this plugin.
* Plugin Versioning
The plugin version tracks the version of the ANTLR tool that it controls. Hence if you
use version 4.0 of the plugin, you will build your grammars using version 4.0 of the
ANTLR tool, version 4.2 of the plugin will use version 4.2 of the ANTLR tool and so on.
You may also find that there are patch versions of the plugin such as 4.0-1 4.0-2 and
so on. Use the latest patch release of the plugin.
The current version of the plugin is shown at the top of this page after the <<Last Deployed>> date.
* Default directories
As with all Maven plugins, this plugin will automatically default to standard locations
for your grammar and import files. Organizing your source code to reflect this standard
layout will greatly reduce the configuration effort required. The standard layout lookd
like this:
+--
src/main/
|
+--- antlr4/... .g4 files organized in the required package structure
|
+--- imports/ .g4 files that are imported by other grammars.
+--
If your grammar is intended to be part of a package called <<<org.foo.bar>>> then you would
place it in the directory <<<src/main/antlr4/org/foo/bar>>>. The plugin will then produce
<<<.java>>> and <<<.tokens>>> files in the output directory <<<target/generated-sources/antlr4/org/foo/bar>>>
When the Java files are compiled they will be in the correct location for the Javac
compiler without any special configuration. The generated java files are automatically
submitted for compilation by the plugin.
The <<<src/main/antlr4/imports>>> directory is treated in a special way. It should contain
any grammar files that are imported by other grammar files (do not make subdirectories here.)
Such files are never built on their own, but the plugin will automatically tell the ANTLR
tool to look in this directory for library files.

View File

@ -0,0 +1,59 @@
Usage
The ANTLR 4 plugin for Maven can generate parsers for any number of grammars in
your project.
* Compiling Grammars into Parsers
By default, the <<<{{{./antlr4-mojo.html}antlr4}}>>> goal will search for grammar
files in the directory <<<$\{basedir\}/src/main/antlr4>>> and any additional
<<<.tokens>>> files in the directory <<<$\{basedir\}/src/main/antlr4/imports>>>.
This can be configured to search other directories using the plugin configuration
parameters as described in the <<<{{{./antlr4-mojo.html}antlr4}}>>> goal
documentation.
The following figure shows the expected layout of files for the default
configuration of this plugin.
+--
src/main/
|
+--- antlr4/... .g4 files organized in the required package structure
|
+--- imports/ user-created .tokens files and .g4 files that are imported by other grammars
+--
The next step is to configure your POM to call the plugin. The goals will
normally run during the generate-sources phase of the build. Examples of how to
configure your POM can be found on the various examples pages, reachable via
the page menu. If you stick with the default values, the snippet below will
suffice:
+--
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
...
</project>
+--
Note that you can create multiple executions, and thus build some grammars with
different options to others (such as setting the <<<debug>>> option for
instance).

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="ANTLR v4 Maven plugin">
<publishDate position="left"/>
<version position="left"/>
<poweredBy>
<logo name="ANTLR Web Site" href="http://antlr.org/"
img="http://www.antlr.org/wiki/download/attachments/292/ANTLR4"/>
</poweredBy>
<body>
<links>
<item name="Antlr Web Site" href="http://www.antlr.org/"/>
</links>
<menu name="Overview">
<item name="Introduction" href="index.html"/>
<item name="Goals" href="plugin-info.html"/>
<item name="Usage" href="usage.html"/>
<item name="FAQ" href="faq.html"/>
</menu>
<menu name="Examples">
<item name="Simple configurations" href="examples/simple.html"/>
<item name="Using library directories" href="examples/libraries.html"/>
<item name="Using imported grammars" href="examples/import.html"/>
</menu>
<menu ref="reports" />
<menu ref="modules" />
</body>
</project>

292
bild.py
View File

@ -1,292 +0,0 @@
# !/usr/bin/env python
import os
import string
"""
This script uses my experimental build tool http://www.bildtool.org
In order to build the complete ANTLR4 product with Java, CSharp, Python 2/3, and JavaScript
targets, do the following from a UNIX command line. Windows build using this script
is not yet supported. Please use the mvn build or ant build.
You will also need python 2.7, python 3.4, node.js and mono (on Mac/Linux)
!!!You must set path values in test_properties dictionary below to ensure non Java targets tests run.!!!
mkdir -p /usr/local/antlr # somewhere appropriate where you want to install stuff
cd /usr/local/antlr
git clone git@github.com:antlr/antlr4.git
git clone git@github.com:antlr/antlr4-python3.git
git clone git@github.com:antlr/antlr4-python2.git
git clone git@github.com:antlr/antlr4-csharp.git
git clone git@github.com:antlr/antlr4-javascript.git
cd antlr4
./bild.py tests
"""
# bootstrap by downloading bilder.py if not found
import urllib
import os
if not os.path.exists("bilder.py"):
print "bootstrapping; downloading bilder.py"
urllib.urlretrieve(
"https://raw.githubusercontent.com/parrt/bild/master/src/python/bilder.py",
"bilder.py")
# assumes bilder.py is in current directory
from bilder import *
VERSION = "4.4"
JAVA_TARGET = "."
PYTHON2_TARGET = "../antlr4-python2"
PYTHON3_TARGET = "../antlr4-python3"
CSHARP_TARGET = "../antlr4-csharp"
JAVASCRIPT_TARGET = "../antlr4-javascript"
# Properties needed to run Python[23] tests
test_properties = {
"antlr-python2-runtime": uniformpath(PYTHON2_TARGET) + "/src",
"antlr-python3-runtime": uniformpath(PYTHON3_TARGET) + "/src",
"antlr-javascript-runtime": uniformpath(JAVASCRIPT_TARGET) + "/src",
"antlr-csharp-runtime-project": uniformpath(CSHARP_TARGET) + "/runtime/CSharp/Antlr4.Runtime/Antlr4.Runtime.mono.csproj"
}
TARGETS = {
"Java": uniformpath(JAVA_TARGET),
"CSharp":uniformpath(CSHARP_TARGET),
"Python2": uniformpath(PYTHON2_TARGET),
"Python3": uniformpath(PYTHON3_TARGET),
"JavaScript":uniformpath(JAVASCRIPT_TARGET)
}
def parsers():
antlr3("tool/src/org/antlr/v4/parse", "gen3", package="org.antlr.v4.parse")
antlr3("tool/src/org/antlr/v4/codegen", "gen3", package="org.antlr.v4.codegen",
args=["-lib", uniformpath("gen3/org/antlr/v4/parse")])
antlr4("runtime/Java/src/org/antlr/v4/runtime/tree/xpath", "gen4", package="org.antlr.v4.runtime.tree.xpath")
def compile():
require(parsers)
cp = uniformpath("out") + os.pathsep + \
os.path.join(JARCACHE, "antlr-3.5.1-complete.jar") + os.pathsep + \
"runtime/Java/lib/org.abego.treelayout.core.jar" + os.pathsep
if os.path.exists(JARCACHE + "/antlr-" + VERSION + "-complete.jar"):
cp += JARCACHE + "/antlr-" + VERSION + "-complete.jar"
srcpath = ["gen3", "gen4", "runtime/JavaAnnotations/src", "runtime/Java/src", "tool/src"]
args = ["-Xlint", "-Xlint:-serial", "-g", "-sourcepath", string.join(srcpath, os.pathsep)]
for sp in srcpath:
javac(sp, "out", version="1.6", cp=cp, args=args)
# pull in targets
for t in TARGETS:
javac(TARGETS[t] + "/tool/src", "out", version="1.6", cp=cp, args=args)
def mkjar_complete():
require(compile)
copytree(src="tool/resources", trg="out") # messages, Java code gen, etc...
manifest = \
"Main-Class: org.antlr.v4.Tool\n" +\
"Implementation-Title: ANTLR 4 Tool\n" +\
"Implementation-Version: %s\n" +\
"Implementation-Vendor: ANTLR\n" +\
"Implementation-Vendor-Id: org.antlr\n" +\
"Built-By: %s\n" +\
"Build-Jdk: 1.6\n" +\
"Created-By: http://www.bildtool.org\n" +\
"\n"
manifest = manifest % (VERSION, os.getlogin())
# unjar required libraries
unjar("runtime/Java/lib/org.abego.treelayout.core.jar", trgdir="out")
download("http://www.antlr3.org/download/antlr-3.5.1-runtime.jar", JARCACHE)
unjar(os.path.join(JARCACHE, "antlr-3.5.1-runtime.jar"), trgdir="out")
download("http://www.stringtemplate.org/download/ST-4.0.8.jar", JARCACHE)
unjar(os.path.join(JARCACHE, "ST-4.0.8.jar"), trgdir="out")
# pull in target templates
for t in TARGETS:
trgdir = "out/org/antlr/v4/tool/templates/codegen/" + t
mkdir(trgdir)
copyfile(TARGETS[t] + "/tool/resources/org/antlr/v4/tool/templates/codegen/" + t + "/" + t + ".stg",
trgdir)
jarfile = "dist/antlr4-" + VERSION + "-complete.jar"
jar(jarfile, srcdir="out", manifest=manifest)
print "Generated " + jarfile
def mkjar_runtime():
# out/... dir is full of tool-related stuff, make special dir out/runtime
# unjar required library
unjar("runtime/Java/lib/org.abego.treelayout.core.jar", trgdir="out/runtime")
cp = uniformpath("out/runtime") + os.pathsep + \
"runtime/Java/lib/org.abego.treelayout.core.jar"
srcpath = ["gen4", "runtime/JavaAnnotations/src", "runtime/Java/src"]
args = ["-nowarn", "-Xlint", "-Xlint:-serial", "-g", "-sourcepath", string.join(srcpath, os.pathsep)]
for sp in srcpath:
javac(sp, "out/runtime", version="1.6", cp=cp, args=args)
manifest = \
"Implementation-Vendor: ANTLR\n" +\
"Implementation-Vendor-Id: org.antlr\n" +\
"Implementation-Title: ANTLR 4 Runtime\n" +\
"Implementation-Version: %s\n" +\
"Built-By: %s\n" +\
"Build-Jdk: 1.6\n" +\
"Created-By: http://www.bildtool.org\n" +\
"\n"
manifest = manifest % (VERSION, os.getlogin())
jarfile = "dist/antlr4-" + VERSION + ".jar"
jar(jarfile, srcdir="out/runtime", manifest=manifest)
print "Generated " + jarfile
def mkjar():
mkjar_complete()
# put it in JARCARCHE too so bild can find it during antlr4()
copyfile(src="dist/antlr4-" + VERSION + "-complete.jar", trg=JARCACHE)
# rebuild/bootstrap XPath with 4.4 so it can use 4.4 runtime (gen'd with 4.3 at this point)
rmdir("gen4/org/antlr/v4/runtime/tree/xpath") # kill 4.3-generated version
antlr4("runtime/Java/src/org/antlr/v4/runtime/tree/xpath", "gen4", version=VERSION,
package="org.antlr.v4.runtime.tree.xpath")
compile()
mkjar_complete() # make it again with up to date XPath lexer
mkjar_runtime() # now build the runtime jar
def tests():
require(mkjar)
junit_jar, hamcrest_jar = load_junitjars()
cp = uniformpath("dist/antlr4-" + VERSION + "-complete.jar") \
+ os.pathsep + uniformpath("out/test/Java") \
+ os.pathsep + junit_jar \
+ os.pathsep + hamcrest_jar
juprops = ["-D%s=%s" % (p, test_properties[p]) for p in test_properties]
args = ["-nowarn", "-Xlint", "-Xlint:-serial", "-g"]
# don't compile generator
skip = [ uniformpath(TARGETS['Java'] + "/tool/test/org/antlr/v4/test/rt/gen/") ]
javac("tool/test", "out/test/Java", version="1.6", cp=cp, args=args, skip=skip) # all targets can use org.antlr.v4.test.*
for t in TARGETS:
print "Testing %s ..." % t
try:
test(t, cp, juprops, args)
print t + " tests complete"
except:
print t + " tests failed"
def test(t, cp, juprops, args):
srcdir = uniformpath(TARGETS[t] + "/tool/test")
dstdir = uniformpath( "out/test/" + t)
# Prefix CLASSPATH with individual target tests
thiscp = dstdir + os.pathsep + cp
skip = []
if t=='Java':
# don't test generator
skip = [ "/org/antlr/v4/test/rt/gen/", "TestPerformance" ]
elif t=='Python2':
# need BaseTest located in Py3 target
base = uniformpath(TARGETS['Python3'] + "/tool/test")
skip = [ "/org/antlr/v4/test/rt/py3/" ]
javac(base, "out/test/" + t, version="1.6", cp=thiscp, args=args, skip=skip)
skip = []
elif t=='JavaScript':
# don't test browsers automatically, this is overkilling and unreliable
browsers = ["safari","chrome","firefox","explorer"]
skip = [ uniformpath(srcdir + "/org/antlr/v4/test/rt/js/" + b) for b in browsers ]
javac(srcdir, "out/test/" + t, version="1.6", cp=thiscp, args=args, skip=skip)
# copy resource files required for testing
files = allfiles(srcdir)
for src in files:
if not ".java" in src and not ".stg" in src and not ".DS_Store" in src:
dst = src.replace(srcdir, uniformpath("out/test/" + t))
# only copy files from test dirs
if os.path.exists(os.path.split(dst)[0]):
shutil.copyfile(src, dst)
junit("out/test/" + t, cp=thiscp, verbose=False, args=juprops)
def all():
clean(True)
mkjar()
tests()
mkdoc()
mksrc()
install()
clean()
def install():
mvn_install("dist/antlr4-" + VERSION + "-complete.jar",
"dist/antlr4-" + VERSION + "-complete-sources.jar",
"dist/antlr4-" + VERSION + "-complete-javadoc.jar",
"org.antlr",
"antlr4",
VERSION)
mvn_install("dist/antlr4-" + VERSION + ".jar",
"dist/antlr4-" + VERSION + "-sources.jar",
"dist/antlr4-" + VERSION + "-javadoc.jar",
"org.antlr",
"antlr4-runtime",
VERSION)
def clean(dist=False):
if dist:
rmdir("dist")
rmdir("out")
rmdir("gen3")
rmdir("gen4")
rmdir("doc")
def mksrc():
srcpath = "runtime/Java/src/org"
jarfile = "dist/antlr4-" + VERSION + "-sources.jar"
zip(jarfile, srcpath)
print "Generated " + jarfile
jarfile = "dist/antlr4-" + VERSION + "-complete-sources.jar"
srcpaths = [ srcpath, "gen3/org", "gen4/org", "runtime/JavaAnnotations/src/org", "tool/src/org"]
zip(jarfile, srcpaths)
print "Generated " + jarfile
def mkdoc():
# add a few source dirs to reduce the number of javadoc errors
# JavaDoc needs antlr annotations source code
mkdir("out/Annotations")
download("http://search.maven.org/remotecontent?filepath=org/antlr/antlr4-annotations/4.3/antlr4-annotations-4.3-sources.jar", "out/Annotations")
unjar("out/Annotations/antlr4-annotations-4.3-sources.jar", trgdir="out/Annotations")
# JavaDoc needs abego treelayout source code
mkdir("out/TreeLayout")
download("http://search.maven.org/remotecontent?filepath=org/abego/treelayout/org.abego.treelayout.core/1.0.1/org.abego.treelayout.core-1.0.1-sources.jar", "out/TreeLayout")
unjar("out/TreeLayout/org.abego.treelayout.core-1.0.1-sources.jar", trgdir="out/TreeLayout")
# JavaDoc needs antlr runtime 3.5.2 source code
mkdir("out/Antlr352Runtime")
download("http://search.maven.org/remotecontent?filepath=org/antlr/antlr-runtime/3.5.2/antlr-runtime-3.5.2-sources.jar", "out/Antlr352Runtime")
unjar("out/Antlr352Runtime/antlr-runtime-3.5.2-sources.jar", trgdir="out/Antlr352Runtime")
# JavaDoc needs antlr ST4 source code
mkdir("out/ST4")
download("http://search.maven.org/remotecontent?filepath=org/antlr/ST4/4.0.8/ST4-4.0.8-sources.jar", "out/ST4")
unjar("out/ST4/ST4-4.0.8-sources.jar", trgdir="out/ST4")
# go!
mkdir("doc/Java")
mkdir("doc/JavaTool")
dirs = ["runtime/Java/src"]
dirs += ["out/Annotations"]
dirs += ["out/TreeLayout"]
exclude = ["org/antlr/runtime",
"org/abego",
"org/stringtemplate",
"org/antlr/stringtemplate"]
javadoc(srcdir=dirs, trgdir="doc/Java", packages="org.antlr.v4.runtime", exclude=exclude)
dirs += ["gen3"]
dirs += [TARGETS[t] + "/tool/src" for t in TARGETS]
dirs += ["out/Antlr352Runtime"]
dirs += ["out/ST4"]
javadoc(srcdir=dirs, trgdir="doc/JavaTool", packages="org.antlr.v4", exclude=exclude)
# build stack merge PredictionContext and ATNState images from DOT
# DOT Images are in runtime/Java/src/main/dot/org/antlr/v4/runtime/atn/images/
# Gen into E.g., doc/Java/org/antlr/v4/runtime/atn/images/SingletonMerge_DiffRootSamePar.svg
mkdir("doc/Java/org/antlr/v4/runtime/atn/images")
for f in glob.glob("runtime/Java/src/main/dot/org/antlr/v4/runtime/atn/images/*.dot"):
dot(f, "doc/Java/org/antlr/v4/runtime/atn/images", format="svg")
zip("dist/antlr4-" + VERSION + "-javadoc.jar", "doc/Java")
zip("dist/antlr4-" + VERSION + "-complete-javadoc.jar", "doc/JavaTool")
processargs(globals()) # E.g., "python bild.py all"

285
build.xml
View File

@ -1,285 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="ANTLR4" default="distribute" basedir=".">
<target name="basic-init">
<property file="user.build.properties"/>
<property name="dist.dir" value="${basedir}/dist" />
<property name="build.dir" value="${basedir}/build" />
<property name="lib.dir" value="${basedir}/lib" />
</target>
<target name="antlr3-init" depends="basic-init">
<property name="antlr3.version" value="3.5.2"/>
<property name="antlr3.jar.name" value="antlr-${antlr3.version}-complete-no-st3.jar"/>
<property name="antlr3.jar" value="${lib.dir}/${antlr3.jar.name}"/>
<mkdir dir="${lib.dir}"/>
<get src="http://www.antlr3.org/download/${antlr3.jar.name}" dest="${antlr3.jar}" skipexisting="true"/>
<path id="cp.antlr3" path="${antlr3.jar}"/>
<property name="build.antlr3.dir" value="${build.dir}/generated-sources/antlr3" />
<property name="antlr3.touch" value="${build.dir}/antlr3-${antlr3.version}.touch"/>
</target>
<target name="antlr4-init" depends="basic-init">
<property name="antlr4.version" value="4.3"/>
<property name="antlr4.jar.name" value="antlr-${antlr4.version}-complete.jar"/>
<property name="antlr4.jar" value="${lib.dir}/${antlr4.jar.name}"/>
<mkdir dir="${lib.dir}"/>
<get src="http://www.antlr.org/download/${antlr4.jar.name}" dest="${antlr4.jar}" skipexisting="true"/>
<path id="cp.antlr4" path="${antlr4.jar}"/>
<property name="build.antlr4.dir" value="${build.dir}/generated-sources/antlr4" />
<property name="antlr4.touch" value="${build.dir}/antlr4-${antlr4.version}.touch"/>
</target>
<target name="build-init" depends="basic-init">
<property name="version" value="4.4"/>
<property name="build.sysclasspath" value="ignore"/>
<property name="install.root.dir" value="${dist.dir}/antlr-${version}" />
<property name="jar.file" value="${dist.dir}/antlr-${version}-complete.jar" />
</target>
<target name="clean" depends="basic-init">
<delete dir="${build.dir}" includeemptydirs="true"/>
<delete dir="${dist.dir}" includeemptydirs="true"/>
</target>
<target name="clean-all" depends="clean">
<delete dir="${lib.dir}" includeemptydirs="true"/>
</target>
<target name="antlr3-up-to-date" depends="basic-init,antlr3-init">
<uptodate targetfile="${antlr3.touch}" property="is.antlr3.uptodate">
<srcfiles dir="${basedir}/tool/src">
<include name="**/*.g"/>
<include name="**/*.tokens"/>
</srcfiles>
<srcfiles file="${antlr3.jar}"/>
</uptodate>
</target>
<target name="antlr4-up-to-date" depends="basic-init,antlr4-init">
<uptodate targetfile="${antlr4.touch}" property="is.antlr4.uptodate">
<srcfiles dir="${basedir}/tool/src">
<include name="**/*.g4"/>
<include name="**/*.tokens"/>
</srcfiles>
<srcfiles file="${antlr4.jar}"/>
</uptodate>
</target>
<target name="up-to-date" depends="antlr3-up-to-date,antlr4-up-to-date,build-init">
<uptodate targetfile="${jar.file}" property="is.source.uptodate">
<srcfiles dir="${basedir}/tool/src">
<include name="**/*.java"/>
<include name="**/*.g"/>
<include name="**/*.tokens"/>
</srcfiles>
<srcfiles dir="${basedir}/tool/resources">
<include name="**/*.st"/>
<include name="**/*.stg"/>
</srcfiles>
<srcfiles dir="${basedir}/runtime/Java/src/">
<include name="**/*.java"/>
<include name="**/*.g"/>
<include name="**/*.st"/>
<include name="**/*.stg"/>
</srcfiles>
<srcfiles dir="${build.antlr3.dir}"/>
<srcfiles file="${basedir}/runtime/Java/lib/org.abego.treelayout.core.jar"/>
<srcfiles file="${antlr3.jar}"/>
</uptodate>
<condition property="is.jar.uptodate">
<and>
<istrue value="${is.source.uptodate}"/>
<istrue value="${is.antlr3.uptodate}"/>
</and>
</condition>
</target>
<macrodef name="antlr3">
<attribute name="srcpath"/>
<element name="args" optional="true"/>
<sequential>
<local name="path.antlr3.local"/>
<local name="sources.antlr3.local"/>
<path id="path.antlr3.local">
<fileset dir="${basedir}/tool/src/@{srcpath}" includes="*.g"/>
</path>
<pathconvert pathsep=" " property="sources.antlr3.local" refid="path.antlr3.local">
<map from="${basedir}/tool/src/@{srcpath}/" to=""/>
</pathconvert>
<mkdir dir="${build.antlr3.dir}/@{srcpath}"/>
<java classname="org.antlr.Tool" fork="true" failonerror="true" maxmemory="300m"
dir="${basedir}/tool/src/@{srcpath}">
<arg value="-o"/>
<arg value="${build.antlr3.dir}/@{srcpath}"/>
<args/>
<arg line="${sources.antlr3.local}"/>
<classpath>
<path refid="cp.antlr3"/>
<pathelement location="${java.class.path}"/>
</classpath>
</java>
</sequential>
</macrodef>
<macrodef name="antlr4">
<attribute name="srcpath"/>
<element name="args" optional="true"/>
<sequential>
<local name="path.antlr4.local"/>
<local name="sources.antlr4.local"/>
<path id="path.antlr4.local">
<fileset dir="${basedir}/runtime/Java/src/@{srcpath}" includes="*.g4"/>
</path>
<pathconvert pathsep=" " property="sources.antlr4.local" refid="path.antlr4.local">
<map from="${basedir}/runtime/Java/src/@{srcpath}/" to=""/>
</pathconvert>
<mkdir dir="${build.antlr4.dir}/@{srcpath}"/>
<java classname="org.antlr.v4.Tool" fork="true" failonerror="true" maxmemory="300m"
dir="${basedir}/runtime/Java/src/@{srcpath}">
<arg value="-o"/>
<arg value="${build.antlr4.dir}/@{srcpath}"/>
<args/>
<arg line="${sources.antlr4.local}"/>
<classpath>
<path refid="cp.antlr4"/>
<pathelement location="${java.class.path}"/>
</classpath>
</java>
</sequential>
</macrodef>
<target name="antlr3" depends="build-init,antlr3-init,antlr3-up-to-date" unless="is.antlr3.uptodate">
<mkdir dir="${build.antlr3.dir}" />
<path id="sources.antlr3">
<fileset dir="${basedir}/tool/src" includes="**/*.g"/>
</path>
<pathconvert pathsep="${line.separator} " property="echo.sources.antlr3" refid="sources.antlr3">
<map from="${basedir}/tool/src/" to=""/>
</pathconvert>
<echo message="Generating ANTLR 3 grammars:${line.separator} ${echo.sources.antlr3}"/>
<antlr3 srcpath="org/antlr/v4/parse"/>
<antlr3 srcpath="org/antlr/v4/codegen">
<args>
<arg value="-lib"/>
<arg value="${build.antlr3.dir}/org/antlr/v4/parse"/>
</args>
</antlr3>
<touch file="${antlr3.touch}" mkdirs="true"/>
</target>
<target name="antlr4" depends="build-init,antlr4-init,antlr4-up-to-date" unless="is.antlr4.uptodate">
<mkdir dir="${build.antlr4.dir}" />
<path id="sources.antlr4">
<fileset dir="${basedir}/runtime/Java/src" includes="**/*.g4"/>
</path>
<pathconvert pathsep="${line.separator} " property="echo.sources.antlr4" refid="sources.antlr4">
<map from="${basedir}/runtime/Java/src/" to=""/>
</pathconvert>
<echo message="Generating ANTLR 4 grammars:${line.separator} ${echo.sources.antlr4}"/>
<antlr4 srcpath="org/antlr/v4/runtime/tree/xpath">
<args>
<arg value="-package"/>
<arg value="org.antlr.v4.runtime.tree.xpath"/>
</args>
</antlr4>
<touch file="${antlr4.touch}" mkdirs="true"/>
</target>
<target name="compile" depends="build-init,antlr3,antlr4,up-to-date" description="Compile for generic OS" unless="is.jar.uptodate">
<mkdir dir="${build.dir}/classes"/>
<javac
destdir="${build.dir}/classes"
source="1.6"
target="1.6"
debug="true"
excludes="org/antlr/v4/test/**">
<compilerarg value="-Xlint"/>
<compilerarg value="-Xlint:-serial"/>
<classpath>
<path refid="cp.antlr3"/>
<pathelement location="${basedir}/runtime/Java/lib/org.abego.treelayout.core.jar"/>
</classpath>
<src path="${basedir}/tool/src:${basedir}/runtime/JavaAnnotations/src:${basedir}/runtime/Java/src:${build.antlr3.dir}:${build.antlr4.dir}"/>
</javac>
</target>
<target name="build-jar" depends="up-to-date,compile" description="Build ANTLR 4.jar" unless="is.jar.uptodate">
<mkdir dir="${dist.dir}"/>
<jar jarfile="${jar.file}">
<fileset dir="${build.dir}/classes" includes="**/*.class"/>
<fileset dir="${basedir}/tool/resources">
<include name="**/*.st"/>
<include name="**/*.stg"/>
</fileset>
<zipfileset includes="org/antlr/**, org/antlr/stringtemplate/**, org/stringtemplate/v4/**" src="${antlr3.jar}"/>
<zipfileset includes="**/*.class" src="${basedir}/runtime/Java/lib/org.abego.treelayout.core.jar"/>
<manifest>
<attribute name="Version" value="${version}"/>
<attribute name="Main-Class" value="org.antlr.v4.Tool"/>
</manifest>
</jar>
</target>
<target name="zip-source" depends="compile">
<mkdir dir="${install.root.dir}"/>
<mkdir dir="${install.root.dir}/src"/>
<copy todir="${install.root.dir}/src">
<fileset dir="${basedir}/tool/src/">
<include name="**/*.java"/>
<include name="**/*.g"/>
<include name="**/*.st"/>
<include name="**/*.stg"/>
</fileset>
<fileset dir="${basedir}/tool/resources/">
<include name="**/*.st"/>
<include name="**/*.stg"/>
</fileset>
<fileset dir="${basedir}/runtime/JavaAnnotations/resources/">
<include name="**/*.Processor"/>
</fileset>
<fileset dir="${basedir}/runtime/JavaAnnotations/src/">
<include name="**/*.java"/>
</fileset>
<fileset dir="${basedir}/runtime/Java/src/">
<include name="**/*.java"/>
<include name="**/*.g"/>
<include name="**/*.st"/>
<include name="**/*.stg"/>
</fileset>
<fileset dir="${build.antlr3.dir}"/>
</copy>
<copy todir="${install.root.dir}">
<fileset dir=".">
<include name="build.properties"/>
<include name="build.xml"/>
<include name="LICENSE.txt"/>
<include name="README.md"/>
<include name="doxyfile"/>
</fileset>
</copy>
<copy todir="${install.root.dir}/lib" file="${antlr3.jar}">
</copy>
<zip destfile="${dist.dir}/antlr-${version}-src.zip">
<zipfileset dir="${install.root.dir}" prefix="antlr-${version}"/>
</zip>
</target>
<target name="distribute" depends="clean, zip-source, build-jar">
</target>
</project>

View File

@ -63,6 +63,7 @@
<module>runtime/JavaAnnotations</module> <module>runtime/JavaAnnotations</module>
<module>tool</module> <module>tool</module>
<module>antlr4-maven-plugin</module> <module>antlr4-maven-plugin</module>
<module>antlr4-testgen-maven-plugin</module>
</modules> </modules>
<properties> <properties>

View File

@ -1,35 +1,20 @@
digraph "" { digraph "" {
graph[fontname="CourierNew";rankdir="LR";pad="0.25"]; graph[fontname="Consolas";rankdir="LR";pad="0.25"];
node[fontname="CourierNew";target="_parent"]; node[fontname="Consolas";target="_parent"];
edge[fontname="CourierNew"]; edge[fontname="Consolas"];
subgraph clusterA {
color="invis";
{ node[shape="record"];
BasicBlockStartState[URL="../BasicBlockStartState.html";label="{BasicBlockStartState | {<alt1> alt 1 |<alt2> alt 2 | &#0183;\n&#0183;\n&#0183; |<altn> alt n}}"];
BlockEndState[URL="../BlockEndState.html"];
}
{ node[style="dashed"]; net35client[label="net35-client"]
content1[label="alt 1"]; net40client[label="net40-client"]
content2[label="alt 2"]; portablenet40[label="portable-net40"]
more[label="alt n"]; portablenet45[label="portable-net45"]
}
}
{ node[style="dashed"]; net20 -> net30
begin; net30 -> net35client
end; net35client -> net40client[style="dashed"]
} net40client -> net45
begin -> BasicBlockStartState[style="dashed"]; portablenet40 -> net40client
BlockEndState -> end[label="&#0949;"]; portablenet40 -> portablenet45
portablenet45 -> win
BasicBlockStartState:alt1 -> content1[label="&#0949;"]; win -> net45
content1 -> BlockEndState[style="dashed"];
BasicBlockStartState:alt2 -> content2[label="&#0949;"];
content2 -> BlockEndState[style="dashed"];
BasicBlockStartState:altn -> more[label="&#0949;"];
more -> BlockEndState[style="dashed"];
} }

View File

@ -154,6 +154,22 @@
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-testgen-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>antlr4.testgen</goal>
</goals>
<configuration>
<runtimeTemplates>test/org/antlr/v4/test/runtime/java/Java.test.stg</runtimeTemplates>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>

View File

@ -162,105 +162,9 @@ public class Generator {
list.add(buildParseTrees()); list.add(buildParseTrees());
list.add(buildSemPredEvalLexer()); list.add(buildSemPredEvalLexer());
list.add(buildSemPredEvalParser()); list.add(buildSemPredEvalParser());
list.add(buildSets());
return list; return list;
} }
private JUnitTestFile buildSets() throws Exception {
JUnitTestFile file = new JUnitTestFile("Sets");
// this must return A not I to the parser; calling a nonfragment rule
// from a nonfragment rule does not set the overall token.
file.addParserTest(input, "SeqDoesNotBecomeSet", "T", "a",
"34",
"34\n",
null);
file.addParserTest(input, "ParserSet", "T", "a",
"x",
"x\n",
null);
file.addParserTest(input, "ParserNotSet", "T", "a",
"zz",
"z\n",
null);
file.addParserTest(input, "ParserNotToken", "T", "a",
"zz",
"zz\n",
null);
file.addParserTest(input, "ParserNotTokenWithLabel", "T", "a",
"zz",
"z\n",
null);
file.addParserTest(input, "RuleAsSet", "T", "a",
"b",
"b\n",
null);
file.addParserTest(input, "NotChar", "T", "a",
"x",
"x\n",
null);
file.addParserTest(input, "OptionalSingleElement", "T", "a",
"bc",
"bc\n",
null);
file.addParserTest(input, "OptionalLexerSingleElement", "T", "a",
"bc",
"bc\n",
null);
file.addParserTests(input, "StarLexerSingleElement", "T", "a",
"bbbbc", "bbbbc\n",
"c", "c\n");
file.addParserTest(input, "PlusLexerSingleElement", "T", "a",
"bbbbc",
"bbbbc\n",
null);
file.addParserTest(input, "OptionalSet", "T", "a",
"ac",
"ac\n",
null);
file.addParserTest(input, "StarSet", "T", "a",
"abaac",
"abaac\n",
null);
file.addParserTest(input, "PlusSet", "T", "a",
"abaac",
"abaac\n",
null);
file.addParserTest(input, "LexerOptionalSet", "T", "a",
"ac",
"ac\n",
null);
file.addParserTest(input, "LexerStarSet", "T", "a",
"abaac",
"abaac\n",
null);
file.addParserTest(input, "LexerPlusSet", "T", "a",
"abaac",
"abaac\n",
null);
file.addParserTest(input, "NotCharSet", "T", "a",
"x",
"x\n",
null);
file.addParserTest(input, "NotCharSetWithLabel", "T", "a",
"x",
"x\n",
null);
file.addParserTest(input, "NotCharSetWithRuleRef3", "T", "a",
"x",
"x\n",
null);
file.addParserTest(input, "CharSetLiteral", "T", "a",
"A a B b",
"A\n" + "a\n" + "B\n" + "b\n",
null);
file.addParserTest(input, "ComplementSet", "T", "parse",
"a",
"",
"line 1:0 token recognition error at: 'a'\n" +
"line 1:1 missing {} at '<EOF>'\n");
return file;
}
private JUnitTestFile buildSemPredEvalParser() throws Exception { private JUnitTestFile buildSemPredEvalParser() throws Exception {
JUnitTestFile file = new JUnitTestFile("SemPredEvalParser"); JUnitTestFile file = new JUnitTestFile("SemPredEvalParser");
JUnitTestMethod tm = file.addParserTest(input, "SimpleValidate", "T", "s", JUnitTestMethod tm = file.addParserTest(input, "SimpleValidate", "T", "s",

View File

@ -1,4 +0,0 @@
grammar <grammarName>;
a : (A {<writeln("$A.text")>})+ ;
A : [AaBb] ;
WS : (' '|'\n')+ -> skip ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
parse : ~NEW_LINE;
NEW_LINE: '\\r'? '\\n';

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<InputText():writeln()>} ;
A : ('a'|'b')? 'c' ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<InputText():writeln()>} ;
A : ('a'|'b')+ 'c' ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<InputText():writeln()>} ;
A : ('a'|'b')* 'c' ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<writeln("$A.text")>} ;
A : ~'b' ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<writeln("$A.text")>} ;
A : ~('b'|'c') ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<writeln("$A.text")>} ;
A : h=~('b'|'c') ;

View File

@ -1,5 +0,0 @@
grammar <grammarName>;
a : A {<writeln("$A.text")>} ;
A : ('a'|B) ; // this doesn't collapse to set but works
fragment
B : ~('a'|'c') ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<InputText():writeln()>} ;
A : 'b'? 'c' ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a : ('a'|'b')? 'c' {<InputText():writeln()>} ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A? 'c' {<InputText():writeln()>} ;
A : 'b' ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a : t=~('x'|'y') 'z' {<writeln("$t.text")>} ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a : ~'x' 'z' {<InputText():writeln()>} ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a : t=~'x' 'z' {<writeln("$t.text")>} ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a : t=('x'|'y') {<writeln("$t.text")>} ;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<InputText():writeln()>} ;
A : 'b'+ 'c' ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a : ('a'|'b')+ 'c' {<InputText():writeln()>} ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a @after {<InputText():writeln()>} : 'a' | 'b' |'c' ;

View File

@ -1,5 +0,0 @@
grammar <grammarName>;
a : C {<InputText():writeln()>} ;
fragment A : '1' | '2';
fragment B : '3' '4';
C : A | B;

View File

@ -1,3 +0,0 @@
grammar <grammarName>;
a : A {<InputText():writeln()>} ;
A : 'b'* 'c' ;

View File

@ -1,2 +0,0 @@
grammar <grammarName>;
a : ('a'|'b')* 'c' {<InputText():writeln()>} ;

View File

@ -1,261 +0,0 @@
package org.antlr.v4.test.rt.java;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestSets extends BaseTest {
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testSeqDoesNotBecomeSet() throws Exception {
String grammar = "grammar T;\n" +
"a : C {System.out.println(this._input.getText());} ;\n" +
"fragment A : '1' | '2';\n" +
"fragment B : '3' '4';\n" +
"C : A | B;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "34", false);
assertEquals("34\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testParserSet() throws Exception {
String grammar = "grammar T;\n" +
"a : t=('x'|'y') {System.out.println($t.text);} ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "x", false);
assertEquals("x\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testParserNotSet() throws Exception {
String grammar = "grammar T;\n" +
"a : t=~('x'|'y') 'z' {System.out.println($t.text);} ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "zz", false);
assertEquals("z\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testParserNotToken() throws Exception {
String grammar = "grammar T;\n" +
"a : ~'x' 'z' {System.out.println(this._input.getText());} ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "zz", false);
assertEquals("zz\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testParserNotTokenWithLabel() throws Exception {
String grammar = "grammar T;\n" +
"a : t=~'x' 'z' {System.out.println($t.text);} ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "zz", false);
assertEquals("z\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testRuleAsSet() throws Exception {
String grammar = "grammar T;\n" +
"a @after {System.out.println(this._input.getText());} : 'a' | 'b' |'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "b", false);
assertEquals("b\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testNotChar() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ~'b' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "x", false);
assertEquals("x\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testOptionalSingleElement() throws Exception {
String grammar = "grammar T;\n" +
"a : A? 'c' {System.out.println(this._input.getText());} ;\n" +
"A : 'b' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "bc", false);
assertEquals("bc\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testOptionalLexerSingleElement() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println(this._input.getText());} ;\n" +
"A : 'b'? 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "bc", false);
assertEquals("bc\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
String testStarLexerSingleElement(String input) throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println(this._input.getText());} ;\n" +
"A : 'b'* 'c' ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "a", input, false);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testStarLexerSingleElement_1() throws Exception {
String found = testStarLexerSingleElement("bbbbc");
assertEquals("bbbbc\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testStarLexerSingleElement_2() throws Exception {
String found = testStarLexerSingleElement("c");
assertEquals("c\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testPlusLexerSingleElement() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println(this._input.getText());} ;\n" +
"A : 'b'+ 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "bbbbc", false);
assertEquals("bbbbc\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testOptionalSet() throws Exception {
String grammar = "grammar T;\n" +
"a : ('a'|'b')? 'c' {System.out.println(this._input.getText());} ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ac", false);
assertEquals("ac\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testStarSet() throws Exception {
String grammar = "grammar T;\n" +
"a : ('a'|'b')* 'c' {System.out.println(this._input.getText());} ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "abaac", false);
assertEquals("abaac\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testPlusSet() throws Exception {
String grammar = "grammar T;\n" +
"a : ('a'|'b')+ 'c' {System.out.println(this._input.getText());} ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "abaac", false);
assertEquals("abaac\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testLexerOptionalSet() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println(this._input.getText());} ;\n" +
"A : ('a'|'b')? 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ac", false);
assertEquals("ac\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testLexerStarSet() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println(this._input.getText());} ;\n" +
"A : ('a'|'b')* 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "abaac", false);
assertEquals("abaac\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testLexerPlusSet() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println(this._input.getText());} ;\n" +
"A : ('a'|'b')+ 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "abaac", false);
assertEquals("abaac\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testNotCharSet() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ~('b'|'c') ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "x", false);
assertEquals("x\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testNotCharSetWithLabel() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : h=~('b'|'c') ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "x", false);
assertEquals("x\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testNotCharSetWithRuleRef3() throws Exception {
String grammar = "grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ('a'|B) ; // this doesn't collapse to set but works\n" +
"fragment\n" +
"B : ~('a'|'c') ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "x", false);
assertEquals("x\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testCharSetLiteral() throws Exception {
String grammar = "grammar T;\n" +
"a : (A {System.out.println($A.text);})+ ;\n" +
"A : [AaBb] ;\n" +
"WS : (' '|'\\n')+ -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "A a B b", false);
assertEquals("A\na\nB\nb\n", found);
assertNull(this.stderrDuringParse);
}
/* this file and method are generated, any edit will be overwritten by the next generation */
@Test
public void testComplementSet() throws Exception {
String grammar = "grammar T;\n" +
"parse : ~NEW_LINE;\n" +
"NEW_LINE: '\\r'? '\\n';";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "parse", "a", false);
assertEquals("", found);
assertEquals("line 1:0 token recognition error at: 'a'\nline 1:1 missing {} at '<EOF>'\n", this.stderrDuringParse);
}
}

View File

@ -0,0 +1,353 @@
TestFile(file) ::= <<
package org.antlr.v4.test.rt.java;
import org.junit.Test;
import static org.junit.Assert.*;
<if(file.importErrorQueue)>
import org.antlr.v4.test.tool.ErrorQueue;
<endif>
<if(file.importGrammar)>
import org.antlr.v4.tool.Grammar;
<endif>
public class Test<file.name> extends BaseTest {
<file.tests:{test | <test>}; separator="\n", wrap, anchor>
}
>>
LexerTestMethod(test) ::= <<
@Test
public void test<test.name>() throws Exception {
<test.slaveGrammars:{ grammar |
String slave_<grammar.grammarName> = <grammar.lines:{ line | "<line>};separator="\\n\" +\n", wrap, anchor>";
mkdir(tmpdir);
writeFile(tmpdir, "<grammar.grammarName>.g4", slave_<grammar.grammarName>);
};separator="\n", wrap, anchor>
StringBuilder sb = new StringBuilder();
<test.grammar.lines:{ line | sb.append("<line>\\n");};separator="\n", wrap, anchor>
String grammar = sb.toString();
<test.afterGrammar>
String found = execLexer("<test.grammar.grammarName>.g4", grammar, "<test.grammar.grammarName><if(!test.lexerOnly)>Lexer<endif>", "<test.input>", <test.showDFA>);
assertEquals(<test.outputLines:{ line | "<line>\\n"};separator=" + \n", wrap, anchor>, found);
<if(test.expectedErrors)>
assertEquals("<test.expectedErrors>", this.stderrDuringParse);
<else>
assertNull(this.stderrDuringParse);
<endif>
}
>>
CompositeLexerTestMethod(test) ::= <<
<LexerTestMethod(test)>
>>
ParserTestMethod(test) ::= <<
@Test
public void test<test.name>() throws Exception {
<!<test.slaveGrammars:{ grammar |
String slave_<grammar.grammarName> = <grammar.lines:{ line | "<line>};separator="\\n\" +\n", wrap, anchor>";
<if(test.slaveIsLexer)>
rawGenerateAndBuildRecognizer("<grammar.grammarName>.g4", slave_<grammar.grammarName>, null, "<grammar.grammarName>");
<else>
mkdir(tmpdir);
writeFile(tmpdir, "<grammar.grammarName>.g4", slave_<grammar.grammarName>);
<endif>
};separator="\n", wrap, anchor>!>
mkdir(tmpdir);
<test.Grammars: {grammarFileName | writeFile("<grammarFileName>", <string(test.Grammars.(grammarFileName))>);}; separator="\n", anchor>
writeFile(tmpdir, "<test.Grammars.keys>"
String grammar = <test.grammar.lines:{ line | "<line>};separator="\\n\" +\n", wrap, anchor>";
<test.afterGrammar>
String found = execParser("<test.grammar.grammarName>.g4", grammar, "<test.grammar.grammarName><if(!test.slaveIsLexer)>Parser<endif>", "<if(test.slaveIsLexer)><first(test.slaveGrammars).grammarName><else><test.grammar.grammarName>Lexer<endif>", "<test.startRule>", "<test.input>", <test.debug>);
assertEquals("<test.expectedOutput>", found);
<if(test.expectedErrors)>
assertEquals("<test.expectedErrors>", this.stderrDuringParse);
<else>
assertNull(this.stderrDuringParse);
<endif>
}
>>
string(text) ::= <<
"<escape.(text)>"
>>
CompositeParserTestMethod(test) ::= <<
<ParserTestMethod(test)>
>>
AbstractParserTestMethod(test) ::= <<
String test<test.name>(String input) throws Exception {
String grammar = <test.grammar.lines:{ line | "<line>};separator="\\n\" +\n", wrap, anchor>";
return execParser("<test.grammar.grammarName>.g4", grammar, "<test.grammar.grammarName>Parser", "<test.grammar.grammarName>Lexer", "<test.startRule>", input, <test.debug>);
}
>>
ConcreteParserTestMethod(test) ::= <<
@Test
public void test<test.name>() throws Exception {
String found = test<test.baseName>("<test.input>");
assertEquals("<test.expectedOutput>", found);
<if(test.expectedErrors)>
assertEquals("<test.expectedErrors>", this.stderrDuringParse);
<else>
assertNull(this.stderrDuringParse);
<endif>
}
>>
writeln(s) ::= <<System.out.println(<s>);>>
write(s) ::= <<System.out.print(<s>);>>
False() ::= "false"
True() ::= "true"
Not(v) ::= "!<v>"
Assert(s) ::= <<assert(<s>);>>
Cast(t,v) ::= "((<t>)<v>)"
Append(a,b) ::= "<a> + <b>"
Concat(a,b) ::= "<a><b>"
DeclareLocal(s,v) ::= "Object <s> = <v>;"
AssignLocal(s,v) ::= "<s> = <v>;"
InitIntMember(n,v) ::= <%int <n> = <v>;%>
InitBooleanMember(n,v) ::= <%boolean <n> = <v>;%>
GetMember(n) ::= <%this.<n>%>
SetMember(n,v) ::= <%this.<n> = <v>;%>
AddMember(n,v) ::= <%this.<n> += <v>;%>
PlusMember(v,n) ::= <%<v> + this.<n>%>
MemberEquals(n,v) ::= <%this.<n> == <v>%>
ModMemberEquals(n,m,v) ::= <%this.<n> % <m> == <v>%>
ModMemberNotEquals(n,m,v) ::= <%this.<n> % <m> != <v>%>
DumpDFA() ::= "this.dumpDFA();"
Pass() ::= ""
StringList() ::= "List\<String>"
BuildParseTrees() ::= "setBuildParseTree(true);"
BailErrorStrategy() ::= <%setErrorHandler(new BailErrorStrategy());%>
ToStringTree(s) ::= <%<s>.toStringTree(this)%>
Column() ::= "this.getCharPositionInLine()"
Text() ::= "this.getText()"
ValEquals(a,b) ::= <%<a>==<b>%>
TextEquals(a) ::= <%this.getText().equals("<a>")%>
PlusText(a) ::= <%"<a>" + this.getText()%>
InputText() ::= "this._input.getText()"
LTEquals(i, v) ::= <%this._input.LT(<i>).getText().equals(<v>)%>
LANotEquals(i, v) ::= <%this._input.LA(<i>)!=<v>%>
TokenStartColumnEquals(i) ::= <%this._tokenStartCharPositionInLine==<i>%>
ImportListener(X) ::= ""
GetExpectedTokenNames() ::= "this.getExpectedTokens().toString(this.tokenNames)"
RuleInvocationStack() ::= "getRuleInvocationStack()"
LL_EXACT_AMBIG_DETECTION() ::= <<_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);>>
PositionAdjustingLexer() ::= <<
@Override
public Token nextToken() {
if (!(_interp instanceof PositionAdjustingLexerATNSimulator)) {
_interp = new PositionAdjustingLexerATNSimulator(this, _ATN, _decisionToDFA, _sharedContextCache);
}
return super.nextToken();
}
@Override
public Token emit() {
switch (_type) {
case TOKENS:
handleAcceptPositionForKeyword("tokens");
break;
case LABEL:
handleAcceptPositionForIdentifier();
break;
default:
break;
}
return super.emit();
}
private boolean handleAcceptPositionForIdentifier() {
String tokenText = getText();
int identifierLength = 0;
while (identifierLength \< tokenText.length() && isIdentifierChar(tokenText.charAt(identifierLength))) {
identifierLength++;
}
if (getInputStream().index() > _tokenStartCharIndex + identifierLength) {
int offset = identifierLength - 1;
getInterpreter().resetAcceptPosition(getInputStream(), _tokenStartCharIndex + offset, _tokenStartLine, _tokenStartCharPositionInLine + offset);
return true;
}
return false;
}
private boolean handleAcceptPositionForKeyword(String keyword) {
if (getInputStream().index() > _tokenStartCharIndex + keyword.length()) {
int offset = keyword.length() - 1;
getInterpreter().resetAcceptPosition(getInputStream(), _tokenStartCharIndex + offset, _tokenStartLine, _tokenStartCharPositionInLine + offset);
return true;
}
return false;
}
@Override
public PositionAdjustingLexerATNSimulator getInterpreter() {
return (PositionAdjustingLexerATNSimulator)super.getInterpreter();
}
private static boolean isIdentifierChar(char c) {
return Character.isLetterOrDigit(c) || c == '_';
}
protected static class PositionAdjustingLexerATNSimulator extends LexerATNSimulator {
public PositionAdjustingLexerATNSimulator(Lexer recog, ATN atn,
DFA[] decisionToDFA,
PredictionContextCache sharedContextCache)
{
super(recog, atn, decisionToDFA, sharedContextCache);
}
protected void resetAcceptPosition(CharStream input, int index, int line, int charPositionInLine) {
input.seek(index);
this.line = line;
this.charPositionInLine = charPositionInLine;
consume(input);
}
}
>>
BasicListener(X) ::= <<
public static class LeafListener extends TBaseListener {
public void visitTerminal(TerminalNode node) {
System.out.println(node.getSymbol().getText());
}
}
>>
WalkListener(s) ::= <<
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new LeafListener(), <s>);
>>
TokenGetterListener(X) ::= <<
public static class LeafListener extends TBaseListener {
public void exitA(TParser.AContext ctx) {
if (ctx.getChildCount()==2)
System.out.printf("%s %s %s",ctx.INT(0).getSymbol().getText(),
ctx.INT(1).getSymbol().getText(),ctx.INT());
else
System.out.println(ctx.ID().getSymbol());
}
}
>>
RuleGetterListener(X) ::= <<
public static class LeafListener extends TBaseListener {
public void exitA(TParser.AContext ctx) {
if (ctx.getChildCount()==2) {
System.out.printf("%s %s %s",ctx.b(0).start.getText(),
ctx.b(1).start.getText(),ctx.b().get(0).start.getText());
} else
System.out.println(ctx.b(0).start.getText());
}
}
>>
LRListener(X) ::= <<
public static class LeafListener extends TBaseListener {
public void exitE(TParser.EContext ctx) {
if (ctx.getChildCount()==3) {
System.out.printf("%s %s %s\n",ctx.e(0).start.getText(),
ctx.e(1).start.getText(), ctx.e().get(0).start.getText());
} else
System.out.println(ctx.INT().getSymbol().getText());
}
}
>>
LRWithLabelsListener(X) ::= <<
public static class LeafListener extends TBaseListener {
public void exitCall(TParser.CallContext ctx) {
System.out.printf("%s %s",ctx.e().start.getText(),ctx.eList());
}
public void exitInt(TParser.IntContext ctx) {
System.out.println(ctx.INT().getSymbol().getText());
}
}
>>
DeclareContextListGettersFunction() ::= <<
void foo() {
SContext s = null;
List\<? extends AContext> a = s.a();
List\<? extends BContext> b = s.b();
}
>>
Declare_foo() ::= <<public void foo() {System.out.println("foo");}>>
Invoke_foo() ::= "this.foo();"
Declare_pred() ::= <<boolean pred(boolean v) {
System.out.println("eval="+v);
return v;
}
>>
Invoke_pred(v) ::= <<this.pred(<v>)>>

View File

@ -0,0 +1,25 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "A a B b"
Output() ::= <<
A
a
B
b<\n>
>>
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : (A {<writeln("$A.text")>})+ ;
A : [AaBb] ;
WS : (' '|'\n')+ -> skip ;
>>

View File

@ -0,0 +1,22 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "parse"
Input() ::= "a"
Output() ::= ""
Errors() ::= <<
line 1:0 token recognition error at: 'a'
line 1:1 missing {} at '\<EOF>'<\n>
>>
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : ~NEW_LINE;
NEW_LINE: '\\r'? '\\n';
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "ac"
Output() ::= "ac<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<InputText():writeln()>} ;
A : ('a'|'b')? 'c' ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "abaac"
Output() ::= "abaac<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<InputText():writeln()>} ;
A : ('a'|'b')+ 'c' ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "abaac"
Output() ::= "abaac<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<InputText():writeln()>} ;
A : ('a'|'b')* 'c' ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "x"
Output() ::= "x<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<writeln("$A.text")>} ;
A : ~'b' ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "x"
Output() ::= "x<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<writeln("$A.text")>} ;
A : ~('b'|'c') ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "x"
Output() ::= "x<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<writeln("$A.text")>} ;
A : h=~('b'|'c') ;
>>

View File

@ -0,0 +1,21 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "x"
Output() ::= "x<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<writeln("$A.text")>} ;
A : ('a'|B) ; // this doesn't collapse to set but works
fragment
B : ~('a'|'c') ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "bc"
Output() ::= "bc<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<InputText():writeln()>} ;
A : 'b'? 'c' ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "ac"
Output() ::= "ac<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : ('a'|'b')? 'c' {<InputText():writeln()>} ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "bc"
Output() ::= "bc<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A? 'c' {<InputText():writeln()>} ;
A : 'b' ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "zz"
Output() ::= "z<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : t=~('x'|'y') 'z' {<writeln("$t.text")>} ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "zz"
Output() ::= "zz<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : ~'x' 'z' {<InputText():writeln()>} ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "zz"
Output() ::= "z<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : t=~'x' 'z' {<writeln("$t.text")>} ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "x"
Output() ::= "x<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : t=('x'|'y') {<writeln("$t.text")>} ;
>>

View File

@ -0,0 +1,19 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "bbbbc"
Output() ::= "bbbbc<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<InputText():writeln()>} ;
A : 'b'+ 'c' ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "abaac"
Output() ::= "abaac<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : ('a'|'b')+ 'c' {<InputText():writeln()>} ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "b"
Output() ::= "b<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> @after {<InputText():writeln()>} : 'a' | 'b' |'c' ;
>>

View File

@ -0,0 +1,21 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "34"
Output() ::= "34<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : C {<InputText():writeln()>} ;
fragment A : '1' | '2';
fragment B : '3' '4';
C : A | B;
>>

View File

@ -0,0 +1,28 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input ::= [
"1": "bbbbc",
"2": "c"
]
Output ::= [
"1": {bbbbc<\n>},
"2": {c<\n>}
]
Errors ::= [
"1": "",
"2": ""
]
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : A {<InputText():writeln()>} ;
A : 'b'* 'c' ;
>>

View File

@ -0,0 +1,18 @@
TestType() ::= "Parser"
Grammars ::= [
"T.g4": {<grammar("T")>}
]
Rule() ::= "a"
Input() ::= "abaac"
Output() ::= "abaac<\n>"
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
<Rule()> : ('a'|'b')* 'c' {<InputText():writeln()>} ;
>>