Submitted by: Stephen Chin, aphid@versionablestore.com git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272941 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -54,6 +54,71 @@ | |||||
| </td> | </td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">glib</td> | |||||
| <td valign="top"> | |||||
| An optional super grammar file that the target grammar overrides. This | |||||
| feature is only needed for advanced vocabularies. | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">debug</td> | |||||
| <td valign="top"> | |||||
| When set to "yes", this flag adds code to the generated parser that will | |||||
| launch the ParseView debugger upon invocation. The default is "no". | |||||
| <br> | |||||
| Note: ParseView is a separate component that needs to be installed or your | |||||
| grammar will have compilation errors. | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">html</td> | |||||
| <td valign="top"> | |||||
| Emit an html version of the grammar with hyperlinked actions. | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">diagnostic</td> | |||||
| <td valign="top"> | |||||
| Generates a text file with debugging infomation based on the target grammar. | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">trace</td> | |||||
| <td valign="top"> | |||||
| Forces <b>all</b> rules to call traceIn/traceOut if set to "yes". | |||||
| The default is "no". | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">traceParser</td> | |||||
| <td valign="top"> | |||||
| Only forces parser rules to call traceIn/traceOut if set to "yes". | |||||
| The default is "no". | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">traceLexer</td> | |||||
| <td valign="top"> | |||||
| Only forces lexer rules to call traceIn/traceOut if set to "yes". | |||||
| The default is "no". | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">traceTreeWalker</td> | |||||
| <td valign="top"> | |||||
| Only forces tree walker rules to call traceIn/traceOut if set to | |||||
| "yes". The default is "no". | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <!--tr> | <!--tr> | ||||
| <td valign="top">fork</td> | <td valign="top">fork</td> | ||||
| <td valign="top">Run ANTLR in a separate VM.</td> | <td valign="top">Run ANTLR in a separate VM.</td> | ||||
| @@ -40,10 +40,46 @@ | |||||
| <target name="test7"> | <target name="test7"> | ||||
| <antlr target="antlr.xml"/> | <antlr target="antlr.xml"/> | ||||
| </target> | |||||
| </target> | |||||
| <target name="test8"> | |||||
| <antlr target="extended.calc.g" outputdirectory="${tmp.dir}" glib="non-existant-file.g"/> | |||||
| </target> | |||||
| <target name="test9"> | |||||
| <mkdir dir="${tmp.dir}"/> | |||||
| <!-- Note that I had to copy the grammars over to the temporary directory. --> | |||||
| <!-- This is because ANTLR expects the super grammar and its generated java --> | |||||
| <!-- files to be in the same directory, which won't be the case if I use --> | |||||
| <!-- the output directory option. --> | |||||
| <copy file="antlr.g" todir="${tmp.dir}"/> | |||||
| <copy file="extended.calc.g" todir="${tmp.dir}"/> | |||||
| <antlr target="${tmp.dir}/antlr.g"/> | |||||
| <antlr target="${tmp.dir}/extended.calc.g" glib="${tmp.dir}/antlr.g"/> | |||||
| </target> | |||||
| <target name="test10"> | |||||
| <mkdir dir="${tmp.dir}"/> | |||||
| <antlr target="antlr.g" outputdirectory="${tmp.dir}" html="yes"/> | |||||
| </target> | |||||
| <target name="test11"> | |||||
| <mkdir dir="${tmp.dir}"/> | |||||
| <antlr target="antlr.g" outputdirectory="${tmp.dir}" diagnostic="yes"/> | |||||
| </target> | |||||
| <target name="test12"> | |||||
| <mkdir dir="${tmp.dir}"/> | |||||
| <antlr target="antlr.g" outputdirectory="${tmp.dir}" trace="yes"/> | |||||
| </target> | |||||
| <target name="test13"> | |||||
| <mkdir dir="${tmp.dir}"/> | |||||
| <antlr target="antlr.g" outputdirectory="${tmp.dir}" traceLexer="yes" traceParser="yes" traceTreeWalker="yes"/> | |||||
| </target> | |||||
| <target name="cleanup"> | <target name="cleanup"> | ||||
| <delete dir="${tmp.dir}" /> | <delete dir="${tmp.dir}" /> | ||||
| </target> | </target> | ||||
| </project> | |||||
| </project> | |||||
| @@ -0,0 +1,7 @@ | |||||
| // Not really a great extension, but it is only a test after all! | |||||
| class ExtendedCalcParser extends CalcParser; | |||||
| exprList | |||||
| : LPAREN (expr)* RPAREN | |||||
| ; | |||||
| @@ -74,6 +74,7 @@ import org.apache.tools.ant.types.Path; | |||||
| * | * | ||||
| * @author <a href="mailto:emeade@geekfarm.org">Erik Meade</a> | * @author <a href="mailto:emeade@geekfarm.org">Erik Meade</a> | ||||
| * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | ||||
| * @author <a href="mailto:aphid@browsecode.org">Stephen Chin</a> | |||||
| */ | */ | ||||
| public class ANTLR extends Task { | public class ANTLR extends Task { | ||||
| @@ -85,6 +86,30 @@ public class ANTLR extends Task { | |||||
| /** where to output the result */ | /** where to output the result */ | ||||
| private File outputDirectory; | private File outputDirectory; | ||||
| /** an optional super grammar file */ | |||||
| private String superGrammar; | |||||
| /** optional flag to enable parseView debugging */ | |||||
| private boolean debug; | |||||
| /** optional flag to enable html output */ | |||||
| private boolean html; | |||||
| /** optional flag to print out a diagnostic file */ | |||||
| private boolean diagnostic; | |||||
| /** optional flag to add trace 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; | |||||
| /** optional flag to add trace methods to the tree walker only */ | |||||
| private boolean traceTreeWalker; | |||||
| /** should fork ? */ | /** should fork ? */ | ||||
| private final boolean fork = true; | private final boolean fork = true; | ||||
| @@ -106,15 +131,70 @@ public class ANTLR extends Task { | |||||
| this.outputDirectory = outputDirectory; | this.outputDirectory = outputDirectory; | ||||
| } | } | ||||
| /** | |||||
| * Sets an optional super grammar file | |||||
| */ | |||||
| public void setGlib(String superGrammar) { | |||||
| this.superGrammar = superGrammar; | |||||
| } | |||||
| /** | |||||
| * Sets a flag to enable ParseView debugging | |||||
| */ | |||||
| public void setDebug(boolean enable) { | |||||
| debug = enable; | |||||
| } | |||||
| /** | |||||
| * Sets a flag to emit html | |||||
| */ | |||||
| public void setHtml(boolean enable) { | |||||
| html = enable; | |||||
| } | |||||
| /** | |||||
| * Sets a flag to emit diagnostic text | |||||
| */ | |||||
| public void setDiagnostic(boolean enable) { | |||||
| diagnostic = enable; | |||||
| } | |||||
| /** | |||||
| * Sets a flag to enable all tracing | |||||
| */ | |||||
| public void setTrace(boolean enable) { | |||||
| trace = enable; | |||||
| } | |||||
| /** | |||||
| * Sets a flag to enable parser tracing | |||||
| */ | |||||
| public void setTraceParser(boolean enable) { | |||||
| traceParser = enable; | |||||
| } | |||||
| /** | |||||
| * Sets a flag to allow the user to enable lexer tracing | |||||
| */ | |||||
| public void setTraceLexer(boolean enable) { | |||||
| traceLexer = enable; | |||||
| } | |||||
| /** | |||||
| * Sets a flag to allow the user to enable tree walker tracing | |||||
| */ | |||||
| public void setTraceTreeWalker(boolean enable) { | |||||
| traceTreeWalker = enable; | |||||
| } | |||||
| // we are forced to fork ANTLR since there is a call | // we are forced to fork ANTLR since there is a call | ||||
| // to System.exit() and there is nothing we can do | // to System.exit() and there is nothing we can do | ||||
| // right now to avoid this. :-( (SBa) | // right now to avoid this. :-( (SBa) | ||||
| // I'm not removing this method to keep backward compatibility | // I'm not removing this method to keep backward compatibility | ||||
| // and | |||||
| public void setFork(boolean s) { | public void setFork(boolean s) { | ||||
| //this.fork = s; | //this.fork = s; | ||||
| } | } | ||||
| /** | /** | ||||
| * The working directory of the process | * The working directory of the process | ||||
| */ | */ | ||||
| @@ -184,10 +264,9 @@ public class ANTLR extends Task { | |||||
| validateAttributes(); | validateAttributes(); | ||||
| //TODO: use ANTLR to parse the grammer file to do this. | //TODO: use ANTLR to parse the grammer file to do this. | ||||
| if (target.lastModified() > getGeneratedFile().lastModified()) { | if (target.lastModified() > getGeneratedFile().lastModified()) { | ||||
| commandline.createArgument().setValue("-o"); | |||||
| commandline.createArgument().setValue(outputDirectory.toString()); | |||||
| populateAttributes(); | |||||
| commandline.createArgument().setValue(target.toString()); | commandline.createArgument().setValue(target.toString()); | ||||
| log(commandline.describeCommand(), Project.MSG_VERBOSE); | log(commandline.describeCommand(), Project.MSG_VERBOSE); | ||||
| int err = run(commandline.getCommandline()); | int err = run(commandline.getCommandline()); | ||||
| if (err == 1) { | if (err == 1) { | ||||
| @@ -198,11 +277,47 @@ public class ANTLR extends Task { | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * 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()); | |||||
| if (superGrammar != null) { | |||||
| commandline.createArgument().setValue("-glib"); | |||||
| commandline.createArgument().setValue(superGrammar); | |||||
| } | |||||
| if (html) { | |||||
| commandline.createArgument().setValue("-html"); | |||||
| } | |||||
| if (diagnostic) { | |||||
| commandline.createArgument().setValue("-diagnostic"); | |||||
| } | |||||
| if (trace) { | |||||
| commandline.createArgument().setValue("-trace"); | |||||
| } | |||||
| if (traceParser) { | |||||
| commandline.createArgument().setValue("-traceParser"); | |||||
| } | |||||
| if (traceLexer) { | |||||
| commandline.createArgument().setValue("-traceLexer"); | |||||
| } | |||||
| if (traceTreeWalker) { | |||||
| commandline.createArgument().setValue("-traceTreeWalker"); | |||||
| } | |||||
| } | |||||
| private void validateAttributes() throws BuildException { | private void validateAttributes() throws BuildException { | ||||
| if (target == null || !target.isFile()) { | if (target == null || !target.isFile()) { | ||||
| throw new BuildException("Invalid target: " + target); | throw new BuildException("Invalid target: " + target); | ||||
| } | } | ||||
| // validate the superGrammar file | |||||
| if (superGrammar != null && !new File(superGrammar).isFile()) { | |||||
| throw new BuildException("Invalid super grammar file: " + superGrammar); | |||||
| } | |||||
| // if no output directory is specified, used the target's directory | // if no output directory is specified, used the target's directory | ||||
| if (outputDirectory == null) { | if (outputDirectory == null) { | ||||
| String fileName = target.toString(); | String fileName = target.toString(); | ||||
| @@ -68,6 +68,7 @@ import org.apache.tools.ant.BuildFileTest; | |||||
| * system classpath. (see ANTLR install.html) | * system classpath. (see ANTLR install.html) | ||||
| * | * | ||||
| * @author Erik Meade <emeade@geekfarm.org> | * @author Erik Meade <emeade@geekfarm.org> | ||||
| * @author Stephen Chin <aphid@browsecode.org> | |||||
| */ | */ | ||||
| public class ANTLRTest extends BuildFileTest { | public class ANTLRTest extends BuildFileTest { | ||||
| @@ -117,6 +118,57 @@ public class ANTLRTest extends BuildFileTest { | |||||
| public void test7() { | public void test7() { | ||||
| expectBuildException("test7", "Unable to determine generated class"); | expectBuildException("test7", "Unable to determine generated class"); | ||||
| } | } | ||||
| /** | |||||
| * This is a negative test for the super grammar (glib) option. | |||||
| */ | |||||
| public void test8() { | |||||
| expectBuildException("test8", "Invalid super grammar file"); | |||||
| } | |||||
| /** | |||||
| * This is a positive test for the super grammar (glib) option. ANTLR | |||||
| * will throw an error if everything is not correct. | |||||
| */ | |||||
| public void test9() { | |||||
| executeTarget("test9"); | |||||
| } | |||||
| /** | |||||
| * This test creates an html-ized version of the calculator grammar. | |||||
| * The sanity check is simply whether or not an html file was generated. | |||||
| */ | |||||
| public void test10() { | |||||
| executeTarget("test10"); | |||||
| File outputDirectory = new File(TASKDEFS_DIR + "antlr.tmp"); | |||||
| String[] calcFiles = outputDirectory.list(new HTMLFilter()); | |||||
| assertEquals(1, calcFiles.length); | |||||
| } | |||||
| /** | |||||
| * This is just a quick sanity check to run the diagnostic option and | |||||
| * make sure that it doesn't throw any funny exceptions. | |||||
| */ | |||||
| public void test11() { | |||||
| executeTarget("test11"); | |||||
| } | |||||
| /** | |||||
| * This is just a quick sanity check to run the trace option and | |||||
| * make sure that it doesn't throw any funny exceptions. | |||||
| */ | |||||
| public void test12() { | |||||
| executeTarget("test12"); | |||||
| } | |||||
| /** | |||||
| * This is just a quick sanity check to run all the rest of the | |||||
| * trace options (traceLexer, traceParser, and traceTreeWalker) to | |||||
| * make sure that they don't throw any funny exceptions. | |||||
| */ | |||||
| public void test13() { | |||||
| executeTarget("test13"); | |||||
| } | |||||
| } | } | ||||
| class CalcFileFilter implements FilenameFilter { | class CalcFileFilter implements FilenameFilter { | ||||
| @@ -124,3 +176,9 @@ class CalcFileFilter implements FilenameFilter { | |||||
| return name.startsWith("Calc"); | return name.startsWith("Calc"); | ||||
| } | } | ||||
| } | } | ||||
| class HTMLFilter implements FilenameFilter { | |||||
| public boolean accept(File dir, String name) { | |||||
| return name.endsWith("html"); | |||||
| } | |||||
| } | |||||