PJ is a new tool for JTS specifically written to support the GenBorg model. PJ compacts extension chains for classes, interfaces., and state diagrams To call PJ:
> java PJ.Main [-tk] <base-file-name> <extension-file-name>
where:
The Bali command to build PJ is:
> java Bali.Main PJ
The layers that are included in PJ, along with a description of their semantics, is briefly below:
The following topics are covered in this document:
The GenBorg model produces a set of equations that define the extension chains or extension hierarchies of generated files. An equation r = a(b(c)) means compose base class or interface c with extension b, and that with extension a to produce r. PJ flattens this extension chain to produce a single file. If this composition were to be performed via a command-line, you would write:
> java PJ.Main -tk c.java b.java > tmp.java > java PJ.Main -tk tmp.java a.java > result.java
This isn't the preferred way to do this composition, for several reasons. First, PJ annotates parse trees with information that is lost when outputting intermediate results to files. This information isn't critical for running the current stable of regression tests, but will be very important later on. Second, the above runs slowly.
The preferred way is via a programmatic means:
import PJ.*;// Step 1: set the -t and -k flags in PJLang.JTSParseTree.setFlags( true, true ); // set the -t and -k flags in PJ// Step 2: create parse trees for files a, b, and c Lang.JTSParseTree a = new Lang.JTSParseTree( "a.java" ); Lang.JTSParseTree b = new Lang.JTSParseTree( "b.java" ); Lang.JTSParseTree c = new Lang.JTSParseTree( "c.java" );// Step 3: compose the trees, a.compose(b) merges b into a // so a is modifieda.compose(b); a.compose(c);// Step 4: set package name. The produced file will be // in package "foo", and output the file. a.setPackageName("foo"); a.print2file( "abc.java");
The above calling sequence will be used in GUI tools that take GenBorg equations, expand them, and invoke the corresponding extension-hierarchy compaction tools (of which PJ will be the tool for compacting code chains).
Use the following to invoke PJ from the command line:
> java PJ.Main -tk Basefile Extension1file Extension2file ... > output
The option -t selects type sorting, -k selects key sorting. The resulting output (error messages and all) are sent to standard out.
PJ is a package that can be called from another program (i.e., tool) in the following way.
(a) set PJ flags, clear error and warning counters, and specify the destination of error and warning messages:
PJ.JTSParseTree.setFlags( true, true ); PJ.JTSParseTree.resetCounters(); JTSParseTree.setReportStream( new PrintWriter( System.out ) );(b) create a JTSParseTree for each file, such as below:
try { PJ.JTSParseTree base = new PJ.JTSParseTree( "base-file-name" ); PJ.JTSParseTree ext = new PJ.JTSParseTree( "extn-file-name" ); } catch (Exception e) { System.err.println( "can't parse or open base or extension files" + e.getMessage() ); }(c) compose the trees, as below:
try { base.compose( ext ); if (PJ.JTSParseTree.errorCount() == 0) { // composition succeeded } else { // composition failed -- error string appears in reportStream PrintWriter } } catch (Exception e) { System.err.println( e.getMessage() ); // fatal error occurred in composition; something is likely wrong with PJ }note: compose can throw a RuntimeException if there are fatal errors; do not try to perform further compositions beyond this point. Composition errors can result, but exceptions will not be thrown.
(d) after all required files have been composed, set the name of the package for the generated class.
base.setPackageName( "name-of-package" );(e) output the resulting file. This can be done by any one of several methods:
- print() -- to standard out
- print2file( Writer w ) -- to the given writer
- print2file( File f ) -- to the given file
- print2file( String name ) -- to a file with the given name
As an example:
base.print();
In regression/PJ you will find regression tests for interfaces and classes. To run the entire suite of tests type:
> bash regress
PJ currently understands extensions to Java classes, interfaces, and state diagrams. It does not yet understand other extensions that have been added to Java, such as AST constructors. Extending PJ to support most of these features should be very simple.
To extend PJ, every AST_FieldDecl and TypeDeclaration production of the Java grammar must support a compose method. See the preprocess, CompInt, CompClass, and CompSm layers for details.
Another limitation variable capture. For now, this means that programmers must be very careful in selecting the names of variables and methods so that there is no name collision. More on this later.
PJ is still undergoing changes. Known problems include: