Added Antlr compiler/runtime and wrote initial grammar.
Grammar is just a collection of rules. Change-Id: I556a8f74668b11b80f673fc7d665704322c2dac9
This commit is contained in:
parent
a1bd87e7b2
commit
8242986221
9
Makefile
Normal file
9
Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
all: CongressLexer.py
|
||||
|
||||
CongressLexer.py CongressParser.py: policy/Congress.g
|
||||
java -jar outside/antlr-3.5-complete.jar policy/Congress.g
|
||||
|
||||
|
||||
|
||||
|
BIN
outside/antlr-3.5-complete.jar
Normal file
BIN
outside/antlr-3.5-complete.jar
Normal file
Binary file not shown.
30
outside/antlr3-antlr-3.5/.gitignore
vendored
Normal file
30
outside/antlr3-antlr-3.5/.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# Maven build folders
|
||||
target/
|
||||
|
||||
# IntelliJ project files
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# Eclipse project files
|
||||
.project
|
||||
.classpath
|
||||
.settings/
|
||||
|
||||
# NetBeans user configuration
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
|
||||
# Python runtime files
|
||||
*.py[co]
|
||||
|
||||
# ANTLR C# target build folders
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime/bin/
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime/obj/
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime.Debug/bin/
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime.Debug/obj/
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime.JavaExtensions/bin/
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime.JavaExtensions/obj/
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime.Test/bin/
|
||||
/runtime/CSharp3/Sources/Antlr3.Runtime.Test/obj/
|
6
outside/antlr3-antlr-3.5/BUILD.txt
Normal file
6
outside/antlr3-antlr-3.5/BUILD.txt
Normal file
@ -0,0 +1,6 @@
|
||||
We have moved instructions for building ANTLR with the maven build system to:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/Building+ANTLR+with+Maven
|
||||
|
||||
The notes are by Jim Idle (and are a bit out of date but we hope to
|
||||
update them).
|
142
outside/antlr3-antlr-3.5/README.txt
Normal file
142
outside/antlr3-antlr-3.5/README.txt
Normal file
@ -0,0 +1,142 @@
|
||||
ANTLR v3.5
|
||||
January 4, 2013
|
||||
|
||||
Terence Parr, parrt at cs usfca edu
|
||||
ANTLR project lead and supreme dictator for life
|
||||
University of San Francisco
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
Welcome to ANTLR v3! ANTLR (ANother Tool for Language Recognition) is
|
||||
a language tool that provides a framework for constructing
|
||||
recognizers, interpreters, compilers, and translators from grammatical
|
||||
descriptions containing actions in a variety of target
|
||||
languages. ANTLR provides excellent support for tree construction,
|
||||
tree walking, translation, error recovery, and error reporting. I've
|
||||
been working on parser generators for 25 years and on this particular
|
||||
version of ANTLR for 9 years.
|
||||
|
||||
You should use v3 in conjunction with ANTLRWorks:
|
||||
|
||||
http://www.antlr.org/works/index.html
|
||||
|
||||
and gUnit (grammar unit testing tool included in distribution):
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/gUnit+-+Grammar+Unit+Testing
|
||||
|
||||
The book will also help you a great deal (printed May 15, 2007); you
|
||||
can also buy the PDF:
|
||||
|
||||
http://www.pragmaticprogrammer.com/titles/tpantlr/index.html
|
||||
|
||||
2nd book, Language Implementation Patterns:
|
||||
|
||||
http://pragprog.com/titles/tpdsl/language-implementation-patterns
|
||||
|
||||
See the getting started document:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/FAQ+-+Getting+Started
|
||||
|
||||
You also have the examples plus the source to guide you.
|
||||
|
||||
See the wiki FAQ:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/ANTLR+v3+FAQ
|
||||
|
||||
and general doc root:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/ANTLR+3+Wiki+Home
|
||||
|
||||
Please help add/update FAQ entries.
|
||||
|
||||
If all else fails, you can buy support or ask the antlr-interest list:
|
||||
|
||||
http://www.antlr.org/support.html
|
||||
|
||||
Per the license in LICENSE.txt, this software is not guaranteed to
|
||||
work and might even destroy all life on this planet:
|
||||
|
||||
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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
EXAMPLES
|
||||
|
||||
ANTLR v3 sample grammars:
|
||||
|
||||
https://github.com/antlr/examples-v3
|
||||
|
||||
Examples from Language Implementation Patterns:
|
||||
|
||||
http://www.pragprog.com/titles/tpdsl/source_code
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
What is ANTLR?
|
||||
|
||||
ANTLR stands for (AN)other (T)ool for (L)anguage (R)ecognition
|
||||
and generates LL(*) recursive-descent parsers. ANTLR is a language tool
|
||||
that provides a framework for constructing recognizers, compilers, and
|
||||
translators from grammatical descriptions containing actions.
|
||||
Target language list:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/Code+Generation+Targets
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
How is ANTLR v3 different than ANTLR v2?
|
||||
|
||||
See "What is the difference between ANTLR v2 and v3?"
|
||||
|
||||
http://www.antlr.org/wiki/pages/viewpage.action?pageId=719
|
||||
|
||||
See migration guide:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/Migrating+from+ANTLR+2+to+ANTLR+3
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
How do I install this damn thing?
|
||||
|
||||
You will have grabbed either of these:
|
||||
|
||||
http://antlr.org/download/antlr-3.5-complete-no-antlrv2.jar
|
||||
http://antlr.org/download/antlr-3.5-complete.jar
|
||||
|
||||
It has all of the jars you need combined into one. Then you need to
|
||||
add antlr-3.5-complete.jar to your CLASSPATH or add to arg list; e.g., on unix:
|
||||
|
||||
$ java -cp "/usr/local/lib/antlr-3.5-complete.jar:$CLASSPATH" org.antlr.Tool Test.g
|
||||
|
||||
Source + java binaries: Just untar antlr-3.5.tar.gz and you'll get:
|
||||
|
||||
antlr-3.5/BUILD.txt
|
||||
antlr-3.5/antlr3-maven-plugin
|
||||
antlr-3.5/antlrjar.xml
|
||||
antlr-3.5/antlrsources.xml
|
||||
antlr-3.5/gunit
|
||||
antlr-3.5/gunit-maven-plugin
|
||||
antlr-3.5/pom.xml
|
||||
antlr-3.5/runtime
|
||||
antlr-3.5/tool
|
||||
antlr-3.5/lib
|
||||
|
||||
Please see the FAQ
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/ANTLR+v3+FAQ
|
||||
|
||||
-------------------------
|
||||
|
||||
How can I contribute to ANTLR v3?
|
||||
|
||||
http://www.antlr.org/wiki/pages/viewpage.action?pageId=33947666
|
@ -0,0 +1,61 @@
|
||||
Changes:
|
||||
|
||||
19.08.2008
|
||||
Dependency check for composed grammars added.
|
||||
Might need some further improvements.
|
||||
|
||||
09.08.2008
|
||||
Inspecting environment variable ANTLR_HOME to detect and add
|
||||
antlr- and stringtemplate libraries to the classpath
|
||||
|
||||
09.08.2008
|
||||
Removed routine checkGenerateFile. It got feeble with the
|
||||
introduction of composed grammars, e.g. "import T.g".
|
||||
From now one it is always antlr itself via the depend option
|
||||
which decides about dependecies
|
||||
|
||||
31.12.2007
|
||||
With option "depend=true" proceed even if first pass failed so
|
||||
that ANTLR can spit out its errors
|
||||
|
||||
31.12.2007
|
||||
Support the -Xconversiontimeout option (Jim Idle)
|
||||
|
||||
21.10.2007
|
||||
Evaluation of dependencies via ANTLRs 'depend' option.
|
||||
Added noprune and nocollapse option.
|
||||
'grammar parser' will be recognized.
|
||||
|
||||
17.05.2007
|
||||
Adapted the grammar type recognition to the changed naming conventions for tree parsers.
|
||||
Compiled the antlr3 taks with -source 5 -target 5 for compatibility with Java 5.
|
||||
Dropped trace, tracelexer and traceparser options as they are not supported by antlr any more.
|
||||
Added depend and dbgST options.
|
||||
Added project "SimpleTreeWalker" as an example for a multi grammar project.
|
||||
|
||||
How to build the antlr3 task:
|
||||
|
||||
Prerequisites:
|
||||
1) apache-ant-1.7.0 installed
|
||||
2) antlr jar files (antlr-3.1b1.jar, antlr-2.7.7.jar and stringtemplate-3.1b1.jar)
|
||||
contained in the CLASSPATH environment variable
|
||||
3) Java 5 or Java 6 installed
|
||||
|
||||
javac -source 5 -target 5 -classpath C:/Programme/apache-ant-1.7.0/lib/ant.jar org/apache/tools/ant/antlr/ANTLR3.java
|
||||
jar cvf antlr3.jar org/apache/tools/ant/antlr/antlib.xml org/apache/tools/ant/antlr/ANTLR3.class
|
||||
|
||||
a) d2u.tp
|
||||
|
||||
Simple example on how to use the antlr3 task with ant
|
||||
|
||||
b) simplecTreeParser.tp
|
||||
|
||||
Example on how to build a multi grammar project with ant.
|
||||
|
||||
c) polydiff_build.zip
|
||||
|
||||
Example build file for polydiff example grammar added.
|
||||
|
||||
d) composite-java_build.zip
|
||||
|
||||
Example build file for composite-java example grammar added
|
@ -0,0 +1,776 @@
|
||||
/*
|
||||
* Copyright 2000-2004 The Apache Software Foundation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 2006-12-29: Modified to work for antlr3 by Jürgen Pfundt
|
||||
* 2007-01-04: Some minor correction after checking code with findBugs tool
|
||||
* 2007-02-10: Adapted the grammar type recognition to the changed naming
|
||||
* conventions for Tree Parser
|
||||
* 2007-10-17: Options "trace", "traceLexer", "traceParser" and "glib" emit
|
||||
* warnings when being used.
|
||||
* Added recognition of "parser grammar T".
|
||||
* Added options "nocollapse", "noprune".
|
||||
* ANTLR option "depend" is being used to resolve build dependencies.
|
||||
* 2007-11-15: Embedded Classpath statement had not been observed
|
||||
* with option depend="true" (Reported by Mats Behre)
|
||||
* 2008-03-31: Support the option conversiontimeout. (Jim Idle)
|
||||
* 2007-12-31: With option "depend=true" proceed even if first pass failed so
|
||||
* that ANTLR can spit out its errors
|
||||
* 2008-08-09: Inspecting environment variable ANTLR_HOME to detect and add
|
||||
* antlr- and stringtemplate libraries to the classpath
|
||||
* 2008-08-09: Removed routine checkGenerateFile. It got feeble with the
|
||||
* introduction of composed grammars, e.g. "import T.g" and after
|
||||
* a short struggle it started it's journey to /dev/null.
|
||||
* From now one it is always antlr itself via the depend option
|
||||
* which decides about dependecies
|
||||
* 2008-08-19: Dependency check for composed grammars added.
|
||||
* Might need some further improvements.
|
||||
*/
|
||||
package org.apache.tools.ant.antlr;
|
||||
|
||||
import java.util.regex.*;
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.apache.tools.ant.taskdefs.Execute;
|
||||
import org.apache.tools.ant.taskdefs.LogOutputStream;
|
||||
import org.apache.tools.ant.taskdefs.PumpStreamHandler;
|
||||
import org.apache.tools.ant.taskdefs.Redirector;
|
||||
import org.apache.tools.ant.types.Commandline;
|
||||
import org.apache.tools.ant.types.CommandlineJava;
|
||||
import org.apache.tools.ant.types.Path;
|
||||
import org.apache.tools.ant.util.JavaEnvUtils;
|
||||
import org.apache.tools.ant.util.LoaderUtils;
|
||||
import org.apache.tools.ant.util.TeeOutputStream;
|
||||
import org.apache.tools.ant.util.FileUtils;
|
||||
|
||||
/**
|
||||
* Invokes the ANTLR3 Translator generator on a grammar file.
|
||||
*
|
||||
*/
|
||||
public class ANTLR3 extends Task {
|
||||
|
||||
private CommandlineJava commandline = new CommandlineJava();
|
||||
/** the file to process */
|
||||
private File target = null;
|
||||
/** where to output the result */
|
||||
private File outputDirectory = null;
|
||||
/** location of token files */
|
||||
private File libDirectory = null;
|
||||
/** an optional super grammar file */
|
||||
private File superGrammar;
|
||||
/** depend */
|
||||
private boolean depend = false;
|
||||
/** fork */
|
||||
private boolean fork;
|
||||
/** name of output style for messages */
|
||||
private String messageFormatName;
|
||||
/** optional flag to print out a diagnostic file */
|
||||
private boolean diagnostic;
|
||||
/** optional flag to add methods */
|
||||
private boolean trace;
|
||||
/** optional flag to add trace methods to the parser only */
|
||||
private boolean traceParser;
|
||||
/** optional flag to add trace methods to the lexer only */
|
||||
private boolean traceLexer;
|
||||
/** working directory */
|
||||
private File workingdir = null;
|
||||
/** captures ANTLR's output */
|
||||
private ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
/** The debug attribute */
|
||||
private boolean debug;
|
||||
/** The report attribute */
|
||||
private boolean report;
|
||||
/** The print attribute */
|
||||
private boolean print;
|
||||
/** The profile attribute */
|
||||
private boolean profile;
|
||||
/** The nfa attribute */
|
||||
private boolean nfa;
|
||||
/** The dfa attribute */
|
||||
private boolean dfa;
|
||||
/** multi threaded analysis */
|
||||
private boolean multiThreaded;
|
||||
/** collapse incident edges into DFA states */
|
||||
private boolean nocollapse;
|
||||
/** test lookahead against EBNF block exit branches */
|
||||
private boolean noprune;
|
||||
/** put tags at start/stop of all templates in output */
|
||||
private boolean dbgST;
|
||||
/** print AST */
|
||||
private boolean grammarTree;
|
||||
/** Instance of a utility class to use for file operations. */
|
||||
private FileUtils fileUtils;
|
||||
/**
|
||||
* Whether to override the default conversion timeout with -Xconversiontimeout nnnn
|
||||
*/
|
||||
private String conversiontimeout;
|
||||
|
||||
public ANTLR3() {
|
||||
commandline.setVm(JavaEnvUtils.getJreExecutable("java"));
|
||||
commandline.setClassname("org.antlr.Tool");
|
||||
fileUtils = FileUtils.getFileUtils();
|
||||
}
|
||||
|
||||
/**
|
||||
* The grammar file to process.
|
||||
*/
|
||||
public void setTarget(File targetFile) {
|
||||
log("Setting target to: " + targetFile.toString(), Project.MSG_VERBOSE);
|
||||
this.target = targetFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* The directory to write the generated files to.
|
||||
*/
|
||||
public void setOutputdirectory(File outputDirectoryFile) {
|
||||
log("Setting output directory to: " + outputDirectoryFile.toString(), Project.MSG_VERBOSE);
|
||||
this.outputDirectory = outputDirectoryFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* The directory to write the generated files to.
|
||||
*/
|
||||
public File getOutputdirectory() {
|
||||
return outputDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The token files output directory.
|
||||
*/
|
||||
public void setLibdirectory(File libDirectoryFile) {
|
||||
log("Setting lib directory to: " + libDirectoryFile.toString(), Project.MSG_VERBOSE);
|
||||
this.libDirectory = libDirectoryFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* The output style for messages.
|
||||
*/
|
||||
public void setMessageformat(String name) {
|
||||
log("Setting message-format to: " + name, Project.MSG_VERBOSE);
|
||||
this.messageFormatName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an optional super grammar file
|
||||
* @deprecated
|
||||
*/
|
||||
public void setGlib(File superGrammarFile) {
|
||||
this.superGrammar = superGrammarFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to enable ParseView debugging
|
||||
*/
|
||||
public void setDebug(boolean enable) {
|
||||
this.debug = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to enable report statistics
|
||||
*/
|
||||
public void setReport(boolean enable) {
|
||||
this.report = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to print out the grammar without actions
|
||||
*/
|
||||
public void setPrint(boolean enable) {
|
||||
this.print = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to enable profiling
|
||||
*/
|
||||
public void setProfile(boolean enable) {
|
||||
this.profile = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to enable nfa generation
|
||||
*/
|
||||
public void setNfa(boolean enable) {
|
||||
this.nfa = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to enable nfa generation
|
||||
*/
|
||||
public void setDfa(boolean enable) {
|
||||
this.dfa = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the analysis multithreaded
|
||||
* @param enable
|
||||
*/
|
||||
public void setMultithreaded(boolean enable) {
|
||||
multiThreaded = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* collapse incident edges into DFA states
|
||||
* @param enable
|
||||
*/
|
||||
public void setNocollapse(boolean enable) {
|
||||
nocollapse = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* test lookahead against EBNF block exit branches
|
||||
* @param enable
|
||||
*/
|
||||
public void setNoprune(boolean enable) {
|
||||
noprune = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* test lookahead against EBNF block exit branches
|
||||
* @param enable
|
||||
*/
|
||||
public void setDbgST(boolean enable) {
|
||||
dbgST = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* override the default conversion timeout with -Xconversiontimeout nnnn
|
||||
* @param conversiontimeoutString
|
||||
*/
|
||||
public void setConversiontimeout(String conversiontimeoutString) {
|
||||
log("Setting conversiontimeout to: " + conversiontimeoutString, Project.MSG_VERBOSE);
|
||||
try {
|
||||
int timeout = Integer.valueOf(conversiontimeoutString);
|
||||
this.conversiontimeout = conversiontimeoutString;
|
||||
} catch (NumberFormatException e) {
|
||||
log("Option ConversionTimeOut ignored due to illegal value: '" + conversiontimeoutString + "'", Project.MSG_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a flag to enable printing of the grammar tree
|
||||
*/
|
||||
public void setGrammartree(boolean enable) {
|
||||
grammarTree = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a flag to enable dependency checking by ANTLR itself
|
||||
* The depend option is always used implicitely inside the antlr3 task
|
||||
* @deprecated
|
||||
*/
|
||||
public void setDepend(boolean s) {
|
||||
this.depend = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to emit diagnostic text
|
||||
*/
|
||||
public void setDiagnostic(boolean enable) {
|
||||
diagnostic = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, enables all tracing.
|
||||
* @deprecated
|
||||
*/
|
||||
public void setTrace(boolean enable) {
|
||||
trace = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, enables parser tracing.
|
||||
* @deprecated
|
||||
*/
|
||||
public void setTraceParser(boolean enable) {
|
||||
traceParser = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, enables lexer tracing.
|
||||
* @deprecated
|
||||
*/
|
||||
public void setTraceLexer(boolean enable) {
|
||||
traceLexer = enable;
|
||||
}
|
||||
|
||||
// we are forced to fork ANTLR since there is a call
|
||||
// to System.exit() and there is nothing we can do
|
||||
// right now to avoid this. :-( (SBa)
|
||||
// I'm not removing this method to keep backward compatibility
|
||||
/**
|
||||
* @ant.attribute ignore="true"
|
||||
*/
|
||||
public void setFork(boolean s) {
|
||||
this.fork = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* The working directory of the process
|
||||
*/
|
||||
public void setDir(File d) {
|
||||
this.workingdir = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a classpath to be set
|
||||
* because a directory might be given for Antlr debug.
|
||||
*/
|
||||
public Path createClasspath() {
|
||||
return commandline.createClasspath(getProject()).createPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new JVM argument.
|
||||
* @return create a new JVM argument so that any argument can be passed to the JVM.
|
||||
* @see #setFork(boolean)
|
||||
*/
|
||||
public Commandline.Argument createJvmarg() {
|
||||
return commandline.createVmArgument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the jars or directories containing Antlr and associates.
|
||||
* This should make the forked JVM work without having to
|
||||
* specify it directly.
|
||||
*/
|
||||
@Override
|
||||
public void init() throws BuildException {
|
||||
/* Inquire environment variables */
|
||||
Map<String, String> variables = System.getenv();
|
||||
/* Get value for key "ANTLR_HOME" which should hopefully point to
|
||||
* the directory where the current version of antlr3 is installed */
|
||||
String antlrHome = variables.get("ANTLR_HOME");
|
||||
if (antlrHome != null) {
|
||||
/* Environment variable ANTLR_HOME has been defined.
|
||||
* Now add all antlr and stringtemplate libraries to the
|
||||
* classpath */
|
||||
addAntlrJarsToClasspath(antlrHome + "/lib");
|
||||
}
|
||||
addClasspathEntry("/antlr/ANTLRGrammarParseBehavior.class", "AntLR2");
|
||||
addClasspathEntry("/org/antlr/tool/ANTLRParser.class", "AntLR3");
|
||||
addClasspathEntry("/org/antlr/stringtemplate/StringTemplate.class", "Stringtemplate");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the given resource and add the directory or archive
|
||||
* that contains it to the classpath.
|
||||
*
|
||||
* <p>Doesn't work for archives in JDK 1.1 as the URL returned by
|
||||
* getResource doesn't contain the name of the archive.</p>
|
||||
*/
|
||||
protected void addClasspathEntry(String resource, String msg) {
|
||||
/*
|
||||
* pre Ant 1.6 this method used to call getClass().getResource
|
||||
* while Ant 1.6 will call ClassLoader.getResource().
|
||||
*
|
||||
* The difference is that Class.getResource expects a leading
|
||||
* slash for "absolute" resources and will strip it before
|
||||
* delegating to ClassLoader.getResource - so we now have to
|
||||
* emulate Class's behavior.
|
||||
*/
|
||||
if (resource.startsWith("/")) {
|
||||
resource = resource.substring(1);
|
||||
} else {
|
||||
resource = "org/apache/tools/ant/taskdefs/optional/" + resource;
|
||||
}
|
||||
|
||||
File f = LoaderUtils.getResourceSource(getClass().getClassLoader(), resource);
|
||||
if (f != null) {
|
||||
log("Found via classpath: " + f.getAbsolutePath(), Project.MSG_VERBOSE);
|
||||
createClasspath().setLocation(f);
|
||||
} else {
|
||||
log("Couldn\'t find resource " + resource + " for library " + msg + " in external classpath", Project.MSG_VERBOSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the environment variable ANTLR_HOME is defined and points
|
||||
* to the installation directory of antlr3 then look for all antlr-*.jar and
|
||||
* stringtemplate-*.jar files in the lib directory and add them
|
||||
* to the classpath.
|
||||
* This feature should make working with eclipse or netbeans projects a
|
||||
* little bit easier. As wildcards are being used for the version part
|
||||
* of the jar-archives it makes the task independent of
|
||||
* new releases. Just let ANTLR_HOME point to the new installation
|
||||
* directory.
|
||||
*/
|
||||
private void addAntlrJarsToClasspath(String antlrLibDir) {
|
||||
String[] includes = {"antlr-*.jar", "stringtemplate-*.jar"};
|
||||
|
||||
DirectoryScanner ds = new DirectoryScanner();
|
||||
ds.setIncludes(includes);
|
||||
ds.setBasedir(new File(antlrLibDir));
|
||||
ds.setCaseSensitive(true);
|
||||
ds.scan();
|
||||
|
||||
String separator = System.getProperty("file.separator");
|
||||
String[] files = ds.getIncludedFiles();
|
||||
for (String file : files) {
|
||||
File f = new File(antlrLibDir + separator + file);
|
||||
log("Found via ANTLR_HOME: " + f.getAbsolutePath(), Project.MSG_VERBOSE);
|
||||
createClasspath().setLocation(f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
|
||||
validateAttributes();
|
||||
|
||||
// Use ANTLR itself to resolve dependencies and decide whether
|
||||
// to invoke ANTLR for compilation
|
||||
if (dependencyCheck()) {
|
||||
populateAttributes();
|
||||
commandline.createArgument().setValue(target.toString());
|
||||
|
||||
log(commandline.describeCommand(), Project.MSG_VERBOSE);
|
||||
int err = 0;
|
||||
try {
|
||||
err = run(commandline.getCommandline(), new LogOutputStream(this, Project.MSG_INFO), new LogOutputStream(this, Project.MSG_WARN));
|
||||
} catch (IOException e) {
|
||||
throw new BuildException(e, getLocation());
|
||||
} finally {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
throw new BuildException("ANTLR returned: " + err, getLocation());
|
||||
} else {
|
||||
Pattern p = Pattern.compile("error\\([0-9]+\\):");
|
||||
Matcher m = p.matcher(bos.toString());
|
||||
if (m.find()) {
|
||||
throw new BuildException("ANTLR signaled an error.", getLocation());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
log("All dependencies of grammar file \'" + target.getCanonicalPath() + "\' are up to date.", Project.MSG_VERBOSE);
|
||||
} catch (IOException ex) {
|
||||
log("All dependencies of grammar file \'" + target.toString() + "\' are up to date.", Project.MSG_VERBOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A refactored method for populating all the command line arguments based
|
||||
* on the user-specified attributes.
|
||||
*/
|
||||
private void populateAttributes() {
|
||||
|
||||
commandline.createArgument().setValue("-o");
|
||||
commandline.createArgument().setValue(outputDirectory.toString());
|
||||
|
||||
commandline.createArgument().setValue("-lib");
|
||||
commandline.createArgument().setValue(libDirectory.toString());
|
||||
|
||||
if (superGrammar != null) {
|
||||
log("Option 'glib' is not supported by ANTLR v3. Option ignored!", Project.MSG_WARN);
|
||||
}
|
||||
|
||||
if (diagnostic) {
|
||||
commandline.createArgument().setValue("-diagnostic");
|
||||
}
|
||||
if (depend) {
|
||||
log("Option 'depend' is implicitely always used by ANTLR v3. Option can safely be omitted!", Project.MSG_WARN);
|
||||
}
|
||||
if (trace) {
|
||||
log("Option 'trace' is not supported by ANTLR v3. Option ignored!", Project.MSG_WARN);
|
||||
}
|
||||
if (traceParser) {
|
||||
log("Option 'traceParser' is not supported by ANTLR v3. Option ignored!", Project.MSG_WARN);
|
||||
}
|
||||
if (traceLexer) {
|
||||
log("Option 'traceLexer' is not supported by ANTLR v3. Option ignored!", Project.MSG_WARN);
|
||||
}
|
||||
if (debug) {
|
||||
commandline.createArgument().setValue("-debug");
|
||||
}
|
||||
if (report) {
|
||||
commandline.createArgument().setValue("-report");
|
||||
}
|
||||
if (print) {
|
||||
commandline.createArgument().setValue("-print");
|
||||
}
|
||||
if (profile) {
|
||||
commandline.createArgument().setValue("-profile");
|
||||
}
|
||||
if (messageFormatName != null) {
|
||||
commandline.createArgument().setValue("-message-format");
|
||||
commandline.createArgument().setValue(messageFormatName);
|
||||
}
|
||||
if (nfa) {
|
||||
commandline.createArgument().setValue("-nfa");
|
||||
}
|
||||
if (dfa) {
|
||||
commandline.createArgument().setValue("-dfa");
|
||||
}
|
||||
if (multiThreaded) {
|
||||
commandline.createArgument().setValue("-Xmultithreaded");
|
||||
}
|
||||
if (nocollapse) {
|
||||
commandline.createArgument().setValue("-Xnocollapse");
|
||||
}
|
||||
if (noprune) {
|
||||
commandline.createArgument().setValue("-Xnoprune");
|
||||
}
|
||||
if (dbgST) {
|
||||
commandline.createArgument().setValue("-XdbgST");
|
||||
}
|
||||
if (conversiontimeout != null) {
|
||||
commandline.createArgument().setValue("-Xconversiontimeout");
|
||||
commandline.createArgument().setValue(conversiontimeout);
|
||||
}
|
||||
if (grammarTree) {
|
||||
commandline.createArgument().setValue("-Xgrtree");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateAttributes() throws BuildException {
|
||||
|
||||
if (target == null) {
|
||||
throw new BuildException("No target grammar, lexer grammar or tree parser specified!");
|
||||
} else if (!target.isFile()) {
|
||||
throw new BuildException("Target: " + target + " is not a file!");
|
||||
}
|
||||
|
||||
// if no output directory is specified, use the target's directory
|
||||
if (outputDirectory == null) {
|
||||
setOutputdirectory(new File(target.getParent()));
|
||||
}
|
||||
|
||||
if (!outputDirectory.isDirectory()) {
|
||||
throw new BuildException("Invalid output directory: " + outputDirectory);
|
||||
}
|
||||
|
||||
if (workingdir != null && !workingdir.isDirectory()) {
|
||||
throw new BuildException("Invalid working directory: " + workingdir);
|
||||
}
|
||||
|
||||
// if no libDirectory is specified, use the target's directory
|
||||
if (libDirectory == null) {
|
||||
setLibdirectory(new File(target.getParent()));
|
||||
}
|
||||
|
||||
if (!libDirectory.isDirectory()) {
|
||||
throw new BuildException("Invalid lib directory: " + libDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean dependencyCheck() throws BuildException {
|
||||
// using "antlr -o <OutputDirectory> -lib <LibDirectory> -depend <T>"
|
||||
// to get the list of dependencies
|
||||
CommandlineJava cmdline;
|
||||
try {
|
||||
cmdline = (CommandlineJava) commandline.clone();
|
||||
} catch (java.lang.CloneNotSupportedException e) {
|
||||
throw new BuildException("Clone of commandline failed: " + e);
|
||||
}
|
||||
|
||||
cmdline.createArgument().setValue("-depend");
|
||||
cmdline.createArgument().setValue("-o");
|
||||
cmdline.createArgument().setValue(outputDirectory.toString());
|
||||
cmdline.createArgument().setValue("-lib");
|
||||
cmdline.createArgument().setValue(libDirectory.toString());
|
||||
cmdline.createArgument().setValue(target.toString());
|
||||
|
||||
log(cmdline.describeCommand(), Project.MSG_VERBOSE);
|
||||
|
||||
// redirect output generated by ANTLR to temporary file
|
||||
Redirector r = new Redirector(this);
|
||||
File f;
|
||||
try {
|
||||
f = File.createTempFile("depend", null, getOutputdirectory());
|
||||
f.deleteOnExit();
|
||||
log("Write dependencies for '" + target.toString() + "' to file '" + f.getCanonicalPath() + "'", Project.MSG_VERBOSE);
|
||||
r.setOutput(f);
|
||||
r.setAlwaysLog(false);
|
||||
r.createStreams();
|
||||
} catch (IOException e) {
|
||||
throw new BuildException("Redirection of output failed: " + e);
|
||||
}
|
||||
|
||||
// execute antlr -depend ...
|
||||
int err = 0;
|
||||
try {
|
||||
err = run(cmdline.getCommandline(), r.getOutputStream(), null);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
r.complete();
|
||||
log("Redirection of output terminated.", Project.MSG_VERBOSE);
|
||||
} catch (IOException ex) {
|
||||
log("Termination of output redirection failed: " + ex, Project.MSG_ERR);
|
||||
}
|
||||
throw new BuildException(e, getLocation());
|
||||
} finally {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
r.complete();
|
||||
log("Redirection of output terminated.", Project.MSG_VERBOSE);
|
||||
} catch (IOException e) {
|
||||
log("Termination of output redirection failed: " + e, Project.MSG_ERR);
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
if (f.exists()) {
|
||||
f.delete();
|
||||
}
|
||||
if (cmdline.getClasspath() == null) {
|
||||
log("Antlr libraries not found in external classpath or embedded classpath statement ", Project.MSG_ERR);
|
||||
}
|
||||
log("Dependency check failed. ANTLR returned: " + err, Project.MSG_ERR);
|
||||
return true;
|
||||
} else {
|
||||
Pattern p = Pattern.compile("error\\([0-9]+\\):");
|
||||
Matcher m = p.matcher(bos.toString());
|
||||
if (m.find()) {
|
||||
if (f.exists()) {
|
||||
f.delete();
|
||||
}
|
||||
// On error always recompile
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean compile = false;
|
||||
|
||||
// open temporary file
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
in = new BufferedReader(new FileReader(f));
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new BuildException("Could not close file\'" + f.toString() + "\'.");
|
||||
}
|
||||
if (f.exists()) {
|
||||
f.delete();
|
||||
}
|
||||
try {
|
||||
throw new BuildException("Could not open \'" + f.getCanonicalPath() + "\' for reading.");
|
||||
} catch (IOException ex) {
|
||||
throw new BuildException("Could not open \'" + f.toString() + "\' for reading.");
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate dependencies in temporary file
|
||||
String s;
|
||||
|
||||
try {
|
||||
while ((s = in.readLine()) != null) {
|
||||
String a;
|
||||
String b;
|
||||
// As the separator string in lines emitted by the depend option
|
||||
// is either " : " or ": " trim is invoked for the first file name of a line
|
||||
int to = s.indexOf(": ");
|
||||
if (to >= 0) {
|
||||
a = s.substring(0, to).trim();
|
||||
File lhs = new File(a);
|
||||
if (!lhs.isFile()) {
|
||||
log("File '" + a + "' is not a regular file", Project.MSG_VERBOSE);
|
||||
String name = lhs.getName();
|
||||
String[] parts = splitRightHandSide(name, "\\u002E");
|
||||
if (parts.length <= 1) {
|
||||
a += ".java";
|
||||
lhs = new File(a);
|
||||
if (lhs.isFile()) {
|
||||
log("File '" + a + "' is a regular file last modified at " + lhs.lastModified(), Project.MSG_VERBOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b = s.substring(to + ": ".length());
|
||||
String[] names = splitRightHandSide(b, ", ?");
|
||||
File aFile = new File(a);
|
||||
for (String name : names) {
|
||||
File bFile = new File(name);
|
||||
log("File '" + a + "' depends on file '" + name + "'", Project.MSG_VERBOSE);
|
||||
log("File '" + a + "' modified at " + aFile.lastModified(), Project.MSG_VERBOSE);
|
||||
log("File '" + name + "' modified at " + bFile.lastModified(), Project.MSG_VERBOSE);
|
||||
if (fileUtils.isUpToDate(aFile, bFile)) {
|
||||
log("Compiling " + target + " as '" + name + "' is newer than '" + a + "'", Project.MSG_VERBOSE);
|
||||
// Feeling not quite comfortable with touching the file
|
||||
fileUtils.setFileLastModified(aFile, -1);
|
||||
log("Touching file '" + a + "'", Project.MSG_VERBOSE);
|
||||
compile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (compile) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
if (f.exists()) {
|
||||
f.delete();
|
||||
}
|
||||
throw new BuildException("Error reading file '" + f.toString() + "'");
|
||||
}
|
||||
|
||||
if (f.exists()) {
|
||||
f.delete();
|
||||
}
|
||||
|
||||
return compile;
|
||||
}
|
||||
|
||||
private String[] splitRightHandSide(String fileNames, String pattern) {
|
||||
String[] names = fileNames.split(pattern);
|
||||
for (String name : names) {
|
||||
log("Split right hand side '" + name + "'", Project.MSG_VERBOSE);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/** execute in a forked VM */
|
||||
private int run(String[] command, OutputStream out, OutputStream err) throws IOException {
|
||||
PumpStreamHandler psh;
|
||||
if (err == null) {
|
||||
psh = new PumpStreamHandler(out, bos);
|
||||
} else {
|
||||
psh = new PumpStreamHandler(out, new TeeOutputStream(err, bos));
|
||||
}
|
||||
|
||||
Execute exe = new Execute(psh, null);
|
||||
|
||||
exe.setAntRun(getProject());
|
||||
if (workingdir != null) {
|
||||
exe.setWorkingDirectory(workingdir);
|
||||
}
|
||||
|
||||
exe.setCommandline(command);
|
||||
|
||||
return exe.execute();
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<antlib>
|
||||
<taskdef
|
||||
name="antlr3"
|
||||
classname="org.apache.tools.ant.antlr.ANTLR3"
|
||||
/>
|
||||
</antlib>
|
Binary file not shown.
1957
outside/antlr3-antlr-3.5/antlr-ant/main/antlr3-task/antlr3-task.htm
Normal file
1957
outside/antlr3-antlr-3.5/antlr-ant/main/antlr3-task/antlr3-task.htm
Normal file
File diff suppressed because it is too large
Load Diff
BIN
outside/antlr3-antlr-3.5/antlr-ant/main/antlr3-task/antlr3.jar
Normal file
BIN
outside/antlr3-antlr-3.5/antlr-ant/main/antlr3-task/antlr3.jar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
outside/antlr3-antlr-3.5/antlr-ant/main/antlr3-task/d2u.zip
Normal file
BIN
outside/antlr3-antlr-3.5/antlr-ant/main/antlr3-task/d2u.zip
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
144
outside/antlr3-antlr-3.5/antlr-complete/pom.xml
Normal file
144
outside/antlr3-antlr-3.5/antlr-complete/pom.xml
Normal file
@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>antlr-complete</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ANTLR 3 Complete</name>
|
||||
<description>Complete distribution for ANTLR 3</description>
|
||||
|
||||
<!--
|
||||
|
||||
Inherit from the ANTLR master pom, which tells us what
|
||||
version we are and allows us to inherit dependencies
|
||||
and so on.
|
||||
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-master</artifactId>
|
||||
<version>3.5</version>
|
||||
</parent>
|
||||
|
||||
<url>http://antlr.org/</url>
|
||||
|
||||
<!--
|
||||
The complete distribution includes the following modules and their dependencies:
|
||||
ANTLR 3 Tool
|
||||
ANTLR 3 Runtime
|
||||
gUnit for ANTLR 3
|
||||
StringTemplate 4 (dependency of code generator in the ANTLR 3 Tool)
|
||||
StringTemplate 3 (dependency of grammars with output=template)
|
||||
ANTLR 2.7.7 (dependency of template parser in StringTemplate 3)
|
||||
-->
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-runtime</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>gunit</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr3-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration></configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>antlr</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
<configuration>
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<createSourcesJar>true</createSourcesJar>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>org.antlr:antlr-complete</artifact>
|
||||
<includes>
|
||||
<include>META-INF/**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
</filters>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.antlr.Tool</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>complete-no-st3</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||
<shadedClassifierName>no-st3</shadedClassifierName>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>antlr:antlr</artifact>
|
||||
<excludes>
|
||||
<exclude>**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.antlr:stringtemplate</artifact>
|
||||
<excludes>
|
||||
<exclude>**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>complete</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
</project>
|
0
outside/antlr3-antlr-3.5/antlr.config
Normal file
0
outside/antlr3-antlr-3.5/antlr.config
Normal file
50
outside/antlr3-antlr-3.5/antlr3-maven-archetype/pom.xml
Normal file
50
outside/antlr3-antlr-3.5/antlr3-maven-archetype/pom.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr3-maven-archetype</artifactId>
|
||||
<packaging>maven-archetype</packaging>
|
||||
<name>ANTLR 3 Maven Archetype</name>
|
||||
<description>ANTLR 3 Maven Archetype</description>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
Inherit from the ANTLR master pom, which tells us what
|
||||
version we are and allows us to inherit dependencies
|
||||
and so on.
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-master</artifactId>
|
||||
<version>3.5</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
<extensions>
|
||||
|
||||
<extension>
|
||||
<groupId>org.apache.maven.archetype</groupId>
|
||||
<artifactId>archetype-packaging</artifactId>
|
||||
<version>2.2</version>
|
||||
</extension>
|
||||
|
||||
</extensions>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-archetype-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><archetype-descriptor name="antlr3-maven-archetype">
|
||||
<fileSets>
|
||||
<fileSet filtered="true" packaged="true" encoding="UTF-8">
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.java</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet filtered="true" packaged="true" encoding="UTF-8">
|
||||
<directory>src/main/antlr3</directory>
|
||||
<includes>
|
||||
<include>**/*.g</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/imports/*.*</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
<fileSet filtered="true" encoding="UTF-8">
|
||||
<directory>src/main/antlr3/imports</directory>
|
||||
<includes>
|
||||
<include>**/*.g</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</archetype-descriptor>
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archetype>
|
||||
<id>antlr3-maven-archetype</id>
|
||||
<sources>
|
||||
<source>src\main\java\org\antlr\demo\AbstractTLexer.java</source>
|
||||
<source>src\main\java\org\antlr\demo\AbstractTParser.java</source>
|
||||
<source>src\main\java\org\antlr\demo\Main.java</source>
|
||||
</sources>
|
||||
<resources>
|
||||
<resource>src\main\antlr3\imports\Ruleb.g</resource>
|
||||
<resource>src\main\antlr3\TLexer.g</resource>
|
||||
<resource>src\main\antlr3\TParser.g</resource>
|
||||
<resource>src\main\antlr3\TTree.g</resource>
|
||||
</resources>
|
||||
</archetype>
|
@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
|
||||
<!-- =======================================================================
|
||||
A quickstart pom.xml that creates a sample project that uses ANTLR 3.x
|
||||
grammars. You should replace the sample grammars in src/main/antlr3
|
||||
with your own grammar files and use packages.
|
||||
|
||||
A .g file in
|
||||
|
||||
src/main/antlr3/com/temporalwave
|
||||
|
||||
belongs in the package
|
||||
|
||||
com.temporalwave
|
||||
|
||||
See http://antlr.org/antlr3-maven-plugin for more details.
|
||||
|
||||
This project produces both a jar file of the project and an executeable
|
||||
jar file that contains all the dependencies so you can run it standalone.
|
||||
See below for more details.
|
||||
|
||||
Archetype by Jim Idle (jimi@temporal-wave.com) - Oct 2009
|
||||
Report bugs to the ANTLR interest list at http://www.antlr.org
|
||||
|
||||
Generated by antlr3-maven-archetype version 3.4.1-SNAPSHOT
|
||||
=======================================================================
|
||||
-->
|
||||
|
||||
<!-- This is your organizations normal group name
|
||||
such as org.antlr
|
||||
All the artifacts you create will be under this
|
||||
group id.
|
||||
-->
|
||||
<groupId>${groupId}</groupId>
|
||||
|
||||
<!-- This is how maven knows your artifact
|
||||
-->
|
||||
<artifactId>${artifactId}</artifactId>
|
||||
|
||||
<!-- This is the human oriented name for the package
|
||||
so you can call it anything you like
|
||||
-->
|
||||
<name>ANTLR3 project: ${package}</name>
|
||||
|
||||
<!-- This is the version of YOUR project -->
|
||||
<version>${version}</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
<url>http://antlr.org</url>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--
|
||||
We need to have the ANTLR runtime jar when running and compiling.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-runtime</artifactId>
|
||||
<version>3.4.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<!--
|
||||
|
||||
Tell Maven which other artifacts we need in order to
|
||||
build with the ANTLR Tool. Here we also make the default
|
||||
goal be install so that you can just type mvn at the command
|
||||
line instead of mvn install. And we add the java compiler plugin
|
||||
for convenience to show how you can use 1.6 source files but
|
||||
generate 1.4 compatible .class files (as few people seem to
|
||||
know about the jsr14 target).
|
||||
-->
|
||||
<build>
|
||||
|
||||
<defaultGoal>install</defaultGoal>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr3-maven-plugin</artifactId>
|
||||
<version>3.4.1-SNAPSHOT</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>antlr</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
Strictly speaking, we did not need to generate this for you from
|
||||
the prototype, but we use it to illustrate how you can get
|
||||
the JDK 6 Java compiler to accept 1.5 or 1.6 targeted source code
|
||||
but produce class files that are compatible with JRE 1.4. As
|
||||
Michael Caine might say, "Not a lot of people know that!"
|
||||
-->
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>jsr14</target>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
|
||||
<!--
|
||||
|
||||
Build an uber-jar that is packaged with all the other dependencies,
|
||||
such as the antlr-runtime and so on. This will be useful
|
||||
for developers, who then do not need to download anything else or
|
||||
remember that they need antlr.jar in their CLASSPATH and so
|
||||
on.
|
||||
|
||||
You can delete this plugin of course and you will then
|
||||
get a jar file with only the code generated and included
|
||||
directly in this project. With this plugin though you will
|
||||
find that when you build with:
|
||||
|
||||
mvn install
|
||||
|
||||
There will be an executable jar generated. You can run this
|
||||
as:
|
||||
|
||||
java -jar ${artifactId}-${version}-jar-with-dependencies.jar demosource.dmo
|
||||
|
||||
assuming you have a file called demosource.dmo to attempt a parse.
|
||||
|
||||
-->
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<!--
|
||||
|
||||
Specify that we want the resulting jar to be executable
|
||||
via java -jar, which we do by modifying the manifest
|
||||
of course.
|
||||
-->
|
||||
<archive>
|
||||
|
||||
<manifest>
|
||||
<mainClass>${package}.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
|
||||
</configuration>
|
||||
|
||||
<!--
|
||||
|
||||
We don't want to have to specifically ask for the uber jar, so we attach the
|
||||
running of this plugin to the execution of the package life-cycle
|
||||
phase.
|
||||
-->
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>attached</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,80 @@
|
||||
// This is a sample lexer generated by the ANTLR3 Maven Archetype
|
||||
// generator. It shows how to use a superclass to implement
|
||||
// support methods and variables you may use in the lexer actions
|
||||
// rather than create a messy lexer that has the Java code embedded
|
||||
// in it.
|
||||
//
|
||||
|
||||
lexer grammar TLexer;
|
||||
|
||||
options {
|
||||
|
||||
language=Java; // Default
|
||||
|
||||
// Tell ANTLR to make the generated lexer class extend the
|
||||
// the named class, which is where any supporting code and
|
||||
// variables will be placed.
|
||||
//
|
||||
superClass = AbstractTLexer;
|
||||
}
|
||||
|
||||
// What package should the generated source exist in?
|
||||
//
|
||||
@header {
|
||||
|
||||
package ${package};
|
||||
}
|
||||
|
||||
// This is just a simple lexer that matches the usual suspects
|
||||
//
|
||||
|
||||
KEYSER : 'Keyser' ;
|
||||
SOZE : 'Soze' ;
|
||||
|
||||
ADD : '+' ;
|
||||
SEMI: ';' ;
|
||||
|
||||
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
|
||||
;
|
||||
|
||||
INT : '0'..'9'+
|
||||
;
|
||||
|
||||
COMMENT
|
||||
: '//' ~('\n'|'\r')* '\r'? '\n' {skip();}
|
||||
| '/*' ( options {greedy=false;} : . )* '*/' {skip();}
|
||||
;
|
||||
|
||||
WS : ( ' '
|
||||
| '\t'
|
||||
| '\r'
|
||||
| '\n'
|
||||
) {skip();}
|
||||
;
|
||||
|
||||
STRING
|
||||
: '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
|
||||
;
|
||||
|
||||
fragment
|
||||
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
|
||||
|
||||
fragment
|
||||
ESC_SEQ
|
||||
: '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
|
||||
| UNICODE_ESC
|
||||
| OCTAL_ESC
|
||||
;
|
||||
|
||||
fragment
|
||||
OCTAL_ESC
|
||||
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
|
||||
| '\\' ('0'..'7') ('0'..'7')
|
||||
| '\\' ('0'..'7')
|
||||
;
|
||||
|
||||
fragment
|
||||
UNICODE_ESC
|
||||
: '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
|
||||
;
|
||||
|
@ -0,0 +1,74 @@
|
||||
parser grammar TParser;
|
||||
|
||||
options {
|
||||
|
||||
// Default language but name it anyway
|
||||
//
|
||||
language = Java;
|
||||
|
||||
// Produce an AST
|
||||
//
|
||||
output = AST;
|
||||
|
||||
// Use a superclass to implement all helper
|
||||
// methods, instance variables and overrides
|
||||
// of ANTLR default methods, such as error
|
||||
// handling.
|
||||
//
|
||||
superClass = AbstractTParser;
|
||||
|
||||
// Use the vocabulary generated by the accompanying
|
||||
// lexer. Maven knows how to work out the relationship
|
||||
// between the lexer and parser and will build the
|
||||
// lexer before the parser. It will also rebuild the
|
||||
// parser if the lexer changes.
|
||||
//
|
||||
tokenVocab = TLexer;
|
||||
}
|
||||
|
||||
// Import a grammar file, even though it does not really need it in this
|
||||
// simle demo parser. We do the import to show where imported grammars should be
|
||||
// stored for maven builds.
|
||||
//
|
||||
import Ruleb;
|
||||
|
||||
// Some imaginary tokens for tree rewrites
|
||||
//
|
||||
tokens {
|
||||
SCRIPT;
|
||||
}
|
||||
|
||||
// What package should the generated source exist in?
|
||||
//
|
||||
@header {
|
||||
|
||||
package ${package};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// This is just a simple parser for demo purpose
|
||||
//
|
||||
a : b* EOF
|
||||
|
||||
-> ^(SCRIPT b*)
|
||||
;
|
||||
|
||||
|
||||
|
||||
keyser
|
||||
: KEYSER^ SOZE
|
||||
;
|
||||
|
||||
expression
|
||||
: addExpr (ADD^ addExpr)*
|
||||
;
|
||||
|
||||
addExpr
|
||||
: ID
|
||||
| INT
|
||||
| STRING
|
||||
;
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
tree grammar TTree;
|
||||
|
||||
options {
|
||||
|
||||
// Default but name it anyway
|
||||
//
|
||||
language = Java;
|
||||
|
||||
// Use the vocab from the parser (not the lexer)
|
||||
// The ANTLR Maven plugin knows how to work out the
|
||||
// relationships between the .g files and it will build
|
||||
// the tree parser after the parser. It will also rebuild
|
||||
// the tree parser if the parser is rebuilt.
|
||||
//
|
||||
tokenVocab = TParser;
|
||||
|
||||
// Use ANTLR built-in CommonToken for tree nodes
|
||||
//
|
||||
ASTLabelType = CommonToken;
|
||||
}
|
||||
|
||||
// What package should the generated source exist in?
|
||||
//
|
||||
@header {
|
||||
|
||||
package ${package};
|
||||
}
|
||||
|
||||
a : ^(SCRIPT stuff+)
|
||||
| SCRIPT
|
||||
;
|
||||
|
||||
stuff
|
||||
: keyser
|
||||
| expression
|
||||
;
|
||||
|
||||
keyser
|
||||
: ^(KEYSER SOZE)
|
||||
{ System.out.println("Found Keyser Soze!!"); }
|
||||
;
|
||||
|
||||
expression
|
||||
: ^(ADD expression expression)
|
||||
| ID
|
||||
| INT
|
||||
| STRING
|
||||
;
|
||||
|
@ -0,0 +1,11 @@
|
||||
// A single rule in a grammar that must be imported by the demo
|
||||
// parser Tparser.g
|
||||
// This is just here to show that import grammars are stored in their
|
||||
// own imports directory: src/main/antlr3/imports
|
||||
//
|
||||
parser grammar Ruleb;
|
||||
|
||||
b
|
||||
: keyser SEMI!
|
||||
| expression SEMI!
|
||||
;
|
@ -0,0 +1,55 @@
|
||||
#set( $symbol_pound = '#' )
|
||||
#set( $symbol_dollar = '$' )
|
||||
#set( $symbol_escape = '\' )
|
||||
package ${package};
|
||||
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.runtime.Lexer;
|
||||
import org.antlr.runtime.RecognizerSharedState;
|
||||
|
||||
/**
|
||||
|
||||
* This is the super class for the lexer. It is extended by the lexer class
|
||||
* generated from TLexer.g.
|
||||
*
|
||||
* Do not place code and declarations in the lexer .g files, use
|
||||
* a superclass like this and place all the support methods and
|
||||
* error overrides etc in the super class. This way you will keep
|
||||
* the lexer grammar clean and hunky dory.
|
||||
*
|
||||
* @author Jim Idle - Temporal Wave LLC (jimi@idle.ws)
|
||||
*/
|
||||
public abstract class AbstractTLexer
|
||||
extends Lexer
|
||||
|
||||
{
|
||||
/**
|
||||
* Default constructor for the lexer, when you do not yet know what
|
||||
* the character stream to be provided is.
|
||||
*/
|
||||
public AbstractTLexer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the lexer using the given character stream as
|
||||
* the input to lex into tokens.
|
||||
*
|
||||
* @param input A valid character stream that contains the ruleSrc code you
|
||||
* wish to compile (or lex at least)
|
||||
*/
|
||||
public AbstractTLexer(CharStream input) {
|
||||
this(input, new RecognizerSharedState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal constructor for ANTLR - do not use.
|
||||
*
|
||||
* @param input The character stream we are going to lex
|
||||
* @param state The shared state object, shared between all lexer comonents
|
||||
*/
|
||||
public AbstractTLexer(CharStream input, RecognizerSharedState state) {
|
||||
super(input,state);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
#set( $symbol_pound = '#' )
|
||||
#set( $symbol_dollar = '$' )
|
||||
#set( $symbol_escape = '\' )
|
||||
package ${package};
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
|
||||
/**
|
||||
* The super class of the generated parser. It is extended by the generated
|
||||
* code because of the superClass optoin in the .g file.
|
||||
*
|
||||
* This class contains any helper functions used within the parser
|
||||
* grammar itself, as well as any overrides of the standard ANTLR Java
|
||||
* runtime methods, such as an implementation of a custom error reporting
|
||||
* method, symbol table populating methods and so on.
|
||||
*
|
||||
* @author Jim Idle - Temporal Wave LLC - jimi@temporal-wave.com
|
||||
*/
|
||||
public abstract class AbstractTParser
|
||||
|
||||
extends Parser
|
||||
|
||||
{
|
||||
/**
|
||||
* Create a new parser instance, pre-supplying the input token stream.
|
||||
*
|
||||
* @param input The stream of tokens that will be pulled from the lexer
|
||||
*/
|
||||
protected AbstractTParser(TokenStream input) {
|
||||
super(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new parser instance, pre-supplying the input token stream
|
||||
* and the shared state.
|
||||
*
|
||||
* This is only used when a grammar is imported into another grammar, but
|
||||
* we must supply this constructor to satisfy the super class contract.
|
||||
*
|
||||
* @param input The stream of tokesn that will be pulled from the lexer
|
||||
* @param state The shared state object created by an interconnectd grammar
|
||||
*/
|
||||
protected AbstractTParser(TokenStream input, RecognizerSharedState state) {
|
||||
super(input, state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the error/warning message that we need to show users/IDEs when
|
||||
* ANTLR has found a parsing error, has recovered from it and is now
|
||||
* telling us that a parsing exception occurred.
|
||||
*
|
||||
* @param tokenNames token names as known by ANTLR (which we ignore)
|
||||
* @param e The exception that was thrown
|
||||
*/
|
||||
@Override
|
||||
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
|
||||
|
||||
// This is just a place holder that shows how to override this method
|
||||
//
|
||||
super.displayRecognitionError(tokenNames, e);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,250 @@
|
||||
#set( $symbol_pound = '#' )
|
||||
#set( $symbol_dollar = '$' )
|
||||
#set( $symbol_escape = '\' )
|
||||
package ${package};
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.*;
|
||||
import org.antlr.stringtemplate.*;
|
||||
|
||||
import java.io.*;
|
||||
import ${package}.TParser.a_return;
|
||||
|
||||
|
||||
/**
|
||||
* Test driver program for the ANTLR3 Maven Architype demo
|
||||
*
|
||||
* @author Jim Idle (jimi@temporal-wave.com)
|
||||
*/
|
||||
class Main {
|
||||
|
||||
private static boolean makeDot = false;
|
||||
|
||||
static TLexer lexer;
|
||||
|
||||
/** Just a simple test driver for the ASP parser
|
||||
* to show how to call it.
|
||||
*/
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the lexer, which we can keep reusing if we like
|
||||
//
|
||||
lexer = new TLexer();
|
||||
|
||||
if (args.length > 0)
|
||||
{
|
||||
int s = 0;
|
||||
|
||||
if (args[0].startsWith("-dot"))
|
||||
{
|
||||
makeDot = true;
|
||||
s = 1;
|
||||
}
|
||||
// Recursively parse each directory, and each file on the
|
||||
// command line
|
||||
//
|
||||
for (int i=s; i<args.length; i++)
|
||||
{
|
||||
parse(new File(args[i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("Usage: java -jar ${artifactId}-${version}-jar-with-dependencies.jar <directory | filename.dmo>");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.err.println("ANTLR demo parser threw exception:");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void parse(File source) throws Exception
|
||||
{
|
||||
|
||||
// Open the supplied file or directory
|
||||
//
|
||||
try
|
||||
{
|
||||
|
||||
// From here, any exceptions are just thrown back up the chain
|
||||
//
|
||||
if (source.isDirectory())
|
||||
{
|
||||
System.out.println("Directory: " + source.getAbsolutePath());
|
||||
String files[] = source.list();
|
||||
|
||||
for (int i=0; i<files.length; i++)
|
||||
{
|
||||
parse(new File(source, files[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Else find out if it is an ASP.Net file and parse it if it is
|
||||
//
|
||||
else
|
||||
{
|
||||
// File without paths etc
|
||||
//
|
||||
String sourceFile = source.getName();
|
||||
|
||||
if (sourceFile.length() > 3)
|
||||
{
|
||||
String suffix = sourceFile.substring(sourceFile.length()-4).toLowerCase();
|
||||
|
||||
// Ensure that this is a DEMO script (or seemingly)
|
||||
//
|
||||
if (suffix.compareTo(".dmo") == 0)
|
||||
{
|
||||
parseSource(source.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.err.println("ANTLR demo parser caught error on file open:");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void parseSource(String source) throws Exception
|
||||
{
|
||||
// Parse an ANTLR demo file
|
||||
//
|
||||
try
|
||||
{
|
||||
// First create a file stream using the povided file/path
|
||||
// and tell the lexer that that is the character source.
|
||||
// You can also use text that you have already read of course
|
||||
// by using the string stream.
|
||||
//
|
||||
lexer.setCharStream(new ANTLRFileStream(source, "UTF8"));
|
||||
|
||||
// Using the lexer as the token source, we create a token
|
||||
// stream to be consumed by the parser
|
||||
//
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
|
||||
// Now we need an instance of our parser
|
||||
//
|
||||
TParser parser = new TParser(tokens);
|
||||
|
||||
System.out.println("file: " + source);
|
||||
|
||||
// Provide some user feedback
|
||||
//
|
||||
System.out.println(" Lexer Start");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
// Force token load and lex (don't do this normally,
|
||||
// it is just for timing the lexer)
|
||||
//
|
||||
tokens.LT(1);
|
||||
long lexerStop = System.currentTimeMillis();
|
||||
System.out.println(" lexed in " + (lexerStop - start) + "ms.");
|
||||
|
||||
// And now we merely invoke the start rule for the parser
|
||||
//
|
||||
System.out.println(" Parser Start");
|
||||
long pStart = System.currentTimeMillis();
|
||||
a_return psrReturn = parser.a();
|
||||
long stop = System.currentTimeMillis();
|
||||
System.out.println(" Parsed in " + (stop - pStart) + "ms.");
|
||||
|
||||
// If we got a valid a tree (the syntactic validity of the source code
|
||||
// was found to be solid), then let's print the tree to show we
|
||||
// did something; our testing public wants to know!
|
||||
// We do something fairly cool here and generate a graphviz/dot
|
||||
// specification for the tree, which will allow the users to visualize
|
||||
// it :-) we only do that if asked via the -dot option though as not
|
||||
// all users will hsve installed the graphviz toolset from
|
||||
// http://www.graphviz.org
|
||||
//
|
||||
|
||||
// Pick up the generic tree
|
||||
//
|
||||
Tree t = (Tree)psrReturn.getTree();
|
||||
|
||||
// NOw walk it with the generic tree walker, which does nothing but
|
||||
// verify the tree really.
|
||||
//
|
||||
try
|
||||
{
|
||||
if (parser.getNumberOfSyntaxErrors() == 0) {
|
||||
TTree walker = new TTree(new CommonTreeNodeStream(t));
|
||||
System.out.println(" AST Walk Start${symbol_escape}n");
|
||||
pStart = System.currentTimeMillis();
|
||||
walker.a();
|
||||
stop = System.currentTimeMillis();
|
||||
System.out.println("${symbol_escape}n AST Walked in " + (stop - pStart) + "ms.");
|
||||
}
|
||||
}
|
||||
catch(Exception w)
|
||||
{
|
||||
System.out.println("AST walk caused exception.");
|
||||
w.printStackTrace();
|
||||
}
|
||||
|
||||
if (makeDot && tokens.size() < 4096)
|
||||
{
|
||||
|
||||
// Now stringify it if you want to...
|
||||
//
|
||||
// System.out.println(t.toStringTree());
|
||||
|
||||
// Use the ANLTR built in dot generator
|
||||
//
|
||||
DOTTreeGenerator gen = new DOTTreeGenerator();
|
||||
|
||||
// Which we can cause to generate the DOT specification
|
||||
// with the input file name suffixed with .dot. You can then use
|
||||
// the graphviz tools or zgrviewer (Java) to view the graphical
|
||||
// version of the dot file.
|
||||
//
|
||||
source = source.substring(0, source.length()-3);
|
||||
String outputName = source + "dot";
|
||||
|
||||
System.out.println(" Producing AST dot (graphviz) file");
|
||||
|
||||
// It produces a jguru string template.
|
||||
//
|
||||
StringTemplate st = gen.toDOT(t, new CommonTreeAdaptor());
|
||||
|
||||
// Create the output file and write the dot spec to it
|
||||
//
|
||||
FileWriter outputStream = new FileWriter(outputName);
|
||||
outputStream.write(st.toString());
|
||||
outputStream.close();
|
||||
|
||||
// Invoke dot to generate a .png file
|
||||
//
|
||||
System.out.println(" Producing png graphic for tree");
|
||||
pStart = System.currentTimeMillis();
|
||||
Process proc = Runtime.getRuntime().exec("dot -Tpng -o" + source + "png " + outputName);
|
||||
proc.waitFor();
|
||||
stop = System.currentTimeMillis();
|
||||
System.out.println(" PNG graphic produced in " + (stop - pStart) + "ms.");
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
// The file we tried to parse does not exist
|
||||
//
|
||||
System.err.println("${symbol_escape}n !!The file " + source + " does not exist!!${symbol_escape}n");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Something went wrong in the parser, report this
|
||||
//
|
||||
System.err.println("Parser threw an exception:${symbol_escape}n${symbol_escape}n");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
234
outside/antlr3-antlr-3.5/antlr3-maven-plugin/pom.xml
Normal file
234
outside/antlr3-antlr-3.5/antlr3-maven-plugin/pom.xml
Normal file
@ -0,0 +1,234 @@
|
||||
<!--
|
||||
|
||||
[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">
|
||||
|
||||
<!-- Maven model we are inheriting from
|
||||
-->
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!--
|
||||
|
||||
Now that the ANTLR project has adopted Maven with a vengence,
|
||||
all ANTLR tools will be grouped under org.antlr and will be
|
||||
controlled by a project member.
|
||||
-->
|
||||
<groupId>org.antlr</groupId>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
This is the ANTLR plugin for ANTLR version 3.1.3 and above. It might
|
||||
have been best to change the name of the plugin as the 3.1.2 plugins
|
||||
behave a little differently, however for the sake of one transitional
|
||||
phase to a much better plugin, it was decided that the name should
|
||||
remain the same.
|
||||
-->
|
||||
<artifactId>antlr3-maven-plugin</artifactId>
|
||||
<packaging>maven-plugin</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-master</artifactId>
|
||||
<version>3.5</version>
|
||||
</parent>
|
||||
|
||||
<name>ANTLR 3 Maven plugin</name>
|
||||
<prerequisites>
|
||||
<maven>2.0</maven>
|
||||
</prerequisites>
|
||||
|
||||
<!--
|
||||
Where does our actual project live on the interwebs.
|
||||
-->
|
||||
<url>http://antlr.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<description>
|
||||
|
||||
This is the brand new, re-written from scratch plugin for ANTLR v3.
|
||||
|
||||
Previous valiant efforts all suffered from being unable to modify the ANTLR Tool
|
||||
itself to provide support not just for Maven oriented things but any other tool
|
||||
that might wish to invoke ANTLR without resorting to the command line interface.
|
||||
|
||||
Rather than try to shoe-horn new code into the existing Mojo (in fact I think that
|
||||
by incorporating a patch supplied by someone I ended up with tow versions of the
|
||||
Mojo, I elected to rewrite everything from scratch, including the documentation, so
|
||||
that we might end up with a perfect Mojo that can do everything that ANTLR v3 supports
|
||||
such as imported grammar processing, proper support for library directories and
|
||||
locating token files from generated sources, and so on.
|
||||
|
||||
In the end I decided to also change the the ANTLR Tool.java code so that it
|
||||
would be the provider of all the things that a build tool needs, rather than
|
||||
delegating things to 5 different tools. So, things like dependencies, dependency
|
||||
sorting, option tracking, generating sources and so on are all folded back
|
||||
in to ANTLR's Tool.java code, where they belong, and they now provide a
|
||||
public interface to anyone that might want to interface with them.
|
||||
|
||||
One other goal of this rewrite was to completely document the whole thing
|
||||
to death. Hence even this pom has more comments than funcitonal elements,
|
||||
in case I get run over by a bus or fall off a cliff while skiing.
|
||||
|
||||
Jim Idle - March 2009
|
||||
|
||||
</description>
|
||||
|
||||
<developers>
|
||||
|
||||
<developer>
|
||||
<name>Jim Idle</name>
|
||||
<url>http://www.temporal-wave.com</url>
|
||||
<roles>
|
||||
<role>Originator, version 3.1.3</role>
|
||||
</roles>
|
||||
</developer>
|
||||
|
||||
<developer>
|
||||
<name>Terence Parr</name>
|
||||
<url>http://antlr.org/wiki/display/~admin/Home</url>
|
||||
<roles>
|
||||
<role>Project lead - ANTLR</role>
|
||||
</roles>
|
||||
</developer>
|
||||
|
||||
<developer>
|
||||
<name>David Holroyd</name>
|
||||
<url>http://david.holroyd.me.uk/</url>
|
||||
<roles>
|
||||
<role>Originator - prior version</role>
|
||||
</roles>
|
||||
</developer>
|
||||
|
||||
<developer>
|
||||
<name>Kenny MacDermid</name>
|
||||
<url>mailto:kenny "at" kmdconsulting.ca</url>
|
||||
<roles>
|
||||
<role>Contributor - prior versions</role>
|
||||
</roles>
|
||||
</developer>
|
||||
|
||||
</developers>
|
||||
|
||||
<!-- ============================================================================= -->
|
||||
|
||||
<!--
|
||||
|
||||
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>2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-project</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-compiler-api</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
The version of ANTLR tool that this version of the plugin controls.
|
||||
We have decided that this should be in lockstep with ANTLR itself, other
|
||||
than -1 -2 -3 etc patch releases.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.shared</groupId>
|
||||
<artifactId>maven-plugin-testing-harness</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.6</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.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</project>
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
[The "BSD licence"]
|
||||
|
||||
ANTLR - Copyright (c) 2005-2008 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.
|
||||
*/
|
||||
package org.antlr.mojo.antlr3;
|
||||
|
||||
import org.antlr.tool.ANTLRErrorListener;
|
||||
import org.antlr.tool.Message;
|
||||
import org.antlr.tool.ToolMessage;
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
|
||||
/**
|
||||
* The Maven plexus container gives us a Log logging provider
|
||||
* which we can use to install an error listener for the ANTLR
|
||||
* tool to report errors by.
|
||||
*/
|
||||
public class Antlr3ErrorLog implements ANTLRErrorListener {
|
||||
|
||||
private Log log;
|
||||
|
||||
/**
|
||||
* Instantiate an ANTLR ErrorListner that communicates any messages
|
||||
* it receives to the Maven error sink.
|
||||
*
|
||||
* @param log The Maven Error Log
|
||||
*/
|
||||
public Antlr3ErrorLog(Log log) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an informational message to the Maven log sink.
|
||||
* @param s The message to send to Maven
|
||||
*/
|
||||
public void info(String message) {
|
||||
log.info(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an error message from ANTLR analysis to the Maven Log sink.
|
||||
*
|
||||
* @param message The message to send to Maven.
|
||||
*/
|
||||
public void error(Message message) {
|
||||
log.error(message.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a warning message to the Maven log sink.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void warning(Message message) {
|
||||
log.warn(message.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an error message from the ANTLR tool to the Maven Log sink.
|
||||
* @param toolMessage
|
||||
*/
|
||||
public void error(ToolMessage toolMessage) {
|
||||
log.error(toolMessage.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,501 @@
|
||||
/**
|
||||
[The "BSD licence"]
|
||||
|
||||
ANTLR - Copyright (c) 2005-2008 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.
|
||||
*/
|
||||
|
||||
/* ========================================================================
|
||||
* This is the definitive ANTLR3 Mojo set. All other sets are belong to us.
|
||||
*/
|
||||
package org.antlr.mojo.antlr3;
|
||||
|
||||
import antlr.RecognitionException;
|
||||
import antlr.TokenStreamException;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.antlr.Tool;
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
|
||||
import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
|
||||
import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
|
||||
import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
|
||||
import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
|
||||
|
||||
/**
|
||||
* Parses ANTLR grammar files {@code *.g} and transforms them into Java source
|
||||
* files.
|
||||
*
|
||||
* @goal antlr
|
||||
* @phase generate-sources
|
||||
* @requiresDependencyResolution compile
|
||||
* @requiresProject true
|
||||
*
|
||||
* @author <a href="mailto:jimi@temporal-wave.com">Jim Idle</a>
|
||||
*/
|
||||
public class Antlr3Mojo
|
||||
extends AbstractMojo {
|
||||
|
||||
// First, let's deal with the options that the ANTLR tool itself
|
||||
// can be configured by.
|
||||
//
|
||||
/**
|
||||
* If set to true, then after the tool has processed an input grammar file
|
||||
* it will report various statistics about the parser, such as information
|
||||
* on cyclic DFAs, which rules may use backtracking, and so on.
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean report;
|
||||
/**
|
||||
* If set to true, then the ANTLR tool will print a version of the input
|
||||
* grammar(s) which are stripped of any embedded actions.
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean printGrammar;
|
||||
/**
|
||||
* If set to true, then the code generated by the ANTLR code generator will
|
||||
* be set to debug mode. This means that when run, the code will 'hang' and
|
||||
* wait for a debug connection on a TCP port (49100 by default).
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean debug;
|
||||
/**
|
||||
* If set to true, then the generated parser will compute and report profile
|
||||
* information at runtime.
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean profile;
|
||||
/**
|
||||
* If set to true, then the ANTLR tool will generate a description of the
|
||||
* NFA for each rule in <a href="http://www.graphviz.org">Dot format</a>
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean nfa;
|
||||
/**
|
||||
* If set to true, then the ANTLR tool will generate a description of the
|
||||
* DFA for each decision in the grammar in
|
||||
* <a href="http://www.graphviz.org">Dot format</a>.
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean dfa;
|
||||
/**
|
||||
* If set to true, the generated parser code will log rule entry and exit
|
||||
* points to stdout ({@link System#out} for the Java target) as an aid to
|
||||
* debugging.
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean trace;
|
||||
/**
|
||||
* If this parameter is set, it indicates that any warning or error messages
|
||||
* returned by ANLTR, should be formatted in the specified way. Currently,
|
||||
* ANTLR supports the built-in formats {@code antlr}, {@code gnu} and
|
||||
* {@code vs2005}.
|
||||
*
|
||||
* @parameter default-value="antlr"
|
||||
*/
|
||||
protected String messageFormat;
|
||||
/**
|
||||
* If set to true, then ANTLR will report verbose messages during the code
|
||||
* generation process. This includes the names of files, the version of
|
||||
* ANTLR, and more.
|
||||
*
|
||||
* @parameter default-value="true"
|
||||
*/
|
||||
protected boolean verbose;
|
||||
|
||||
/**
|
||||
* The maximum number of alternatives allowed in an inline switch statement.
|
||||
* Beyond this, ANTLR will not generate a switch statement for the DFA.
|
||||
*
|
||||
* @parameter default-value="300"
|
||||
*/
|
||||
private int maxSwitchCaseLabels;
|
||||
|
||||
/**
|
||||
* The minimum number of alternatives for ANTLR to generate a switch
|
||||
* statement. For decisions with fewer alternatives, an if/else if/else
|
||||
* statement will be used instead.
|
||||
*
|
||||
* @parameter default-value="3"
|
||||
*/
|
||||
private int minSwitchAlts;
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* The following are Maven specific parameters, rather than specific
|
||||
* options that the ANTLR tool can use.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides an explicit list of all the grammars that should be included in
|
||||
* the generate phase of the plugin. Note that the plugin is smart enough to
|
||||
* realize that imported grammars should be included but not acted upon
|
||||
* directly by the ANTLR Tool.
|
||||
* <p/>
|
||||
* A set of Ant-like inclusion patterns used to select files from the source
|
||||
* directory for processing. By default, the pattern <code>**/*.g</code>
|
||||
* is used to select grammar files.
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected Set<String> includes = new HashSet<String>();
|
||||
/**
|
||||
* A set of Ant-like exclusion patterns used to prevent certain files from
|
||||
* being processed. By default, this set is empty such that no files are
|
||||
* excluded.
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected Set<String> excludes = new HashSet<String>();
|
||||
/**
|
||||
* The current Maven project.
|
||||
*
|
||||
* @parameter expression="${project}"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected MavenProject project;
|
||||
/**
|
||||
* The directory where the ANTLR grammar files ({@code *.g}) are located.
|
||||
*
|
||||
* @parameter default-value="${basedir}/src/main/antlr3"
|
||||
*/
|
||||
private File sourceDirectory;
|
||||
/**
|
||||
* The directory where the parser files generated by ANTLR will be stored.
|
||||
* The directory will be registered as a compile source root of the project
|
||||
* such that the generated files will participate in later build phases like
|
||||
* compiling and packaging.
|
||||
*
|
||||
* @parameter default-value="${project.build.directory}/generated-sources/antlr3"
|
||||
* @required
|
||||
*/
|
||||
private File outputDirectory;
|
||||
/**
|
||||
* Location for imported token files, e.g. {@code *.tokens} and imported
|
||||
* grammars. Note that ANTLR will not try to process grammars that it finds
|
||||
* to be imported into other grammars (in the same processing session).
|
||||
*
|
||||
* @parameter default-value="${basedir}/src/main/antlr3/imports"
|
||||
*/
|
||||
private File libDirectory;
|
||||
|
||||
public File getSourceDirectory() {
|
||||
return sourceDirectory;
|
||||
}
|
||||
|
||||
public File getOutputDirectory() {
|
||||
return outputDirectory;
|
||||
}
|
||||
|
||||
public File getLibDirectory() {
|
||||
return libDirectory;
|
||||
}
|
||||
|
||||
void addSourceRoot(File outputDir) {
|
||||
project.addCompileSourceRoot(outputDir.getPath());
|
||||
}
|
||||
/**
|
||||
* An instance of the ANTLR tool build.
|
||||
*/
|
||||
protected Tool tool;
|
||||
|
||||
/**
|
||||
* The main entry point for this Mojo, it is responsible for converting
|
||||
* ANTLR 3.x grammars into the target language specified by the grammar.
|
||||
*
|
||||
* @throws MojoExecutionException if a configuration or grammar error causes
|
||||
* the code generation process to fail
|
||||
* @throws MojoFailureException if an instance of the ANTLR 3 {@link Tool}
|
||||
* cannot be created
|
||||
*/
|
||||
public void execute()
|
||||
throws MojoExecutionException, MojoFailureException {
|
||||
|
||||
Log log = getLog();
|
||||
|
||||
// Check to see if the user asked for debug information, then dump all the
|
||||
// parameters we have picked up if they did.
|
||||
//
|
||||
if (log.isDebugEnabled()) {
|
||||
|
||||
// Excludes
|
||||
//
|
||||
for (String e : excludes) {
|
||||
log.debug("ANTLR: Exclude: " + e);
|
||||
}
|
||||
|
||||
// Includes
|
||||
//
|
||||
for (String e : includes) {
|
||||
log.debug("ANTLR: Include: " + e);
|
||||
}
|
||||
|
||||
// Output location
|
||||
//
|
||||
log.debug("ANTLR: Output: " + outputDirectory);
|
||||
|
||||
// Library directory
|
||||
//
|
||||
log.debug("ANTLR: Library: " + libDirectory);
|
||||
|
||||
// Flags
|
||||
//
|
||||
log.debug("ANTLR: report : " + report);
|
||||
log.debug("ANTLR: printGrammar : " + printGrammar);
|
||||
log.debug("ANTLR: debug : " + debug);
|
||||
log.debug("ANTLR: profile : " + profile);
|
||||
log.debug("ANTLR: nfa : " + nfa);
|
||||
log.debug("ANTLR: dfa : " + dfa);
|
||||
log.debug("ANTLR: trace : " + trace);
|
||||
log.debug("ANTLR: messageFormat : " + messageFormat);
|
||||
log.debug("ANTLR: maxSwitchCaseLabels : " + maxSwitchCaseLabels);
|
||||
log.debug("ANTLR: minSwitchAlts : " + minSwitchAlts);
|
||||
log.debug("ANTLR: verbose : " + verbose);
|
||||
}
|
||||
|
||||
// Ensure that the output directory path is all in tact so that
|
||||
// ANTLR can just write into it.
|
||||
//
|
||||
File outputDir = getOutputDirectory();
|
||||
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.mkdirs();
|
||||
}
|
||||
|
||||
// First thing we need is an instance of the ANTLR 3.1 build tool
|
||||
//
|
||||
try {
|
||||
// ANTLR Tool buld interface
|
||||
//
|
||||
tool = new Tool();
|
||||
} catch (Exception e) {
|
||||
log.error("The attempt to create the ANTLR build tool failed, see exception report for details");
|
||||
|
||||
throw new MojoFailureException("Jim failed you!");
|
||||
}
|
||||
|
||||
// Next we need to set the options given to us in the pom into the
|
||||
// tool instance we have created.
|
||||
//
|
||||
tool.setDebug(debug);
|
||||
tool.setGenerate_DFA_dot(dfa);
|
||||
tool.setGenerate_NFA_dot(nfa);
|
||||
tool.setProfile(profile);
|
||||
tool.setReport(report);
|
||||
tool.setPrintGrammar(printGrammar);
|
||||
tool.setTrace(trace);
|
||||
tool.setVerbose(verbose);
|
||||
tool.setMessageFormat(messageFormat);
|
||||
tool.setMaxSwitchCaseLabels(maxSwitchCaseLabels);
|
||||
tool.setMinSwitchAlts(minSwitchAlts);
|
||||
|
||||
// Where do we want ANTLR to produce its output? (Base directory)
|
||||
//
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Output directory base will be " + outputDirectory.getAbsolutePath());
|
||||
}
|
||||
tool.setOutputDirectory(outputDirectory.getAbsolutePath());
|
||||
|
||||
// Tell ANTLR that we always want the output files to be produced in the output directory
|
||||
// using the same relative path as the input file was to the input directory.
|
||||
//
|
||||
tool.setForceRelativeOutput(true);
|
||||
|
||||
// Where do we want ANTLR to look for .tokens and import grammars?
|
||||
//
|
||||
tool.setLibDirectory(libDirectory.getAbsolutePath());
|
||||
|
||||
if (!sourceDirectory.exists()) {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("No ANTLR grammars to compile in " + sourceDirectory.getAbsolutePath());
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("ANTLR: Processing source directory " + sourceDirectory.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
// Set working directory for ANTLR to be the base source directory
|
||||
//
|
||||
tool.setInputDirectory(sourceDirectory.getAbsolutePath());
|
||||
|
||||
try {
|
||||
|
||||
// Now pick up all the files and process them with the Tool
|
||||
//
|
||||
processGrammarFiles(sourceDirectory, outputDirectory);
|
||||
|
||||
} catch (InclusionScanException ie) {
|
||||
|
||||
log.error(ie);
|
||||
throw new MojoExecutionException("Fatal error occured while evaluating the names of the grammar files to analyze");
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
getLog().error(e);
|
||||
throw new MojoExecutionException(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
|
||||
tool.process();
|
||||
|
||||
// If any of the grammar files caused errors but did nto throw exceptions
|
||||
// then we should have accumulated errors in the counts
|
||||
//
|
||||
if (tool.getNumErrors() > 0) {
|
||||
throw new MojoExecutionException("ANTLR caught " + tool.getNumErrors() + " build errors.");
|
||||
}
|
||||
|
||||
// All looks good, so we need to tel Maven about the sources that
|
||||
// we just created.
|
||||
//
|
||||
if (project != null) {
|
||||
// Tell Maven that there are some new source files underneath
|
||||
// the output directory.
|
||||
//
|
||||
addSourceRoot(this.getOutputDirectory());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sourceDirectory
|
||||
* @param outputDirectory
|
||||
* @throws TokenStreamException
|
||||
* @throws RecognitionException
|
||||
* @throws IOException
|
||||
* @throws InclusionScanException
|
||||
*/
|
||||
private void processGrammarFiles(File sourceDirectory, File outputDirectory)
|
||||
throws TokenStreamException, RecognitionException, IOException, InclusionScanException {
|
||||
// Which files under the source set should we be looking for as grammar files
|
||||
//
|
||||
SourceMapping mapping = new SuffixMapping("g", Collections.<String>emptySet());
|
||||
|
||||
// What are the sets of includes (defaulted or otherwise).
|
||||
//
|
||||
Set<String> includes = getIncludesPatterns();
|
||||
|
||||
// Now, to the excludes, we need to add the imports directory
|
||||
// as this is autoscanned for importd grammars and so is auto-excluded from the
|
||||
// set of gramamr fiels we shuold be analyzing.
|
||||
//
|
||||
excludes.add("imports/**");
|
||||
|
||||
SourceInclusionScanner scan = new SimpleSourceInclusionScanner(includes, excludes);
|
||||
|
||||
scan.addSourceMapping(mapping);
|
||||
Set<File> grammarFiles = scan.getIncludedSources(sourceDirectory, null);
|
||||
|
||||
if (grammarFiles.isEmpty()) {
|
||||
if (getLog().isInfoEnabled()) {
|
||||
getLog().info("No grammars to process");
|
||||
}
|
||||
} else {
|
||||
|
||||
// Tell the ANTLR tool that we want sorted build mode
|
||||
//
|
||||
tool.setMake(true);
|
||||
|
||||
// Iterate each grammar file we were given and add it into the tool's list of
|
||||
// grammars to process.
|
||||
//
|
||||
for (File grammar : grammarFiles) {
|
||||
|
||||
if (getLog().isDebugEnabled()) {
|
||||
getLog().debug("Grammar file '" + grammar.getPath() + "' detected.");
|
||||
}
|
||||
|
||||
|
||||
String relPath = findSourceSubdir(sourceDirectory, grammar.getPath()) + grammar.getName();
|
||||
|
||||
if (getLog().isDebugEnabled()) {
|
||||
getLog().debug(" ... relative path is: " + relPath);
|
||||
}
|
||||
tool.addGrammarFile(relPath);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Set<String> getIncludesPatterns() {
|
||||
if (includes == null || includes.isEmpty()) {
|
||||
return Collections.singleton("**/*.g");
|
||||
}
|
||||
return includes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the source directory File object and the full PATH to a
|
||||
* grammar, produce the path to the named grammar file in relative
|
||||
* terms to the {@code sourceDirectory}. This will then allow ANTLR to
|
||||
* produce output relative to the base of the output directory and
|
||||
* reflect the input organization of the grammar files.
|
||||
*
|
||||
* @param sourceDirectory The source directory {@link File} object
|
||||
* @param grammarFileName The full path to the input grammar file
|
||||
* @return The path to the grammar file relative to the source directory
|
||||
*/
|
||||
private String findSourceSubdir(File sourceDirectory, String grammarFileName) {
|
||||
String srcPath = sourceDirectory.getPath() + File.separator;
|
||||
|
||||
if (!grammarFileName.startsWith(srcPath)) {
|
||||
throw new IllegalArgumentException("expected " + grammarFileName + " to be prefixed with " + sourceDirectory);
|
||||
}
|
||||
|
||||
File unprefixedGrammarFileName = new File(grammarFileName.substring(srcPath.length()));
|
||||
if ( unprefixedGrammarFileName.getParent()!=null ) {
|
||||
return unprefixedGrammarFileName.getParent() + File.separator;
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <<<.g>>> 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/antlr3>>> by default of course).
|
||||
|
||||
For a default layout, place your import grammars in the directory: <<<src/main/antlr3/imports>>>
|
@ -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>antlr3-maven-plugin</artifactId>
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<goals>
|
||||
<goal>antlr</goal>
|
||||
</goals>
|
||||
<libDirectory>src/main/antlr_imports</libDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
+--
|
||||
|
||||
|
||||
|
@ -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>antlr3-maven-plugin</artifactId>
|
||||
<version>3.1.3-1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>antlr</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
...
|
||||
</plugins>
|
||||
+--
|
||||
|
||||
When the <<<mvn>>> command is executed all grammar files under <<<src/main/antlr3>>>, except any
|
||||
import grammars under <<<src/main/antlr3/imports>>> will be analyzed and converted to
|
||||
Java source code in the output directory <<<target/generated-sources/antlr3>>>.
|
||||
|
||||
Your input files under <<<antlr3>>> should be stored in sub directories that
|
||||
reflect the package structure of your java parsers. If your grammar file <<<parser.g>>> contains:
|
||||
|
||||
+---
|
||||
@header {
|
||||
package org.jimi.themuss;
|
||||
}
|
||||
+---
|
||||
|
||||
Then the <<<.g>>> file should be stored in: <<<src/main/antlr3/org/jimi/themuss/parser.g>>>. This way
|
||||
the generated <<<.java>>> files will correctly reflect the package structure in which they will
|
||||
finally rest as classes.
|
||||
|
@ -0,0 +1 @@
|
||||
FAQ
|
@ -0,0 +1,62 @@
|
||||
-------------
|
||||
ANTLR v3 Maven Plugin
|
||||
-------------
|
||||
Jim Idle
|
||||
-------------
|
||||
March 2009
|
||||
-------------
|
||||
|
||||
ANTLR v3 Maven plugin
|
||||
|
||||
The ANTLR v3 Maven plugin is completely re-written as of version 3.1.3; 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 3.1.3 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 3.1.3 of the plugin, you will build your grammars using version 3.1.3 of the
|
||||
ANTLR tool, version 3.2 of the plugin will use version 3.2 of the ANTLR tool and so on.
|
||||
|
||||
You may also find that there are patch versions of the plugin such as 3.1.3-1 3.1.3-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/
|
||||
|
|
||||
+--- antlr3/... .g files organized in the required package structure
|
||||
|
|
||||
+--- imports/ .g 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/antlr3/org/foo/bar>>>. The plugin will then produce
|
||||
<<<.java>>> and <<<.tokens>>> files in the output directory <<<target/generated-sources/antlr3/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/antlr3/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.
|
@ -0,0 +1,59 @@
|
||||
Usage
|
||||
|
||||
The ANTLR 3 plugin for Maven can generate parsers for any number of grammars in
|
||||
your project.
|
||||
|
||||
* Compiling Grammars into Parsers
|
||||
|
||||
By default, the <<<{{{./antlr-mojo.html}antlr}}>>> goal will search for grammar
|
||||
files in the directory <<<$\{basedir\}/src/main/antlr3>>> and any additional
|
||||
<<<.tokens>>> files in the directory <<<$\{basedir\}/src/main/antlr3/imports>>>.
|
||||
This can be configured to search other directories using the plugin configuration
|
||||
parameters as described in the <<<{{{./antlr-mojo.html}antlr}}>>> goal
|
||||
documentation.
|
||||
|
||||
The following figure shows the expected layout of files for the default
|
||||
configuration of this plugin.
|
||||
|
||||
+--
|
||||
src/main/
|
||||
|
|
||||
+--- antlr3/... .g files organized in the required package structure
|
||||
|
|
||||
+--- imports/ user-created .tokens files and .g 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>antlr3-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>antlr</id>
|
||||
<goals>
|
||||
<goal>antlr</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).
|
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project name="ANTLR v3 Maven plugin">
|
||||
|
||||
<publishDate position="left"/>
|
||||
<version position="left"/>
|
||||
|
||||
<poweredBy>
|
||||
<logo name="ANTLR Web Site" href="http://antlr3.org/"
|
||||
img="http://www.antlr.org/wiki/download/attachments/292/ANTLR3"/>
|
||||
</poweredBy>
|
||||
|
||||
<body>
|
||||
<links>
|
||||
<item name="Antlr Web Site" href="http://www.antlr3.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>
|
56
outside/antlr3-antlr-3.5/contributors.txt
Normal file
56
outside/antlr3-antlr-3.5/contributors.txt
Normal file
@ -0,0 +1,56 @@
|
||||
ANTLR Project Contributors Certification of Origin and Rights
|
||||
|
||||
All contributors to ANTLR v3 must formally agree to abide by this
|
||||
certificate of origin by signing on the bottom with their github
|
||||
userid, full name, email address (you can obscure your e-mail, but it
|
||||
must be computable by human), and date.
|
||||
|
||||
By signing this agreement, you are warranting and representing that
|
||||
you have the right to release code contributions or other content free
|
||||
of any obligations to third parties and are granting Terence Parr and
|
||||
ANTLR project contributors, henceforth referred to as The ANTLR
|
||||
Project, a license to incorporate it into The ANTLR Project tools
|
||||
(such as ANTLRWorks and StringTemplate) or related works under the BSD
|
||||
license. You understand that The ANTLR Project may or may not
|
||||
incorporate your contribution and you warrant and represent the
|
||||
following:
|
||||
|
||||
1. I am the creator of all my contributions. I am the author of all
|
||||
contributed work submitted and further warrant and represent that
|
||||
such work is my original creation and I have the right to license
|
||||
it to The ANTLR Project for release under the 3-clause BSD
|
||||
license. I hereby grant The ANTLR Project a nonexclusive,
|
||||
irrevocable, royalty-free, worldwide license to reproduce,
|
||||
distribute, prepare derivative works, and otherwise use this
|
||||
contribution as part of the ANTLR project, associated
|
||||
documentation, books, and tools at no cost to The ANTLR Project.
|
||||
|
||||
2. I have the right to submit. This submission does not violate the
|
||||
rights of any person or entity and that I have legal authority over
|
||||
this submission and to make this certification.
|
||||
|
||||
3. If I violate another's rights, liability lies with me. I agree to
|
||||
defend, indemnify, and hold The ANTLR Project and ANTLR users
|
||||
harmless from any claim or demand, including reasonable attorney
|
||||
fees, made by any third party due to or arising out of my violation
|
||||
of these terms and conditions or my violation of the rights of
|
||||
another person or entity.
|
||||
|
||||
4. I understand and agree that this project and the contribution are
|
||||
public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license indicated in the file.
|
||||
|
||||
I have read this agreement and do so certify by adding my signoff to
|
||||
the end of the following contributors list.
|
||||
|
||||
CONTRIBUTORS:
|
||||
|
||||
YYYY/MM/DD, github id, Full name, email
|
||||
2012/07/12, parrt, Terence Parr, parrt@antlr.org
|
||||
2012/08/08, Zannick, Benjamin S Wolf, jokeserver@gmail.com
|
||||
2012/09/15, martint, Martin Traverso, mtraverso@gmail.com
|
||||
2012/09/16, qmx, Douglas Campos, qmx@qmx.me
|
||||
2012/09/17, ksgokul, Gokulakannan Somasundaram, gokul007@gmail.com
|
||||
2012/11/22, sharwell, Sam Harwell, sam@tunnelvisionlabs.com
|
144
outside/antlr3-antlr-3.5/gunit-maven-plugin/pom.xml
Normal file
144
outside/antlr3-antlr-3.5/gunit-maven-plugin/pom.xml
Normal file
@ -0,0 +1,144 @@
|
||||
<!--
|
||||
|
||||
[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>
|
||||
|
||||
<prerequisites>
|
||||
<maven>2.0</maven>
|
||||
</prerequisites>
|
||||
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>maven-gunit-plugin</artifactId>
|
||||
<packaging>maven-plugin</packaging>
|
||||
|
||||
<name>ANTLR 3 gUnit Maven plugin</name>
|
||||
<description>A Maven plugin for incorporating gUnit testing of grammars</description>
|
||||
<url>http://antlr.org</url>
|
||||
|
||||
<!--
|
||||
|
||||
Inherit from the ANTLR master pom, which tells us what
|
||||
version we are and allows us to inherit dependencies
|
||||
and so on.
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-master</artifactId>
|
||||
<version>3.5</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<!--
|
||||
|
||||
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>2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-project</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-compiler-api</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
The version of ANTLR tool that this version of the plugin controls.
|
||||
We have decided that this should be in lockstep with ANTLR itself, other
|
||||
than -1 -2 -3 etc patch releases.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Dependency on the gUnit artifact.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>gunit</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.shared</groupId>
|
||||
<artifactId>maven-plugin-testing-harness</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<dependencyLocationsEnabled>false</dependencyLocationsEnabled>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,397 @@
|
||||
package org.antlr.mojo.antlr3;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.io.FileWriter;
|
||||
import java.io.BufferedWriter;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.artifact.DependencyResolutionRequiredException;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
import org.codehaus.plexus.util.FileUtils;
|
||||
import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
|
||||
import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
|
||||
import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
|
||||
import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
|
||||
import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
|
||||
import org.antlr.runtime.ANTLRFileStream;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.antlr.gunit.GrammarInfo;
|
||||
import org.antlr.gunit.gUnitExecutor;
|
||||
import org.antlr.gunit.AbstractTest;
|
||||
import org.antlr.gunit.Interp;
|
||||
|
||||
/**
|
||||
* Takes gUnit scripts and directly performs testing.
|
||||
*
|
||||
* @goal gunit
|
||||
*
|
||||
* @phase test
|
||||
* @requiresDependencyResolution test
|
||||
* @requiresProject true
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class GUnitExecuteMojo extends AbstractMojo {
|
||||
public static final String ANTLR_GROUP_ID = "org.antlr";
|
||||
public static final String ANTLR_ARTIFACT_NAME = "antlr";
|
||||
public static final String ANTLR_RUNTIME_ARTIFACT_NAME = "antlr-runtime";
|
||||
|
||||
/**
|
||||
* INTERNAL : The Maven Project to which we are attached
|
||||
*
|
||||
* @parameter expression="${project}"
|
||||
* @required
|
||||
*/
|
||||
private MavenProject project;
|
||||
|
||||
/**
|
||||
* INTERNAL : The artifacts associated to the dependencies defined as part
|
||||
* of our configuration within the project to which we are being attached.
|
||||
*
|
||||
* @parameter expression="${plugin.artifacts}"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
private List<Artifact> pluginArtifacts;
|
||||
|
||||
/**
|
||||
* Specifies the directory containing the gUnit testing files.
|
||||
*
|
||||
* @parameter expression="${basedir}/src/test/gunit"
|
||||
* @required
|
||||
*/
|
||||
private File sourceDirectory;
|
||||
|
||||
/**
|
||||
* A set of patterns for matching files from the sourceDirectory that
|
||||
* should be included as gUnit source files.
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
private Set<String> includes;
|
||||
|
||||
/**
|
||||
* A set of exclude patterns.
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
private Set<String> excludes;
|
||||
|
||||
/**
|
||||
* Specifies directory to which gUnit reports should get written.
|
||||
*
|
||||
* @parameter expression="${basedir}/target/gunit-report"
|
||||
* @required
|
||||
*/
|
||||
private File reportDirectory;
|
||||
|
||||
/**
|
||||
* Should gUnit functionality be completely by-passed?
|
||||
* <p/>
|
||||
* By default we skip gUnit tests if the user requested that all testing be skipped using 'maven.test.skip'
|
||||
*
|
||||
* @parameter expression="${maven.test.skip}"
|
||||
*/
|
||||
private boolean skip;
|
||||
|
||||
public Set<String> getIncludePatterns() {
|
||||
return includes == null || includes.isEmpty()
|
||||
? Collections.singleton( "**/*.testsuite" )
|
||||
: includes;
|
||||
}
|
||||
|
||||
public Set<String> getExcludePatterns() {
|
||||
return excludes == null
|
||||
? Collections.<String>emptySet()
|
||||
: excludes;
|
||||
}
|
||||
|
||||
|
||||
public final void execute() throws MojoExecutionException, MojoFailureException {
|
||||
if ( skip ) {
|
||||
getLog().info( "Skipping gUnit processing" );
|
||||
return;
|
||||
}
|
||||
Artifact pluginAntlrArtifact = determinePluginAntlrArtifact();
|
||||
|
||||
validateProjectsAntlrVersion( determineArtifactVersion( pluginAntlrArtifact ) );
|
||||
|
||||
performExecution( determineProjectCompileScopeClassLoader( pluginAntlrArtifact ) );
|
||||
}
|
||||
|
||||
private Artifact determinePluginAntlrArtifact() throws MojoExecutionException {
|
||||
for ( Artifact artifact : pluginArtifacts ) {
|
||||
boolean match = ANTLR_GROUP_ID.equals( artifact.getGroupId() )
|
||||
&& ANTLR_ARTIFACT_NAME.equals( artifact.getArtifactId() );
|
||||
if ( match ) {
|
||||
return artifact;
|
||||
}
|
||||
}
|
||||
throw new MojoExecutionException(
|
||||
"Unexpected state : could not locate " + ANTLR_GROUP_ID + ':' + ANTLR_ARTIFACT_NAME +
|
||||
" in plugin dependencies"
|
||||
);
|
||||
}
|
||||
|
||||
private ArtifactVersion determineArtifactVersion(Artifact artifact) throws MojoExecutionException {
|
||||
try {
|
||||
return artifact.getVersion() != null
|
||||
? new DefaultArtifactVersion( artifact.getVersion() )
|
||||
: artifact.getSelectedVersion();
|
||||
}
|
||||
catch ( OverConstrainedVersionException e ) {
|
||||
throw new MojoExecutionException( "artifact [" + artifact.getId() + "] defined an overly constrained version range" );
|
||||
}
|
||||
}
|
||||
|
||||
private void validateProjectsAntlrVersion(ArtifactVersion pluginAntlrVersion) throws MojoExecutionException {
|
||||
Artifact antlrArtifact = null;
|
||||
Artifact antlrRuntimeArtifact = null;
|
||||
|
||||
if ( project.getCompileArtifacts() != null ) {
|
||||
for ( Object o : project.getCompileArtifacts() ) {
|
||||
final Artifact artifact = ( Artifact ) o;
|
||||
if ( ANTLR_GROUP_ID.equals( artifact.getGroupId() ) ) {
|
||||
if ( ANTLR_ARTIFACT_NAME.equals( artifact.getArtifactId() ) ) {
|
||||
antlrArtifact = artifact;
|
||||
break;
|
||||
}
|
||||
if ( ANTLR_RUNTIME_ARTIFACT_NAME.equals( artifact.getArtifactId() ) ) {
|
||||
antlrRuntimeArtifact = artifact;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validateBuildTimeArtifact( antlrArtifact, pluginAntlrVersion );
|
||||
validateRunTimeArtifact( antlrRuntimeArtifact, pluginAntlrVersion );
|
||||
}
|
||||
|
||||
@SuppressWarnings(value = "unchecked")
|
||||
protected void validateBuildTimeArtifact(Artifact antlrArtifact, ArtifactVersion pluginAntlrVersion)
|
||||
throws MojoExecutionException {
|
||||
if ( antlrArtifact == null ) {
|
||||
validateMissingBuildtimeArtifact();
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, lets make sure they match...
|
||||
ArtifactVersion projectAntlrVersion = determineArtifactVersion( antlrArtifact );
|
||||
if ( pluginAntlrVersion.compareTo( projectAntlrVersion ) != 0 ) {
|
||||
getLog().warn(
|
||||
"Encountered " + ANTLR_GROUP_ID + ':' + ANTLR_ARTIFACT_NAME + ':' + projectAntlrVersion.toString() +
|
||||
" which did not match Antlr version used by plugin [" + pluginAntlrVersion.toString() + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateMissingBuildtimeArtifact() {
|
||||
// generally speaking, its ok for the project to not define a dep on the build-time artifact...
|
||||
}
|
||||
|
||||
@SuppressWarnings(value = "unchecked")
|
||||
protected void validateRunTimeArtifact(Artifact antlrRuntimeArtifact, ArtifactVersion pluginAntlrVersion)
|
||||
throws MojoExecutionException {
|
||||
if ( antlrRuntimeArtifact == null ) {
|
||||
// its possible, if the project instead depends on the build-time (or full) artifact.
|
||||
return;
|
||||
}
|
||||
|
||||
ArtifactVersion projectAntlrVersion = determineArtifactVersion( antlrRuntimeArtifact );
|
||||
if ( pluginAntlrVersion.compareTo( projectAntlrVersion ) != 0 ) {
|
||||
getLog().warn(
|
||||
"Encountered " + ANTLR_GROUP_ID + ':' + ANTLR_RUNTIME_ARTIFACT_NAME + ':' + projectAntlrVersion.toString() +
|
||||
" which did not match Antlr version used by plugin [" + pluginAntlrVersion.toString() + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the classloader to pass to gUnit.
|
||||
*
|
||||
* @param antlrArtifact The plugin's (our) Antlr dependency artifact.
|
||||
*
|
||||
* @return The classloader for gUnit to use
|
||||
*
|
||||
* @throws MojoExecutionException Problem resolving artifacts to {@link java.net.URL urls}.
|
||||
*/
|
||||
private ClassLoader determineProjectCompileScopeClassLoader(Artifact antlrArtifact)
|
||||
throws MojoExecutionException {
|
||||
ArrayList<URL> classPathUrls = new ArrayList<URL>();
|
||||
getLog().info( "Adding Antlr artifact : " + antlrArtifact.getId() );
|
||||
classPathUrls.add( resolveLocalURL( antlrArtifact ) );
|
||||
|
||||
for ( String path : classpathElements() ) {
|
||||
try {
|
||||
getLog().info( "Adding project compile classpath element : " + path );
|
||||
classPathUrls.add( new File( path ).toURI().toURL() );
|
||||
}
|
||||
catch ( MalformedURLException e ) {
|
||||
throw new MojoExecutionException( "Unable to build path URL [" + path + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
return new URLClassLoader( classPathUrls.toArray( new URL[classPathUrls.size()] ), getClass().getClassLoader() );
|
||||
}
|
||||
|
||||
protected static URL resolveLocalURL(Artifact artifact) throws MojoExecutionException {
|
||||
try {
|
||||
return artifact.getFile().toURI().toURL();
|
||||
}
|
||||
catch ( MalformedURLException e ) {
|
||||
throw new MojoExecutionException( "Unable to resolve artifact url : " + artifact.getId(), e );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private List<String> classpathElements() throws MojoExecutionException {
|
||||
try {
|
||||
// todo : should we combine both compile and test scoped elements?
|
||||
return ( List<String> ) project.getTestClasspathElements();
|
||||
}
|
||||
catch ( DependencyResolutionRequiredException e ) {
|
||||
throw new MojoExecutionException( "Call to Project#getCompileClasspathElements required dependency resolution" );
|
||||
}
|
||||
}
|
||||
|
||||
private void performExecution(ClassLoader projectCompileScopeClassLoader) throws MojoExecutionException {
|
||||
getLog().info( "gUnit report directory : " + reportDirectory.getAbsolutePath() );
|
||||
if ( !reportDirectory.exists() ) {
|
||||
boolean directoryCreated = reportDirectory.mkdirs();
|
||||
if ( !directoryCreated ) {
|
||||
getLog().warn( "mkdirs() reported problem creating report directory" );
|
||||
}
|
||||
}
|
||||
|
||||
Result runningResults = new Result();
|
||||
ArrayList<String> failureNames = new ArrayList<String>();
|
||||
|
||||
System.out.println();
|
||||
System.out.println( "-----------------------------------------------------------" );
|
||||
System.out.println( " G U N I T R E S U L T S" );
|
||||
System.out.println( "-----------------------------------------------------------" );
|
||||
|
||||
for ( File script : collectIncludedSourceGrammars() ) {
|
||||
final String scriptPath = script.getAbsolutePath();
|
||||
System.out.println( "Executing script " + scriptPath );
|
||||
try {
|
||||
String scriptBaseName = StringUtils.chompLast( FileUtils.basename( script.getName() ), "." );
|
||||
|
||||
ANTLRFileStream antlrStream = new ANTLRFileStream( scriptPath );
|
||||
GrammarInfo grammarInfo = Interp.parse( antlrStream );
|
||||
gUnitExecutor executor = new gUnitExecutor(
|
||||
grammarInfo,
|
||||
projectCompileScopeClassLoader,
|
||||
script.getParentFile().getAbsolutePath()
|
||||
);
|
||||
|
||||
String report = executor.execTest();
|
||||
writeReportFile( new File( reportDirectory, scriptBaseName + ".txt" ), report );
|
||||
|
||||
Result testResult = new Result();
|
||||
testResult.tests = executor.numOfTest;
|
||||
testResult.failures = executor.numOfFailure;
|
||||
testResult.invalids = executor.numOfInvalidInput;
|
||||
|
||||
System.out.println( testResult.render() );
|
||||
|
||||
runningResults.add( testResult );
|
||||
for ( AbstractTest test : executor.failures ) {
|
||||
failureNames.add( scriptBaseName + "#" + test.getHeader() );
|
||||
}
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new MojoExecutionException( "Could not open specified script file", e );
|
||||
}
|
||||
catch ( RecognitionException e ) {
|
||||
throw new MojoExecutionException( "Could not parse gUnit script", e );
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println( "Summary :" );
|
||||
if ( ! failureNames.isEmpty() ) {
|
||||
System.out.println( " Found " + failureNames.size() + " failures" );
|
||||
for ( String name : failureNames ) {
|
||||
System.out.println( " - " + name );
|
||||
}
|
||||
}
|
||||
System.out.println( runningResults.render() );
|
||||
System.out.println();
|
||||
|
||||
if ( runningResults.failures > 0 ) {
|
||||
throw new MojoExecutionException( "Found gUnit test failures" );
|
||||
}
|
||||
|
||||
if ( runningResults.invalids > 0 ) {
|
||||
throw new MojoExecutionException( "Found invalid gUnit tests" );
|
||||
}
|
||||
}
|
||||
|
||||
private Set<File> collectIncludedSourceGrammars() throws MojoExecutionException {
|
||||
SourceMapping mapping = new SuffixMapping( "g", Collections.<String>emptySet() );
|
||||
SourceInclusionScanner scan = new SimpleSourceInclusionScanner( getIncludePatterns(), getExcludePatterns() );
|
||||
scan.addSourceMapping( mapping );
|
||||
try {
|
||||
return scan.getIncludedSources( sourceDirectory, null );
|
||||
}
|
||||
catch ( InclusionScanException e ) {
|
||||
throw new MojoExecutionException( "Error determining gUnit sources", e );
|
||||
}
|
||||
}
|
||||
|
||||
private void writeReportFile(File reportFile, String results) {
|
||||
try {
|
||||
Writer writer = new FileWriter( reportFile );
|
||||
writer = new BufferedWriter( writer );
|
||||
try {
|
||||
writer.write( results );
|
||||
writer.flush();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
writer.close();
|
||||
}
|
||||
catch ( IOException ignore ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
getLog().warn( "Error writing gUnit report file", e );
|
||||
}
|
||||
}
|
||||
|
||||
private static class Result {
|
||||
private int tests = 0;
|
||||
private int failures = 0;
|
||||
private int invalids = 0;
|
||||
|
||||
public String render() {
|
||||
return String.format( "Tests run: %d, Failures: %d, Invalid: %d", tests, failures, invalids );
|
||||
}
|
||||
|
||||
public void add(Result result) {
|
||||
this.tests += result.tests;
|
||||
this.failures += result.failures;
|
||||
this.invalids += result.invalids;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
127
outside/antlr3-antlr-3.5/gunit/CHANGES.txt
Normal file
127
outside/antlr3-antlr-3.5/gunit/CHANGES.txt
Normal file
@ -0,0 +1,127 @@
|
||||
gUnit
|
||||
|
||||
Leon, Jen-Yuan Su
|
||||
leonsu at mac com
|
||||
|
||||
CHANGES
|
||||
|
||||
December 15, 2010
|
||||
|
||||
* TJP gunit checked tokens.index() != size instead of size()-1
|
||||
|
||||
November 26, 2010
|
||||
|
||||
* Added -p package-name-for-junit-output since test package is usually
|
||||
different than parser package. TJP
|
||||
|
||||
January 24, 2009
|
||||
|
||||
* Improved error messages
|
||||
|
||||
* stderr was being ignored upon exception.
|
||||
|
||||
* generated junit test code indicate lines in gunit script. also error
|
||||
messages during parse time show line number from gunit script.
|
||||
|
||||
* refactored template generation / parameters
|
||||
|
||||
* Allow strings in AST descriptions (gUnit.g). E.g., it handle this rule
|
||||
(I had to quote the "^(" root tokens):
|
||||
|
||||
block:
|
||||
"( ^(A B) | ^(b C) )" -> (BLOCK (ALT ("^(" A B)) (ALT ("^(" b C)))
|
||||
|
||||
|
||||
January 23, 2009
|
||||
|
||||
* whitespace ignored and "x y z" turned into x y z now in expected tree p\
|
||||
attern. E.g.,
|
||||
|
||||
rule:
|
||||
"a : A<X,Y=a.b.c>;" -> (RULE a (BLOCK (ALT
|
||||
(A (ELEMENT_OPTIONS X (= Y "a.b.c")))))
|
||||
)
|
||||
|
||||
July 31, 2009
|
||||
|
||||
* support custom tree adaptor in gUnit script
|
||||
|
||||
March 21, 2009
|
||||
|
||||
* gUnitTestSuite.java: use lexer rule name if parser rule name is null (by Shaoting)
|
||||
|
||||
* add gunit/swingui package for gUnitEditor GUI
|
||||
|
||||
Feb 17, 2009
|
||||
|
||||
* added new interfaces for GUI editor
|
||||
|
||||
* recognizes invalid input as a FAIL case instead of throwing an exception
|
||||
|
||||
Steve Ebersole provided a patch for the following two fixes.
|
||||
* allows setting an output directory (for JUnitCodeGen)
|
||||
|
||||
* allows providing a classloader (for both JUnitCodeGen and gUnitExecutor)
|
||||
|
||||
Nov 25, 2008
|
||||
|
||||
* fixed external test file path issue. if an input test file is not found under the current dir, then try to look for it under the package dir also.
|
||||
|
||||
* fixed multiple-line input indentation issue.
|
||||
|
||||
* fixed bug: FileNotFoundException terminated gUnit tests due to any non-existent input test file.
|
||||
|
||||
* display escaped text for newline characters in the test result for comparing expected and actual string.
|
||||
|
||||
Nov 20, 2008
|
||||
|
||||
* added new functionality of testing lexical rules
|
||||
|
||||
* fixed bug of using PipedInput/Output Stream and changed to ByteArrayOutputStream. Jared Bunting provided a patch on this issue.
|
||||
|
||||
* improved jUnit translation mode and moved supporting codes into gUnitBaseTest.
|
||||
|
||||
Oct 31, 2008
|
||||
|
||||
* fixed bug of testing a tree grammar's template output
|
||||
|
||||
July 9, 2008
|
||||
|
||||
* fixed bug: program exited upon InvocationTargetException
|
||||
Sumanto Biswas pointed out the issue and provided suggestions.
|
||||
|
||||
* Better handle on test rule's StringTemplate output
|
||||
|
||||
May 10, 2008
|
||||
|
||||
* added exit code functionality
|
||||
|
||||
* fixed string escaping bug for junit generator
|
||||
|
||||
1.0.2 - Apr 01, 2008
|
||||
|
||||
* fixed grammar bug: multiple-line input, AST output
|
||||
|
||||
* adjusted the output of test result
|
||||
|
||||
Mar 20, 2008
|
||||
|
||||
* moved test result to string template (gUnitTestResult.stg)
|
||||
|
||||
* added the display of line of test in the test result
|
||||
|
||||
Feb 19, 2008
|
||||
|
||||
* fixed bug of displaying test sequence and error message from ANTLR
|
||||
|
||||
Feb 8, 2008
|
||||
|
||||
* made compatible with ANTLR 3.1b1
|
||||
|
||||
1.0.1 - Jan 11, 2008
|
||||
|
||||
* Kenny MacDermid helps with code refactoring
|
||||
|
||||
1.0 - Aug 20, 2007
|
||||
|
||||
Initial early access release
|
26
outside/antlr3-antlr-3.5/gunit/LICENSE.txt
Normal file
26
outside/antlr3-antlr-3.5/gunit/LICENSE.txt
Normal file
@ -0,0 +1,26 @@
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon, Jen-Yuan Su
|
||||
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.
|
56
outside/antlr3-antlr-3.5/gunit/README.txt
Normal file
56
outside/antlr3-antlr-3.5/gunit/README.txt
Normal file
@ -0,0 +1,56 @@
|
||||
gUnit
|
||||
Feb 21, 2009
|
||||
|
||||
Leon, Jen-Yuan Su
|
||||
leonsu at mac com
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
Welcome to gUnit! I've been working on gUnit from 2007 summer and
|
||||
this is a project in USF CS, sponsored by professor Terence Parr.
|
||||
|
||||
You should use the latest ANTLR v3 with gUnit:
|
||||
|
||||
http://www.antlr.org/download.html
|
||||
|
||||
See the wiki document:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/gUnit+-+Grammar+Unit+Testing
|
||||
|
||||
Per the license in LICENSE.txt, this software is not guaranteed to
|
||||
work and might even destroy all life on this planet:
|
||||
|
||||
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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
EXAMPLES
|
||||
|
||||
See the wiki tutorial of gUnit:
|
||||
|
||||
http://www.antlr.org/wiki/display/ANTLR3/gUnit+-+Grammar+Unit+Testing
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
What is gUnit?
|
||||
|
||||
gUnit is an unit testing framework for ANTLR grammars. It provides a
|
||||
simple way to write and run automated tests for grammars in a manner
|
||||
similar to what jUnit does for unit testing.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
How do I install gUnit?
|
||||
|
||||
It is included in ANTLR v3; it needs both ANTLR and StringTemplate jars
|
||||
in CLASSPATH.
|
0
outside/antlr3-antlr-3.5/gunit/antlr.config
Normal file
0
outside/antlr3-antlr-3.5/gunit/antlr.config
Normal file
82
outside/antlr3-antlr-3.5/gunit/pom.xml
Normal file
82
outside/antlr3-antlr-3.5/gunit/pom.xml
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>gunit</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ANTLR 3 gUnit</name>
|
||||
<description>gUnit grammar testing tool for ANTLR 3</description>
|
||||
|
||||
<!--
|
||||
|
||||
Inherit from the ANTLR master pom, which tells us what
|
||||
version we are and allows us to inherit dependencies
|
||||
and so on.
|
||||
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-master</artifactId>
|
||||
<version>3.5</version>
|
||||
</parent>
|
||||
|
||||
<url>http://www.antlr.org/wiki/display/ANTLR3/gUnit+-+Grammar+Unit+Testing</url>
|
||||
|
||||
<!--
|
||||
|
||||
Tell Maven which other artifacts we need in order to
|
||||
build, run and test the ANTLR Tool. The ANTLR Tool uses earlier versions
|
||||
of ANTLR at runtime (for the moment), uses the current
|
||||
released version of ANTLR String template, but obviously is
|
||||
reliant on the latest snapshot of the runtime, which will either be
|
||||
taken from the antlr-snapshot repository, or your local .m2
|
||||
repository if you built and installed that locally.
|
||||
|
||||
-->
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>stringtemplate</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr3-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration></configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>antlr</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,352 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon Jen-Yuan Su
|
||||
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.
|
||||
*/
|
||||
grammar gUnit;
|
||||
options {language=Java;}
|
||||
tokens {
|
||||
OK = 'OK';
|
||||
FAIL = 'FAIL';
|
||||
DOC_COMMENT;
|
||||
}
|
||||
@header {package org.antlr.gunit;}
|
||||
@lexer::header {
|
||||
package org.antlr.gunit;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
}
|
||||
@members {
|
||||
public GrammarInfo grammarInfo;
|
||||
public gUnitParser(TokenStream input, GrammarInfo grammarInfo) {
|
||||
super(input);
|
||||
this.grammarInfo = grammarInfo;
|
||||
}
|
||||
}
|
||||
|
||||
gUnitDef: 'gunit' g1=id ('walks' g2=id)? ';'
|
||||
{
|
||||
if ( $g2.text!=null ) {
|
||||
grammarInfo.setGrammarName($g2.text);
|
||||
grammarInfo.setTreeGrammarName($g1.text);
|
||||
}
|
||||
else {
|
||||
grammarInfo.setGrammarName($g1.text);
|
||||
}
|
||||
}
|
||||
optionsSpec? header? testsuite*
|
||||
;
|
||||
|
||||
optionsSpec
|
||||
: OPTIONS (option ';')+ '}'
|
||||
;
|
||||
|
||||
// Note: currently, this is the only valid option for setting customized tree adaptor
|
||||
option : id '=' treeAdaptor
|
||||
{
|
||||
if ( $id.text.equals("TreeAdaptor") ) {
|
||||
grammarInfo.setAdaptor($treeAdaptor.text);
|
||||
}
|
||||
// TODO: need a better error logging strategy
|
||||
else System.err.println("Invalid option detected: "+$text);
|
||||
}
|
||||
;
|
||||
|
||||
treeAdaptor
|
||||
: id EXT*
|
||||
;
|
||||
|
||||
header : '@header' ACTION
|
||||
{
|
||||
int pos1, pos2;
|
||||
if ( (pos1=$ACTION.text.indexOf("package"))!=-1 && (pos2=$ACTION.text.indexOf(';'))!=-1 ) {
|
||||
grammarInfo.setGrammarPackage($ACTION.text.substring(pos1+8, pos2).trim()); // substring the package path
|
||||
}
|
||||
else {
|
||||
System.err.println("error(line "+$ACTION.getLine()+"): invalid header");
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
testsuite // gUnit test suite based on individual rule
|
||||
scope {
|
||||
boolean isLexicalRule;
|
||||
}
|
||||
@init {
|
||||
gUnitTestSuite ts = null;
|
||||
$testsuite::isLexicalRule = false;
|
||||
}
|
||||
: ( r1=RULE_REF ('walks' r2=RULE_REF)?
|
||||
{
|
||||
if ( $r2==null ) ts = new gUnitTestSuite($r1.text);
|
||||
else ts = new gUnitTestSuite($r1.text, $r2.text);
|
||||
}
|
||||
| t=TOKEN_REF
|
||||
{
|
||||
ts = new gUnitTestSuite();
|
||||
ts.setLexicalRuleName($t.text);
|
||||
$testsuite::isLexicalRule = true;
|
||||
}
|
||||
)
|
||||
':'
|
||||
testcase[ts]+ {grammarInfo.addRuleTestSuite(ts);}
|
||||
;
|
||||
|
||||
// TODO : currently gUnit just ignores illegal test for lexer rule, but should also emit a reminding message
|
||||
testcase[gUnitTestSuite ts] // individual test within a (rule)testsuite
|
||||
: input expect {$ts.addTestCase($input.in, $expect.out);}
|
||||
;
|
||||
|
||||
input returns [gUnitTestInput in]
|
||||
@init {
|
||||
String testInput = null;
|
||||
boolean inputIsFile = false;
|
||||
int line = -1;
|
||||
}
|
||||
@after {
|
||||
in = new gUnitTestInput(testInput, inputIsFile, line);
|
||||
}
|
||||
: STRING
|
||||
{
|
||||
testInput = $STRING.text.replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t")
|
||||
.replace("\\b", "\b").replace("\\f", "\f").replace("\\\"", "\"").replace("\\'", "\'").replace("\\\\", "\\");
|
||||
line = $STRING.line;
|
||||
}
|
||||
| ML_STRING
|
||||
{
|
||||
testInput = $ML_STRING.text;
|
||||
line = $ML_STRING.line;
|
||||
}
|
||||
| file
|
||||
{
|
||||
testInput = $file.text;
|
||||
inputIsFile = true;
|
||||
line = $file.line;
|
||||
}
|
||||
;
|
||||
|
||||
expect returns [AbstractTest out]
|
||||
: OK {$out = new BooleanTest(true);}
|
||||
| FAIL {$out = new BooleanTest(false);}
|
||||
| 'returns' RETVAL {if ( !$testsuite::isLexicalRule ) $out = new ReturnTest($RETVAL);}
|
||||
| '->' output {if ( !$testsuite::isLexicalRule ) $out = new OutputTest($output.token);}
|
||||
;
|
||||
|
||||
output returns [Token token]
|
||||
: STRING
|
||||
{
|
||||
$STRING.setText($STRING.text.replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t")
|
||||
.replace("\\b", "\b").replace("\\f", "\f").replace("\\\"", "\"").replace("\\'", "\'").replace("\\\\", "\\"));
|
||||
$token = $STRING;
|
||||
}
|
||||
| ML_STRING {$token = $ML_STRING;}
|
||||
| AST {$token = $AST;}
|
||||
| ACTION {$token = $ACTION;}
|
||||
;
|
||||
|
||||
file returns [int line]
|
||||
: id EXT? {$line = $id.line;}
|
||||
;
|
||||
|
||||
id returns [int line]
|
||||
: TOKEN_REF {$line = $TOKEN_REF.line;}
|
||||
| RULE_REF {$line = $RULE_REF.line;}
|
||||
;
|
||||
|
||||
// L E X I C A L R U L E S
|
||||
|
||||
SL_COMMENT
|
||||
: '//' ~('\r'|'\n')* '\r'? '\n' {$channel=HIDDEN;}
|
||||
;
|
||||
|
||||
ML_COMMENT
|
||||
: '/*' {$channel=HIDDEN;} .* '*/'
|
||||
;
|
||||
|
||||
STRING : '"' ( ESC | ~('\\'|'"') )* '"' {setText(getText().substring(1, getText().length()-1));}
|
||||
;
|
||||
|
||||
ML_STRING
|
||||
: {// we need to determine the number of spaces or tabs (indentation) for multi-line input
|
||||
StringBuffer buf = new StringBuffer();
|
||||
int i = -1;
|
||||
int c = input.LA(-1);
|
||||
while ( c==' ' || c=='\t' ) {
|
||||
buf.append((char)c);
|
||||
c = input.LA(--i);
|
||||
}
|
||||
String indentation = buf.reverse().toString();
|
||||
}
|
||||
'<<' .* '>>'
|
||||
{// also determine the appropriate newline separator and get info of the first and last 2 characters (exclude '<<' and '>>')
|
||||
String newline = System.getProperty("line.separator");
|
||||
String front, end;
|
||||
int oldFrontIndex = 2;
|
||||
int oldEndIndex = getText().length()-2;
|
||||
int newFrontIndex, newEndIndex;
|
||||
if ( newline.length()==1 ) {
|
||||
front = getText().substring(2, 3);
|
||||
end = getText().substring(getText().length()-3, getText().length()-2);
|
||||
newFrontIndex = 3;
|
||||
newEndIndex = getText().length()-3;
|
||||
}
|
||||
else {// must be 2, e.g. Windows System which uses \r\n as a line separator
|
||||
front = getText().substring(2, 4);
|
||||
end = getText().substring(getText().length()-4, getText().length()-2);
|
||||
newFrontIndex = 4;
|
||||
newEndIndex = getText().length()-4;
|
||||
}
|
||||
// strip unwanted characters, e.g. '<<' (including a newline after it) or '>>' (including a newline before it)
|
||||
String temp = null;
|
||||
if ( front.equals(newline) && end.equals(newline) ) {
|
||||
// need to handle the special case: <<\n>> or <<\r\n>>
|
||||
if ( newline.length()==1 && getText().length()==5 ) temp = "";
|
||||
else if ( newline.length()==2 && getText().length()==6 ) temp = "";
|
||||
else temp = getText().substring(newFrontIndex, newEndIndex);
|
||||
}
|
||||
else if ( front.equals(newline) ) {
|
||||
temp = getText().substring(newFrontIndex, oldEndIndex);
|
||||
}
|
||||
else if ( end.equals(newline) ) {
|
||||
temp = getText().substring(oldFrontIndex, newEndIndex);
|
||||
}
|
||||
else {
|
||||
temp = getText().substring(oldFrontIndex, oldEndIndex);
|
||||
}
|
||||
// finally we need to prpcess the indentation line by line
|
||||
BufferedReader bufReader = new BufferedReader(new StringReader(temp));
|
||||
buf = new StringBuffer();
|
||||
String line = null;
|
||||
int count = 0;
|
||||
try {
|
||||
while((line = bufReader.readLine()) != null) {
|
||||
if ( line.startsWith(indentation) ) line = line.substring(indentation.length());
|
||||
if ( count>0 ) buf.append(newline);
|
||||
buf.append(line);
|
||||
count++;
|
||||
}
|
||||
setText(buf.toString());
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
setText(temp);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
TOKEN_REF
|
||||
: 'A'..'Z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
RULE_REF
|
||||
: 'a'..'z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
EXT : '.'('a'..'z'|'A'..'Z'|'0'..'9')+;
|
||||
|
||||
RETVAL : NESTED_RETVAL {setText(getText().substring(1, getText().length()-1));}
|
||||
;
|
||||
|
||||
fragment
|
||||
NESTED_RETVAL :
|
||||
'['
|
||||
( options {greedy=false;}
|
||||
: NESTED_RETVAL
|
||||
| .
|
||||
)*
|
||||
']'
|
||||
;
|
||||
|
||||
AST : NESTED_AST (' '? NESTED_AST)*;
|
||||
|
||||
fragment
|
||||
NESTED_AST :
|
||||
'('
|
||||
( NESTED_AST
|
||||
| STRING_LITERAL
|
||||
| ~('('|')'|'"')
|
||||
)*
|
||||
')'
|
||||
;
|
||||
|
||||
OPTIONS : 'options' WS* '{'
|
||||
;
|
||||
|
||||
ACTION
|
||||
: NESTED_ACTION {setText(getText().substring(1, getText().length()-1));}
|
||||
;
|
||||
|
||||
fragment
|
||||
NESTED_ACTION :
|
||||
'{'
|
||||
( options {greedy=false; k=3;}
|
||||
: NESTED_ACTION
|
||||
| STRING_LITERAL
|
||||
| CHAR_LITERAL
|
||||
| .
|
||||
)*
|
||||
'}'
|
||||
;
|
||||
|
||||
fragment
|
||||
CHAR_LITERAL
|
||||
: '\'' ( ESC | ~('\''|'\\') ) '\''
|
||||
;
|
||||
|
||||
fragment
|
||||
STRING_LITERAL
|
||||
: '"' ( ESC | ~('\\'|'"') )* '"'
|
||||
;
|
||||
|
||||
fragment
|
||||
ESC : '\\'
|
||||
( 'n'
|
||||
| 'r'
|
||||
| 't'
|
||||
| 'b'
|
||||
| 'f'
|
||||
| '"'
|
||||
| '\''
|
||||
| '\\'
|
||||
| '>'
|
||||
| 'u' XDIGIT XDIGIT XDIGIT XDIGIT
|
||||
| . // unknown, leave as it is
|
||||
)
|
||||
;
|
||||
|
||||
fragment
|
||||
XDIGIT :
|
||||
'0' .. '9'
|
||||
| 'a' .. 'f'
|
||||
| 'A' .. 'F'
|
||||
;
|
||||
|
||||
WS : ( ' '
|
||||
| '\t'
|
||||
| '\r'? '\n'
|
||||
)+
|
||||
{$channel=HIDDEN;}
|
||||
;
|
@ -0,0 +1,619 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2005-2007 Terence Parr
|
||||
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.
|
||||
*/
|
||||
|
||||
/** ANTLR v3 grammar written in ANTLR v3 with AST construction */
|
||||
grammar ANTLRv3;
|
||||
|
||||
options {
|
||||
output=AST;
|
||||
ASTLabelType=CommonTree;
|
||||
}
|
||||
|
||||
tokens {
|
||||
DOC_COMMENT;
|
||||
PARSER;
|
||||
LEXER;
|
||||
RULE;
|
||||
BLOCK;
|
||||
OPTIONAL;
|
||||
CLOSURE;
|
||||
POSITIVE_CLOSURE;
|
||||
SYNPRED;
|
||||
RANGE;
|
||||
CHAR_RANGE;
|
||||
EPSILON;
|
||||
ALT;
|
||||
EOR;
|
||||
EOB;
|
||||
EOA; // end of alt
|
||||
ID;
|
||||
ARG;
|
||||
ARGLIST;
|
||||
RET;
|
||||
LEXER_GRAMMAR;
|
||||
PARSER_GRAMMAR;
|
||||
TREE_GRAMMAR;
|
||||
COMBINED_GRAMMAR;
|
||||
INITACTION;
|
||||
LABEL; // $x used in rewrite rules
|
||||
TEMPLATE;
|
||||
SCOPE='scope';
|
||||
SEMPRED;
|
||||
GATED_SEMPRED; // {p}? =>
|
||||
SYN_SEMPRED; // (...) => it's a manually-specified synpred converted to sempred
|
||||
BACKTRACK_SEMPRED; // auto backtracking mode syn pred converted to sempred
|
||||
FRAGMENT='fragment';
|
||||
TREE_BEGIN='^(';
|
||||
ROOT='^';
|
||||
BANG='!';
|
||||
RANGE='..';
|
||||
REWRITE='->';
|
||||
}
|
||||
|
||||
@members {
|
||||
int gtype;
|
||||
public List<String> rules;
|
||||
}
|
||||
|
||||
@header {
|
||||
package org.antlr.gunit.swingui.parsers;
|
||||
|
||||
import java.util.List;
|
||||
}
|
||||
|
||||
@lexer::header {
|
||||
package org.antlr.gunit.swingui.parsers;
|
||||
}
|
||||
|
||||
|
||||
grammarDef
|
||||
: DOC_COMMENT?
|
||||
( 'lexer' {gtype=LEXER_GRAMMAR;} // pure lexer
|
||||
| 'parser' {gtype=PARSER_GRAMMAR;} // pure parser
|
||||
| 'tree' {gtype=TREE_GRAMMAR;} // a tree parser
|
||||
| {gtype=COMBINED_GRAMMAR;} // merged parser/lexer
|
||||
)
|
||||
g='grammar' id ';' optionsSpec? tokensSpec? attrScope* action*
|
||||
rule+
|
||||
EOF
|
||||
-> ^( {adaptor.create(gtype,$g)}
|
||||
id DOC_COMMENT? optionsSpec? tokensSpec? attrScope* action* rule+
|
||||
)
|
||||
;
|
||||
|
||||
tokensSpec
|
||||
: TOKENS tokenSpec+ '}' -> ^(TOKENS tokenSpec+)
|
||||
;
|
||||
|
||||
tokenSpec
|
||||
: TOKEN_REF
|
||||
( '=' (lit=STRING_LITERAL|lit=CHAR_LITERAL) -> ^('=' TOKEN_REF $lit)
|
||||
| -> TOKEN_REF
|
||||
)
|
||||
';'
|
||||
;
|
||||
|
||||
attrScope
|
||||
: 'scope' id ACTION -> ^('scope' id ACTION)
|
||||
;
|
||||
|
||||
/** Match stuff like @parser::members {int i;} */
|
||||
action
|
||||
: '@' (actionScopeName '::')? id ACTION -> ^('@' actionScopeName? id ACTION)
|
||||
;
|
||||
|
||||
/** Sometimes the scope names will collide with keywords; allow them as
|
||||
* ids for action scopes.
|
||||
*/
|
||||
actionScopeName
|
||||
: id
|
||||
| l='lexer' -> ID[$l]
|
||||
| p='parser' -> ID[$p]
|
||||
;
|
||||
|
||||
optionsSpec
|
||||
: OPTIONS (option ';')+ '}' -> ^(OPTIONS option+)
|
||||
;
|
||||
|
||||
option
|
||||
: id '=' optionValue -> ^('=' id optionValue)
|
||||
;
|
||||
|
||||
optionValue
|
||||
: id
|
||||
| STRING_LITERAL
|
||||
| CHAR_LITERAL
|
||||
| INT
|
||||
| s='*' -> STRING_LITERAL[$s] // used for k=*
|
||||
;
|
||||
|
||||
rule
|
||||
scope {
|
||||
String name;
|
||||
}
|
||||
@after{
|
||||
this.rules.add($rule::name);
|
||||
}
|
||||
: DOC_COMMENT?
|
||||
( modifier=('protected'|'public'|'private'|'fragment') )?
|
||||
id {$rule::name = $id.text;}
|
||||
'!'?
|
||||
( arg=ARG_ACTION )?
|
||||
( 'returns' rt=ARG_ACTION )?
|
||||
throwsSpec? optionsSpec? ruleScopeSpec? ruleAction*
|
||||
':' altList ';'
|
||||
exceptionGroup?
|
||||
-> ^( RULE id {modifier!=null?adaptor.create(modifier):null} ^(ARG $arg)? ^(RET $rt)?
|
||||
optionsSpec? ruleScopeSpec? ruleAction*
|
||||
altList
|
||||
exceptionGroup?
|
||||
EOR["EOR"]
|
||||
)
|
||||
;
|
||||
|
||||
/** Match stuff like @init {int i;} */
|
||||
ruleAction
|
||||
: '@' id ACTION -> ^('@' id ACTION)
|
||||
;
|
||||
|
||||
throwsSpec
|
||||
: 'throws' id ( ',' id )* -> ^('throws' id+)
|
||||
;
|
||||
|
||||
ruleScopeSpec
|
||||
: 'scope' ACTION -> ^('scope' ACTION)
|
||||
| 'scope' id (',' id)* ';' -> ^('scope' id+)
|
||||
| 'scope' ACTION
|
||||
'scope' id (',' id)* ';'
|
||||
-> ^('scope' ACTION id+ )
|
||||
;
|
||||
|
||||
block
|
||||
: lp='('
|
||||
( (opts=optionsSpec)? ':' )?
|
||||
a1=alternative rewrite ( '|' a2=alternative rewrite )*
|
||||
rp=')'
|
||||
-> ^( BLOCK[$lp,"BLOCK"] optionsSpec? (alternative rewrite?)+ EOB[$rp,"EOB"] )
|
||||
;
|
||||
|
||||
altList
|
||||
@init {
|
||||
// must create root manually as it's used by invoked rules in real antlr tool.
|
||||
// leave here to demonstrate use of {...} in rewrite rule
|
||||
// it's really BLOCK[firstToken,"BLOCK"]; set line/col to previous ( or : token.
|
||||
CommonTree blkRoot = (CommonTree)adaptor.create(BLOCK,input.LT(-1),"BLOCK");
|
||||
}
|
||||
: a1=alternative rewrite ( '|' a2=alternative rewrite )*
|
||||
-> ^( {blkRoot} (alternative rewrite?)+ EOB["EOB"] )
|
||||
;
|
||||
|
||||
alternative
|
||||
@init {
|
||||
Token firstToken = input.LT(1);
|
||||
Token prevToken = input.LT(-1); // either : or | I think
|
||||
}
|
||||
: element+ -> ^(ALT[firstToken,"ALT"] element+ EOA["EOA"])
|
||||
| -> ^(ALT[prevToken,"ALT"] EPSILON[prevToken,"EPSILON"] EOA["EOA"])
|
||||
;
|
||||
|
||||
exceptionGroup
|
||||
: ( exceptionHandler )+ ( finallyClause )?
|
||||
| finallyClause
|
||||
;
|
||||
|
||||
exceptionHandler
|
||||
: 'catch' ARG_ACTION ACTION -> ^('catch' ARG_ACTION ACTION)
|
||||
;
|
||||
|
||||
finallyClause
|
||||
: 'finally' ACTION -> ^('finally' ACTION)
|
||||
;
|
||||
|
||||
element
|
||||
: elementNoOptionSpec
|
||||
;
|
||||
|
||||
elementNoOptionSpec
|
||||
: id (labelOp='='|labelOp='+=') atom
|
||||
( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] ^($labelOp id atom) EOA["EOA"]) EOB["EOB"]))
|
||||
| -> ^($labelOp id atom)
|
||||
)
|
||||
| id (labelOp='='|labelOp='+=') block
|
||||
( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] ^($labelOp id block) EOA["EOA"]) EOB["EOB"]))
|
||||
| -> ^($labelOp id block)
|
||||
)
|
||||
| atom
|
||||
( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] atom EOA["EOA"]) EOB["EOB"]) )
|
||||
| -> atom
|
||||
)
|
||||
| ebnf
|
||||
| ACTION
|
||||
| SEMPRED ( '=>' -> GATED_SEMPRED | -> SEMPRED )
|
||||
| treeSpec
|
||||
( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] treeSpec EOA["EOA"]) EOB["EOB"]) )
|
||||
| -> treeSpec
|
||||
)
|
||||
;
|
||||
|
||||
atom: range ( (op='^'|op='!') -> ^($op range) | -> range )
|
||||
| terminal
|
||||
| notSet ( (op='^'|op='!') -> ^($op notSet) | -> notSet )
|
||||
| RULE_REF ( arg=ARG_ACTION )? ( (op='^'|op='!') )?
|
||||
-> {$arg!=null&&op!=null}? ^($op RULE_REF $arg)
|
||||
-> {$arg!=null}? ^(RULE_REF $arg)
|
||||
-> {$op!=null}? ^($op RULE_REF)
|
||||
-> RULE_REF
|
||||
;
|
||||
|
||||
notSet
|
||||
: '~'
|
||||
( notTerminal -> ^('~' notTerminal)
|
||||
| block -> ^('~' block)
|
||||
)
|
||||
;
|
||||
|
||||
treeSpec
|
||||
: '^(' element ( element )+ ')' -> ^(TREE_BEGIN element+)
|
||||
;
|
||||
|
||||
/** Matches ENBF blocks (and token sets via block rule) */
|
||||
ebnf
|
||||
@init {
|
||||
Token firstToken = input.LT(1);
|
||||
}
|
||||
@after {
|
||||
$ebnf.tree.getToken().setLine(firstToken.getLine());
|
||||
$ebnf.tree.getToken().setCharPositionInLine(firstToken.getCharPositionInLine());
|
||||
}
|
||||
: block
|
||||
( op='?' -> ^(OPTIONAL[op] block)
|
||||
| op='*' -> ^(CLOSURE[op] block)
|
||||
| op='+' -> ^(POSITIVE_CLOSURE[op] block)
|
||||
| '=>' // syntactic predicate
|
||||
-> {gtype==COMBINED_GRAMMAR &&
|
||||
Character.isUpperCase($rule::name.charAt(0))}?
|
||||
// if lexer rule in combined, leave as pred for lexer
|
||||
^(SYNPRED["=>"] block)
|
||||
// in real antlr tool, text for SYN_SEMPRED is predname
|
||||
-> SYN_SEMPRED
|
||||
| -> block
|
||||
)
|
||||
;
|
||||
|
||||
range!
|
||||
: c1=CHAR_LITERAL RANGE c2=CHAR_LITERAL -> ^(CHAR_RANGE[$c1,".."] $c1 $c2)
|
||||
;
|
||||
|
||||
terminal
|
||||
: ( CHAR_LITERAL -> CHAR_LITERAL
|
||||
// Args are only valid for lexer rules
|
||||
| TOKEN_REF
|
||||
( ARG_ACTION -> ^(TOKEN_REF ARG_ACTION)
|
||||
| -> TOKEN_REF
|
||||
)
|
||||
| STRING_LITERAL -> STRING_LITERAL
|
||||
| '.' -> '.'
|
||||
)
|
||||
( '^' -> ^('^' $terminal)
|
||||
| '!' -> ^('!' $terminal)
|
||||
)?
|
||||
;
|
||||
|
||||
notTerminal
|
||||
: CHAR_LITERAL
|
||||
| TOKEN_REF
|
||||
| STRING_LITERAL
|
||||
;
|
||||
|
||||
ebnfSuffix
|
||||
@init {
|
||||
Token op = input.LT(1);
|
||||
}
|
||||
: '?' -> OPTIONAL[op]
|
||||
| '*' -> CLOSURE[op]
|
||||
| '+' -> POSITIVE_CLOSURE[op]
|
||||
;
|
||||
|
||||
|
||||
|
||||
// R E W R I T E S Y N T A X
|
||||
|
||||
rewrite
|
||||
@init {
|
||||
Token firstToken = input.LT(1);
|
||||
}
|
||||
: (rew+='->' preds+=SEMPRED predicated+=rewrite_alternative)*
|
||||
rew2='->' last=rewrite_alternative
|
||||
-> ^($rew $preds $predicated)* ^($rew2 $last)
|
||||
|
|
||||
;
|
||||
|
||||
rewrite_alternative
|
||||
options {backtrack=true;}
|
||||
: rewrite_template
|
||||
| rewrite_tree_alternative
|
||||
| /* empty rewrite */ -> ^(ALT["ALT"] EPSILON["EPSILON"] EOA["EOA"])
|
||||
;
|
||||
|
||||
rewrite_tree_block
|
||||
: lp='(' rewrite_tree_alternative ')'
|
||||
-> ^(BLOCK[$lp,"BLOCK"] rewrite_tree_alternative EOB[$lp,"EOB"])
|
||||
;
|
||||
|
||||
rewrite_tree_alternative
|
||||
: rewrite_tree_element+ -> ^(ALT["ALT"] rewrite_tree_element+ EOA["EOA"])
|
||||
;
|
||||
|
||||
rewrite_tree_element
|
||||
: rewrite_tree_atom
|
||||
| rewrite_tree_atom ebnfSuffix
|
||||
-> ^( ebnfSuffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] rewrite_tree_atom EOA["EOA"]) EOB["EOB"]))
|
||||
| rewrite_tree
|
||||
( ebnfSuffix
|
||||
-> ^(ebnfSuffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] rewrite_tree EOA["EOA"]) EOB["EOB"]))
|
||||
| -> rewrite_tree
|
||||
)
|
||||
| rewrite_tree_ebnf
|
||||
;
|
||||
|
||||
rewrite_tree_atom
|
||||
: CHAR_LITERAL
|
||||
| TOKEN_REF ARG_ACTION? -> ^(TOKEN_REF ARG_ACTION?) // for imaginary nodes
|
||||
| RULE_REF
|
||||
| STRING_LITERAL
|
||||
| d='$' id -> LABEL[$d,$id.text] // reference to a label in a rewrite rule
|
||||
| ACTION
|
||||
;
|
||||
|
||||
rewrite_tree_ebnf
|
||||
@init {
|
||||
Token firstToken = input.LT(1);
|
||||
}
|
||||
@after {
|
||||
$rewrite_tree_ebnf.tree.getToken().setLine(firstToken.getLine());
|
||||
$rewrite_tree_ebnf.tree.getToken().setCharPositionInLine(firstToken.getCharPositionInLine());
|
||||
}
|
||||
: rewrite_tree_block ebnfSuffix -> ^(ebnfSuffix rewrite_tree_block)
|
||||
;
|
||||
|
||||
rewrite_tree
|
||||
: '^(' rewrite_tree_atom rewrite_tree_element* ')'
|
||||
-> ^(TREE_BEGIN rewrite_tree_atom rewrite_tree_element* )
|
||||
;
|
||||
|
||||
/** Build a tree for a template rewrite:
|
||||
^(TEMPLATE (ID|ACTION) ^(ARGLIST ^(ARG ID ACTION) ...) )
|
||||
where ARGLIST is always there even if no args exist.
|
||||
ID can be "template" keyword. If first child is ACTION then it's
|
||||
an indirect template ref
|
||||
|
||||
-> foo(a={...}, b={...})
|
||||
-> ({string-e})(a={...}, b={...}) // e evaluates to template name
|
||||
-> {%{$ID.text}} // create literal template from string (done in ActionTranslator)
|
||||
-> {st-expr} // st-expr evaluates to ST
|
||||
*/
|
||||
rewrite_template
|
||||
: // -> template(a={...},...) "..." inline template
|
||||
id lp='(' rewrite_template_args ')'
|
||||
( str=DOUBLE_QUOTE_STRING_LITERAL | str=DOUBLE_ANGLE_STRING_LITERAL )
|
||||
-> ^(TEMPLATE[$lp,"TEMPLATE"] id rewrite_template_args $str)
|
||||
|
||||
| // -> foo(a={...}, ...)
|
||||
rewrite_template_ref
|
||||
|
||||
| // -> ({expr})(a={...}, ...)
|
||||
rewrite_indirect_template_head
|
||||
|
||||
| // -> {...}
|
||||
ACTION
|
||||
;
|
||||
|
||||
/** -> foo(a={...}, ...) */
|
||||
rewrite_template_ref
|
||||
: id lp='(' rewrite_template_args ')'
|
||||
-> ^(TEMPLATE[$lp,"TEMPLATE"] id rewrite_template_args)
|
||||
;
|
||||
|
||||
/** -> ({expr})(a={...}, ...) */
|
||||
rewrite_indirect_template_head
|
||||
: lp='(' ACTION ')' '(' rewrite_template_args ')'
|
||||
-> ^(TEMPLATE[$lp,"TEMPLATE"] ACTION rewrite_template_args)
|
||||
;
|
||||
|
||||
rewrite_template_args
|
||||
: rewrite_template_arg (',' rewrite_template_arg)*
|
||||
-> ^(ARGLIST rewrite_template_arg+)
|
||||
| -> ARGLIST
|
||||
;
|
||||
|
||||
rewrite_template_arg
|
||||
: id '=' ACTION -> ^(ARG[$id.start] id ACTION)
|
||||
;
|
||||
|
||||
id : TOKEN_REF -> ID[$TOKEN_REF]
|
||||
| RULE_REF -> ID[$RULE_REF]
|
||||
;
|
||||
|
||||
// L E X I C A L R U L E S
|
||||
|
||||
SL_COMMENT
|
||||
: '//'
|
||||
( ' $ANTLR ' SRC // src directive
|
||||
| ~('\r'|'\n')*
|
||||
)
|
||||
'\r'? '\n'
|
||||
{$channel=HIDDEN;}
|
||||
;
|
||||
|
||||
ML_COMMENT
|
||||
: '/*' {if (input.LA(1)=='*') $type=DOC_COMMENT; else $channel=HIDDEN;} .* '*/'
|
||||
;
|
||||
|
||||
CHAR_LITERAL
|
||||
: '\'' LITERAL_CHAR '\''
|
||||
;
|
||||
|
||||
STRING_LITERAL
|
||||
: '\'' LITERAL_CHAR LITERAL_CHAR* '\''
|
||||
;
|
||||
|
||||
fragment
|
||||
LITERAL_CHAR
|
||||
: ESC
|
||||
| ~('\''|'\\')
|
||||
;
|
||||
|
||||
DOUBLE_QUOTE_STRING_LITERAL
|
||||
: '"' (ESC | ~('\\'|'"'))* '"'
|
||||
;
|
||||
|
||||
DOUBLE_ANGLE_STRING_LITERAL
|
||||
: '<<' .* '>>'
|
||||
;
|
||||
|
||||
fragment
|
||||
ESC : '\\'
|
||||
( 'n'
|
||||
| 'r'
|
||||
| 't'
|
||||
| 'b'
|
||||
| 'f'
|
||||
| '"'
|
||||
| '\''
|
||||
| '\\'
|
||||
| '>'
|
||||
| 'u' XDIGIT XDIGIT XDIGIT XDIGIT
|
||||
| . // unknown, leave as it is
|
||||
)
|
||||
;
|
||||
|
||||
fragment
|
||||
XDIGIT :
|
||||
'0' .. '9'
|
||||
| 'a' .. 'f'
|
||||
| 'A' .. 'F'
|
||||
;
|
||||
|
||||
INT : '0'..'9'+
|
||||
;
|
||||
|
||||
ARG_ACTION
|
||||
: NESTED_ARG_ACTION
|
||||
;
|
||||
|
||||
fragment
|
||||
NESTED_ARG_ACTION :
|
||||
'['
|
||||
( options {greedy=false; k=1;}
|
||||
: NESTED_ARG_ACTION
|
||||
| ACTION_STRING_LITERAL
|
||||
| ACTION_CHAR_LITERAL
|
||||
| .
|
||||
)*
|
||||
']'
|
||||
{setText(getText().substring(1, getText().length()-1));}
|
||||
;
|
||||
|
||||
ACTION
|
||||
: NESTED_ACTION ( '?' {$type = SEMPRED;} )?
|
||||
;
|
||||
|
||||
fragment
|
||||
NESTED_ACTION :
|
||||
'{'
|
||||
( options {greedy=false; k=2;}
|
||||
: NESTED_ACTION
|
||||
| SL_COMMENT
|
||||
| ML_COMMENT
|
||||
| ACTION_STRING_LITERAL
|
||||
| ACTION_CHAR_LITERAL
|
||||
| .
|
||||
)*
|
||||
'}'
|
||||
;
|
||||
|
||||
fragment
|
||||
ACTION_CHAR_LITERAL
|
||||
: '\'' (ACTION_ESC|~('\\'|'\'')) '\''
|
||||
;
|
||||
|
||||
fragment
|
||||
ACTION_STRING_LITERAL
|
||||
: '"' (ACTION_ESC|~('\\'|'"'))* '"'
|
||||
;
|
||||
|
||||
fragment
|
||||
ACTION_ESC
|
||||
: '\\\''
|
||||
| '\\' '"' // ANTLR doesn't like: '\\"'
|
||||
| '\\' ~('\''|'"')
|
||||
;
|
||||
|
||||
TOKEN_REF
|
||||
: 'A'..'Z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
RULE_REF
|
||||
: 'a'..'z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
/** Match the start of an options section. Don't allow normal
|
||||
* action processing on the {...} as it's not a action.
|
||||
*/
|
||||
OPTIONS
|
||||
: 'options' WS_LOOP '{'
|
||||
;
|
||||
|
||||
TOKENS
|
||||
: 'tokens' WS_LOOP '{'
|
||||
;
|
||||
|
||||
/** Reset the file and line information; useful when the grammar
|
||||
* has been generated so that errors are shown relative to the
|
||||
* original file like the old C preprocessor used to do.
|
||||
*/
|
||||
fragment
|
||||
SRC : 'src' ' ' file=ACTION_STRING_LITERAL ' ' line=INT
|
||||
;
|
||||
|
||||
WS : ( ' '
|
||||
| '\t'
|
||||
| '\r'? '\n'
|
||||
)+
|
||||
{$channel=HIDDEN;}
|
||||
;
|
||||
|
||||
fragment
|
||||
WS_LOOP
|
||||
: ( WS
|
||||
| SL_COMMENT
|
||||
| ML_COMMENT
|
||||
)*
|
||||
;
|
||||
|
||||
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon Jen-Yuan Su
|
||||
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.
|
||||
*/
|
||||
|
||||
grammar StGUnit;
|
||||
|
||||
options {language=Java;}
|
||||
|
||||
tokens {
|
||||
OK = 'OK';
|
||||
FAIL = 'FAIL';
|
||||
DOC_COMMENT;
|
||||
}
|
||||
|
||||
@header {
|
||||
package org.antlr.gunit.swingui.parsers;
|
||||
import org.antlr.gunit.swingui.model.*;
|
||||
import org.antlr.gunit.swingui.runner.*;
|
||||
}
|
||||
|
||||
@lexer::header {package org.antlr.gunit.swingui.parsers;}
|
||||
|
||||
@members {
|
||||
public TestSuiteAdapter adapter ;;
|
||||
}
|
||||
|
||||
gUnitDef
|
||||
: 'gunit' name=id {adapter.setGrammarName($name.text);}
|
||||
('walks' id)? ';'
|
||||
header? suite*
|
||||
;
|
||||
|
||||
header
|
||||
: '@header' ACTION
|
||||
;
|
||||
|
||||
suite
|
||||
: ( parserRule=RULE_REF ('walks' RULE_REF)?
|
||||
{adapter.startRule($parserRule.text);}
|
||||
| lexerRule=TOKEN_REF
|
||||
{adapter.startRule($lexerRule.text);}
|
||||
)
|
||||
':'
|
||||
test+
|
||||
{adapter.endRule();}
|
||||
;
|
||||
|
||||
test
|
||||
: input expect
|
||||
{adapter.addTestCase($input.in, $expect.out);}
|
||||
;
|
||||
|
||||
expect returns [ITestCaseOutput out]
|
||||
: OK {$out = TestSuiteAdapter.createBoolOutput(true);}
|
||||
| FAIL {$out = TestSuiteAdapter.createBoolOutput(false);}
|
||||
| 'returns' RETVAL {$out = TestSuiteAdapter.createReturnOutput($RETVAL.text);}
|
||||
| '->' output {$out = TestSuiteAdapter.createStdOutput($output.text);}
|
||||
| '->' AST {$out = TestSuiteAdapter.createAstOutput($AST.text);}
|
||||
;
|
||||
|
||||
input returns [ITestCaseInput in]
|
||||
: STRING {$in = TestSuiteAdapter.createStringInput($STRING.text);}
|
||||
| ML_STRING {$in = TestSuiteAdapter.createMultiInput($ML_STRING.text);}
|
||||
| fileInput {$in = TestSuiteAdapter.createFileInput($fileInput.path);}
|
||||
;
|
||||
|
||||
output
|
||||
: STRING
|
||||
| ML_STRING
|
||||
| ACTION
|
||||
;
|
||||
|
||||
fileInput returns [String path]
|
||||
: id {$path = $id.text;} (EXT {$path += $EXT.text;})?
|
||||
;
|
||||
|
||||
id : TOKEN_REF
|
||||
| RULE_REF
|
||||
;
|
||||
|
||||
// L E X I C A L R U L E S
|
||||
|
||||
SL_COMMENT
|
||||
: '//' ~('\r'|'\n')* '\r'? '\n' {$channel=HIDDEN;}
|
||||
;
|
||||
|
||||
ML_COMMENT
|
||||
: '/*' {$channel=HIDDEN;} .* '*/'
|
||||
;
|
||||
|
||||
STRING
|
||||
: '"' ( ESC | ~('\\'|'"') )* '"'
|
||||
;
|
||||
|
||||
ML_STRING
|
||||
: '<<' .* '>>'
|
||||
;
|
||||
|
||||
TOKEN_REF
|
||||
: 'A'..'Z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
RULE_REF
|
||||
: 'a'..'z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
EXT : '.'('a'..'z'|'A'..'Z'|'0'..'9')+;
|
||||
|
||||
RETVAL : NESTED_RETVAL
|
||||
;
|
||||
|
||||
fragment
|
||||
NESTED_RETVAL :
|
||||
'['
|
||||
( options {greedy=false;}
|
||||
: NESTED_RETVAL
|
||||
| .
|
||||
)*
|
||||
']'
|
||||
;
|
||||
|
||||
AST : NESTED_AST (' '? NESTED_AST)*;
|
||||
|
||||
fragment
|
||||
NESTED_AST :
|
||||
'('
|
||||
( options {greedy=false;}
|
||||
: NESTED_AST
|
||||
| .
|
||||
)*
|
||||
')'
|
||||
;
|
||||
|
||||
ACTION
|
||||
: NESTED_ACTION
|
||||
;
|
||||
|
||||
fragment
|
||||
NESTED_ACTION :
|
||||
'{'
|
||||
( options {greedy=false; k=3;}
|
||||
: NESTED_ACTION
|
||||
| STRING_LITERAL
|
||||
| CHAR_LITERAL
|
||||
| .
|
||||
)*
|
||||
'}'
|
||||
;
|
||||
|
||||
fragment
|
||||
CHAR_LITERAL
|
||||
: '\'' ( ESC | ~('\''|'\\') ) '\''
|
||||
;
|
||||
|
||||
fragment
|
||||
STRING_LITERAL
|
||||
: '"' ( ESC | ~('\\'|'"') )* '"'
|
||||
;
|
||||
|
||||
fragment
|
||||
ESC : '\\'
|
||||
( 'n'
|
||||
| 'r'
|
||||
| 't'
|
||||
| 'b'
|
||||
| 'f'
|
||||
| '"'
|
||||
| '\''
|
||||
| '\\'
|
||||
| '>'
|
||||
| 'u' XDIGIT XDIGIT XDIGIT XDIGIT
|
||||
| . // unknown, leave as it is
|
||||
)
|
||||
;
|
||||
|
||||
fragment
|
||||
XDIGIT :
|
||||
'0' .. '9'
|
||||
| 'a' .. 'f'
|
||||
| 'A' .. 'F'
|
||||
;
|
||||
|
||||
WS : ( ' '
|
||||
| '\t'
|
||||
| '\r'? '\n'
|
||||
)+
|
||||
{$channel=HIDDEN;}
|
||||
;
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2007 Kenny MacDermid
|
||||
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.gunit;
|
||||
|
||||
public abstract class AbstractTest implements ITestCase {
|
||||
// store essential individual test result for string template
|
||||
protected String header;
|
||||
protected String actual;
|
||||
|
||||
protected boolean hasErrorMsg;
|
||||
|
||||
private String testedRuleName;
|
||||
private int testCaseIndex;
|
||||
|
||||
// TODO: remove these. They're only used as part of a refactor to keep the
|
||||
// code cleaner. It is a mock-instanceOf() replacement.
|
||||
public abstract int getType();
|
||||
public abstract String getText();
|
||||
|
||||
public abstract String getExpected();
|
||||
// return an escaped string of the expected result
|
||||
public String getExpectedResult() {
|
||||
String expected = getExpected();
|
||||
if ( expected!=null ) expected = JUnitCodeGen.escapeForJava(expected);
|
||||
return expected;
|
||||
}
|
||||
public abstract String getResult(gUnitTestResult testResult);
|
||||
public String getHeader() { return this.header; }
|
||||
public String getActual() { return this.actual; }
|
||||
// return an escaped string of the actual result
|
||||
public String getActualResult() {
|
||||
String actual = getActual();
|
||||
// there is no need to escape the error message from ANTLR
|
||||
if ( actual!=null && !hasErrorMsg ) actual = JUnitCodeGen.escapeForJava(actual);
|
||||
return actual;
|
||||
}
|
||||
|
||||
public String getTestedRuleName() { return this.testedRuleName; }
|
||||
public int getTestCaseIndex() { return this.testCaseIndex; }
|
||||
|
||||
public void setHeader(String rule, String lexicalRule, String treeRule, int numOfTest, int line, String input) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("test" + numOfTest + " (");
|
||||
if ( treeRule!=null ) {
|
||||
buf.append(treeRule+" walks ");
|
||||
}
|
||||
if ( lexicalRule!=null ) {
|
||||
buf.append(lexicalRule + ", line"+line+")" + " - ");
|
||||
}
|
||||
else buf.append(rule + ", line"+line+")" + " - ");
|
||||
buf.append( "\"" );
|
||||
buf.append( input );
|
||||
buf.append( "\"" );
|
||||
this.header = buf.toString();
|
||||
}
|
||||
public void setActual(String actual) { this.actual = actual; }
|
||||
|
||||
public void setTestedRuleName(String testedRuleName) { this.testedRuleName = testedRuleName; }
|
||||
public void setTestCaseIndex(int testCaseIndex) { this.testCaseIndex = testCaseIndex; }
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2007 Kenny MacDermid
|
||||
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.gunit;
|
||||
|
||||
public class BooleanTest extends AbstractTest {
|
||||
private boolean ok;
|
||||
|
||||
public BooleanTest(boolean ok) {
|
||||
this.ok = ok;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return (ok)? "OK" : "FAIL";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return (ok)? gUnitParser.OK : gUnitParser.FAIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResult(gUnitTestResult testResult) {
|
||||
if ( testResult.isLexerTest() ) {
|
||||
if ( testResult.isSuccess() ) return "OK";
|
||||
else {
|
||||
hasErrorMsg = true; // return error message for boolean test of lexer
|
||||
return testResult.getError();
|
||||
}
|
||||
}
|
||||
return (testResult.isSuccess())? "OK" : "FAIL";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpected() {
|
||||
return (ok)? "OK" : "FAIL";
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon, Jen-Yuan Su
|
||||
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.gunit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class GrammarInfo {
|
||||
|
||||
private String grammarName; // targeted grammar for unit test
|
||||
private String treeGrammarName = null; // optional, required for testing tree grammar
|
||||
private String grammarPackage = null; // optional, package parser lives in
|
||||
private String testPackage = null; // optional, package of junit code
|
||||
private String adaptor = null; // optional, required if using customized tree adaptor
|
||||
private List<gUnitTestSuite> ruleTestSuites = new ArrayList<gUnitTestSuite>(); // testsuites for each testing rule
|
||||
private StringBuffer unitTestResult = new StringBuffer();
|
||||
|
||||
public String getGrammarName() {
|
||||
return grammarName;
|
||||
}
|
||||
|
||||
public void setGrammarName(String grammarName) {
|
||||
this.grammarName = grammarName;
|
||||
}
|
||||
|
||||
public String getTreeGrammarName() {
|
||||
return treeGrammarName;
|
||||
}
|
||||
|
||||
public void setTreeGrammarName(String treeGrammarName) {
|
||||
this.treeGrammarName = treeGrammarName;
|
||||
}
|
||||
|
||||
public String getTestPackage() {
|
||||
return testPackage;
|
||||
}
|
||||
|
||||
public void setTestPackage(String testPackage) {
|
||||
this.testPackage = testPackage;
|
||||
}
|
||||
|
||||
public String getGrammarPackage() {
|
||||
return grammarPackage;
|
||||
}
|
||||
|
||||
public void setGrammarPackage(String grammarPackage) {
|
||||
this.grammarPackage = grammarPackage;
|
||||
}
|
||||
|
||||
public String getAdaptor() {
|
||||
return adaptor;
|
||||
}
|
||||
|
||||
public void setAdaptor(String adaptor) {
|
||||
this.adaptor = adaptor;
|
||||
}
|
||||
|
||||
public List<gUnitTestSuite> getRuleTestSuites() {
|
||||
// Make this list unmodifiable so that we can refactor knowing it's not changed.
|
||||
return Collections.unmodifiableList(ruleTestSuites);
|
||||
}
|
||||
|
||||
public void addRuleTestSuite(gUnitTestSuite testSuite) {
|
||||
this.ruleTestSuites.add(testSuite);
|
||||
}
|
||||
|
||||
public void appendUnitTestResult(String result) {
|
||||
this.unitTestResult.append(result);
|
||||
}
|
||||
|
||||
// We don't want people messing with the string buffer here, so don't return it.
|
||||
public String getUnitTestResult() {
|
||||
return unitTestResult.toString();
|
||||
}
|
||||
|
||||
public void setUnitTestResult(StringBuffer unitTestResult) {
|
||||
this.unitTestResult = unitTestResult;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit;
|
||||
|
||||
/**
|
||||
* ITestCase object locates one test case in a gUnit script by specifying the
|
||||
* tested rule and the index number of the test case in that group.
|
||||
*
|
||||
* For example:
|
||||
* ----------------------
|
||||
* ...
|
||||
* varDef:
|
||||
* "int i;" OK
|
||||
* "float 2f;" FAIL
|
||||
* ...
|
||||
* ----------------------
|
||||
* The "testedRuleName" for these two test cases will be "varDef".
|
||||
* The "index" for the "int"-test will be 0.
|
||||
* The "index" for the "float"-test will be 1. And so on.
|
||||
*
|
||||
* @see ITestSuite
|
||||
*/
|
||||
public interface ITestCase {
|
||||
|
||||
/**
|
||||
* Get the name of the rule that is tested by this test case.
|
||||
* @return name of the tested rule.
|
||||
*/
|
||||
public String getTestedRuleName();
|
||||
|
||||
/**
|
||||
* Get the index of the test case in the test group for a rule. Starting
|
||||
* from 0.
|
||||
* @return index number of the test case.
|
||||
*/
|
||||
public int getTestCaseIndex();
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit;
|
||||
|
||||
/**
|
||||
* A gUnit script file is an Antlr "test suite". The interface is defined to
|
||||
* allow the Swing GUI test runner be notified when gUnit interpreter runner
|
||||
* runs a passed/failed test case.
|
||||
*
|
||||
* CHANGES:
|
||||
* 2009-03-01: SHAOTING
|
||||
* - change method return void, parameter test object.
|
||||
*/
|
||||
public interface ITestSuite {
|
||||
|
||||
public void onPass(ITestCase passTest);
|
||||
|
||||
public void onFail(ITestCase failTest);
|
||||
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon Jen-Yuan Su
|
||||
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.gunit;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
|
||||
/** The main gUnit interpreter entry point.
|
||||
* Read a gUnit script, run unit tests or generate a junit file.
|
||||
*/
|
||||
public class Interp {
|
||||
static String testPackage;
|
||||
static boolean genJUnit;
|
||||
static String gunitFile;
|
||||
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException, RecognitionException {
|
||||
/** Pull char from where? */
|
||||
CharStream input = null;
|
||||
/** If the input source is a testsuite file, where is it? */
|
||||
String testsuiteDir = System.getProperty("user.dir");
|
||||
|
||||
processArgs(args);
|
||||
|
||||
if ( genJUnit ) {
|
||||
if ( gunitFile!=null ) {
|
||||
input = new ANTLRFileStream(gunitFile);
|
||||
File f = new File(gunitFile);
|
||||
testsuiteDir = getTestsuiteDir(f.getCanonicalPath(), f.getName());
|
||||
}
|
||||
else {
|
||||
input = new ANTLRInputStream(System.in);
|
||||
}
|
||||
GrammarInfo grammarInfo = parse(input);
|
||||
grammarInfo.setTestPackage(testPackage);
|
||||
JUnitCodeGen generater = new JUnitCodeGen(grammarInfo, testsuiteDir);
|
||||
generater.compile();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( gunitFile!=null ) {
|
||||
input = new ANTLRFileStream(gunitFile);
|
||||
File f = new File(gunitFile);
|
||||
testsuiteDir = getTestsuiteDir(f.getCanonicalPath(), f.getName());
|
||||
}
|
||||
else
|
||||
input = new ANTLRInputStream(System.in);
|
||||
|
||||
gUnitExecutor executer = new gUnitExecutor(parse(input), testsuiteDir);
|
||||
|
||||
System.out.print(executer.execTest()); // unit test result
|
||||
|
||||
//return an error code of the number of failures
|
||||
System.exit(executer.failures.size() + executer.invalids.size());
|
||||
}
|
||||
|
||||
public static void processArgs(String[] args) {
|
||||
if (args == null || args.length == 0) return;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].equals("-p")) {
|
||||
if (i + 1 >= args.length) {
|
||||
System.err.println("missing library directory with -lib option; ignoring");
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
testPackage = args[i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals("-o")) genJUnit = true;
|
||||
else gunitFile = args[i]; // Must be the gunit file
|
||||
}
|
||||
}
|
||||
|
||||
public static GrammarInfo parse(CharStream input) throws RecognitionException {
|
||||
gUnitLexer lexer = new gUnitLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
|
||||
GrammarInfo grammarInfo = new GrammarInfo();
|
||||
gUnitParser parser = new gUnitParser(tokens, grammarInfo);
|
||||
parser.gUnitDef(); // parse gunit script and save elements to grammarInfo
|
||||
return grammarInfo;
|
||||
}
|
||||
|
||||
public static String getTestsuiteDir(String fullPath, String fileName) {
|
||||
return fullPath.substring(0, fullPath.length()-fileName.length());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2007 Kenny MacDermid
|
||||
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.gunit;
|
||||
|
||||
public class InvalidInputException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
@ -0,0 +1,407 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon Jen-Yuan Su
|
||||
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.gunit;
|
||||
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||
import org.antlr.stringtemplate.StringTemplateGroupLoader;
|
||||
import org.antlr.stringtemplate.CommonGroupLoader;
|
||||
import org.antlr.stringtemplate.language.AngleBracketTemplateLexer;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class JUnitCodeGen {
|
||||
public GrammarInfo grammarInfo;
|
||||
public Map<String, String> ruleWithReturn;
|
||||
private final String testsuiteDir;
|
||||
private String outputDirectoryPath = ".";
|
||||
|
||||
private final static Handler console = new ConsoleHandler();
|
||||
private static final Logger logger = Logger.getLogger(JUnitCodeGen.class.getName());
|
||||
static {
|
||||
logger.addHandler(console);
|
||||
}
|
||||
|
||||
public JUnitCodeGen(GrammarInfo grammarInfo, String testsuiteDir) throws ClassNotFoundException {
|
||||
this( grammarInfo, determineClassLoader(), testsuiteDir);
|
||||
}
|
||||
|
||||
private static ClassLoader determineClassLoader() {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if ( classLoader == null ) {
|
||||
classLoader = JUnitCodeGen.class.getClassLoader();
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public JUnitCodeGen(GrammarInfo grammarInfo, ClassLoader classLoader, String testsuiteDir) throws ClassNotFoundException {
|
||||
this.grammarInfo = grammarInfo;
|
||||
this.testsuiteDir = testsuiteDir;
|
||||
/** Map the name of rules having return value to its return type */
|
||||
ruleWithReturn = new HashMap<String, String>();
|
||||
Class<?> parserClass = locateParserClass( grammarInfo, classLoader );
|
||||
Method[] methods = parserClass.getDeclaredMethods();
|
||||
for(Method method : methods) {
|
||||
if ( !method.getReturnType().getName().equals("void") ) {
|
||||
ruleWithReturn.put(method.getName(), method.getReturnType().getName().replace('$', '.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> locateParserClass(GrammarInfo grammarInfo, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
String parserClassName = grammarInfo.getGrammarName() + "Parser";
|
||||
if ( grammarInfo.getGrammarPackage() != null ) {
|
||||
parserClassName = grammarInfo.getGrammarPackage()+ "." + parserClassName;
|
||||
}
|
||||
return classLoader.loadClass( parserClassName );
|
||||
}
|
||||
|
||||
public String getOutputDirectoryPath() {
|
||||
return outputDirectoryPath;
|
||||
}
|
||||
|
||||
public void setOutputDirectoryPath(String outputDirectoryPath) {
|
||||
this.outputDirectoryPath = outputDirectoryPath;
|
||||
}
|
||||
|
||||
public void compile() throws IOException{
|
||||
String junitFileName;
|
||||
if ( grammarInfo.getTreeGrammarName()!=null ) {
|
||||
junitFileName = "Test"+grammarInfo.getTreeGrammarName();
|
||||
}
|
||||
else {
|
||||
junitFileName = "Test"+grammarInfo.getGrammarName();
|
||||
}
|
||||
String lexerName = grammarInfo.getGrammarName()+"Lexer";
|
||||
String parserName = grammarInfo.getGrammarName()+"Parser";
|
||||
|
||||
StringTemplateGroupLoader loader = new CommonGroupLoader("org/antlr/gunit", null);
|
||||
StringTemplateGroup.registerGroupLoader(loader);
|
||||
StringTemplateGroup.registerDefaultLexer(AngleBracketTemplateLexer.class);
|
||||
StringBuffer buf = compileToBuffer(junitFileName, lexerName, parserName);
|
||||
writeTestFile(".", junitFileName+".java", buf.toString());
|
||||
}
|
||||
|
||||
public StringBuffer compileToBuffer(String className, String lexerName, String parserName) {
|
||||
StringTemplateGroup group = StringTemplateGroup.loadGroup("junit");
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(genClassHeader(group, className, lexerName, parserName));
|
||||
buf.append(genTestRuleMethods(group));
|
||||
buf.append("\n\n}");
|
||||
return buf;
|
||||
}
|
||||
|
||||
protected String genClassHeader(StringTemplateGroup group, String junitFileName, String lexerName, String parserName) {
|
||||
StringTemplate classHeaderST = group.getInstanceOf("classHeader");
|
||||
if ( grammarInfo.getTestPackage()!=null ) { // Set up class package if there is
|
||||
classHeaderST.setAttribute("header", "package "+grammarInfo.getTestPackage()+";");
|
||||
}
|
||||
classHeaderST.setAttribute("junitFileName", junitFileName);
|
||||
|
||||
String lexerPath = null;
|
||||
String parserPath = null;
|
||||
String treeParserPath = null;
|
||||
String packagePath = null;
|
||||
boolean isTreeGrammar = false;
|
||||
boolean hasPackage = false;
|
||||
/** Set up appropriate class path for parser/tree parser if using package */
|
||||
if ( grammarInfo.getGrammarPackage()!=null ) {
|
||||
hasPackage = true;
|
||||
packagePath = "./"+grammarInfo.getGrammarPackage().replace('.', '/');
|
||||
lexerPath = grammarInfo.getGrammarPackage()+"."+lexerName;
|
||||
parserPath = grammarInfo.getGrammarPackage()+"."+parserName;
|
||||
if ( grammarInfo.getTreeGrammarName()!=null ) {
|
||||
treeParserPath = grammarInfo.getGrammarPackage()+"."+grammarInfo.getTreeGrammarName();
|
||||
isTreeGrammar = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lexerPath = lexerName;
|
||||
parserPath = parserName;
|
||||
if ( grammarInfo.getTreeGrammarName()!=null ) {
|
||||
treeParserPath = grammarInfo.getTreeGrammarName();
|
||||
isTreeGrammar = true;
|
||||
}
|
||||
}
|
||||
// also set up custom tree adaptor if necessary
|
||||
String treeAdaptorPath = null;
|
||||
boolean hasTreeAdaptor = false;
|
||||
if ( grammarInfo.getAdaptor()!=null ) {
|
||||
hasTreeAdaptor = true;
|
||||
treeAdaptorPath = grammarInfo.getAdaptor();
|
||||
}
|
||||
classHeaderST.setAttribute("hasTreeAdaptor", hasTreeAdaptor);
|
||||
classHeaderST.setAttribute("treeAdaptorPath", treeAdaptorPath);
|
||||
classHeaderST.setAttribute("hasPackage", hasPackage);
|
||||
classHeaderST.setAttribute("packagePath", packagePath);
|
||||
classHeaderST.setAttribute("lexerPath", lexerPath);
|
||||
classHeaderST.setAttribute("parserPath", parserPath);
|
||||
classHeaderST.setAttribute("treeParserPath", treeParserPath);
|
||||
classHeaderST.setAttribute("isTreeGrammar", isTreeGrammar);
|
||||
return classHeaderST.toString();
|
||||
}
|
||||
|
||||
protected String genTestRuleMethods(StringTemplateGroup group) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if ( grammarInfo.getTreeGrammarName()!=null ) { // Generate junit codes of for tree grammar rule
|
||||
genTreeMethods(group, buf);
|
||||
}
|
||||
else { // Generate junit codes of for grammar rule
|
||||
genParserMethods(group, buf);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void genParserMethods(StringTemplateGroup group, StringBuffer buf) {
|
||||
for ( gUnitTestSuite ts: grammarInfo.getRuleTestSuites() ) {
|
||||
int i = 0;
|
||||
for ( Map.Entry<gUnitTestInput, AbstractTest> entry : ts.testSuites.entrySet() ) { // each rule may contain multiple tests
|
||||
gUnitTestInput input = entry.getKey();
|
||||
i++;
|
||||
StringTemplate testRuleMethodST;
|
||||
/** If rule has multiple return values or ast*/
|
||||
if ( entry.getValue().getType()== gUnitParser.ACTION && ruleWithReturn.containsKey(ts.getRuleName()) ) {
|
||||
testRuleMethodST = group.getInstanceOf("testRuleMethod2");
|
||||
String outputString = entry.getValue().getText();
|
||||
testRuleMethodST.setAttribute("methodName", "test"+changeFirstCapital(ts.getRuleName())+i);
|
||||
testRuleMethodST.setAttribute("testRuleName", '"'+ts.getRuleName()+'"');
|
||||
testRuleMethodST.setAttribute("test", input);
|
||||
testRuleMethodST.setAttribute("returnType", ruleWithReturn.get(ts.getRuleName()));
|
||||
testRuleMethodST.setAttribute("expecting", outputString);
|
||||
}
|
||||
else {
|
||||
String testRuleName;
|
||||
// need to determine whether it's a test for parser rule or lexer rule
|
||||
if ( ts.isLexicalRule() ) testRuleName = ts.getLexicalRuleName();
|
||||
else testRuleName = ts.getRuleName();
|
||||
testRuleMethodST = group.getInstanceOf("testRuleMethod");
|
||||
String outputString = entry.getValue().getText();
|
||||
testRuleMethodST.setAttribute("isLexicalRule", ts.isLexicalRule());
|
||||
testRuleMethodST.setAttribute("methodName", "test"+changeFirstCapital(testRuleName)+i);
|
||||
testRuleMethodST.setAttribute("testRuleName", '"'+testRuleName+'"');
|
||||
testRuleMethodST.setAttribute("test", input);
|
||||
testRuleMethodST.setAttribute("tokenType", getTypeString(entry.getValue().getType()));
|
||||
|
||||
// normalize whitespace
|
||||
outputString = normalizeTreeSpec(outputString);
|
||||
|
||||
if ( entry.getValue().getType()==gUnitParser.ACTION ) { // trim ';' at the end of ACTION if there is...
|
||||
//testRuleMethodST.setAttribute("expecting", outputString.substring(0, outputString.length()-1));
|
||||
testRuleMethodST.setAttribute("expecting", outputString);
|
||||
}
|
||||
else if ( entry.getValue().getType()==gUnitParser.RETVAL ) { // Expected: RETVAL
|
||||
testRuleMethodST.setAttribute("expecting", outputString);
|
||||
}
|
||||
else { // Attach "" to expected STRING or AST
|
||||
// strip newlines for (...) tree stuff
|
||||
outputString = outputString.replaceAll("\n", "");
|
||||
testRuleMethodST.setAttribute("expecting", '"'+escapeForJava(outputString)+'"');
|
||||
}
|
||||
}
|
||||
buf.append(testRuleMethodST.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void genTreeMethods(StringTemplateGroup group, StringBuffer buf) {
|
||||
for ( gUnitTestSuite ts: grammarInfo.getRuleTestSuites() ) {
|
||||
int i = 0;
|
||||
for ( Map.Entry<gUnitTestInput, AbstractTest> entry : ts.testSuites.entrySet() ) { // each rule may contain multiple tests
|
||||
gUnitTestInput input = entry.getKey();
|
||||
i++;
|
||||
StringTemplate testRuleMethodST;
|
||||
/** If rule has multiple return values or ast*/
|
||||
if ( entry.getValue().getType()== gUnitParser.ACTION && ruleWithReturn.containsKey(ts.getTreeRuleName()) ) {
|
||||
testRuleMethodST = group.getInstanceOf("testTreeRuleMethod2");
|
||||
String outputString = entry.getValue().getText();
|
||||
testRuleMethodST.setAttribute("methodName", "test"+changeFirstCapital(ts.getTreeRuleName())+"_walks_"+
|
||||
changeFirstCapital(ts.getRuleName())+i);
|
||||
testRuleMethodST.setAttribute("testTreeRuleName", '"'+ts.getTreeRuleName()+'"');
|
||||
testRuleMethodST.setAttribute("testRuleName", '"'+ts.getRuleName()+'"');
|
||||
testRuleMethodST.setAttribute("test", input);
|
||||
testRuleMethodST.setAttribute("returnType", ruleWithReturn.get(ts.getTreeRuleName()));
|
||||
testRuleMethodST.setAttribute("expecting", outputString);
|
||||
}
|
||||
else {
|
||||
testRuleMethodST = group.getInstanceOf("testTreeRuleMethod");
|
||||
String outputString = entry.getValue().getText();
|
||||
testRuleMethodST.setAttribute("methodName", "test"+changeFirstCapital(ts.getTreeRuleName())+"_walks_"+
|
||||
changeFirstCapital(ts.getRuleName())+i);
|
||||
testRuleMethodST.setAttribute("testTreeRuleName", '"'+ts.getTreeRuleName()+'"');
|
||||
testRuleMethodST.setAttribute("testRuleName", '"'+ts.getRuleName()+'"');
|
||||
testRuleMethodST.setAttribute("test", input);
|
||||
testRuleMethodST.setAttribute("tokenType", getTypeString(entry.getValue().getType()));
|
||||
|
||||
if ( entry.getValue().getType()==gUnitParser.ACTION ) { // trim ';' at the end of ACTION if there is...
|
||||
//testRuleMethodST.setAttribute("expecting", outputString.substring(0, outputString.length()-1));
|
||||
testRuleMethodST.setAttribute("expecting", outputString);
|
||||
}
|
||||
else if ( entry.getValue().getType()==gUnitParser.RETVAL ) { // Expected: RETVAL
|
||||
testRuleMethodST.setAttribute("expecting", outputString);
|
||||
}
|
||||
else { // Attach "" to expected STRING or AST
|
||||
testRuleMethodST.setAttribute("expecting", '"'+escapeForJava(outputString)+'"');
|
||||
}
|
||||
}
|
||||
buf.append(testRuleMethodST.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return a meaningful gUnit token type name instead of using the magic number
|
||||
public String getTypeString(int type) {
|
||||
String typeText;
|
||||
switch (type) {
|
||||
case gUnitParser.OK :
|
||||
typeText = "org.antlr.gunit.gUnitParser.OK";
|
||||
break;
|
||||
case gUnitParser.FAIL :
|
||||
typeText = "org.antlr.gunit.gUnitParser.FAIL";
|
||||
break;
|
||||
case gUnitParser.STRING :
|
||||
typeText = "org.antlr.gunit.gUnitParser.STRING";
|
||||
break;
|
||||
case gUnitParser.ML_STRING :
|
||||
typeText = "org.antlr.gunit.gUnitParser.ML_STRING";
|
||||
break;
|
||||
case gUnitParser.RETVAL :
|
||||
typeText = "org.antlr.gunit.gUnitParser.RETVAL";
|
||||
break;
|
||||
case gUnitParser.AST :
|
||||
typeText = "org.antlr.gunit.gUnitParser.AST";
|
||||
break;
|
||||
default :
|
||||
typeText = "org.antlr.gunit.gUnitParser.EOF";
|
||||
break;
|
||||
}
|
||||
return typeText;
|
||||
}
|
||||
|
||||
protected void writeTestFile(String dir, String fileName, String content) {
|
||||
try {
|
||||
File f = new File(dir, fileName);
|
||||
FileWriter w = new FileWriter(f);
|
||||
BufferedWriter bw = new BufferedWriter(w);
|
||||
bw.write(content);
|
||||
bw.close();
|
||||
w.close();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
logger.log(Level.SEVERE, "can't write file", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public static String escapeForJava(String inputString) {
|
||||
// Gotta escape literal backslash before putting in specials that use escape.
|
||||
inputString = inputString.replace("\\", "\\\\");
|
||||
// Then double quotes need escaping (singles are OK of course).
|
||||
inputString = inputString.replace("\"", "\\\"");
|
||||
// note: replace newline to String ".\n", replace tab to String ".\t"
|
||||
inputString = inputString.replace("\n", "\\n").replace("\t", "\\t").replace("\r", "\\r").replace("\b", "\\b").replace("\f", "\\f");
|
||||
|
||||
return inputString;
|
||||
}
|
||||
|
||||
protected String changeFirstCapital(String ruleName) {
|
||||
String firstChar = String.valueOf(ruleName.charAt(0));
|
||||
return firstChar.toUpperCase()+ruleName.substring(1);
|
||||
}
|
||||
|
||||
public static String normalizeTreeSpec(String t) {
|
||||
List<String> words = new ArrayList<String>();
|
||||
int i = 0;
|
||||
StringBuilder word = new StringBuilder();
|
||||
while ( i<t.length() ) {
|
||||
if ( t.charAt(i)=='(' || t.charAt(i)==')' ) {
|
||||
if ( word.length()>0 ) {
|
||||
words.add(word.toString());
|
||||
word.setLength(0);
|
||||
}
|
||||
words.add(String.valueOf(t.charAt(i)));
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if ( Character.isWhitespace(t.charAt(i)) ) {
|
||||
// upon WS, save word
|
||||
if ( word.length()>0 ) {
|
||||
words.add(word.toString());
|
||||
word.setLength(0);
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// ... "x" or ...("x"
|
||||
if ( t.charAt(i)=='"' && (i-1)>=0 &&
|
||||
(t.charAt(i-1)=='(' || Character.isWhitespace(t.charAt(i-1))) )
|
||||
{
|
||||
i++;
|
||||
while ( i<t.length() && t.charAt(i)!='"' ) {
|
||||
if ( t.charAt(i)=='\\' &&
|
||||
(i+1)<t.length() && t.charAt(i+1)=='"' ) // handle \"
|
||||
{
|
||||
word.append('"');
|
||||
i+=2;
|
||||
continue;
|
||||
}
|
||||
word.append(t.charAt(i));
|
||||
i++;
|
||||
}
|
||||
i++; // skip final "
|
||||
words.add(word.toString());
|
||||
word.setLength(0);
|
||||
continue;
|
||||
}
|
||||
word.append(t.charAt(i));
|
||||
i++;
|
||||
}
|
||||
if ( word.length()>0 ) {
|
||||
words.add(word.toString());
|
||||
}
|
||||
//System.out.println("words="+words);
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int j=0; j<words.size(); j++) {
|
||||
if ( j>0 && !words.get(j).equals(")") &&
|
||||
!words.get(j-1).equals("(") ) {
|
||||
buf.append(' ');
|
||||
}
|
||||
buf.append(words.get(j));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2007 Kenny MacDermid
|
||||
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.gunit;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
|
||||
/** OutputTest represents a test for not only standard output string,
|
||||
* but also AST output which is actually a return value from a parser.
|
||||
*/
|
||||
public class OutputTest extends AbstractTest {
|
||||
private final Token token;
|
||||
|
||||
public OutputTest(Token token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return token.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return token.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
// return ANTLR error msg if test failed
|
||||
public String getResult(gUnitTestResult testResult) {
|
||||
// Note: we treat the standard output string as a return value also
|
||||
if ( testResult.isSuccess() ) return testResult.getReturned();
|
||||
else {
|
||||
hasErrorMsg = true;
|
||||
return testResult.getError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpected() {
|
||||
return token.getText();
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2007 Kenny MacDermid
|
||||
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.gunit;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
|
||||
public class ReturnTest extends AbstractTest {
|
||||
private final Token retval;
|
||||
|
||||
public ReturnTest(Token retval) {
|
||||
this.retval = retval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return retval.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return retval.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
// return ANTLR error msg if test failed
|
||||
public String getResult(gUnitTestResult testResult) {
|
||||
if ( testResult.isSuccess() ) return testResult.getReturned();
|
||||
else {
|
||||
hasErrorMsg = true;
|
||||
return testResult.getError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpected() {
|
||||
String expect = retval.getText();
|
||||
|
||||
if ( expect.charAt(0)=='"' && expect.charAt(expect.length()-1)=='"' ) {
|
||||
expect = expect.substring(1, expect.length()-1);
|
||||
}
|
||||
|
||||
return expect;
|
||||
}
|
||||
}
|
@ -0,0 +1,475 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon, Jen-Yuan Su
|
||||
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.gunit;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.*;
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
/** All gUnit-generated JUnit class should extend this class
|
||||
* which implements the essential methods for triggering
|
||||
* ANTLR parser/tree walker
|
||||
*/
|
||||
public abstract class gUnitBaseTest extends TestCase {
|
||||
|
||||
public String treeAdaptorPath;
|
||||
public String packagePath;
|
||||
public String lexerPath;
|
||||
public String parserPath;
|
||||
public String treeParserPath;
|
||||
|
||||
protected String stdout;
|
||||
protected String stderr;
|
||||
|
||||
private PrintStream console = System.out;
|
||||
private PrintStream consoleErr = System.err;
|
||||
|
||||
// Invoke target lexer.rule
|
||||
public String execLexer(String testRuleName, int line, String testInput, boolean isFile) throws Exception {
|
||||
CharStream input;
|
||||
/** Set up ANTLR input stream based on input source, file or String */
|
||||
if ( isFile ) {
|
||||
String filePath = testInput;
|
||||
File testInputFile = new File(filePath);
|
||||
// if input test file is not found under the current dir, also try to look for it under the package dir
|
||||
if ( !testInputFile.exists() && packagePath!=null ) {
|
||||
testInputFile = new File(packagePath, filePath);
|
||||
if ( testInputFile.exists() ) filePath = testInputFile.getCanonicalPath();
|
||||
}
|
||||
input = new ANTLRFileStream(filePath);
|
||||
}
|
||||
else {
|
||||
input = new ANTLRStringStream(testInput);
|
||||
}
|
||||
Class<? extends Lexer> lexer;
|
||||
PrintStream ps = null; // for redirecting stdout later
|
||||
PrintStream ps2 = null; // for redirecting stderr later
|
||||
try {
|
||||
/** Use Reflection to create instances of lexer and parser */
|
||||
lexer = Class.forName(lexerPath).asSubclass(Lexer.class);
|
||||
Constructor<? extends Lexer> lexConstructor = lexer.getConstructor(CharStream.class);
|
||||
Lexer lexObj = lexConstructor.newInstance(input); // makes new instance of lexer
|
||||
input.setLine(line);
|
||||
|
||||
Method ruleName = lexer.getMethod("m"+testRuleName);
|
||||
|
||||
/** Start of I/O Redirecting */
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||
ps = new PrintStream(out);
|
||||
ps2 = new PrintStream(err);
|
||||
System.setOut(ps);
|
||||
System.setErr(ps2);
|
||||
/** End of redirecting */
|
||||
|
||||
/** Invoke lexer rule, and get the current index in CharStream */
|
||||
ruleName.invoke(lexObj, new Object[0]);
|
||||
Method ruleName2 = lexer.getMethod("getCharIndex");
|
||||
int currentIndex = (Integer) ruleName2.invoke(lexObj, new Object[0]);
|
||||
if ( currentIndex!=input.size() ) {
|
||||
ps2.println("extra text found, '"+input.substring(currentIndex, input.size()-1)+"'");
|
||||
}
|
||||
|
||||
this.stdout = null;
|
||||
this.stderr = null;
|
||||
|
||||
if ( err.toString().length()>0 ) {
|
||||
this.stderr = err.toString();
|
||||
return this.stderr;
|
||||
}
|
||||
if ( out.toString().length()>0 ) {
|
||||
this.stdout = out.toString();
|
||||
}
|
||||
if ( err.toString().length()==0 && out.toString().length()==0 ) {
|
||||
return null;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (SecurityException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (InstantiationException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (InvocationTargetException e) { // This exception could be caused from ANTLR Runtime Exception, e.g. MismatchedTokenException
|
||||
if ( e.getCause()!=null ) this.stderr = e.getCause().toString();
|
||||
else this.stderr = e.toString();
|
||||
return this.stderr;
|
||||
} finally {
|
||||
try {
|
||||
if ( ps!=null ) ps.close();
|
||||
if ( ps2!=null ) ps2.close();
|
||||
System.setOut(console); // Reset standard output
|
||||
System.setErr(consoleErr); // Reset standard err out
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return this.stdout;
|
||||
}
|
||||
|
||||
// Invoke target parser.rule
|
||||
|
||||
public Object execParser(String testRuleName, int line, String testInput, boolean isFile) throws Exception {
|
||||
CharStream input;
|
||||
/** Set up ANTLR input stream based on input source, file or String */
|
||||
if ( isFile ) {
|
||||
String filePath = testInput;
|
||||
File testInputFile = new File(filePath);
|
||||
// if input test file is not found under the current dir, also try to look for it under the package dir
|
||||
if ( !testInputFile.exists() && packagePath!=null ) {
|
||||
testInputFile = new File(packagePath, filePath);
|
||||
if ( testInputFile.exists() ) filePath = testInputFile.getCanonicalPath();
|
||||
}
|
||||
input = new ANTLRFileStream(filePath);
|
||||
}
|
||||
else {
|
||||
input = new ANTLRStringStream(testInput);
|
||||
}
|
||||
Class<? extends Lexer> lexer;
|
||||
Class<? extends Parser> parser;
|
||||
PrintStream ps = null; // for redirecting stdout later
|
||||
PrintStream ps2 = null; // for redirecting stderr later
|
||||
ByteArrayOutputStream out = null;
|
||||
ByteArrayOutputStream err = null;
|
||||
try {
|
||||
/** Use Reflection to create instances of lexer and parser */
|
||||
lexer = Class.forName(lexerPath).asSubclass(Lexer.class);
|
||||
Constructor<? extends Lexer> lexConstructor = lexer.getConstructor(CharStream.class);
|
||||
Lexer lexObj = lexConstructor.newInstance(input); // makes new instance of lexer
|
||||
input.setLine(line);
|
||||
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexObj);
|
||||
parser = Class.forName(parserPath).asSubclass(Parser.class);
|
||||
Constructor<? extends Parser> parConstructor = parser.getConstructor(TokenStream.class);
|
||||
Parser parObj = parConstructor.newInstance(tokens); // makes new instance of parser
|
||||
|
||||
// set up customized tree adaptor if necessary
|
||||
if ( treeAdaptorPath!=null ) {
|
||||
Method _setTreeAdaptor = parser.getMethod("setTreeAdaptor", TreeAdaptor.class);
|
||||
Class<? extends TreeAdaptor> _treeAdaptor = Class.forName(treeAdaptorPath).asSubclass(TreeAdaptor.class);
|
||||
_setTreeAdaptor.invoke(parObj, _treeAdaptor.newInstance());
|
||||
}
|
||||
|
||||
Method ruleName = parser.getMethod(testRuleName);
|
||||
|
||||
/** Start of I/O Redirecting */
|
||||
out = new ByteArrayOutputStream();
|
||||
err = new ByteArrayOutputStream();
|
||||
ps = new PrintStream(out);
|
||||
ps2 = new PrintStream(err);
|
||||
System.setOut(ps);
|
||||
System.setErr(ps2);
|
||||
/** End of redirecting */
|
||||
|
||||
/** Invoke grammar rule, and store if there is a return value */
|
||||
Object ruleReturn = ruleName.invoke(parObj);
|
||||
String astString = null;
|
||||
String stString = null;
|
||||
/** If rule has return value, determine if it contains an AST or a ST */
|
||||
if ( ruleReturn!=null ) {
|
||||
if ( ruleReturn.getClass().toString().indexOf(testRuleName+"_return")>0 ) {
|
||||
try { // NullPointerException may happen here...
|
||||
Class<?> _return = Class.forName(parserPath+"$"+testRuleName+"_return");
|
||||
Method[] methods = _return.getDeclaredMethods();
|
||||
for(Method method : methods) {
|
||||
if ( method.getName().equals("getTree") ) {
|
||||
Method returnName = _return.getMethod("getTree");
|
||||
CommonTree tree = (CommonTree) returnName.invoke(ruleReturn);
|
||||
astString = tree.toStringTree();
|
||||
}
|
||||
else if ( method.getName().equals("getTemplate") ) {
|
||||
Method returnName = _return.getMethod("getTemplate");
|
||||
StringTemplate st = (StringTemplate) returnName.invoke(ruleReturn);
|
||||
stString = st.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
System.err.println(e); // Note: If any exception occurs, the test is viewed as failed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.stdout = "";
|
||||
this.stderr = "";
|
||||
|
||||
/** Invalid input */
|
||||
if ( tokens.index()!=tokens.size()-1 ) {
|
||||
//throw new InvalidInputException();
|
||||
this.stderr += "Stopped parsing at token index "+tokens.index()+": ";
|
||||
}
|
||||
|
||||
// retVal could be actual return object from rule, stderr or stdout
|
||||
this.stdout += out.toString();
|
||||
this.stderr += err.toString();
|
||||
|
||||
if ( err.toString().length()>0 ) return this.stderr;
|
||||
if ( out.toString().length()>0 ) return this.stdout;
|
||||
if ( astString!=null ) { // Return toStringTree of AST
|
||||
return astString;
|
||||
}
|
||||
else if ( stString!=null ) {// Return toString of ST
|
||||
return stString;
|
||||
}
|
||||
if ( ruleReturn!=null ) {
|
||||
return ruleReturn;
|
||||
}
|
||||
if ( err.toString().length()==0 && out.toString().length()==0 ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
handleUnexpectedException(e);
|
||||
}
|
||||
catch (SecurityException e) {
|
||||
handleUnexpectedException(e);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
handleUnexpectedException(e);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
handleUnexpectedException(e);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
this.stdout = out.toString();
|
||||
this.stderr = err.toString();
|
||||
|
||||
if ( e.getCause()!=null ) this.stderr += e.getCause().toString();
|
||||
else this.stderr += e.toString();
|
||||
return this.stderr;
|
||||
} finally {
|
||||
try {
|
||||
if ( ps!=null ) ps.close();
|
||||
if ( ps2!=null ) ps2.close();
|
||||
System.setOut(console); // Reset standard output
|
||||
System.setErr(consoleErr); // Reset standard err out
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return this.stdout;
|
||||
}
|
||||
|
||||
// Invoke target parser.rule
|
||||
public Object execTreeParser(String testTreeRuleName, String testRuleName, String testInput, boolean isFile) throws Exception {
|
||||
CharStream input;
|
||||
if ( isFile ) {
|
||||
String filePath = testInput;
|
||||
File testInputFile = new File(filePath);
|
||||
// if input test file is not found under the current dir, also try to look for it under the package dir
|
||||
if ( !testInputFile.exists() && packagePath!=null ) {
|
||||
testInputFile = new File(packagePath, filePath);
|
||||
if ( testInputFile.exists() ) filePath = testInputFile.getCanonicalPath();
|
||||
}
|
||||
input = new ANTLRFileStream(filePath);
|
||||
}
|
||||
else {
|
||||
input = new ANTLRStringStream(testInput);
|
||||
}
|
||||
Class<? extends Lexer> lexer;
|
||||
Class<? extends Parser> parser;
|
||||
Class<? extends TreeParser> treeParser;
|
||||
PrintStream ps = null; // for redirecting stdout later
|
||||
PrintStream ps2 = null; // for redirecting stderr later
|
||||
try {
|
||||
/** Use Reflection to create instances of lexer and parser */
|
||||
lexer = Class.forName(lexerPath).asSubclass(Lexer.class);
|
||||
Constructor<? extends Lexer> lexConstructor = lexer.getConstructor(CharStream.class);
|
||||
Lexer lexObj = lexConstructor.newInstance(input); // makes new instance of lexer
|
||||
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexObj);
|
||||
|
||||
parser = Class.forName(parserPath).asSubclass(Parser.class);
|
||||
Constructor<? extends Parser> parConstructor = parser.getConstructor(TokenStream.class);
|
||||
Parser parObj = parConstructor.newInstance(tokens); // makes new instance of parser
|
||||
|
||||
// set up customized tree adaptor if necessary
|
||||
TreeAdaptor customTreeAdaptor = null;
|
||||
if ( treeAdaptorPath!=null ) {
|
||||
Method _setTreeAdaptor = parser.getMethod("setTreeAdaptor", TreeAdaptor.class);
|
||||
Class<? extends TreeAdaptor> _treeAdaptor = Class.forName(treeAdaptorPath).asSubclass(TreeAdaptor.class);
|
||||
customTreeAdaptor = _treeAdaptor.newInstance();
|
||||
_setTreeAdaptor.invoke(parObj, customTreeAdaptor);
|
||||
}
|
||||
|
||||
Method ruleName = parser.getMethod(testRuleName);
|
||||
|
||||
/** Start of I/O Redirecting */
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||
ps = new PrintStream(out);
|
||||
ps2 = new PrintStream(err);
|
||||
System.setOut(ps);
|
||||
System.setErr(ps2);
|
||||
/** End of redirecting */
|
||||
|
||||
/** Invoke grammar rule, and get the return value */
|
||||
Object ruleReturn = ruleName.invoke(parObj);
|
||||
|
||||
Class<?> _return = Class.forName(parserPath+"$"+testRuleName+"_return");
|
||||
Method returnName = _return.getMethod("getTree");
|
||||
CommonTree tree = (CommonTree) returnName.invoke(ruleReturn);
|
||||
|
||||
// Walk resulting tree; create tree nodes stream first
|
||||
CommonTreeNodeStream nodes;
|
||||
if ( customTreeAdaptor!=null ) {
|
||||
nodes = new CommonTreeNodeStream(customTreeAdaptor, tree);
|
||||
}
|
||||
else {
|
||||
nodes = new CommonTreeNodeStream(tree);
|
||||
}
|
||||
// AST nodes have payload that point into token stream
|
||||
nodes.setTokenStream(tokens);
|
||||
// Create a tree walker attached to the nodes stream
|
||||
treeParser = Class.forName(treeParserPath).asSubclass(TreeParser.class);
|
||||
Constructor<? extends TreeParser> treeParConstructor = treeParser.getConstructor(TreeNodeStream.class);
|
||||
TreeParser treeParObj = treeParConstructor.newInstance(nodes); // makes new instance of tree parser
|
||||
// Invoke the tree rule, and store the return value if there is
|
||||
Method treeRuleName = treeParser.getMethod(testTreeRuleName);
|
||||
Object treeRuleReturn = treeRuleName.invoke(treeParObj);
|
||||
|
||||
String astString = null;
|
||||
String stString = null;
|
||||
/** If tree rule has return value, determine if it contains an AST or a ST */
|
||||
if ( treeRuleReturn!=null ) {
|
||||
if ( treeRuleReturn.getClass().toString().indexOf(testTreeRuleName+"_return")>0 ) {
|
||||
try { // NullPointerException may happen here...
|
||||
Class<?> _treeReturn = Class.forName(treeParserPath+"$"+testTreeRuleName+"_return");
|
||||
Method[] methods = _treeReturn.getDeclaredMethods();
|
||||
for(Method method : methods) {
|
||||
if ( method.getName().equals("getTree") ) {
|
||||
Method treeReturnName = _treeReturn.getMethod("getTree");
|
||||
CommonTree returnTree = (CommonTree) treeReturnName.invoke(treeRuleReturn);
|
||||
astString = returnTree.toStringTree();
|
||||
}
|
||||
else if ( method.getName().equals("getTemplate") ) {
|
||||
Method treeReturnName = _return.getMethod("getTemplate");
|
||||
StringTemplate st = (StringTemplate) treeReturnName.invoke(treeRuleReturn);
|
||||
stString = st.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
System.err.println(e); // Note: If any exception occurs, the test is viewed as failed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.stdout = null;
|
||||
this.stderr = null;
|
||||
|
||||
/** Invalid input */
|
||||
if ( tokens.index()!=tokens.size()-1 ) {
|
||||
throw new InvalidInputException();
|
||||
}
|
||||
|
||||
// retVal could be actual return object from rule, stderr or stdout
|
||||
if ( err.toString().length()>0 ) {
|
||||
this.stderr = err.toString();
|
||||
return this.stderr;
|
||||
}
|
||||
if ( out.toString().length()>0 ) {
|
||||
this.stdout = out.toString();
|
||||
}
|
||||
if ( astString!=null ) { // Return toStringTree of AST
|
||||
return astString;
|
||||
}
|
||||
else if ( stString!=null ) {// Return toString of ST
|
||||
return stString;
|
||||
}
|
||||
if ( treeRuleReturn!=null ) {
|
||||
return treeRuleReturn;
|
||||
}
|
||||
if ( err.toString().length()==0 && out.toString().length()==0 ) {
|
||||
return null;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (SecurityException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
handleUnexpectedException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
if ( e.getCause()!=null ) this.stderr = e.getCause().toString();
|
||||
else this.stderr = e.toString();
|
||||
return this.stderr;
|
||||
} finally {
|
||||
try {
|
||||
if ( ps!=null ) ps.close();
|
||||
if ( ps2!=null ) ps2.close();
|
||||
System.setOut(console); // Reset standard output
|
||||
System.setErr(consoleErr); // Reset standard err out
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return stdout;
|
||||
}
|
||||
|
||||
// Modify the return value if the expected token type is OK or FAIL
|
||||
public Object examineExecResult(int tokenType, Object retVal) {
|
||||
System.out.println("expect "+(tokenType==gUnitParser.OK?"OK":"FAIL")+
|
||||
"stderr=="+stderr);
|
||||
if ( tokenType==gUnitParser.OK ) { // expected Token: OK
|
||||
if ( this.stderr==null || this.stderr.length()==0 ) {
|
||||
return "OK";
|
||||
}
|
||||
else {
|
||||
return "FAIL, "+this.stderr;
|
||||
}
|
||||
}
|
||||
else if ( tokenType==gUnitParser.FAIL ) { // expected Token: FAIL
|
||||
if ( this.stderr!=null && this.stderr.length()>0 ) {
|
||||
return "FAIL";
|
||||
}
|
||||
else {
|
||||
return "OK";
|
||||
}
|
||||
}
|
||||
else { // return the same object for the other token types
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleUnexpectedException(Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,655 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon Jen-Yuan Su
|
||||
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.gunit;
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.CommonTree;
|
||||
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
||||
import org.antlr.runtime.tree.TreeAdaptor;
|
||||
import org.antlr.runtime.tree.TreeNodeStream;
|
||||
import org.antlr.stringtemplate.CommonGroupLoader;
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||
import org.antlr.stringtemplate.StringTemplateGroupLoader;
|
||||
import org.antlr.stringtemplate.language.AngleBracketTemplateLexer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.antlr.runtime.tree.TreeParser;
|
||||
|
||||
public class gUnitExecutor implements ITestSuite {
|
||||
public GrammarInfo grammarInfo;
|
||||
|
||||
private final ClassLoader grammarClassLoader;
|
||||
|
||||
private final String testsuiteDir;
|
||||
|
||||
public int numOfTest;
|
||||
|
||||
public int numOfSuccess;
|
||||
|
||||
public int numOfFailure;
|
||||
|
||||
private String title;
|
||||
|
||||
public int numOfInvalidInput;
|
||||
|
||||
private String parserName;
|
||||
|
||||
private String lexerName;
|
||||
|
||||
public List<AbstractTest> failures;
|
||||
public List<AbstractTest> invalids;
|
||||
|
||||
private PrintStream console = System.out;
|
||||
private PrintStream consoleErr = System.err;
|
||||
|
||||
public gUnitExecutor(GrammarInfo grammarInfo, String testsuiteDir) {
|
||||
this( grammarInfo, determineClassLoader(), testsuiteDir);
|
||||
}
|
||||
|
||||
private static ClassLoader determineClassLoader() {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if ( classLoader == null ) {
|
||||
classLoader = gUnitExecutor.class.getClassLoader();
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public gUnitExecutor(GrammarInfo grammarInfo, ClassLoader grammarClassLoader, String testsuiteDir) {
|
||||
this.grammarInfo = grammarInfo;
|
||||
this.grammarClassLoader = grammarClassLoader;
|
||||
this.testsuiteDir = testsuiteDir;
|
||||
numOfTest = 0;
|
||||
numOfSuccess = 0;
|
||||
numOfFailure = 0;
|
||||
numOfInvalidInput = 0;
|
||||
failures = new ArrayList<AbstractTest>();
|
||||
invalids = new ArrayList<AbstractTest>();
|
||||
}
|
||||
|
||||
protected ClassLoader getGrammarClassLoader() {
|
||||
return grammarClassLoader;
|
||||
}
|
||||
|
||||
protected final Class<?> classForName(String name) throws ClassNotFoundException {
|
||||
return getGrammarClassLoader().loadClass( name );
|
||||
}
|
||||
|
||||
public String execTest() throws IOException{
|
||||
// Set up string template for testing result
|
||||
StringTemplate testResultST = getTemplateGroup().getInstanceOf("testResult");
|
||||
try {
|
||||
/** Set up appropriate path for parser/lexer if using package */
|
||||
if (grammarInfo.getGrammarPackage()!=null ) {
|
||||
parserName = grammarInfo.getGrammarPackage()+"."+grammarInfo.getGrammarName()+"Parser";
|
||||
lexerName = grammarInfo.getGrammarPackage()+"."+grammarInfo.getGrammarName()+"Lexer";
|
||||
}
|
||||
else {
|
||||
parserName = grammarInfo.getGrammarName()+"Parser";
|
||||
lexerName = grammarInfo.getGrammarName()+"Lexer";
|
||||
}
|
||||
|
||||
/*** Start Unit/Functional Testing ***/
|
||||
// Execute unit test of for parser, lexer and tree grammar
|
||||
if ( grammarInfo.getTreeGrammarName()!=null ) {
|
||||
title = "executing testsuite for tree grammar:"+grammarInfo.getTreeGrammarName()+" walks "+parserName;
|
||||
}
|
||||
else {
|
||||
title = "executing testsuite for grammar:"+grammarInfo.getGrammarName();
|
||||
}
|
||||
executeTests();
|
||||
// End of exection of unit testing
|
||||
|
||||
// Fill in the template holes with the test results
|
||||
testResultST.setAttribute("title", title);
|
||||
testResultST.setAttribute("num_of_test", numOfTest);
|
||||
testResultST.setAttribute("num_of_failure", numOfFailure);
|
||||
if ( numOfFailure>0 ) {
|
||||
testResultST.setAttribute("failure", failures);
|
||||
}
|
||||
if ( numOfInvalidInput>0 ) {
|
||||
testResultST.setAttribute("has_invalid", true);
|
||||
testResultST.setAttribute("num_of_invalid", numOfInvalidInput);
|
||||
testResultST.setAttribute("invalid", invalids);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
handleUnexpectedException(e);
|
||||
}
|
||||
return testResultST.toString();
|
||||
}
|
||||
|
||||
private StringTemplateGroup getTemplateGroup() {
|
||||
StringTemplateGroupLoader loader = new CommonGroupLoader("org/antlr/gunit", null);
|
||||
StringTemplateGroup.registerGroupLoader(loader);
|
||||
StringTemplateGroup.registerDefaultLexer(AngleBracketTemplateLexer.class);
|
||||
StringTemplateGroup group = StringTemplateGroup.loadGroup("gUnitTestResult");
|
||||
return group;
|
||||
}
|
||||
|
||||
// TODO: throw more specific exceptions
|
||||
private gUnitTestResult runCorrectParser(String parserName, String lexerName, String rule, String lexicalRule, String treeRule, gUnitTestInput input) throws Exception
|
||||
{
|
||||
if ( lexicalRule!=null ) return runLexer(lexerName, lexicalRule, input);
|
||||
else if ( treeRule!=null ) return runTreeParser(parserName, lexerName, rule, treeRule, input);
|
||||
else return runParser(parserName, lexerName, rule, input);
|
||||
}
|
||||
|
||||
private void executeTests() throws Exception {
|
||||
for ( gUnitTestSuite ts: grammarInfo.getRuleTestSuites() ) {
|
||||
String rule = ts.getRuleName();
|
||||
String lexicalRule = ts.getLexicalRuleName();
|
||||
String treeRule = ts.getTreeRuleName();
|
||||
for ( Map.Entry<gUnitTestInput, AbstractTest> entry : ts.testSuites.entrySet() ) { // each rule may contain multiple tests
|
||||
gUnitTestInput input = entry.getKey();
|
||||
numOfTest++;
|
||||
// Run parser, and get the return value or stdout or stderr if there is
|
||||
gUnitTestResult result = null;
|
||||
AbstractTest test = entry.getValue();
|
||||
try {
|
||||
// TODO: create a -debug option to turn on logging, which shows progress of running tests
|
||||
//System.out.print(numOfTest + ". Running rule: " + rule + "; input: '" + input.testInput + "'");
|
||||
result = runCorrectParser(parserName, lexerName, rule, lexicalRule, treeRule, input);
|
||||
// TODO: create a -debug option to turn on logging, which shows progress of running tests
|
||||
//System.out.println("; Expecting " + test.getExpected() + "; Success?: " + test.getExpected().equals(test.getResult(result)));
|
||||
} catch ( InvalidInputException e) {
|
||||
numOfInvalidInput++;
|
||||
test.setHeader(rule, lexicalRule, treeRule, numOfTest, input.line, input.input);
|
||||
test.setActual(input.input);
|
||||
invalids.add(test);
|
||||
continue;
|
||||
} // TODO: ensure there's no other exceptions required to be handled here...
|
||||
|
||||
String expected = test.getExpected();
|
||||
String actual = test.getResult(result);
|
||||
test.setActual(actual);
|
||||
|
||||
if (actual == null) {
|
||||
numOfFailure++;
|
||||
test.setHeader(rule, lexicalRule, treeRule, numOfTest, input.line, input.input);
|
||||
test.setActual("null");
|
||||
failures.add(test);
|
||||
onFail(test);
|
||||
}
|
||||
// the 2nd condition is used for the assertFAIL test of lexer rule because BooleanTest return err msg instead of 'FAIL' if isLexerTest
|
||||
else if ( expected.equals(actual) || (expected.equals("FAIL")&&!actual.equals("OK") ) ) {
|
||||
numOfSuccess++;
|
||||
onPass(test);
|
||||
}
|
||||
// TODO: something with ACTIONS - at least create action test type and throw exception.
|
||||
else if ( ts.testSuites.get(input).getType()==gUnitParser.ACTION ) { // expected Token: ACTION
|
||||
numOfFailure++;
|
||||
test.setHeader(rule, lexicalRule, treeRule, numOfTest, input.line, input.input);
|
||||
test.setActual("\t"+"{ACTION} is not supported in the grammarInfo yet...");
|
||||
failures.add(test);
|
||||
onFail(test);
|
||||
}
|
||||
else {
|
||||
numOfFailure++;
|
||||
test.setHeader(rule, lexicalRule, treeRule, numOfTest, input.line, input.input);
|
||||
failures.add(test);
|
||||
onFail(test);
|
||||
}
|
||||
} // end of 2nd for-loop: tests for individual rule
|
||||
} // end of 1st for-loop: testsuites for grammar
|
||||
}
|
||||
|
||||
// TODO: throw proper exceptions
|
||||
protected gUnitTestResult runLexer(String lexerName, String testRuleName, gUnitTestInput testInput) throws Exception {
|
||||
CharStream input;
|
||||
Class<? extends Lexer> lexer;
|
||||
PrintStream ps = null; // for redirecting stdout later
|
||||
PrintStream ps2 = null; // for redirecting stderr later
|
||||
try {
|
||||
/** Set up ANTLR input stream based on input source, file or String */
|
||||
input = getANTLRInputStream(testInput);
|
||||
|
||||
/** Use Reflection to create instances of lexer and parser */
|
||||
lexer = classForName(lexerName).asSubclass(Lexer.class);
|
||||
Constructor<? extends Lexer> lexConstructor = lexer.getConstructor(CharStream.class);
|
||||
Lexer lexObj = lexConstructor.newInstance(input); // makes new instance of lexer
|
||||
|
||||
Method ruleName = lexer.getMethod("m"+testRuleName);
|
||||
|
||||
/** Start of I/O Redirecting */
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||
ps = new PrintStream(out);
|
||||
ps2 = new PrintStream(err);
|
||||
System.setOut(ps);
|
||||
System.setErr(ps2);
|
||||
/** End of redirecting */
|
||||
|
||||
/** Invoke lexer rule, and get the current index in CharStream */
|
||||
ruleName.invoke(lexObj);
|
||||
Method ruleName2 = lexer.getMethod("getCharIndex");
|
||||
int currentIndex = (Integer) ruleName2.invoke(lexObj);
|
||||
if ( currentIndex!=input.size() ) {
|
||||
ps2.print("extra text found, '"+input.substring(currentIndex, input.size()-1)+"'");
|
||||
}
|
||||
|
||||
if ( err.toString().length()>0 ) {
|
||||
gUnitTestResult testResult = new gUnitTestResult(false, err.toString(), true);
|
||||
testResult.setError(err.toString());
|
||||
return testResult;
|
||||
}
|
||||
String stdout = null;
|
||||
if ( out.toString().length()>0 ) {
|
||||
stdout = out.toString();
|
||||
}
|
||||
return new gUnitTestResult(true, stdout, true);
|
||||
} catch (IOException e) {
|
||||
return getTestExceptionResult(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (SecurityException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (NoSuchMethodException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (IllegalArgumentException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (InstantiationException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (IllegalAccessException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (InvocationTargetException e) { // This exception could be caused from ANTLR Runtime Exception, e.g. MismatchedTokenException
|
||||
return getTestExceptionResult(e);
|
||||
} finally {
|
||||
try {
|
||||
if ( ps!=null ) ps.close();
|
||||
if ( ps2!=null ) ps2.close();
|
||||
System.setOut(console); // Reset standard output
|
||||
System.setErr(consoleErr); // Reset standard err out
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO: verify this:
|
||||
throw new Exception("This should be unreachable?");
|
||||
}
|
||||
|
||||
// TODO: throw proper exceptions
|
||||
protected gUnitTestResult runParser(String parserName, String lexerName, String testRuleName, gUnitTestInput testInput) throws Exception {
|
||||
CharStream input;
|
||||
Class<? extends Lexer> lexer;
|
||||
Class<? extends Parser> parser;
|
||||
PrintStream ps = null; // for redirecting stdout later
|
||||
PrintStream ps2 = null; // for redirecting stderr later
|
||||
try {
|
||||
/** Set up ANTLR input stream based on input source, file or String */
|
||||
input = getANTLRInputStream(testInput);
|
||||
|
||||
/** Use Reflection to create instances of lexer and parser */
|
||||
lexer = classForName(lexerName).asSubclass(Lexer.class);
|
||||
Constructor<? extends Lexer> lexConstructor = lexer.getConstructor(CharStream.class);
|
||||
Lexer lexObj = lexConstructor.newInstance(input); // makes new instance of lexer
|
||||
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexObj);
|
||||
|
||||
parser = classForName(parserName).asSubclass(Parser.class);
|
||||
Constructor<? extends Parser> parConstructor = parser.getConstructor(TokenStream.class);
|
||||
Parser parObj = parConstructor.newInstance(tokens); // makes new instance of parser
|
||||
|
||||
// set up customized tree adaptor if necessary
|
||||
if ( grammarInfo.getAdaptor()!=null ) {
|
||||
Method _setTreeAdaptor = parser.getMethod("setTreeAdaptor", TreeAdaptor.class);
|
||||
Class<? extends TreeAdaptor> _treeAdaptor = classForName(grammarInfo.getAdaptor()).asSubclass(TreeAdaptor.class);
|
||||
_setTreeAdaptor.invoke(parObj, _treeAdaptor.newInstance());
|
||||
}
|
||||
|
||||
Method ruleName = parser.getMethod(testRuleName);
|
||||
|
||||
/** Start of I/O Redirecting */
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||
ps = new PrintStream(out);
|
||||
ps2 = new PrintStream(err);
|
||||
System.setOut(ps);
|
||||
System.setErr(ps2);
|
||||
/** End of redirecting */
|
||||
|
||||
/** Invoke grammar rule, and store if there is a return value */
|
||||
Object ruleReturn = ruleName.invoke(parObj);
|
||||
String astString = null;
|
||||
String stString = null;
|
||||
/** If rule has return value, determine if it contains an AST or a ST */
|
||||
if ( ruleReturn!=null ) {
|
||||
if ( ruleReturn.getClass().toString().indexOf(testRuleName+"_return")>0 ) {
|
||||
try { // NullPointerException may happen here...
|
||||
Class<?> _return = classForName(parserName+"$"+testRuleName+"_return");
|
||||
Method[] methods = _return.getDeclaredMethods();
|
||||
for(Method method : methods) {
|
||||
if ( method.getName().equals("getTree") ) {
|
||||
Method returnName = _return.getMethod("getTree");
|
||||
CommonTree tree = (CommonTree) returnName.invoke(ruleReturn);
|
||||
astString = tree.toStringTree();
|
||||
}
|
||||
else if ( method.getName().equals("getTemplate") ) {
|
||||
Method returnName = _return.getMethod("getTemplate");
|
||||
StringTemplate st = (StringTemplate) returnName.invoke(ruleReturn);
|
||||
stString = st.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
System.err.println(e); // Note: If any exception occurs, the test is viewed as failed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkForValidInput(tokens, ps2);
|
||||
|
||||
if ( err.toString().length()>0 ) {
|
||||
gUnitTestResult testResult = new gUnitTestResult(false, err.toString());
|
||||
testResult.setError(err.toString());
|
||||
return testResult;
|
||||
}
|
||||
String stdout = null;
|
||||
// TODO: need to deal with the case which has both ST return value and stdout
|
||||
if ( out.toString().length()>0 ) {
|
||||
stdout = out.toString();
|
||||
}
|
||||
if ( astString!=null ) { // Return toStringTree of AST
|
||||
return new gUnitTestResult(true, stdout, astString);
|
||||
}
|
||||
else if ( stString!=null ) {// Return toString of ST
|
||||
return new gUnitTestResult(true, stdout, stString);
|
||||
}
|
||||
|
||||
if ( ruleReturn!=null ) {
|
||||
// TODO: currently only works for a single return with int or String value
|
||||
return new gUnitTestResult(true, stdout, String.valueOf(ruleReturn));
|
||||
}
|
||||
return new gUnitTestResult(true, stdout, stdout);
|
||||
} catch (IOException e) {
|
||||
return getTestExceptionResult(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (SecurityException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (NoSuchMethodException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (IllegalArgumentException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (InstantiationException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (IllegalAccessException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (InvocationTargetException e) { // This exception could be caused from ANTLR Runtime Exception, e.g. MismatchedTokenException
|
||||
return getTestExceptionResult(e);
|
||||
} finally {
|
||||
try {
|
||||
if ( ps!=null ) ps.close();
|
||||
if ( ps2!=null ) ps2.close();
|
||||
System.setOut(console); // Reset standard output
|
||||
System.setErr(consoleErr); // Reset standard err out
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO: verify this:
|
||||
throw new Exception("This should be unreachable?");
|
||||
}
|
||||
|
||||
protected gUnitTestResult runTreeParser(String parserName, String lexerName, String testRuleName, String testTreeRuleName, gUnitTestInput testInput) throws Exception {
|
||||
CharStream input;
|
||||
String treeParserPath;
|
||||
Class<? extends Lexer> lexer;
|
||||
Class<? extends Parser> parser;
|
||||
Class<? extends TreeParser> treeParser;
|
||||
PrintStream ps = null; // for redirecting stdout later
|
||||
PrintStream ps2 = null; // for redirecting stderr later
|
||||
try {
|
||||
/** Set up ANTLR input stream based on input source, file or String */
|
||||
input = getANTLRInputStream(testInput);
|
||||
|
||||
/** Set up appropriate path for tree parser if using package */
|
||||
if ( grammarInfo.getGrammarPackage()!=null ) {
|
||||
treeParserPath = grammarInfo.getGrammarPackage()+"."+grammarInfo.getTreeGrammarName();
|
||||
}
|
||||
else {
|
||||
treeParserPath = grammarInfo.getTreeGrammarName();
|
||||
}
|
||||
|
||||
/** Use Reflection to create instances of lexer and parser */
|
||||
lexer = classForName(lexerName).asSubclass(Lexer.class);
|
||||
Constructor<? extends Lexer> lexConstructor = lexer.getConstructor(CharStream.class);
|
||||
Lexer lexObj = lexConstructor.newInstance(input); // makes new instance of lexer
|
||||
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexObj);
|
||||
|
||||
parser = classForName(parserName).asSubclass(Parser.class);
|
||||
Constructor<? extends Parser> parConstructor = parser.getConstructor(TokenStream.class);
|
||||
Parser parObj = parConstructor.newInstance(tokens); // makes new instance of parser
|
||||
|
||||
// set up customized tree adaptor if necessary
|
||||
TreeAdaptor customTreeAdaptor = null;
|
||||
if ( grammarInfo.getAdaptor()!=null ) {
|
||||
Method _setTreeAdaptor = parser.getMethod("setTreeAdaptor", TreeAdaptor.class);
|
||||
Class<? extends TreeAdaptor> _treeAdaptor = classForName(grammarInfo.getAdaptor()).asSubclass(TreeAdaptor.class);
|
||||
customTreeAdaptor = _treeAdaptor.newInstance();
|
||||
_setTreeAdaptor.invoke(parObj, customTreeAdaptor);
|
||||
}
|
||||
|
||||
Method ruleName = parser.getMethod(testRuleName);
|
||||
|
||||
/** Start of I/O Redirecting */
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||
ps = new PrintStream(out);
|
||||
ps2 = new PrintStream(err);
|
||||
System.setOut(ps);
|
||||
System.setErr(ps2);
|
||||
/** End of redirecting */
|
||||
|
||||
/** Invoke grammar rule, and get the return value */
|
||||
Object ruleReturn = ruleName.invoke(parObj);
|
||||
|
||||
Class<?> _return = classForName(parserName+"$"+testRuleName+"_return");
|
||||
Method returnName = _return.getMethod("getTree");
|
||||
CommonTree tree = (CommonTree) returnName.invoke(ruleReturn);
|
||||
|
||||
// Walk resulting tree; create tree nodes stream first
|
||||
CommonTreeNodeStream nodes;
|
||||
if ( customTreeAdaptor!=null ) {
|
||||
nodes = new CommonTreeNodeStream(customTreeAdaptor, tree);
|
||||
}
|
||||
else {
|
||||
nodes = new CommonTreeNodeStream(tree);
|
||||
}
|
||||
// AST nodes have payload that point into token stream
|
||||
nodes.setTokenStream(tokens);
|
||||
// Create a tree walker attached to the nodes stream
|
||||
treeParser = classForName(treeParserPath).asSubclass(TreeParser.class);
|
||||
Constructor<? extends TreeParser> treeParConstructor = treeParser.getConstructor(TreeNodeStream.class);
|
||||
TreeParser treeParObj = treeParConstructor.newInstance(nodes); // makes new instance of tree parser
|
||||
// Invoke the tree rule, and store the return value if there is
|
||||
Method treeRuleName = treeParser.getMethod(testTreeRuleName);
|
||||
Object treeRuleReturn = treeRuleName.invoke(treeParObj);
|
||||
|
||||
String astString = null;
|
||||
String stString = null;
|
||||
/** If tree rule has return value, determine if it contains an AST or a ST */
|
||||
if ( treeRuleReturn!=null ) {
|
||||
if ( treeRuleReturn.getClass().toString().indexOf(testTreeRuleName+"_return")>0 ) {
|
||||
try { // NullPointerException may happen here...
|
||||
Class<?> _treeReturn = classForName(treeParserPath+"$"+testTreeRuleName+"_return");
|
||||
Method[] methods = _treeReturn.getDeclaredMethods();
|
||||
for(Method method : methods) {
|
||||
if ( method.getName().equals("getTree") ) {
|
||||
Method treeReturnName = _treeReturn.getMethod("getTree");
|
||||
CommonTree returnTree = (CommonTree) treeReturnName.invoke(treeRuleReturn);
|
||||
astString = returnTree.toStringTree();
|
||||
}
|
||||
else if ( method.getName().equals("getTemplate") ) {
|
||||
Method treeReturnName = _return.getMethod("getTemplate");
|
||||
StringTemplate st = (StringTemplate) treeReturnName.invoke(treeRuleReturn);
|
||||
stString = st.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
System.err.println(e); // Note: If any exception occurs, the test is viewed as failed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkForValidInput( tokens, ps2 );
|
||||
|
||||
if ( err.toString().length()>0 ) {
|
||||
gUnitTestResult testResult = new gUnitTestResult(false, err.toString());
|
||||
testResult.setError(err.toString());
|
||||
return testResult;
|
||||
}
|
||||
|
||||
String stdout = null;
|
||||
// TODO: need to deal with the case which has both ST return value and stdout
|
||||
if ( out.toString().length()>0 ) {
|
||||
stdout = out.toString();
|
||||
}
|
||||
if ( astString!=null ) { // Return toStringTree of AST
|
||||
return new gUnitTestResult(true, stdout, astString);
|
||||
}
|
||||
else if ( stString!=null ) {// Return toString of ST
|
||||
return new gUnitTestResult(true, stdout, stString);
|
||||
}
|
||||
|
||||
if ( treeRuleReturn!=null ) {
|
||||
// TODO: again, currently only works for a single return with int or String value
|
||||
return new gUnitTestResult(true, stdout, String.valueOf(treeRuleReturn));
|
||||
}
|
||||
return new gUnitTestResult(true, stdout, stdout);
|
||||
} catch (IOException e) {
|
||||
return getTestExceptionResult(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (SecurityException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (NoSuchMethodException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (IllegalArgumentException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (InstantiationException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (IllegalAccessException e) {
|
||||
handleUnexpectedException( e );
|
||||
} catch (InvocationTargetException e) { // note: This exception could be caused from ANTLR Runtime Exception...
|
||||
return getTestExceptionResult(e);
|
||||
} finally {
|
||||
try {
|
||||
if ( ps!=null ) ps.close();
|
||||
if ( ps2!=null ) ps2.close();
|
||||
System.setOut(console); // Reset standard output
|
||||
System.setErr(consoleErr); // Reset standard err out
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO: verify this:
|
||||
throw new Exception("Should not be reachable?");
|
||||
}
|
||||
|
||||
// Create ANTLR input stream based on input source, file or String
|
||||
private CharStream getANTLRInputStream(gUnitTestInput testInput) throws IOException {
|
||||
CharStream input;
|
||||
if ( testInput.isFile) {
|
||||
String filePath = testInput.input;
|
||||
File testInputFile = new File(filePath);
|
||||
// if input test file is not found under the current dir, try to look for it from dir where the testsuite file locates
|
||||
if ( !testInputFile.exists() ) {
|
||||
testInputFile = new File(this.testsuiteDir, filePath);
|
||||
if ( testInputFile.exists() ) filePath = testInputFile.getCanonicalPath();
|
||||
// if still not found, also try to look for it under the package dir
|
||||
else if ( grammarInfo.getGrammarPackage()!=null ) {
|
||||
testInputFile = new File("."+File.separator+grammarInfo.getGrammarPackage().replace(".", File.separator), filePath);
|
||||
if ( testInputFile.exists() ) filePath = testInputFile.getCanonicalPath();
|
||||
}
|
||||
}
|
||||
input = new ANTLRFileStream(filePath);
|
||||
}
|
||||
else {
|
||||
input = new ANTLRStringStream(testInput.input);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
// set up the cause of exception or the exception name into a gUnitTestResult instance
|
||||
private gUnitTestResult getTestExceptionResult(Exception e) {
|
||||
gUnitTestResult testResult;
|
||||
if ( e.getCause()!=null ) {
|
||||
testResult = new gUnitTestResult(false, e.getCause().toString(), true);
|
||||
testResult.setError(e.getCause().toString());
|
||||
}
|
||||
else {
|
||||
testResult = new gUnitTestResult(false, e.toString(), true);
|
||||
testResult.setError(e.toString());
|
||||
}
|
||||
return testResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the input has been properly consumed
|
||||
*/
|
||||
protected void checkForValidInput(CommonTokenStream tokens, PrintStream ps2) {
|
||||
if ( tokens.index() != tokens.size() - 1 ) {
|
||||
//At this point we need to check for redundant EOF tokens
|
||||
//which might have been added by the Parser:
|
||||
List<? extends Token> endingTokens = tokens.getTokens(tokens.index(), tokens.size() -1);
|
||||
for (Token endToken : endingTokens) {
|
||||
if (! "<EOF>".equals(endToken.getText())) {
|
||||
//writing to ps2 will mark the test as failed:
|
||||
ps2.print( "Invalid input" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onPass(ITestCase passTest) {
|
||||
|
||||
}
|
||||
|
||||
public void onFail(ITestCase failTest) {
|
||||
|
||||
}
|
||||
|
||||
protected void handleUnexpectedException(Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon, Jen-Yuan Su
|
||||
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.gunit;
|
||||
|
||||
/** A class which contains input information of an individual testuite */
|
||||
public class gUnitTestInput {
|
||||
public String input; // a test input string for a testsuite
|
||||
public boolean isFile; // if true, the input represents a filename
|
||||
public int line; // line number in the script
|
||||
|
||||
public gUnitTestInput(String input, boolean isFile, int line) {
|
||||
this.input = input;
|
||||
this.isFile = isFile;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public String getInputEscaped() {
|
||||
return JUnitCodeGen.escapeForJava(input);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2007 Kenny MacDermid
|
||||
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.gunit;
|
||||
|
||||
public class gUnitTestResult {
|
||||
|
||||
private boolean success;
|
||||
private String output; // stdout
|
||||
private String error; // stderr
|
||||
private String returned; // AST (toStringTree) or ST (toString)
|
||||
private boolean isLexerTest;
|
||||
|
||||
public gUnitTestResult(boolean success, String output) {
|
||||
this.success = success;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public gUnitTestResult(boolean success, String output, boolean isLexerTest) {
|
||||
this(success, output);
|
||||
this.isLexerTest = isLexerTest;
|
||||
}
|
||||
|
||||
public gUnitTestResult(boolean success, String output, String returned) {
|
||||
this(success, output);
|
||||
this.returned = returned;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public String getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getReturned() {
|
||||
return returned;
|
||||
}
|
||||
|
||||
public boolean isLexerTest() {
|
||||
return isLexerTest;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon Jen-Yuan Su
|
||||
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.gunit;
|
||||
|
||||
/** A class which wraps all testsuites for an individual rule */
|
||||
import java.util.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class gUnitTestSuite {
|
||||
protected String rule = null; // paeser rule name for unit testing
|
||||
protected String lexicalRule = null; // lexical rule name
|
||||
protected String treeRule = null; // optional, required for testing tree grammar rule
|
||||
protected boolean isLexicalRule = false;
|
||||
|
||||
/** A map which stores input/output pairs (individual testsuites).
|
||||
* In other words, it maps input data for unit test (gUnitTestInput object)
|
||||
* to an expected output (Token object).
|
||||
*/
|
||||
protected Map<gUnitTestInput, AbstractTest> testSuites = new LinkedHashMap<gUnitTestInput, AbstractTest>();
|
||||
|
||||
public gUnitTestSuite() {
|
||||
}
|
||||
|
||||
public gUnitTestSuite(String rule) {
|
||||
this.rule = rule;
|
||||
}
|
||||
|
||||
public gUnitTestSuite(String treeRule, String rule) {
|
||||
this.rule = rule;
|
||||
this.treeRule = treeRule;
|
||||
}
|
||||
|
||||
public void setRuleName(String ruleName) { this.rule = ruleName; }
|
||||
public void setLexicalRuleName(String lexicalRule) { this.lexicalRule = lexicalRule; this.isLexicalRule = true; }
|
||||
public void setTreeRuleName(String treeRuleName) { this.treeRule = treeRuleName; }
|
||||
|
||||
public String getRuleName() { return this.rule; }
|
||||
public String getLexicalRuleName() { return this.lexicalRule; }
|
||||
public String getTreeRuleName() { return this.treeRule; }
|
||||
public boolean isLexicalRule() { return this.isLexicalRule; }
|
||||
|
||||
public void addTestCase(gUnitTestInput input, AbstractTest expect) {
|
||||
if ( input!=null && expect!=null ) {
|
||||
/*
|
||||
* modified by shaoting
|
||||
* if rule is null, use lexRule name
|
||||
*/
|
||||
//expect.setTestedRuleName(this.rule);
|
||||
expect.setTestedRuleName(this.rule ==null ? this.lexicalRule : this.rule);
|
||||
expect.setTestCaseIndex(this.testSuites.size());
|
||||
this.testSuites.put(input, expect);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import org.antlr.gunit.swingui.model.ITestCaseInput;
|
||||
import java.awt.event.ActionListener;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public abstract class AbstractInputEditor {
|
||||
|
||||
protected ITestCaseInput input;
|
||||
public void setInput(ITestCaseInput input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
protected JComponent comp;
|
||||
public JComponent getControl() { return comp; }
|
||||
|
||||
abstract public void addActionListener(ActionListener l) ;
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import java.awt.Component;
|
||||
|
||||
public interface IController {
|
||||
public Object getModel() ;
|
||||
public Component getView() ;
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package org.antlr.gunit.swingui;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
public class ImageFactory {
|
||||
|
||||
private static ImageFactory singleton ;
|
||||
|
||||
public static ImageFactory getSingleton() {
|
||||
if(singleton == null) singleton = new ImageFactory();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
private ImageFactory() {
|
||||
ACCEPT = getImage("accept.png");
|
||||
ADD = getImage("add.png");
|
||||
DELETE = getImage("delete24.png");
|
||||
TEXTFILE = getImage("textfile24.png");
|
||||
TEXTFILE16 = getImage("textfile16.png");
|
||||
ADDFILE = getImage("addfile24.png");
|
||||
WINDOW16 = getImage("windowb16.png");
|
||||
FAV16 = getImage("favb16.png");
|
||||
SAVE = getImage("floppy24.png");
|
||||
OPEN = getImage("folder24.png");
|
||||
EDIT16 = getImage("edit16.png");
|
||||
FILE16 = getImage("file16.png");
|
||||
RUN_PASS = getImage("runpass.png");
|
||||
RUN_FAIL = getImage("runfail.png");
|
||||
TESTSUITE = getImage("testsuite.png");
|
||||
TESTGROUP = getImage("testgroup.png");
|
||||
TESTGROUPX = getImage("testgroupx.png");
|
||||
NEXT = getImage("next24.png");
|
||||
}
|
||||
|
||||
private ImageIcon getImage(String name) {
|
||||
name = IMG_DIR + name;
|
||||
try {
|
||||
final ClassLoader loader = ImageFactory.class.getClassLoader();
|
||||
final InputStream in = loader.getResourceAsStream(name);
|
||||
final byte[] data = new byte[in.available()];
|
||||
in.read(data);
|
||||
in.close();
|
||||
return new ImageIcon(data);
|
||||
} catch (IOException ex) {
|
||||
System.err.println("Can't load image file: " + name);
|
||||
System.exit(1);
|
||||
} catch(RuntimeException e) {
|
||||
System.err.println("Can't load image file: " + name);
|
||||
System.exit(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final String IMG_DIR = "org/antlr/gunit/swingui/images/";
|
||||
|
||||
public ImageIcon ACCEPT;
|
||||
public ImageIcon ADD;
|
||||
public ImageIcon DELETE;
|
||||
public ImageIcon TEXTFILE ;
|
||||
public ImageIcon ADDFILE;
|
||||
|
||||
public ImageIcon TEXTFILE16 ;
|
||||
public ImageIcon WINDOW16;
|
||||
public ImageIcon FAV16;
|
||||
public ImageIcon SAVE ;
|
||||
|
||||
public ImageIcon OPEN ;
|
||||
public ImageIcon EDIT16;
|
||||
public ImageIcon FILE16;
|
||||
public ImageIcon NEXT;
|
||||
|
||||
public ImageIcon RUN_PASS;
|
||||
public ImageIcon RUN_FAIL;
|
||||
public ImageIcon TESTSUITE;
|
||||
public ImageIcon TESTGROUP ;
|
||||
public ImageIcon TESTGROUPX;
|
||||
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import javax.swing.event.ListDataListener;
|
||||
import org.antlr.gunit.swingui.model.Rule;
|
||||
import org.antlr.gunit.swingui.ImageFactory;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.List;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.ListModel;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import org.antlr.gunit.swingui.model.TestSuite;
|
||||
|
||||
public class RuleListController implements IController {
|
||||
|
||||
/* Sub-controls */
|
||||
private final JList list = new JList();
|
||||
private final JScrollPane scroll = new JScrollPane( list,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
/* Model */
|
||||
private ListModel model = null;
|
||||
private TestSuite testSuite = null;
|
||||
|
||||
public RuleListController() {
|
||||
this.initComponents();
|
||||
}
|
||||
|
||||
public JScrollPane getView() {
|
||||
return scroll;
|
||||
}
|
||||
|
||||
private void setTestSuite(TestSuite newTestSuite) {
|
||||
testSuite = newTestSuite;
|
||||
model = new RuleListModel();
|
||||
list.setModel(model);
|
||||
}
|
||||
|
||||
public void initialize(TestSuite ts) {
|
||||
setTestSuite(ts);
|
||||
if(model.getSize() > 0) list.setSelectedIndex(0);
|
||||
list.updateUI();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize view.
|
||||
*/
|
||||
private void initComponents() {
|
||||
|
||||
scroll.setViewportBorder(BorderFactory.createEtchedBorder());
|
||||
scroll.setBorder(BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEmptyBorder(), "Rules"));
|
||||
scroll.setOpaque(false);
|
||||
|
||||
list.setOpaque(false);
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
|
||||
list.setLayoutOrientation(JList.VERTICAL);
|
||||
list.setCellRenderer(new RuleListItemRenderer());
|
||||
}
|
||||
|
||||
public void setListSelectionListener(ListSelectionListener l) {
|
||||
this.list.addListSelectionListener(l);
|
||||
}
|
||||
|
||||
public Object getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
/* ITEM RENDERER */
|
||||
|
||||
private class RuleListItemRenderer extends JLabel implements ListCellRenderer{
|
||||
|
||||
public RuleListItemRenderer() {
|
||||
this.setPreferredSize(new Dimension(50, 18));
|
||||
}
|
||||
|
||||
public Component getListCellRendererComponent(
|
||||
JList list, Object value, int index,
|
||||
boolean isSelected, boolean hasFocus) {
|
||||
|
||||
if(value instanceof Rule) {
|
||||
final Rule item = (Rule) value;
|
||||
setText(item.toString());
|
||||
setForeground(list.getForeground());
|
||||
|
||||
setIcon(item.getNotEmpty() ? ImageFactory.getSingleton().FAV16 : null);
|
||||
|
||||
if(list.getSelectedValue() == item ) {
|
||||
setBackground(Color.LIGHT_GRAY);
|
||||
setOpaque(true);
|
||||
} else {
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
} else {
|
||||
this.setText("Error!");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private class RuleListModel implements ListModel {
|
||||
|
||||
public RuleListModel() {
|
||||
if(testSuite == null)
|
||||
throw new NullPointerException("Null test suite");
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return testSuite.getRuleCount();
|
||||
}
|
||||
|
||||
public Object getElementAt(int index) {
|
||||
return testSuite.getRule(index);
|
||||
}
|
||||
|
||||
public void addListDataListener(ListDataListener l) {}
|
||||
public void removeListDataListener(ListDataListener l) {}
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.event.TreeModelListener;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeCellRenderer;
|
||||
import javax.swing.tree.TreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import org.antlr.gunit.swingui.ImageFactory;
|
||||
import org.antlr.gunit.swingui.model.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class RunnerController implements IController {
|
||||
|
||||
/* MODEL */
|
||||
//private TestSuite testSuite;
|
||||
|
||||
/* VIEW */
|
||||
private RunnerView view = new RunnerView();
|
||||
public class RunnerView extends JPanel {
|
||||
|
||||
private JTextArea textArea = new JTextArea();
|
||||
|
||||
private JTree tree = new JTree();
|
||||
|
||||
private JScrollPane scroll = new JScrollPane(tree,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
public void initComponents() {
|
||||
//textArea.setOpaque(false);
|
||||
tree.setOpaque(false);
|
||||
scroll.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
||||
scroll.setOpaque(false);
|
||||
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
this.add(scroll);
|
||||
this.setBorder(BorderFactory.createEmptyBorder());
|
||||
this.setOpaque(false);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public RunnerController() {
|
||||
}
|
||||
|
||||
public Object getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Component getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
view.initComponents();
|
||||
}
|
||||
|
||||
public void OnShowSuiteResult(TestSuite suite) {
|
||||
update();
|
||||
view.tree.setModel(new RunnerTreeModel(suite));
|
||||
view.tree.setCellRenderer(new RunnerTreeRenderer());
|
||||
}
|
||||
|
||||
public void OnShowRuleResult(Rule rule) {
|
||||
update();
|
||||
|
||||
|
||||
|
||||
/*
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
result.append("Testing result for rule: " + rule.getName());
|
||||
result.append("\n--------------------\n\n");
|
||||
|
||||
for(TestCase testCase: rule.getTestCases()){
|
||||
result.append(testCase.isPass() ? "PASS" : "FAIL");
|
||||
result.append("\n");
|
||||
}
|
||||
result.append("\n--------------------\n");
|
||||
view.textArea.setText(result.toString());
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class TestSuiteTreeNode extends DefaultMutableTreeNode {
|
||||
|
||||
private TestSuite data ;
|
||||
|
||||
public TestSuiteTreeNode(TestSuite suite) {
|
||||
super(suite.getGrammarName());
|
||||
for(int i=0; i<suite.getRuleCount(); ++i) {
|
||||
final Rule rule = suite.getRule(i);
|
||||
if(rule.getNotEmpty()) this.add(new TestGroupTreeNode(rule));
|
||||
}
|
||||
data = suite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s (%d test groups)",
|
||||
data.getGrammarName(),
|
||||
this.getChildCount());
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
private class TestGroupTreeNode extends DefaultMutableTreeNode {
|
||||
|
||||
private Rule data;
|
||||
private boolean hasFail = false;
|
||||
|
||||
private TestGroupTreeNode(Rule rule) {
|
||||
super(rule.getName());
|
||||
for(TestCase tc: rule.getTestCases()) {
|
||||
this.add(new TestCaseTreeNode(tc));
|
||||
}
|
||||
|
||||
data = rule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
int iPass = 0;
|
||||
int iFail = 0;
|
||||
for(TestCase tc: data.getTestCases()) {
|
||||
if(tc.isPass())
|
||||
++iPass;
|
||||
else
|
||||
++iFail;
|
||||
}
|
||||
|
||||
hasFail = iFail > 0;
|
||||
|
||||
return String.format("%s (pass %d, fail %d)",
|
||||
data.getName(), iPass, iFail);
|
||||
}
|
||||
} ;
|
||||
|
||||
private class TestCaseTreeNode extends DefaultMutableTreeNode {
|
||||
|
||||
private TestCase data;
|
||||
|
||||
private TestCaseTreeNode(TestCase tc) {
|
||||
super(tc.toString());
|
||||
data = tc;
|
||||
}
|
||||
} ;
|
||||
|
||||
private class RunnerTreeModel extends DefaultTreeModel {
|
||||
|
||||
public RunnerTreeModel(TestSuite testSuite) {
|
||||
super(new TestSuiteTreeNode(testSuite));
|
||||
}
|
||||
}
|
||||
|
||||
private class RunnerTreeRenderer implements TreeCellRenderer {
|
||||
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value,
|
||||
boolean selected, boolean expanded, boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
|
||||
JLabel label = new JLabel();
|
||||
|
||||
if(value instanceof TestSuiteTreeNode) {
|
||||
|
||||
label.setText(value.toString());
|
||||
label.setIcon(ImageFactory.getSingleton().TESTSUITE);
|
||||
|
||||
} else if(value instanceof TestGroupTreeNode) {
|
||||
|
||||
TestGroupTreeNode node = (TestGroupTreeNode) value;
|
||||
label.setText(value.toString());
|
||||
label.setIcon( node.hasFail ?
|
||||
ImageFactory.getSingleton().TESTGROUPX :
|
||||
ImageFactory.getSingleton().TESTGROUP);
|
||||
|
||||
} else if(value instanceof TestCaseTreeNode) {
|
||||
|
||||
TestCaseTreeNode node = (TestCaseTreeNode) value;
|
||||
label.setIcon( (node.data.isPass())?
|
||||
ImageFactory.getSingleton().RUN_PASS :
|
||||
ImageFactory.getSingleton().RUN_FAIL);
|
||||
label.setText(value.toString());
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalide tree node type + " + value.getClass().getName());
|
||||
}
|
||||
|
||||
return label;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
|
||||
public class StatusBarController implements IController {
|
||||
|
||||
private final JPanel panel = new JPanel();
|
||||
|
||||
private final JLabel labelText = new JLabel("Ready");
|
||||
private final JLabel labelRuleName = new JLabel("");
|
||||
private final JProgressBar progress = new JProgressBar();
|
||||
|
||||
public StatusBarController() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
labelText.setPreferredSize(new Dimension(300, 20));
|
||||
labelText.setHorizontalTextPosition(JLabel.LEFT);
|
||||
progress.setPreferredSize(new Dimension(100, 15));
|
||||
|
||||
final JLabel labRuleHint = new JLabel("Rule: ");
|
||||
|
||||
FlowLayout layout = new FlowLayout();
|
||||
layout.setAlignment(FlowLayout.LEFT);
|
||||
panel.setLayout(layout);
|
||||
panel.add(labelText);
|
||||
panel.add(progress);
|
||||
panel.add(labRuleHint);
|
||||
panel.add(labelRuleName);
|
||||
panel.setOpaque(false);
|
||||
panel.setBorder(javax.swing.BorderFactory.createEmptyBorder());
|
||||
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
labelText.setText(text);
|
||||
}
|
||||
|
||||
public void setRule(String name) {
|
||||
this.labelRuleName.setText(name);
|
||||
}
|
||||
|
||||
public Object getModel() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public JPanel getView() {
|
||||
return panel;
|
||||
}
|
||||
|
||||
public void setProgressIndetermined(boolean value) {
|
||||
this.progress.setIndeterminate(value);
|
||||
}
|
||||
|
||||
public void setProgress(int value) {
|
||||
this.progress.setIndeterminate(false);
|
||||
this.progress.setValue(value);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,633 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import org.antlr.gunit.swingui.model.*;
|
||||
import org.antlr.gunit.swingui.ImageFactory;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.HashMap;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class TestCaseEditController implements IController {
|
||||
|
||||
private JPanel view = new JPanel();
|
||||
|
||||
private JScrollPane scroll;
|
||||
private JPanel paneDetail;
|
||||
private AbstractEditorPane paneDetailInput, paneDetailOutput;
|
||||
private JToolBar toolbar;
|
||||
private JList listCases;
|
||||
private ListModel listModel ;
|
||||
|
||||
public ActionListener onTestCaseNumberChange;
|
||||
|
||||
/* EDITORS */
|
||||
private InputFileEditor editInputFile;
|
||||
private InputStringEditor editInputString;
|
||||
private InputMultiEditor editInputMulti;
|
||||
private OutputResultEditor editOutputResult;
|
||||
private OutputAstEditor editOutputAST;
|
||||
private OutputStdEditor editOutputStd;
|
||||
private OutputReturnEditor editOutputReturn;
|
||||
|
||||
private JComboBox comboInputType, comboOutputType;
|
||||
|
||||
/* TYPE NAME */
|
||||
private static final String IN_TYPE_STRING = "Single-line Text";
|
||||
private static final String IN_TYPE_MULTI = "Multi-line Text";
|
||||
private static final String IN_TYPE_FILE = "Disk File";
|
||||
private static final String OUT_TYPE_BOOL = "OK or Fail";
|
||||
private static final String OUT_TYPE_AST = "AST";
|
||||
private static final String OUT_TYPE_STD = "Standard Output";
|
||||
private static final String OUT_TYPE_RET = "Return Value";
|
||||
|
||||
private static final String DEFAULT_IN_SCRIPT = "";
|
||||
private static final String DEFAULT_OUT_SCRIPT = "";
|
||||
|
||||
private static final Object[] INPUT_TYPE = {
|
||||
IN_TYPE_STRING, IN_TYPE_MULTI, IN_TYPE_FILE
|
||||
};
|
||||
|
||||
private static final Object[] OUTPUT_TYPE = {
|
||||
OUT_TYPE_BOOL, OUT_TYPE_AST, OUT_TYPE_STD, OUT_TYPE_RET
|
||||
};
|
||||
|
||||
/* SIZE */
|
||||
private static final int TEST_CASE_DETAIL_WIDTH = 300;
|
||||
private static final int TEST_EDITOR_WIDTH = 280;
|
||||
private static final int TEST_CASE_DETAIL_HEIGHT = 250;
|
||||
private static final int TEST_EDITOR_HEIGHT = 120;
|
||||
|
||||
/* MODEL */
|
||||
private Rule currentRule = null;
|
||||
private TestCase currentTestCase = null;
|
||||
|
||||
/* END OF MODEL*/
|
||||
|
||||
private static final HashMap<Class<?>, String> TypeNameTable;
|
||||
static {
|
||||
TypeNameTable = new HashMap<Class<?>, String> ();
|
||||
TypeNameTable.put(TestCaseInputString.class, IN_TYPE_STRING);
|
||||
TypeNameTable.put(TestCaseInputMultiString.class, IN_TYPE_MULTI);
|
||||
TypeNameTable.put(TestCaseInputFile.class, IN_TYPE_FILE);
|
||||
|
||||
TypeNameTable.put(TestCaseOutputResult.class, OUT_TYPE_BOOL);
|
||||
TypeNameTable.put(TestCaseOutputAST.class, OUT_TYPE_AST);
|
||||
TypeNameTable.put(TestCaseOutputStdOut.class, OUT_TYPE_STD);
|
||||
TypeNameTable.put(TestCaseOutputReturn.class, OUT_TYPE_RET);
|
||||
}
|
||||
|
||||
//private WorkSpaceView owner;
|
||||
|
||||
public TestCaseEditController(WorkSpaceView workspace) {
|
||||
//this.owner = workspace;
|
||||
initComponents();
|
||||
}
|
||||
|
||||
public TestCaseEditController() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
public void OnLoadRule(Rule rule) {
|
||||
if(rule == null) throw new IllegalArgumentException("Null");
|
||||
this.currentRule = rule;
|
||||
this.currentTestCase = null;
|
||||
this.listModel = rule;
|
||||
this.listCases.setModel(this.listModel);
|
||||
}
|
||||
|
||||
public void setCurrentTestCase(TestCase testCase) {
|
||||
if(testCase == null) throw new IllegalArgumentException("Null");
|
||||
this.listCases.setSelectedValue(testCase, true);
|
||||
this.currentTestCase = testCase;
|
||||
}
|
||||
|
||||
public Rule getCurrentRule() {
|
||||
return this.currentRule;
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
|
||||
/* CASE LIST */
|
||||
listCases = new JList();
|
||||
listCases.addListSelectionListener(new TestCaseListSelectionListener());
|
||||
listCases.setCellRenderer(listRenderer);
|
||||
listCases.setOpaque(false);
|
||||
|
||||
scroll = new JScrollPane(listCases);
|
||||
scroll.setBorder(BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEmptyBorder(), "Test Cases"));
|
||||
scroll.setOpaque(false);
|
||||
scroll.setViewportBorder(BorderFactory.createEtchedBorder());
|
||||
|
||||
/* CASE DETAIL */
|
||||
|
||||
editInputString = new InputStringEditor();
|
||||
editInputMulti = new InputMultiEditor();
|
||||
editInputFile = new InputFileEditor();
|
||||
|
||||
editOutputResult = new OutputResultEditor();
|
||||
editOutputAST = new OutputAstEditor();
|
||||
editOutputStd = new OutputStdEditor();
|
||||
editOutputReturn = new OutputReturnEditor();
|
||||
|
||||
paneDetail = new JPanel();
|
||||
paneDetail.setBorder(BorderFactory.createEmptyBorder());
|
||||
paneDetail.setOpaque(false);
|
||||
|
||||
comboInputType = new JComboBox(INPUT_TYPE);
|
||||
comboInputType.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
OnInputTestCaseTypeChanged(comboInputType.getSelectedItem());
|
||||
}
|
||||
});
|
||||
comboOutputType = new JComboBox(OUTPUT_TYPE);
|
||||
comboOutputType.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
OnOutputTestCaseTypeChanged(comboOutputType.getSelectedItem());
|
||||
}
|
||||
});
|
||||
paneDetailInput = new InputEditorPane(comboInputType);
|
||||
paneDetailOutput = new OutputEditorPane(comboOutputType);
|
||||
|
||||
BoxLayout layout = new BoxLayout(paneDetail, BoxLayout.PAGE_AXIS);
|
||||
paneDetail.setLayout(layout);
|
||||
|
||||
paneDetail.add(this.paneDetailInput);
|
||||
paneDetail.add(this.paneDetailOutput);
|
||||
|
||||
/* TOOLBAR */
|
||||
toolbar = new JToolBar("Edit TestCases", JToolBar.VERTICAL);
|
||||
toolbar.setFloatable(false);
|
||||
toolbar.add(new AddTestCaseAction());
|
||||
toolbar.add(new RemoveTestCaseAction());
|
||||
|
||||
/* COMPOSITE */
|
||||
view.setLayout(new BorderLayout());
|
||||
view.setBorder(BorderFactory.createEmptyBorder());
|
||||
view.setOpaque(false);
|
||||
view.add(toolbar, BorderLayout.WEST);
|
||||
view.add(scroll, BorderLayout.CENTER);
|
||||
view.add(paneDetail, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
private void updateInputEditor() {
|
||||
JComponent editor = null;
|
||||
|
||||
if(currentTestCase != null ) {
|
||||
ITestCaseInput input = this.currentTestCase.getInput();
|
||||
if(input instanceof TestCaseInputString) {
|
||||
this.editInputString.setText(input.getScript());
|
||||
editor = this.editInputString;
|
||||
comboInputType.setSelectedItem(IN_TYPE_STRING);
|
||||
} else if(input instanceof TestCaseInputMultiString) {
|
||||
this.editInputMulti.setText(input.getScript());
|
||||
editor = this.editInputMulti.getView();
|
||||
comboInputType.setSelectedItem(IN_TYPE_MULTI);
|
||||
} else if(input instanceof TestCaseInputFile) {
|
||||
this.editInputFile.setText(input.getScript());
|
||||
editor = this.editInputFile;
|
||||
comboInputType.setSelectedItem(IN_TYPE_FILE);
|
||||
} else {
|
||||
throw new Error("Wrong type");
|
||||
}
|
||||
}
|
||||
|
||||
paneDetailInput.setEditor(editor);
|
||||
}
|
||||
|
||||
private void updateOutputEditor() {
|
||||
JComponent editor = null;
|
||||
|
||||
if(currentTestCase != null) {
|
||||
|
||||
ITestCaseOutput output = this.currentTestCase.getOutput();
|
||||
|
||||
if(output instanceof TestCaseOutputAST) {
|
||||
|
||||
this.editOutputAST.setText(output.getScript());
|
||||
editor = this.editOutputAST.getView();
|
||||
comboOutputType.setSelectedItem(OUT_TYPE_AST);
|
||||
|
||||
} else if(output instanceof TestCaseOutputResult) {
|
||||
|
||||
this.editOutputResult.setValue(output.getScript());
|
||||
editor = this.editOutputResult;
|
||||
comboOutputType.setSelectedItem(OUT_TYPE_BOOL);
|
||||
|
||||
} else if(output instanceof TestCaseOutputStdOut) {
|
||||
|
||||
this.editOutputStd.setText(output.getScript());
|
||||
editor = this.editOutputStd.getView();
|
||||
comboOutputType.setSelectedItem(OUT_TYPE_STD);
|
||||
|
||||
} else if(output instanceof TestCaseOutputReturn) {
|
||||
|
||||
this.editOutputReturn.setText(output.getScript());
|
||||
editor = this.editOutputReturn.getView();
|
||||
comboOutputType.setSelectedItem(OUT_TYPE_RET);
|
||||
|
||||
} else {
|
||||
|
||||
throw new Error("Wrong type");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
this.paneDetailOutput.setEditor(editor);
|
||||
}
|
||||
|
||||
private void OnInputTestCaseTypeChanged(Object inputTypeStr) {
|
||||
if(this.currentTestCase != null) {
|
||||
ITestCaseInput input ;
|
||||
if(inputTypeStr == IN_TYPE_STRING) {
|
||||
input = new TestCaseInputString(DEFAULT_IN_SCRIPT);
|
||||
} else if(inputTypeStr == IN_TYPE_MULTI) {
|
||||
input = new TestCaseInputMultiString(DEFAULT_IN_SCRIPT);
|
||||
} else if(inputTypeStr == IN_TYPE_FILE) {
|
||||
input = new TestCaseInputFile(DEFAULT_IN_SCRIPT);
|
||||
} else {
|
||||
throw new Error("Wrong Type");
|
||||
}
|
||||
|
||||
if(input.getClass().equals(this.currentTestCase.getInput().getClass()))
|
||||
return ;
|
||||
|
||||
this.currentTestCase.setInput(input);
|
||||
}
|
||||
this.updateInputEditor();
|
||||
}
|
||||
|
||||
private void OnOutputTestCaseTypeChanged(Object outputTypeStr) {
|
||||
if(this.currentTestCase != null) {
|
||||
|
||||
ITestCaseOutput output ;
|
||||
if(outputTypeStr == OUT_TYPE_AST) {
|
||||
output = new TestCaseOutputAST(DEFAULT_OUT_SCRIPT);
|
||||
} else if(outputTypeStr == OUT_TYPE_BOOL) {
|
||||
output = new TestCaseOutputResult(false);
|
||||
} else if(outputTypeStr == OUT_TYPE_STD) {
|
||||
output = new TestCaseOutputStdOut(DEFAULT_OUT_SCRIPT);
|
||||
} else if(outputTypeStr == OUT_TYPE_RET) {
|
||||
output = new TestCaseOutputReturn(DEFAULT_OUT_SCRIPT);
|
||||
} else {
|
||||
throw new Error("Wrong Type");
|
||||
}
|
||||
|
||||
if(output.getClass().equals(this.currentTestCase.getOutput().getClass()))
|
||||
return ;
|
||||
|
||||
this.currentTestCase.setOutput(output);
|
||||
}
|
||||
this.updateOutputEditor();
|
||||
}
|
||||
|
||||
|
||||
private void OnTestCaseSelected(TestCase testCase) {
|
||||
//if(testCase == null) throw new RuntimeException("Null TestCase");
|
||||
this.currentTestCase = testCase;
|
||||
updateInputEditor();
|
||||
updateOutputEditor();
|
||||
|
||||
}
|
||||
|
||||
private void OnAddTestCase() {
|
||||
if(currentRule == null) return;
|
||||
|
||||
final TestCase newCase = new TestCase(
|
||||
new TestCaseInputString(""),
|
||||
new TestCaseOutputResult(true));
|
||||
this.currentRule.addTestCase(newCase);
|
||||
setCurrentTestCase(newCase);
|
||||
|
||||
this.listCases.setSelectedValue(newCase, true);
|
||||
this.listCases.updateUI();
|
||||
this.OnTestCaseSelected(newCase);
|
||||
this.onTestCaseNumberChange.actionPerformed(null);
|
||||
}
|
||||
|
||||
private void OnRemoveTestCase() {
|
||||
if(currentTestCase == null) return;
|
||||
currentRule.removeElement(currentTestCase);
|
||||
listCases.updateUI();
|
||||
|
||||
final TestCase nextActiveCase = listCases.isSelectionEmpty() ?
|
||||
null : (TestCase) listCases.getSelectedValue() ;
|
||||
OnTestCaseSelected(nextActiveCase);
|
||||
this.onTestCaseNumberChange.actionPerformed(null);
|
||||
}
|
||||
|
||||
public Object getModel() {
|
||||
return currentRule;
|
||||
}
|
||||
|
||||
public Component getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
/* EDITOR CONTAINER */
|
||||
|
||||
abstract public class AbstractEditorPane extends JPanel {
|
||||
|
||||
private JComboBox combo;
|
||||
private JComponent editor;
|
||||
private String title;
|
||||
private JLabel placeHolder = new JLabel();
|
||||
|
||||
public AbstractEditorPane(JComboBox comboBox, String title) {
|
||||
this.combo = comboBox;
|
||||
this.editor = placeHolder;
|
||||
this.title = title;
|
||||
this.initComponents();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
placeHolder.setPreferredSize(new Dimension(
|
||||
TEST_CASE_DETAIL_WIDTH, TEST_CASE_DETAIL_HEIGHT));
|
||||
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
this.add(combo, BorderLayout.NORTH);
|
||||
this.add(editor, BorderLayout.CENTER);
|
||||
this.setOpaque(false);
|
||||
this.setBorder(BorderFactory.createTitledBorder(title));
|
||||
this.setPreferredSize(new Dimension(
|
||||
TEST_CASE_DETAIL_WIDTH, TEST_CASE_DETAIL_HEIGHT));
|
||||
}
|
||||
|
||||
public void setEditor(JComponent newEditor) {
|
||||
if(newEditor == null) newEditor = placeHolder;
|
||||
this.remove(editor);
|
||||
this.add(newEditor);
|
||||
this.editor = newEditor;
|
||||
this.updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
public class InputEditorPane extends AbstractEditorPane {
|
||||
public InputEditorPane(JComboBox comboBox) {
|
||||
super(comboBox, "Input");
|
||||
}
|
||||
}
|
||||
|
||||
public class OutputEditorPane extends AbstractEditorPane {
|
||||
public OutputEditorPane(JComboBox comboBox) {
|
||||
super(comboBox, "Output");
|
||||
}
|
||||
}
|
||||
|
||||
/* INPUT EDITORS */
|
||||
|
||||
public class InputStringEditor extends JTextField implements CaretListener {
|
||||
public InputStringEditor() {
|
||||
super();
|
||||
|
||||
this.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
||||
this.addCaretListener(this);
|
||||
}
|
||||
|
||||
public void caretUpdate(CaretEvent arg0) {
|
||||
currentTestCase.getInput().setScript(getText());
|
||||
listCases.updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
public class InputMultiEditor implements CaretListener {
|
||||
private JTextArea textArea = new JTextArea(20, 30);
|
||||
private JScrollPane scroll = new JScrollPane(textArea,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||
|
||||
public InputMultiEditor() {
|
||||
super();
|
||||
scroll.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
||||
textArea.addCaretListener(this);
|
||||
}
|
||||
|
||||
public void caretUpdate(CaretEvent arg0) {
|
||||
currentTestCase.getInput().setScript(getText());
|
||||
listCases.updateUI();
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return textArea.getText();
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
textArea.setText(text);
|
||||
}
|
||||
|
||||
public JComponent getView() {
|
||||
return scroll;
|
||||
}
|
||||
}
|
||||
|
||||
public class InputFileEditor extends InputStringEditor {};
|
||||
|
||||
public class OutputResultEditor extends JPanel implements ActionListener {
|
||||
|
||||
private JToggleButton tbFail, tbOk;
|
||||
|
||||
public OutputResultEditor() {
|
||||
super();
|
||||
|
||||
tbFail = new JToggleButton("Fail");
|
||||
tbOk = new JToggleButton("OK");
|
||||
ButtonGroup group = new ButtonGroup();
|
||||
group.add(tbFail);
|
||||
group.add(tbOk);
|
||||
|
||||
this.add(tbFail);
|
||||
this.add(tbOk);
|
||||
|
||||
this.tbFail.addActionListener(this);
|
||||
this.tbOk.addActionListener(this);
|
||||
|
||||
this.setPreferredSize(
|
||||
new Dimension(TEST_EDITOR_WIDTH, 100));
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TestCaseOutputResult output =
|
||||
(TestCaseOutputResult) currentTestCase.getOutput();
|
||||
|
||||
if(e.getSource() == tbFail) {
|
||||
output.setScript(false);
|
||||
} else {
|
||||
output.setScript(true);
|
||||
}
|
||||
|
||||
listCases.updateUI();
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
if(TestCaseOutputResult.OK.equals(value)) {
|
||||
this.tbOk.setSelected(true);
|
||||
} else {
|
||||
this.tbFail.setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class OutputAstEditor implements CaretListener {
|
||||
private JTextArea textArea = new JTextArea(20, 30);
|
||||
private JScrollPane scroll = new JScrollPane(textArea,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||
|
||||
public OutputAstEditor() {
|
||||
super();
|
||||
scroll.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
||||
textArea.addCaretListener(this);
|
||||
}
|
||||
|
||||
public void caretUpdate(CaretEvent arg0) {
|
||||
currentTestCase.getOutput().setScript(getText());
|
||||
listCases.updateUI();
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.textArea.setText(text);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return this.textArea.getText();
|
||||
}
|
||||
|
||||
public JScrollPane getView() {
|
||||
return this.scroll;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class OutputStdEditor extends OutputAstEditor {}
|
||||
public class OutputReturnEditor extends OutputAstEditor {}
|
||||
|
||||
/* EVENT HANDLERS */
|
||||
|
||||
private class TestCaseListSelectionListener implements ListSelectionListener {
|
||||
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
|
||||
if(e.getValueIsAdjusting()) return;
|
||||
final JList list = (JList) e.getSource();
|
||||
final TestCase value = (TestCase) list.getSelectedValue();
|
||||
if(value != null) OnTestCaseSelected(value);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ACTIONS */
|
||||
|
||||
private class AddTestCaseAction extends AbstractAction {
|
||||
public AddTestCaseAction() {
|
||||
super("Add", ImageFactory.getSingleton().ADD);
|
||||
putValue(SHORT_DESCRIPTION, "Add a gUnit test case.");
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
OnAddTestCase();
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoveTestCaseAction extends AbstractAction {
|
||||
public RemoveTestCaseAction() {
|
||||
super("Remove", ImageFactory.getSingleton().DELETE);
|
||||
putValue(SHORT_DESCRIPTION, "Remove a gUnit test case.");
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
OnRemoveTestCase();
|
||||
}
|
||||
}
|
||||
|
||||
/* CELL RENDERERS */
|
||||
|
||||
private static TestCaseListRenderer listRenderer
|
||||
= new TestCaseListRenderer();
|
||||
|
||||
private static class TestCaseListRenderer implements ListCellRenderer {
|
||||
|
||||
private static Font IN_FONT = new Font("mono", Font.PLAIN, 12);
|
||||
private static Font OUT_FONT = new Font("default", Font.BOLD, 12);
|
||||
|
||||
public static String clamp(String text, int len) {
|
||||
if(text.length() > len) {
|
||||
return text.substring(0, len - 3).concat("...");
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
public static String clampAtNewLine(String text) {
|
||||
int pos = text.indexOf('\n');
|
||||
if(pos >= 0) {
|
||||
return text.substring(0, pos).concat("...");
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
public Component getListCellRendererComponent(
|
||||
JList list, Object value, int index,
|
||||
boolean isSelected, boolean hasFocus) {
|
||||
|
||||
final JPanel pane = new JPanel();
|
||||
|
||||
if (value instanceof TestCase) {
|
||||
final TestCase item = (TestCase) value;
|
||||
|
||||
// create components
|
||||
final JLabel labIn = new JLabel(
|
||||
clamp(clampAtNewLine(item.getInput().getScript()), 18));
|
||||
final JLabel labOut = new JLabel(
|
||||
clamp(clampAtNewLine(item.getOutput().getScript()), 18));
|
||||
labOut.setFont(OUT_FONT);
|
||||
labIn.setFont(IN_FONT);
|
||||
|
||||
labIn.setIcon(item.getInput() instanceof TestCaseInputFile ?
|
||||
ImageFactory.getSingleton().FILE16 :
|
||||
ImageFactory.getSingleton().EDIT16);
|
||||
|
||||
pane.setBorder(BorderFactory.createEtchedBorder());
|
||||
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
|
||||
pane.add(labIn);
|
||||
pane.add(labOut);
|
||||
pane.setBackground(isSelected ? Color.LIGHT_GRAY : Color.WHITE);
|
||||
}
|
||||
|
||||
return pane;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
public class Tool {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
if(args.length == 1 && "-version".equals(args[0])) {
|
||||
System.out.println("gUnitEditor Swing GUI\nby Shaoting Cai\n");
|
||||
} else {
|
||||
showUI();
|
||||
}
|
||||
}
|
||||
|
||||
private static void showUI() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
WorkSpaceController control = new WorkSpaceController();
|
||||
control.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,288 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.antlr.gunit.swingui.runner.gUnitAdapter;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import org.antlr.gunit.swingui.model.*;
|
||||
import org.antlr.gunit.swingui.ImageFactory;
|
||||
import java.awt.event.*;
|
||||
import java.io.File;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class WorkSpaceController implements IController{
|
||||
|
||||
/* MODEL */
|
||||
private TestSuite currentTestSuite;
|
||||
private String testSuiteFileName = null; // path + file
|
||||
|
||||
/* VIEW */
|
||||
private final WorkSpaceView view = new WorkSpaceView();
|
||||
|
||||
/* SUB-CONTROL */
|
||||
private final RunnerController runner = new RunnerController();
|
||||
|
||||
public WorkSpaceController() {
|
||||
view.resultPane = (JPanel) runner.getView();
|
||||
view.initComponents();
|
||||
this.initEventHandlers();
|
||||
this.initToolbar();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
this.view.setTitle("gUnitEditor");
|
||||
this.view.setVisible(true);
|
||||
this.view.pack();
|
||||
}
|
||||
|
||||
public Component getEmbeddedView() {
|
||||
return view.paneEditor.getView();
|
||||
}
|
||||
|
||||
private void initEventHandlers() {
|
||||
this.view.tabEditors.addChangeListener(new TabChangeListener());
|
||||
this.view.listRules.setListSelectionListener(new RuleListSelectionListener());
|
||||
this.view.paneEditor.onTestCaseNumberChange = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
view.listRules.getView().updateUI();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void OnCreateTest() {
|
||||
JFileChooser jfc = new JFileChooser();
|
||||
jfc.setDialogTitle("Create test suite from grammar");
|
||||
jfc.setDialogType(JFileChooser.OPEN_DIALOG);
|
||||
jfc.setFileFilter(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory() || f.getName().toLowerCase().endsWith(TestSuiteFactory.GRAMMAR_EXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "ANTLR grammar file (*.g)";
|
||||
}
|
||||
});
|
||||
if( jfc.showOpenDialog(view) != JFileChooser.APPROVE_OPTION ) return;
|
||||
|
||||
view.paneStatus.setProgressIndetermined(true);
|
||||
final File grammarFile = jfc.getSelectedFile();
|
||||
|
||||
currentTestSuite = TestSuiteFactory.createTestSuite(grammarFile);
|
||||
|
||||
view.listRules.initialize(currentTestSuite);
|
||||
view.tabEditors.setSelectedIndex(0);
|
||||
view.paneStatus.setText("Grammar: " + currentTestSuite.getGrammarName());
|
||||
view.paneStatus.setProgressIndetermined(false);
|
||||
|
||||
testSuiteFileName = null;
|
||||
}
|
||||
|
||||
private void OnSaveTest() {
|
||||
TestSuiteFactory.saveTestSuite(currentTestSuite);
|
||||
JOptionPane.showMessageDialog(view, "Testsuite saved to:\n" + currentTestSuite.getTestSuiteFile().getAbsolutePath());
|
||||
}
|
||||
|
||||
private void OnOpenTest() {
|
||||
|
||||
JFileChooser jfc = new JFileChooser();
|
||||
jfc.setDialogTitle("Open existing gUnit test suite");
|
||||
jfc.setDialogType(JFileChooser.OPEN_DIALOG);
|
||||
jfc.setFileFilter(new FileFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory() || f.getName().toLowerCase().endsWith(TestSuiteFactory.TEST_SUITE_EXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "ANTLR unit test file (*.gunit)";
|
||||
}
|
||||
});
|
||||
if( jfc.showOpenDialog(view) != JFileChooser.APPROVE_OPTION ) return;
|
||||
|
||||
final File testSuiteFile = jfc.getSelectedFile();
|
||||
try {
|
||||
testSuiteFileName = testSuiteFile.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
view.paneStatus.setProgressIndetermined(true);
|
||||
|
||||
currentTestSuite = TestSuiteFactory.loadTestSuite(testSuiteFile);
|
||||
view.listRules.initialize(currentTestSuite);
|
||||
view.paneStatus.setText(currentTestSuite.getGrammarName());
|
||||
view.tabEditors.setSelectedIndex(0);
|
||||
|
||||
view.paneStatus.setProgressIndetermined(false);
|
||||
}
|
||||
|
||||
private void OnSelectRule(Rule rule) {
|
||||
if(rule == null) throw new IllegalArgumentException("Null");
|
||||
this.view.paneEditor.OnLoadRule(rule);
|
||||
this.view.paneStatus.setRule(rule.getName());
|
||||
|
||||
// run result
|
||||
this.runner.OnShowRuleResult(rule);
|
||||
}
|
||||
|
||||
private void OnSelectTextPane() {
|
||||
Thread worker = new Thread () {
|
||||
@Override
|
||||
public void run() {
|
||||
view.paneStatus.setProgressIndetermined(true);
|
||||
view.txtEditor.setText(
|
||||
TestSuiteFactory.getScript(currentTestSuite));
|
||||
view.paneStatus.setProgressIndetermined(false);
|
||||
}
|
||||
};
|
||||
|
||||
worker.start();
|
||||
}
|
||||
|
||||
private void OnRunTest() {
|
||||
// save before run
|
||||
TestSuiteFactory.saveTestSuite(currentTestSuite);
|
||||
|
||||
// run
|
||||
try {
|
||||
final gUnitAdapter adapter = new gUnitAdapter(currentTestSuite);
|
||||
if(currentTestSuite == null) return;
|
||||
adapter.run();
|
||||
|
||||
runner.OnShowSuiteResult(currentTestSuite);
|
||||
view.tabEditors.addTab("Test Result", ImageFactory.getSingleton().FILE16, runner.getView());
|
||||
view.tabEditors.setSelectedComponent(runner.getView());
|
||||
} catch (Exception ex) {
|
||||
JOptionPane.showMessageDialog(view, "Fail to run test:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
view.toolbar.add(new JButton(new CreateAction()));
|
||||
view.toolbar.add(new JButton(new OpenAction()));
|
||||
view.toolbar.add(new JButton(new SaveAction()));
|
||||
view.toolbar.add(new JButton(new RunAction()));
|
||||
|
||||
}
|
||||
|
||||
public Object getModel() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public Component getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
/** Event handler for rule list selection. */
|
||||
private class RuleListSelectionListener implements ListSelectionListener {
|
||||
public void valueChanged(ListSelectionEvent event) {
|
||||
if(event.getValueIsAdjusting()) return;
|
||||
final JList list = (JList) event.getSource();
|
||||
final Rule rule = (Rule) list.getSelectedValue();
|
||||
if(rule != null) OnSelectRule(rule);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Event handler for switching between editor view and script view. */
|
||||
public class TabChangeListener implements ChangeListener {
|
||||
public void stateChanged(ChangeEvent evt) {
|
||||
if(view.tabEditors.getSelectedIndex() == 1) {
|
||||
OnSelectTextPane();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Create test suite action. */
|
||||
private class CreateAction extends AbstractAction {
|
||||
public CreateAction() {
|
||||
super("Create", ImageFactory.getSingleton().ADDFILE);
|
||||
putValue(SHORT_DESCRIPTION, "Create a test suite from an ANTLR grammar");
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
OnCreateTest();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Save test suite action. */
|
||||
private class SaveAction extends AbstractAction {
|
||||
public SaveAction() {
|
||||
super("Save", ImageFactory.getSingleton().SAVE);
|
||||
putValue(SHORT_DESCRIPTION, "Save the test suite");
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
OnSaveTest();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Open test suite action. */
|
||||
private class OpenAction extends AbstractAction {
|
||||
public OpenAction() {
|
||||
super("Open", ImageFactory.getSingleton().OPEN);
|
||||
putValue(SHORT_DESCRIPTION, "Open an existing test suite");
|
||||
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(
|
||||
KeyEvent.VK_O, InputEvent.CTRL_MASK));
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
OnOpenTest();
|
||||
}
|
||||
}
|
||||
|
||||
/** Run test suite action. */
|
||||
private class RunAction extends AbstractAction {
|
||||
public RunAction() {
|
||||
super("Run", ImageFactory.getSingleton().NEXT);
|
||||
putValue(SHORT_DESCRIPTION, "Run the current test suite");
|
||||
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(
|
||||
KeyEvent.VK_R, InputEvent.CTRL_MASK));
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
OnRunTest();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.
|
||||
*/
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package org.antlr.gunit.swingui;
|
||||
|
||||
import org.antlr.gunit.swingui.ImageFactory;
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class WorkSpaceView extends JFrame {
|
||||
|
||||
protected JSplitPane splitListClient ;
|
||||
protected JTabbedPane tabEditors;
|
||||
protected JPanel paneToolBar;
|
||||
protected StatusBarController paneStatus;
|
||||
protected TestCaseEditController paneEditor;
|
||||
protected JToolBar toolbar;
|
||||
protected JTextArea txtEditor;
|
||||
protected RuleListController listRules;
|
||||
protected JMenuBar menuBar;
|
||||
protected JScrollPane scrollCode;
|
||||
protected JPanel resultPane;
|
||||
|
||||
protected JButton btnOpenGrammar;
|
||||
|
||||
public WorkSpaceView() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected void initComponents() {
|
||||
|
||||
this.paneEditor = new TestCaseEditController(this);
|
||||
this.paneStatus = new StatusBarController();
|
||||
|
||||
this.toolbar = new JToolBar();
|
||||
this.toolbar.setBorder(BorderFactory.createEmptyBorder());
|
||||
this.toolbar.setFloatable(false);
|
||||
this.toolbar.setBorder(BorderFactory.createEmptyBorder());
|
||||
|
||||
this.txtEditor = new JTextArea();
|
||||
this.txtEditor.setLineWrap(false);
|
||||
this.txtEditor.setFont(new Font("Courier New", Font.PLAIN, 13));
|
||||
this.scrollCode = new JScrollPane(txtEditor,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
this.scrollCode.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
||||
|
||||
this.tabEditors = new JTabbedPane();
|
||||
this.tabEditors.addTab("Case Editor", ImageFactory.getSingleton().TEXTFILE16, this.paneEditor.getView());
|
||||
this.tabEditors.addTab("Script Source", ImageFactory.getSingleton().WINDOW16, this.scrollCode);
|
||||
|
||||
this.listRules = new RuleListController();
|
||||
|
||||
this.splitListClient = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT,
|
||||
this.listRules.getView(), this.tabEditors);
|
||||
this.splitListClient.setResizeWeight(0.4);
|
||||
this.splitListClient.setBorder(BorderFactory.createEmptyBorder());
|
||||
|
||||
|
||||
|
||||
this.getContentPane().add(this.toolbar, BorderLayout.NORTH);
|
||||
this.getContentPane().add(this.splitListClient, BorderLayout.CENTER);
|
||||
this.getContentPane().add(this.paneStatus.getView(), BorderLayout.SOUTH);
|
||||
|
||||
// self
|
||||
this.setPreferredSize(new Dimension(900, 500));
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
public interface ITestCaseInput {
|
||||
|
||||
public void setScript(String script);
|
||||
public String getScript();
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.
|
||||
*/
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package org.antlr.gunit.swingui.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public interface ITestCaseOutput {
|
||||
public void setScript(String script);
|
||||
public String getScript() ;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.DefaultListModel;
|
||||
|
||||
/**
|
||||
* ANTLR v3 Rule Information.
|
||||
* @author scai
|
||||
*/
|
||||
public class Rule extends DefaultListModel {
|
||||
|
||||
private String name;
|
||||
|
||||
public Rule(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
|
||||
public boolean getNotEmpty() {
|
||||
return !this.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void addTestCase(TestCase newItem) {
|
||||
this.addElement(newItem);
|
||||
}
|
||||
|
||||
// for string template
|
||||
public List<TestCase> getTestCases() {
|
||||
List<TestCase> result = new ArrayList<TestCase>();
|
||||
for(int i=0; i<this.size(); i++) {
|
||||
result.add((TestCase)this.getElementAt(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
public class TestCase {
|
||||
|
||||
private ITestCaseInput input;
|
||||
private ITestCaseOutput output;
|
||||
private boolean pass;
|
||||
|
||||
public boolean isPass() {
|
||||
return pass;
|
||||
}
|
||||
|
||||
public void setPass(boolean value) {
|
||||
pass = value;
|
||||
}
|
||||
|
||||
public ITestCaseInput getInput() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
public ITestCaseOutput getOutput() {
|
||||
return this.output;
|
||||
}
|
||||
|
||||
public TestCase(ITestCaseInput input, ITestCaseOutput output) {
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s]->[%s]", input.getScript(), output.getScript());
|
||||
}
|
||||
|
||||
public void setInput(ITestCaseInput in) {
|
||||
this.input = in;
|
||||
}
|
||||
|
||||
public void setOutput(ITestCaseOutput out) {
|
||||
this.output = out;
|
||||
}
|
||||
|
||||
public static String convertPreservedChars(String input) {
|
||||
//return input.replace("\"", "\\\"");
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class TestCaseInputFile implements ITestCaseInput {
|
||||
|
||||
private String fileName;
|
||||
|
||||
public TestCaseInputFile(String file) {
|
||||
this.fileName = file;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return "FILE:" + fileName;
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
this.fileName = script;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return this.fileName;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class TestCaseInputMultiString implements ITestCaseInput {
|
||||
|
||||
private String script;
|
||||
|
||||
public TestCaseInputMultiString(String text) {
|
||||
this.script = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<<" + TestCase.convertPreservedChars(script) + ">>";
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return this.script;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class TestCaseInputString implements ITestCaseInput {
|
||||
|
||||
private String script;
|
||||
|
||||
public TestCaseInputString(String text) {
|
||||
this.script = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return '"' + TestCase.convertPreservedChars(script) + '"';
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setScript(String script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return this.script;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class TestCaseOutputAST implements ITestCaseOutput {
|
||||
|
||||
private String treeString;
|
||||
|
||||
public TestCaseOutputAST(String script) {
|
||||
this.treeString = script;
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
this.treeString = script;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return this.treeString;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(" -> %s", treeString);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class TestCaseOutputResult implements ITestCaseOutput {
|
||||
|
||||
public static String OK = "OK";
|
||||
public static String FAIL = "FAIL";
|
||||
|
||||
private boolean success ;
|
||||
|
||||
public TestCaseOutputResult(boolean result) {
|
||||
this.success = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getScript();
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return success ? OK : FAIL;
|
||||
}
|
||||
|
||||
public void setScript(boolean value) {
|
||||
this.success = value;
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
success = Boolean.parseBoolean(script);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
public class TestCaseOutputReturn implements ITestCaseOutput {
|
||||
private String script;
|
||||
|
||||
public TestCaseOutputReturn(String text) {
|
||||
this.script = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(" returns [%s]", script);
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return this.script;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author scai
|
||||
*/
|
||||
public class TestCaseOutputStdOut implements ITestCaseOutput {
|
||||
private String script;
|
||||
|
||||
public TestCaseOutputStdOut(String text) {
|
||||
this.script = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(" -> \"%s\"", script);
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return this.script;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.antlr.runtime.*;
|
||||
|
||||
public class TestSuite {
|
||||
|
||||
protected List<Rule> rules ;
|
||||
protected String grammarName ;
|
||||
protected CommonTokenStream tokens;
|
||||
protected File testSuiteFile;
|
||||
|
||||
protected TestSuite(String gname, File testFile) {
|
||||
grammarName = gname;
|
||||
testSuiteFile = testFile;
|
||||
rules = new ArrayList<Rule>();
|
||||
}
|
||||
|
||||
/* Get the gUnit test suite file name. */
|
||||
public File getTestSuiteFile() {
|
||||
return testSuiteFile;
|
||||
}
|
||||
|
||||
public void addRule(Rule currentRule) {
|
||||
if(currentRule == null) throw new IllegalArgumentException("Null rule");
|
||||
rules.add(currentRule);
|
||||
}
|
||||
|
||||
// test rule name
|
||||
public boolean hasRule(Rule rule) {
|
||||
for(Rule r: rules) {
|
||||
if(r.getName().equals(rule.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getRuleCount() {
|
||||
return rules.size();
|
||||
}
|
||||
|
||||
public void setRules(List<Rule> newRules) {
|
||||
rules.clear();
|
||||
rules.addAll(newRules);
|
||||
}
|
||||
|
||||
/* GETTERS AND SETTERS */
|
||||
|
||||
public void setGrammarName(String name) { grammarName = name;}
|
||||
|
||||
public String getGrammarName() { return grammarName; }
|
||||
|
||||
public Rule getRule(int index) { return rules.get(index); }
|
||||
|
||||
public CommonTokenStream getTokens() { return tokens; }
|
||||
|
||||
public void setTokens(CommonTokenStream ts) { tokens = ts; }
|
||||
|
||||
public Rule getRule(String name) {
|
||||
for(Rule rule: rules) {
|
||||
if(rule.getName().equals(name)) {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// only for stringtemplate use
|
||||
public List<Rule> getRulesForStringTemplate() {return rules;}
|
||||
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.model;
|
||||
|
||||
import org.antlr.gunit.swingui.parsers.ANTLRv3Lexer;
|
||||
import org.antlr.gunit.swingui.parsers.ANTLRv3Parser;
|
||||
import org.antlr.gunit.swingui.parsers.StGUnitLexer;
|
||||
import org.antlr.gunit.swingui.parsers.StGUnitParser;
|
||||
import org.antlr.gunit.swingui.runner.TestSuiteAdapter;
|
||||
import org.antlr.runtime.ANTLRReaderStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TestSuiteFactory {
|
||||
|
||||
private static String TEMPLATE_FILE = "org/antlr/gunit/swingui/gunit.stg";
|
||||
private static StringTemplateGroup templates;
|
||||
public static final String TEST_SUITE_EXT = ".gunit";
|
||||
public static final String GRAMMAR_EXT = ".g";
|
||||
|
||||
static {
|
||||
ClassLoader loader = TestSuiteFactory.class.getClassLoader();
|
||||
InputStream in = loader.getResourceAsStream(TEMPLATE_FILE);
|
||||
if ( in == null ) {
|
||||
throw new RuntimeException("internal error: Can't find templates "+TEMPLATE_FILE);
|
||||
}
|
||||
Reader rd = new InputStreamReader(in);
|
||||
templates = new StringTemplateGroup(rd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method: create a testsuite from ANTLR grammar. Save the test
|
||||
* suite file in the same directory of the grammar file.
|
||||
* @param grammarFile ANTLRv3 grammar file.
|
||||
* @return test suite object
|
||||
*/
|
||||
public static TestSuite createTestSuite(File grammarFile) {
|
||||
if(grammarFile != null && grammarFile.exists() && grammarFile.isFile()) {
|
||||
|
||||
final String fileName = grammarFile.getName();
|
||||
final String grammarName = fileName.substring(0, fileName.lastIndexOf('.'));
|
||||
final String grammarDir = grammarFile.getParent();
|
||||
final File testFile = new File(grammarDir + File.separator + grammarName + TEST_SUITE_EXT);
|
||||
|
||||
final TestSuite result = new TestSuite(grammarName, testFile);
|
||||
result.rules = loadRulesFromGrammar(grammarFile);
|
||||
|
||||
if(saveTestSuite(result)) {
|
||||
return result;
|
||||
} else {
|
||||
throw new RuntimeException("Can't save test suite file.");
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Invalid grammar file.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Load rules from an ANTLR grammar file. */
|
||||
private static List<Rule> loadRulesFromGrammar(File grammarFile) {
|
||||
|
||||
// get all the rule names
|
||||
final List<String> ruleNames = new ArrayList<String>();
|
||||
try {
|
||||
final Reader reader = new BufferedReader(new FileReader(grammarFile));
|
||||
final ANTLRv3Lexer lexer = new ANTLRv3Lexer(new ANTLRReaderStream(reader));
|
||||
final CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
final ANTLRv3Parser parser = new ANTLRv3Parser(tokens);
|
||||
parser.rules = ruleNames;
|
||||
parser.grammarDef();
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// convert to rule object
|
||||
final List<Rule> ruleList = new ArrayList<Rule>();
|
||||
for(String str: ruleNames) {
|
||||
ruleList.add(new Rule(str));
|
||||
}
|
||||
|
||||
return ruleList;
|
||||
}
|
||||
|
||||
/* Save testsuite to *.gunit file. */
|
||||
public static boolean saveTestSuite(TestSuite testSuite) {
|
||||
final String data = getScript(testSuite);
|
||||
try {
|
||||
FileWriter fw = new FileWriter(testSuite.getTestSuiteFile());
|
||||
fw.write(data);
|
||||
fw.flush();
|
||||
fw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text script from the testSuite.
|
||||
* @param testSuite
|
||||
* @return test script
|
||||
*/
|
||||
public static String getScript(TestSuite testSuite) {
|
||||
if(testSuite == null) return null;
|
||||
StringTemplate gUnitScript = templates.getInstanceOf("gUnitFile");
|
||||
gUnitScript.setAttribute("testSuite", testSuite);
|
||||
|
||||
return gUnitScript.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* From textual script to program model.
|
||||
* @param file testsuite file (.gunit)
|
||||
* @return test suite object
|
||||
*/
|
||||
public static TestSuite loadTestSuite(File file) {
|
||||
if ( file.getName().endsWith(GRAMMAR_EXT) ) {
|
||||
throw new RuntimeException(file.getName()+" is a grammar file not a gunit file");
|
||||
}
|
||||
// check grammar file
|
||||
final File grammarFile = getGrammarFile(file);
|
||||
if(grammarFile == null)
|
||||
throw new RuntimeException("Can't find grammar file associated with gunit file: "+file.getAbsoluteFile());
|
||||
|
||||
TestSuite result = new TestSuite("", file);
|
||||
|
||||
// read in test suite
|
||||
try {
|
||||
final Reader reader = new BufferedReader(new FileReader(file));
|
||||
final StGUnitLexer lexer = new StGUnitLexer(new ANTLRReaderStream(reader));
|
||||
final CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
final StGUnitParser parser = new StGUnitParser(tokens);
|
||||
final TestSuiteAdapter adapter = new TestSuiteAdapter(result);
|
||||
parser.adapter = adapter;
|
||||
parser.gUnitDef();
|
||||
result.setTokens(tokens);
|
||||
reader.close();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Error reading test suite file.\n" + ex.getMessage());
|
||||
}
|
||||
|
||||
// load un-tested rules from grammar
|
||||
final List<Rule> completeRuleList = loadRulesFromGrammar(grammarFile);
|
||||
for(Rule rule: completeRuleList) {
|
||||
if(!result.hasRule(rule)) {
|
||||
result.addRule(rule);
|
||||
//System.out.println("Add rule:" + rule);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grammar file of the testsuite file in the same directory.
|
||||
* @param testsuiteFile
|
||||
* @return grammar file or null
|
||||
*/
|
||||
private static File getGrammarFile(File testsuiteFile) {
|
||||
String sTestFile;
|
||||
try {
|
||||
sTestFile = testsuiteFile.getCanonicalPath();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
// Try Foo.g from Foo.gunit
|
||||
String fname =
|
||||
sTestFile.substring(0, sTestFile.lastIndexOf('.')) + GRAMMAR_EXT;
|
||||
File fileGrammar = new File(fname);
|
||||
if(fileGrammar.exists() && fileGrammar.isFile()) return fileGrammar;
|
||||
// Try FooParser.g from Foo.gunit
|
||||
fname = sTestFile.substring(0, sTestFile.lastIndexOf('.'))+"Parser"+GRAMMAR_EXT;
|
||||
if(fileGrammar.exists() && fileGrammar.isFile()) return fileGrammar;
|
||||
return fileGrammar;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.runner;
|
||||
|
||||
import org.antlr.gunit.*;
|
||||
import org.antlr.gunit.swingui.model.*;
|
||||
|
||||
/**
|
||||
* The gUnit test executer that will respond to the fail/pass event during the
|
||||
* execution. The executer is passed into gUnit Interp for execution.
|
||||
* @author scai
|
||||
*/
|
||||
public class NotifiedTestExecuter extends gUnitExecutor {
|
||||
|
||||
private TestSuite testSuite ;
|
||||
|
||||
public NotifiedTestExecuter(GrammarInfo grammarInfo, ClassLoader loader, String testsuiteDir, TestSuite suite) {
|
||||
super(grammarInfo, loader, testsuiteDir);
|
||||
|
||||
testSuite = suite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(ITestCase failTest) {
|
||||
if(failTest == null) throw new IllegalArgumentException("Null fail test");
|
||||
|
||||
final String ruleName = failTest.getTestedRuleName();
|
||||
if(ruleName == null) throw new NullPointerException("Null rule name");
|
||||
|
||||
final Rule rule = testSuite.getRule(ruleName);
|
||||
final TestCase failCase = (TestCase) rule.getElementAt(failTest.getTestCaseIndex());
|
||||
failCase.setPass(false);
|
||||
//System.out.println(String.format("[FAIL] %s (%d) ", failTest.getTestedRuleName(), failTest.getTestCaseIndex()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPass(ITestCase passTest) {
|
||||
if(passTest == null) throw new IllegalArgumentException("Null pass test");
|
||||
|
||||
final String ruleName = passTest.getTestedRuleName();
|
||||
if(ruleName == null) throw new NullPointerException("Null rule name");
|
||||
|
||||
final Rule rule = testSuite.getRule(ruleName);
|
||||
final TestCase passCase = (TestCase) rule.getElementAt(passTest.getTestCaseIndex());
|
||||
passCase.setPass(true);
|
||||
//System.out.println(String.format("[PASS] %s (%d) ", passTest.getTestedRuleName(), passTest.getTestCaseIndex()));
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.runner;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Class loader for parser & lexer generated by antlr.
|
||||
* @author Shaoting
|
||||
*/
|
||||
public class ParserLoader extends ClassLoader {
|
||||
|
||||
private HashMap<String, Class<?>> classList;
|
||||
private String grammar;
|
||||
|
||||
/**
|
||||
* Create a class loader for antlr parser/lexer.
|
||||
* @param grammarName
|
||||
* @param classDir
|
||||
*/
|
||||
public ParserLoader(String grammarName, String classDir) throws IOException, ClassNotFoundException {
|
||||
|
||||
final String lexerName = grammarName + "Lexer";
|
||||
|
||||
// load all the class files in the "classDir" related to the grammarName
|
||||
File dir = new File(classDir);
|
||||
if(dir.isDirectory()) {
|
||||
classList = new HashMap<String, Class<?>>();
|
||||
grammar = grammarName;
|
||||
File[] files = dir.listFiles(new ClassFilenameFilter(grammarName));
|
||||
for(File f : files) {
|
||||
|
||||
// load class data
|
||||
final InputStream in = new BufferedInputStream(new FileInputStream(f));
|
||||
final byte[] classData = new byte[in.available()];
|
||||
in.read(classData);
|
||||
in.close();
|
||||
|
||||
// define class
|
||||
final Class<?> newClass = defineClass(null, classData, 0, classData.length);
|
||||
assert(newClass != null);
|
||||
resolveClass(newClass);
|
||||
|
||||
// save to hashtable
|
||||
final String fileName = f.getName();
|
||||
final String className = fileName.substring(0, fileName.lastIndexOf("."));
|
||||
classList.put(className, newClass);
|
||||
//System.out.println("adding: " + className);
|
||||
}
|
||||
} else {
|
||||
throw new IOException(classDir + " is not a directory.");
|
||||
}
|
||||
|
||||
if(classList.isEmpty() || !classList.containsKey(lexerName)) {
|
||||
throw new ClassNotFoundException(lexerName + " not found.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
//System.out.print("loading: " + name);
|
||||
if(name.startsWith(grammar)) {
|
||||
if(classList.containsKey(name)) {
|
||||
//System.out.println(" .... found");
|
||||
return classList.get(name);
|
||||
} else {
|
||||
//System.out.println(" .... not found");
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
|
||||
} else {
|
||||
final Class<?> c = findSystemClass(name);
|
||||
//System.out.println(" .... system found " + c.getName());
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts grammarname...($...)?.class
|
||||
*/
|
||||
protected static class ClassFilenameFilter implements FilenameFilter {
|
||||
|
||||
private String grammarName;
|
||||
|
||||
protected ClassFilenameFilter(String name) {
|
||||
grammarName = name;
|
||||
}
|
||||
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.startsWith(grammarName) && name.endsWith(".class");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.runner;
|
||||
|
||||
import org.antlr.gunit.swingui.model.*;
|
||||
|
||||
/**
|
||||
* Adapter class for gunit parser to save information into testsuite object.
|
||||
* @author Shaoting
|
||||
*/
|
||||
public class TestSuiteAdapter {
|
||||
|
||||
private TestSuite model ;
|
||||
private Rule currentRule;
|
||||
|
||||
public TestSuiteAdapter(TestSuite testSuite) {
|
||||
model = testSuite;
|
||||
}
|
||||
|
||||
public void setGrammarName(String name) {
|
||||
model.setGrammarName(name);
|
||||
}
|
||||
|
||||
public void startRule(String name) {
|
||||
currentRule = new Rule(name);
|
||||
}
|
||||
|
||||
public void endRule() {
|
||||
model.addRule(currentRule);
|
||||
currentRule = null;
|
||||
}
|
||||
|
||||
public void addTestCase(ITestCaseInput in, ITestCaseOutput out) {
|
||||
TestCase testCase = new TestCase(in, out);
|
||||
currentRule.addTestCase(testCase);
|
||||
}
|
||||
|
||||
private static String trimChars(String text, int numOfChars) {
|
||||
return text.substring(numOfChars, text.length() - numOfChars);
|
||||
}
|
||||
|
||||
public static ITestCaseInput createFileInput(String fileName) {
|
||||
if(fileName == null) throw new IllegalArgumentException("null");
|
||||
return new TestCaseInputFile(fileName);
|
||||
}
|
||||
|
||||
public static ITestCaseInput createStringInput(String line) {
|
||||
if(line == null) throw new IllegalArgumentException("null");
|
||||
// trim double quotes
|
||||
return new TestCaseInputString(trimChars(line, 1));
|
||||
}
|
||||
|
||||
public static ITestCaseInput createMultiInput(String text) {
|
||||
if(text == null) throw new IllegalArgumentException("null");
|
||||
// trim << and >>
|
||||
return new TestCaseInputMultiString(trimChars(text, 2));
|
||||
}
|
||||
|
||||
public static ITestCaseOutput createBoolOutput(boolean bool) {
|
||||
return new TestCaseOutputResult(bool);
|
||||
}
|
||||
|
||||
public static ITestCaseOutput createAstOutput(String ast) {
|
||||
if(ast == null) throw new IllegalArgumentException("null");
|
||||
return new TestCaseOutputAST(ast);
|
||||
}
|
||||
|
||||
public static ITestCaseOutput createStdOutput(String text) {
|
||||
if(text == null) throw new IllegalArgumentException("null");
|
||||
// trim double quotes
|
||||
return new TestCaseOutputStdOut(trimChars(text, 1));
|
||||
}
|
||||
|
||||
public static ITestCaseOutput createReturnOutput(String text) {
|
||||
if(text == null) throw new IllegalArgumentException("null");
|
||||
// trim square brackets
|
||||
return new TestCaseOutputReturn(trimChars(text, 1));
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2009 Shaoting Cai
|
||||
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.gunit.swingui.runner;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.gunit.*;
|
||||
import org.antlr.gunit.swingui.model.TestSuite;
|
||||
|
||||
/**
|
||||
* Adapter between gUnitEditor Swing GUI and gUnit command-line tool.
|
||||
* @author scai
|
||||
*/
|
||||
public class gUnitAdapter {
|
||||
|
||||
private ParserLoader loader ;
|
||||
private TestSuite testSuite;
|
||||
|
||||
public gUnitAdapter(TestSuite suite) throws IOException, ClassNotFoundException {
|
||||
int i = 3;
|
||||
loader = new ParserLoader(suite.getGrammarName(),
|
||||
suite.getTestSuiteFile().getParent());
|
||||
testSuite = suite;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (testSuite == null)
|
||||
throw new IllegalArgumentException("Null testsuite.");
|
||||
|
||||
|
||||
try {
|
||||
|
||||
// Parse gUnit test suite file
|
||||
final CharStream input = new ANTLRFileStream(testSuite.getTestSuiteFile().getCanonicalPath());
|
||||
final gUnitLexer lexer = new gUnitLexer(input);
|
||||
final CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
final GrammarInfo grammarInfo = new GrammarInfo();
|
||||
final gUnitParser parser = new gUnitParser(tokens, grammarInfo);
|
||||
parser.gUnitDef(); // parse gunit script and save elements to grammarInfo
|
||||
|
||||
// Execute test suite
|
||||
final gUnitExecutor executer = new NotifiedTestExecuter(
|
||||
grammarInfo, loader,
|
||||
testSuite.getTestSuiteFile().getParent(), testSuite);
|
||||
executer.execTest();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon, Jen-Yuan Su
|
||||
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.
|
||||
*/
|
||||
group gUnitTestResult;
|
||||
|
||||
testResult(title, num_of_test, num_of_failure, failure, has_invalid, num_of_invalid, invalid) ::= <<
|
||||
-----------------------------------------------------------------------
|
||||
<title> with <num_of_test> tests
|
||||
-----------------------------------------------------------------------
|
||||
<num_of_failure> failures found:
|
||||
<failure:{<it.header>
|
||||
expected: <it.expectedResult>
|
||||
actual: <it.actualResult>
|
||||
|
||||
}>
|
||||
<if(has_invalid)>
|
||||
<num_of_invalid> invalid inputs found:
|
||||
<invalid:{<it.header>
|
||||
invalid input: <it.actual>
|
||||
}>
|
||||
<endif>
|
||||
|
||||
Tests run: <num_of_test>, Failures: <num_of_failure>
|
||||
|
||||
>>
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2007-2008 Leon, Jen-Yuan Su
|
||||
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.
|
||||
*/
|
||||
group junit;
|
||||
|
||||
classHeader(header,junitFileName,hasTreeAdaptor,treeAdaptorPath,
|
||||
hasPackage,packagePath,lexerPath,parserPath,treeParserPath,isTreeGrammar) ::= <<
|
||||
<header>
|
||||
|
||||
import org.antlr.gunit.gUnitBaseTest;
|
||||
|
||||
public class <junitFileName> extends gUnitBaseTest {
|
||||
|
||||
public void setUp() {
|
||||
<if(hasTreeAdaptor)><\t><\t>this.treeAdaptorPath = "<treeAdaptorPath>";<endif>
|
||||
<if(hasPackage)><\t><\t>this.packagePath = "<packagePath>";<endif>
|
||||
this.lexerPath = "<lexerPath>";
|
||||
this.parserPath = "<parserPath>";
|
||||
<if(isTreeGrammar)><\t><\t>this.treeParserPath = "<treeParserPath>";<endif>
|
||||
}<\n><\n>
|
||||
>>
|
||||
|
||||
testTreeRuleMethod(methodName,testTreeRuleName,testRuleName,test,tokenType,expecting) ::= <<
|
||||
public void <methodName>() throws Exception {
|
||||
// gunit test on line <test.line>
|
||||
Object retval = execTreeParser(<testTreeRuleName>, <testRuleName>, "<test.inputEscaped>", <test.isFile>);
|
||||
Object actual = examineExecResult(<tokenType>, retval);
|
||||
Object expecting = <expecting>;
|
||||
|
||||
assertEquals("testing rule "+<testTreeRuleName>, expecting, actual);
|
||||
}<\n><\n>
|
||||
>>
|
||||
|
||||
testTreeRuleMethod2(methodName,testTreeRuleName,testRuleName,test,returnType,expecting) ::= <<
|
||||
public void <methodName>() throws Exception {
|
||||
// gunit test on line <test.line>
|
||||
<returnType> retval = (<returnType>)execTreeParser(<testTreeRuleName>, <testRuleName>, "<test.inputEscaped>", <test.isFile>);
|
||||
|
||||
assertTrue("testing rule "+<testTreeRuleName>, <expecting>);
|
||||
}<\n><\n>
|
||||
>>
|
||||
|
||||
testRuleMethod(isLexicalRule,methodName,testRuleName,test,tokenType,expecting) ::= <<
|
||||
public void <methodName>() throws Exception {
|
||||
// gunit test on line <test.line>
|
||||
Object retval = <if(isLexicalRule)>execLexer<else>execParser<endif>(<testRuleName>, <test.line>, "<test.inputEscaped>", <test.isFile>);
|
||||
Object actual = examineExecResult(<tokenType>, retval);
|
||||
Object expecting = <expecting>;
|
||||
|
||||
assertEquals("testing rule "+<testRuleName>, expecting, actual);
|
||||
}<\n><\n>
|
||||
>>
|
||||
|
||||
testRuleMethod2(methodName,testRuleName,test,returnType,expecting) ::= <<
|
||||
public void <methodName>() throws Exception {
|
||||
// gunit test on line <test.line>
|
||||
<returnType> retval = (<returnType>)execParser(<testRuleName>, <test.line>, "<test.inputEscaped>", <test.isFile>);
|
||||
|
||||
assertTrue("testing rule "+<testRuleName>, <expecting>);
|
||||
}<\n><\n>
|
||||
>>
|
@ -0,0 +1,19 @@
|
||||
group gunit;
|
||||
|
||||
gUnitFile(testSuite) ::= <<gunit <testSuite.grammarName>;
|
||||
|
||||
<testSuite.rulesForStringTemplate:testGroup()>
|
||||
>>
|
||||
|
||||
testGroup() ::= <<
|
||||
<if(it.notEmpty)>
|
||||
|
||||
//------------------- <it.name>
|
||||
<it.name>:
|
||||
|
||||
<it.testCases: testCase(); separator="\n\n">
|
||||
|
||||
<endif>
|
||||
>>
|
||||
|
||||
testCase() ::= "<it.input> <it.output>"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user