Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRADLE-902 support ANTLR v3 #69

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,114 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.api.plugins.antlr



import org.gradle.integtests.fixtures.WellBehavedPluginTest
import org.hamcrest.Matcher
import static org.gradle.util.Matchers.containsLine
import static org.hamcrest.Matchers.containsString
import static org.hamcrest.Matchers.startsWith
/**
* @author Strong Liu <stliu@hibernate.org>
*/
class Antlr3PluginIntegrationTests extends WellBehavedPluginTest {

def setup() {
writeBuildFile()
}

def "analyze good code"() {
goodCode()

expect:
succeeds('compileJava')
file("build/generated-src/antlr/main/org/gradle/api/plugins/antlr/ExprLexer.java").exists()
file("build/generated-src/antlr/main/org/gradle/api/plugins/antlr/ExprParser.java").exists()
file("build/generated-src/antlr/main/Expr.tokens").exists()
}



private goodCode() {
file('src/main/antlr/org/gradle/api/plugins/antlr/Expr.g') << """
grammar Expr;

@header {
\tpackage org.gradle.api.plugins.antlr;
\timport java.util.Map;
\timport java.util.HashMap;
}
@lexer::header {
\tpackage org.gradle.api.plugins.antlr;
}

@members {
\tMap<String, Integer> memory = new HashMap<String, Integer>();
}
prog : \tstat+;
stat : expr NEWLINE {System.out.println(\$expr.value);}
\t|\tID '=' expr NEWLINE
\t\t{memory.put(\$ID.text, Integer.valueOf(\$expr.value));}
\t|\tNEWLINE
\t;
\t
expr returns [int value]
\t:\te=multExpr{\$value = \$e.value;}
\t \t( '+' e=multExpr {\$value += \$e.value;}
\t\t| '-' e=multExpr {\$value -= \$e.value;}
\t\t)*
\t;
\t
multExpr returns [int value]
\t: e = atom {\$value = \$e.value;} ('*' e=atom{\$value *= \$e.value;})*
\t;
\t
atom returns [int value]
\t:\tINT {\$value = Integer.parseInt(\$INT.text);}
\t| ID
\t\t{
\t\t\tInteger v = memory.get(\$ID.text);
\t\t\tif(v!=null) \$value = v;
\t\t\telse System.err.println("undefined variable "+\$ID.text);
\t\t}
\t| '(' expr ')' {\$value = \$expr.value;}
\t;
\t
ID : ('a'..'z' | 'A'..'Z')+ ;
INT : '0'..'9'+ ;
NEWLINE : '\\r'? '\\n';
WS : (' ' | '\\t')+ {skip();};
"""
}

private void writeBuildFile() {
file("build.gradle") << """
apply plugin: "antlr3"

repositories {
mavenCentral()
}

dependencies{
compile("org.antlr:antlr-runtime:3.4@jar")
}

"""
}

}
@@ -0,0 +1,61 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/



package org.gradle.api.plugins.antlr

/**
* @author Strong Liu <stliu@hibernate.org>
*/
class Antlr3Extension {

File outputDirectory;
Boolean forceAllFilesToOutputDir;
File lib;
String language;
String forcedLanguageOption;
Boolean nfa;
Boolean dfa;
Boolean debug;
Boolean trace;
Boolean report;
Boolean profile;
Boolean print;
Boolean depend;
Boolean verbose;
Boolean make;
String messageFormat;
Boolean xgrtree;
Boolean xdfa;
Boolean xnoprune;
Boolean xnocollapse;
Boolean xdbgconversion;
Boolean xmultithreaded;
Boolean xnomergestopstates;
Boolean xdfaverbose;
Boolean xwatchconversion;
Boolean xdbgST;
Integer xmaxinlinedfastates;
Integer xmaxswitchcaselabels;
Integer xminswitchalts;
Integer xm;
Integer xmaxdfaedges;
Integer xconversiontimeout;
Boolean xnfastates;
Boolean xsavelexer;
String version = "3.4";
}
@@ -0,0 +1,171 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/




package org.gradle.api.plugins.antlr;


import org.gradle.api.Plugin
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.internal.file.DefaultSourceDirectorySet
import org.gradle.api.internal.plugins.DslObject
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.SourceSet
import org.gradle.util.ConfigureUtil
import org.gradle.api.plugins.antlr.internal.AntlrSourceVirtualDirectoryImpl

