View Javadoc

1   package org.codehaus.mojo.javacc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file 
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing, 
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
17   * KIND, either express or implied.  See the License for the 
18   * specific language governing permissions and limitations 
19   * under the License.
20   */
21  
22  import java.io.File;
23  
24  import org.apache.maven.plugin.MojoExecutionException;
25  import org.apache.maven.plugin.MojoFailureException;
26  
27  /**
28   * Preprocesses ordinary grammar files (<code>*.jtb</code>) with JTB and passes the output to JavaCC in order to
29   * finally generate a parser with parse tree actions.<br/><br/><strong>Note:</strong> <a
30   * href="http://compilers.cs.ucla.edu/jtb/">JTB</a> requires Java 1.5 or higher. This goal will not work with earlier
31   * versions of the JRE.
32   * 
33   * @goal jtb-javacc
34   * @phase generate-sources
35   * @since 2.4
36   * @author Benjamin Bentmann
37   * @version $Id: JTBJavaCCMojo.java 8156 2008-11-26 18:20:19Z bentmann $
38   */
39  public class JTBJavaCCMojo
40      extends AbstractJavaCCMojo
41  {
42  
43      /**
44       * This option is short for <code>nodePackageName</code> = <code>&lt;packageName&gt;.syntaxtree</code> and
45       * <code>visitorPackageName</code> = <code>&lt;packageName&gt;.visitor</code>. Note that this option takes
46       * precedence over <code>nodePackageName</code> and <code>visitorPackageName</code> if specified.
47       * 
48       * @parameter expression="${package}"
49       */
50      private String packageName;
51  
52      /**
53       * This option specifies the package for the generated AST nodes. This value may use a leading asterisk to reference
54       * the package of the corresponding parser. For example, if the parser package is <code>org.apache</code> and this
55       * parameter is set to <code>*.demo</code>, the tree node classes will be located in the package
56       * <code>org.apache.demo</code>. Default value is <code>*.syntaxtree</code>.
57       * 
58       * @parameter expression="${nodePackageName}"
59       */
60      private String nodePackageName;
61  
62      /**
63       * This option specifies the package for the generated visitors. This value may use a leading asterisk to reference
64       * the package of the corresponding parser. For example, if the parser package is <code>org.apache</code> and this
65       * parameter is set to <code>*.demo</code>, the visitor classes will be located in the package
66       * <code>org.apache.demo</code>. Default value is <code>*.visitor</code>.
67       * 
68       * @parameter expression="${visitorPackageName}"
69       */
70      private String visitorPackageName;
71  
72      /**
73       * If <code>true</code>, JTB will suppress its semantic error checking. Default value is <code>false</code>.
74       * 
75       * @parameter expression="${supressErrorChecking}"
76       */
77      private Boolean supressErrorChecking;
78  
79      /**
80       * If <code>true</code>, all generated comments will be wrapped in <code>&lt;pre&gt;</code> tags so that they
81       * are formatted correctly in API docs. Default value is <code>false</code>.
82       * 
83       * @parameter expression="${javadocFriendlyComments}"
84       */
85      private Boolean javadocFriendlyComments;
86  
87      /**
88       * Setting this option to <code>true</code> causes JTB to generate field names that reflect the structure of the
89       * tree instead of generic names like <code>f0</code>, <code>f1</code> etc. Default value is <code>false</code>.
90       * 
91       * @parameter expression="${descriptiveFieldNames}"
92       */
93      private Boolean descriptiveFieldNames;
94  
95      /**
96       * The qualified name of a user-defined class from which all AST nodes will inherit. By default, AST nodes will
97       * inherit from the generated class <code>Node</code>.
98       * 
99       * @parameter expression="${nodeParentClass}"
100      */
101     private String nodeParentClass;
102 
103     /**
104      * If <code>true</code>, all nodes will contain fields for its parent node. Default value is <code>false</code>.
105      * 
106      * @parameter expression="${parentPointers}"
107      */
108     private Boolean parentPointers;
109 
110     /**
111      * If <code>true</code>, JTB will include JavaCC "special tokens" in the AST. Default value is <code>false</code>.
112      * 
113      * @parameter expression="${specialTokens}"
114      */
115     private Boolean specialTokens;
116 
117     /**
118      * If <code>true</code>, JTB will generate the following files to support the Schema programming language:
119      * <ul>
120      * <li>Scheme records representing the grammar.</li>
121      * <li>A Scheme tree building visitor.</li>
122      * </ul>
123      * Default value is <code>false</code>.
124      * 
125      * @parameter expression="${scheme}"
126      */
127     private Boolean scheme;
128 
129     /**
130      * If <code>true</code>, JTB will generate a syntax tree dumping visitor. Default value is <code>false</code>.
131      * 
132      * @parameter expression="${printer}"
133      */
134     private Boolean printer;
135 
136     /**
137      * The directory where the JavaCC grammar files (<code>*.jtb</code>) are located. It will be recursively scanned
138      * for input files to pass to JTB. The parameters <code>includes</code> and <code>excludes</code> can be used to
139      * select a subset of files.
140      * 
141      * @parameter expression="${sourceDirectory}" default-value="${basedir}/src/main/jtb"
142      */
143     private File sourceDirectory;
144 
145     /**
146      * The directory where the visitor and AST node files generated by JTB will be stored. The directory will be
147      * registered as a compile source root of the project such that the generated files will participate in later build
148      * phases like compiling and packaging.
149      * 
150      * @parameter expression="${interimDirectory}" default-value="${project.build.directory}/generated-sources/jtb"
151      */
152     private File interimDirectory;
153 
154     /**
155      * The directory where the parser files generated by JavaCC will be stored. The directory will be registered as a
156      * compile source root of the project such that the generated files will participate in later build phases like
157      * compiling and packaging.
158      * 
159      * @parameter expression="${outputDirectory}" default-value="${project.build.directory}/generated-sources/javacc"
160      */
161     private File outputDirectory;
162 
163     /**
164      * A set of Ant-like inclusion patterns used to select files from the source directory for processing. By default,
165      * the patterns <code>**&#47;*.jj</code>, <code>**&#47;*.JJ</code>, <code>**&#47;*.jtb</code> and
166      * <code>**&#47;*.JTB</code> are used to select grammar files.
167      * 
168      * @parameter
169      */
170     private String[] includes;
171 
172     /**
173      * A set of Ant-like exclusion patterns used to prevent certain files from being processing. By default, this set is
174      * empty such that no files are excluded.
175      * 
176      * @parameter
177      */
178     private String[] excludes;
179 
180     /**
181      * The granularity in milliseconds of the last modification date for testing whether a grammar file needs
182      * recompilation.
183      * 
184      * @parameter expression="${lastModGranularityMs}" default-value="0"
185      */
186     private int staleMillis;
187 
188     /**
189      * {@inheritDoc}
190      */
191     protected File getSourceDirectory()
192     {
193         return this.sourceDirectory;
194     }
195 
196     /**
197      * {@inheritDoc}
198      */
199     protected String[] getIncludes()
200     {
201         if ( this.includes != null )
202         {
203             return this.includes;
204         }
205         else
206         {
207             return new String[] { "**/*.jj", "**/*.JJ", "**/*.jtb", "**/*.JTB" };
208         }
209     }
210 
211     /**
212      * {@inheritDoc}
213      */
214     protected String[] getExcludes()
215     {
216         return this.excludes;
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     protected File getOutputDirectory()
223     {
224         return this.outputDirectory;
225     }
226 
227     /**
228      * {@inheritDoc}
229      */
230     protected int getStaleMillis()
231     {
232         return this.staleMillis;
233     }
234 
235     /**
236      * Gets the absolute path to the directory where the interim output from JTB will be stored.
237      * 
238      * @return The absolute path to the directory where the interim output from JTB will be stored.
239      */
240     private File getInterimDirectory()
241     {
242         return this.interimDirectory;
243     }
244 
245     /**
246      * {@inheritDoc}
247      */
248     protected File[] getCompileSourceRoots()
249     {
250         return new File[] { getOutputDirectory(), getInterimDirectory() };
251     }
252 
253     /**
254      * {@inheritDoc}
255      */
256     protected void processGrammar( GrammarInfo grammarInfo )
257         throws MojoExecutionException, MojoFailureException
258     {
259         File jtbFile = grammarInfo.getGrammarFile();
260         File jtbDirectory = jtbFile.getParentFile();
261 
262         File tempDirectory = getTempDirectory();
263 
264         // setup output directory of grammar file (*.jj) generated by JTB
265         File jjDirectory = tempDirectory;
266 
267         // setup output directory of tree node files (*.java) generated by JTB
268         String nodePackage = grammarInfo.resolvePackageName( getNodePackageName() );
269         File nodeDirectory = new File( tempDirectory, "node" );
270 
271         // setup output directory of visitor files (*.java) generated by JTB
272         String visitorPackage = grammarInfo.resolvePackageName( getVisitorPackageName() );
273         File visitorDirectory = new File( tempDirectory, "visitor" );
274 
275         // setup output directory of parser file (*.java) generated by JavaCC
276         File parserDirectory = new File( tempDirectory, "parser" );
277 
278         // generate final grammar file and the node/visitor files
279         JTB jtb = newJTB();
280         jtb.setInputFile( jtbFile );
281         jtb.setOutputDirectory( jjDirectory );
282         jtb.setNodeDirectory( nodeDirectory );
283         jtb.setVisitorDirectory( visitorDirectory );
284         jtb.setNodePackageName( nodePackage );
285         jtb.setVisitorPackageName( visitorPackage );
286         jtb.run();
287 
288         // generate parser files
289         JavaCC javacc = newJavaCC();
290         javacc.setInputFile( jtb.getOutputFile() );
291         javacc.setOutputDirectory( parserDirectory );
292         javacc.run();
293 
294         // copy tree node files from JTB
295         copyGrammarOutput( getInterimDirectory(), nodePackage, nodeDirectory, "!Node*" );
296 
297         // copy visitor files from JTB
298         copyGrammarOutput( getInterimDirectory(), visitorPackage, visitorDirectory, "" );
299 
300         // copy parser files from JavaCC
301         copyGrammarOutput( getOutputDirectory(), grammarInfo.getParserPackage(), parserDirectory,
302                            grammarInfo.getParserName() + "*" );
303 
304         // copy source files which are next to grammar unless the grammar resides in an ordinary source root
305         // (legacy support for custom sources)
306         if ( !isSourceRoot( grammarInfo.getSourceDirectory() ) )
307         {
308             copyGrammarOutput( getOutputDirectory(), grammarInfo.getParserPackage(), jtbDirectory, "*" );
309         }
310 
311         deleteTempDirectory( tempDirectory );
312     }
313 
314     /**
315      * Gets the effective package name for the AST node files.
316      * 
317      * @return The effective package name for the AST node files, never <code>null</code>.
318      */
319     private String getNodePackageName()
320     {
321         if ( this.packageName != null )
322         {
323             return this.packageName + ".syntaxtree";
324         }
325         else if ( this.nodePackageName != null )
326         {
327             return this.nodePackageName;
328         }
329         else
330         {
331             return "*.syntaxtree";
332         }
333     }
334 
335     /**
336      * Gets the effective package name for the visitor files.
337      * 
338      * @return The effective package name for the visitor files, never <code>null</code>.
339      */
340     private String getVisitorPackageName()
341     {
342         if ( this.packageName != null )
343         {
344             return this.packageName + ".visitor";
345         }
346         else if ( this.visitorPackageName != null )
347         {
348             return this.visitorPackageName;
349         }
350         else
351         {
352             return "*.visitor";
353         }
354     }
355 
356     /**
357      * Creates a new facade to invoke JTB. Most options for the invocation are derived from the current values of the
358      * corresponding mojo parameters. The caller is responsible to set the input file, output directories and packages
359      * on the returned facade.
360      * 
361      * @return The facade for the tool invocation, never <code>null</code>.
362      */
363     private JTB newJTB()
364     {
365         JTB jtb = new JTB();
366         jtb.setLog( getLog() );
367         jtb.setDescriptiveFieldNames( this.descriptiveFieldNames );
368         jtb.setJavadocFriendlyComments( this.javadocFriendlyComments );
369         jtb.setNodeParentClass( this.nodeParentClass );
370         jtb.setParentPointers( this.parentPointers );
371         jtb.setPrinter( this.printer );
372         jtb.setScheme( this.scheme );
373         jtb.setSpecialTokens( this.specialTokens );
374         jtb.setSupressErrorChecking( this.supressErrorChecking );
375         return jtb;
376     }
377 
378 }