/**
* A plugin for adding Antlr V3 support to {@link JavaPlugin java projects}.
*
* @author Strong Liu
*/
public class Antlr3Plugin implements Plugin<ProjectInternal> {
private ProjectInternal project;
private static final String CONFIGURATION_NAME = "antlr3";

Antlr3Extension extension;

void apply(ProjectInternal project) {
this.project = project
project.plugins.apply("java")

createConfigurations()

extension = project.extensions.create("antlr3", Antlr3Extension)


project.convention.getPlugin(JavaPluginConvention).sourceSets.all { SourceSet sourceSet ->
final AntlrSourceVirtualDirectory antlrDirectoryDelegate = new AntlrSourceVirtualDirectoryImpl(sourceSet.displayName, project.fileResolver)

antlrDirectoryDelegate.antlr.srcDir("src/${sourceSet.name}/antlr");

new DslObject(sourceSet).convention.plugins.put(
AntlrSourceVirtualDirectory.NAME, antlrDirectoryDelegate);


final String taskName = sourceSet.getTaskName("generate", "GrammarSource");
final File outputDir = project.file("${project.buildDir}/generated-src/antlr/${sourceSet.name}")

sourceSet.with {
allSource.source(antlrDirectoryDelegate.antlr)
java.srcDir(outputDir)
}

project.tasks.getByName(sourceSet.compileJavaTaskName).dependsOn(taskName)

Antlr3Task antlr3Task = project.tasks.add(taskName, Antlr3Task)
antlr3Task.outputDirectory = outputDir
File baseSourcePath = project.file("src/${sourceSet.name}/antlr");
antlr3Task.baseSourcePath = baseSourcePath
antlr3Task.grammarFiles = antlrDirectoryDelegate.antlr.files
antlr3Task.conventionMapping.with {
args = { buildExtensionArgs(antlrDirectoryDelegate, outputDir, baseSourcePath) }
antlr3Classpath = {
def config = project.configurations[CONFIGURATION_NAME]
if (config.dependencies.empty) {
project.dependencies {
antlr3 "org.antlr:antlr:$extension.version"
}
}
config
}
}
}
}


protected Configuration createConfigurations() {
return project.configurations.add(CONFIGURATION_NAME).with {
visible = false
transitive = true
description = "The ${CONFIGURATION_NAME} libraries to be used for this project."
// Don't need these things, they're provided by the runtime
exclude group: 'ant', module: 'ant'
exclude group: 'org.apache.ant', module: 'ant'
exclude group: 'org.apache.ant', module: 'ant-launcher'
exclude group: 'org.codehaus.groovy', module: 'groovy'
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
exclude group: 'org.slf4j', module: 'slf4j-api'
exclude group: 'org.slf4j', module: 'jcl-over-slf4j'
exclude group: 'org.slf4j', module: 'log4j-over-slf4j'
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'log4j', module: 'log4j'
}
}



private List buildExtensionArgs(antlrDirectoryDelegate, outputDir, File baseSourcePath) {
def arguments = []
if (isTrue(extension.forceAllFilesToOutputDir)) {
arguments << "-fo"
} else {
arguments << "-o"
}
arguments << outputDir.absolutePath
arguments << "-lib"
if (extension.lib != null && extension.lib.exists()) {
arguments << extension.lib.absolutePath
} else {
//we set lib to the base out put dir
arguments << outputDir.absolutePath
}

keyArgs.each { arg ->
if (isTrue(extension."${arg}")) arguments << "-" + caseConvert(arg)
}
keyValueArgs.each { arg ->
if (extension."${arg}" != null) {
arguments << "-" + caseConvert(arg)
arguments << extension."${arg}"
}
}
if (extension.messageFormat != null) {
arguments << "-message-format"
arguments << extension.messageFormat
}
antlrDirectoryDelegate.antlr.files.each { File grammarFile ->
arguments << grammarFile.absolutePath.substring(baseSourcePath.absolutePath.length() + 1)
}
return arguments
}

def keyValueArgs = ["xmaxswitchcaselabels", "xmaxinlinedfastates", "language", "xminswitchalts", "xm", "xmaxdfaedges", "xconversiontimeout"]

def keyArgs = ["nfa", "dfa", "debug", "trace", "report", "profile", "print", "depend",
"verbose", "make", "xgrtree", "xdfa", "xnoprune", "xnocollapse", "xdbgconversion",
"xmultithreaded", "xnomergestopstates", "xdfaverbose", "xwatchconversion", "xdbgST", "xnfastates", "xsavelexer"];

private boolean isTrue(Boolean arg) {
return arg != null && arg
}

private String caseConvert(String str) {
if (str.startsWith("x")) {
return "X" + str.substring(1, str.length())
}
return str;
}


}