|
|
|
|
Somusar/tjpp[tm]
User's Guide Francesco Aliverti-Piuri Copyright © 2003-2012 Somusar |
|
|
|
|
|
|
|
Unix is a registered trademark in the United States and other countries, licensed exclusively through X/Open Company Limited.
Linux is a registered trademark of Linus Torvalds in the United States and other countries.
Sun, Sun Microsystems, the Sun logo, Solaris, Java, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
Symbian and all Symbian-based marks and logos are trademarks of Symbian Software Limited.
Apple and Mac OS are registered trademarks of Apple Computer, Inc. in the United States and other countries.
Intel is a registered trademark of Intel Corporation in the United States and other countries.
PowerPC and CICS are registered trademarks of International Business Machines Corporation in the United States and other countries.
Microsoft, Windows, Visual Basic are either trademarks or registered trademarks of Microsoft Corp. in the United States and/or other countries.
Oracle is a registered trademark, and PL/SQL is a trademark of Oracle Corporation.
SAP and ABAP/4 are registered trademarks of SAP AG in Germany and several other countries.
PostScript is a registered trademark of Adobe Systems Incorporated in the United States and/or other countries.
So.mus.ar, the Somusar logo, Somusar/Software Production Technique, Somusar/Software Production Machine, Somusar/Sisendel, Somusar/Tefigel, Somusar/SoProTech, Somusar/SoProMach, Somusar/Software Entity, Somusar/Software Mold, Somusar/Software Mold Kit, Somusar/Software Mold Building, Somusar/Code Generator Building, Somusar/Generator Building, and Somusar/File Generation Scheme are trademarks of so.mus.ar. s.a.s. in Italy, in the European Union, in the United States of America and other countries.
Other trademarks or service marks referenced herein are property of their respective owners.
Contents | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Code Examples | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Tables | ||||||||
---|---|---|---|---|---|---|---|---|
|
This document describes how to install and operate
Somusar/tjpp[tm], independently of the underlying operating system
and of the edition of Somusar/tjpp[tm].
All Somusar's products are
currently available for the
following platforms:
The reader should be familiar with the following basic concepts and
procedures:
Special thanks to Salvatore "JVM" Arnone for his contributions in terms of Java expertise, and to Jack Herrington, author of "Code Generation in Action" and editor of Code Generation Network, for openly discussing pros/cons of an alternative generator model for tjpp.
Somusar/tjpp[tm] is a Java[tm] pre-processor and code generator featuring
the following functions:
Tjpp fits particularly well in text-editor and
command-line oriented
development shops, allowing to reduce, insulate, and
factorize repetitive code blocks and coding practices
into parametrical user-defined macros that allow
to quickly generate and assemble
Java[tm] source files, or parts thereof.
The main advantage of tjpp is the
reduction of redundant code, that can be transparently
generated and re-generated
by means of pre-defined directives and user-defined
parametrical macros at file-system level.
Another advantage is the possibility to insulate in external
macros syntax constructs subject to change as Java evolves,
as shown by directive enumeration. When the new construct
becomes officially available, the required changes
need be applied only once in the macro, and all ".java" files using that
construct can then be regenerated, thus providing higher
flexibility and consistency.
To avoid introducing additional constructs in the
Java files, tjpp translates ".tj" files into ".java" files,
thus leaving untouched the subsequent steps of
the software development and management cycles. Adding the
".tj" to ".java" translation to a command-line oriented
software production chain should be not an issue.
With the only exception of item #4 in the above list,
all tjpp features are implemented as textual macros and
are thus open to any user-defined customization.
Tjpp is a thin shell or ".bat" wrapper around Tefigel,
accepting one input file (a ".tj" file)
and producing one output file (the corresponding ".java" file).
Tefigel is a slim executable file, currently available
for Linux®, Mac OS® X, and Windows®. Tefigel is a scripting language
expressly designed for code generation. "Tefigel" stands for
text file generation language.
The Tefigel code implementing all tjpp's macros
and directives is kept in directory "tjpp_lib", while
the header files (extension ".tjh") are stored
under directory "tjpp_include". Note the clear separation
between macro files and header files:
each tjpp macro resides in exactly one file under "tjpp_lib", and header
files under "tjpp_include" do not define any macro.
After installing tjpp as described in the next chapter,
to run it type
Note that each run will overwrite the generated ".java" file,
unless you set TJPP_BACKS_UP_JAVA to true in file
"tjpp_include/tjpp.defs" to have tjpp
save a time-stamped copy of "YourClass.java"
into (for example) "YourClass.java-Dec02-12.39".
Tjpp has no command line options or flags. In particular,
there is no equivalent to the C/C++ -DSOME_FLAG=some_value
or -Isome_include_path preprocessor options.
All tjpp's error and warning messages output by Tefigel
are described in
"Somusar/SoProMach[tm]: User's Guide
".
prompt> tjpp YourClass.tj
prompt> tjpp subdir/AnotherClass.tj
which will produce "YourClass.java" and
"subdir/AnotherClass.java" respectively.
The software package delivered together with this guide
is a file in tar/gzip (in short: tgz) format
and can be unpacked by means of utilities such
as Winzip® or similar programs.
Alternatively, tgz files can be directly unzipped
and expanded using gunzip and gtar, available
for practically all platforms. More information on this topic
can be found on web page http://www.gzip.org.
The installation of tjpp does not require administrator
(or root) privileges; however, a centralized installation may
require such privileges in order to share the tjpp package
and the related environment variables.
To install tjpp and to verify the installation
proceed as described in the "READ_ME.txt"
included in the delivery package:
==================================================================
Delivery package of somusar/tjpp[tm] - tefigel Java[tm] pre-processor
Copyright (c) 2003 so.mus.ar. s.a.s. - www.somusar.com
This file last edited on: 03 December 2003
==================================================================
==================================================================
Installing somusar/tjpp[tm]
==================================================================
To install tjpp, unpack the compressed file in its
installation directory (suggestion: /opt/somusar),
set environment variable TJPP_PATH to the installation
directory and add TJPP_PATH/bin to your PATH.
To verify the installation, go under TJPP_PATH/sample
and run
tjpp ComplexClass.tj
This command should generate file ComplexClass.java,
containing the code expansion of ComplexClass.tj.
Additional sample files can be preprocessed as follows:
tjpp subpackage/SimpleClass.tj
tjpp Results.tj
==================================================================
somusar/tjpp[tm] package contents
==================================================================
READ_ME.txt this file
bin:
tjpp executable script for tjpp
tefigel executable file for tefigel
(alternatively, tjpp.bat and tefigel.exe for Windows[r])
tjpp_include:
copyright.tjh sample tjpp header file
header.tjh sample tjpp header file
tjpp.defs repository file for code generation
variables
subinc:
subhdr.tjh sample tjpp header file
tjpp_lib: tjpp macro code files in tefigel
assert
attach
checkhdr
enumeration
eofinput
fileprefix
flatpath
gen_warning
getset
getters
include
init.tfg tefigel initialization file
jfileloc
newfile
property
property_get
property_id
property_scan
property_set
property_type
setters
to_string
trace
warning
my_macros: sample user-defined macros
get_results
perc
timestamp
sample: sample code for tjpp
ComplexClass.tj sample tjpp input file
Results.tj sample tjpp input file
TestJavapp.java Java test for ComplexClass.java
and subpackage/SimpleClass.java
subpackage:
SimpleClass.tj sample tjpp input file
==================================================================
A first example of the code generated by tjpp is provided by the translation of "SimpleClass.tj" into "SimpleClass.java". The most relevant code fragments are described below.
Directive include is similar to the well-known #include
of C and C++:
$include(header.tjh)
By convention, tjpp requires header files to bear the
extension ".tjh". Path names are relative to "tjpp_include".
Tjpp issues a warning message when it detects
multiple inclusions of the same file.
Preprocessing variables are defined and set as follows:
: MY_TIME_MACRO_ENABLED=1
Tjpp's preferred file for these variables
is "tjpp_include/tjpp.defs", but users can freely
define additional variables as needed.
Conditional code generation directly uses Tefigel's
instructions IF, ELSE, and ENDIF:
@ IF MY_TIME_MACRO_ENABLED=1
// DATE of preprocessing: $my_macros/timestamp(date)
// TIME of preprocessing: $my_macros/timestamp(time)
@ ELSE
// Oops, my time macro is not enabled!
@ ENDIF
User-defined macros are used as the my_macros/timestamp
macro in the following fragment:
Note that the macro can be used even within Java comments,
as tjpp is unaware of Java syntax and semantics.
The source code of the timestamp
macro is commented at the end of this chapter.
Another example of user macro is provided by "ComplexClass.tj",
a file presented in detail later in this booklet:
Tjpp allows to define more powerful macros, generating
whole blocks of code. An example is presented later in
paragraph "Exercise: Improving Multitier Code Consistency".
// DATE of preprocessing: $my_macros/timestamp(date)
The dollar sign "$" instructs tjpp to call macro "my_macros/timestamp"
with parameter "date", and replace the macro call in input with
its string result in output. The macro file "my_macros/timestamp"
is to be found under "tjpp_lib".
double d = $my_macros/perc(anInt,1000);
The above line translates to
double d = ((anInt) * 100.0 / (1000));
The source code of this macro
is commented at the end of this chapter.
Variable tracing is used as follows:
public void setAThing( Object aThing ) {
$ trace(aThing)
this.aThing = aThing;
}
and generates the following code:
public void setAThing( Object aThing ) {
System.err.println("[T] File subpackage/SimpleClass.java, line 68
(src: subpackage/SimpleClass.tj, 56)");
System.err.println("[T] [aThing = '" + aThing + "']");
this.aThing = aThing;
}
Note that, for debugging convenience, the trace message reports
file name and line number of both ".tj" and ".java" files.
Several variables can be traced in one trace, as shown
by the following fragment from "ComplexClass.tj":
$ trace(aRange,aColor)
Line 1 shows an example of use of a tjpp variable, namely PACKAGE_ROOT, which is set in "tjpp_include/tjpp.defs". |
Source code - File "input_code/subpackage/SimpleClass.tj" |
1 package PACKAGE_ROOT.subpackage; 2 3 /** 4 * Class SimpleClass: 5 * 6 * A simple software entity. 7 */ 8 9 $include(header.tjh) 10 $include(subinc/subhdr.tjh) 11 12 : MY_TIME_MACRO_ENABLED=1 13 @ IF MY_TIME_MACRO_ENABLED=1 14 // DATE of preprocessing: $my_macros/timestamp(date) 15 // TIME of preprocessing: $my_macros/timestamp(time) 16 @ ELSE 17 // Oops, my time macro is not enabled! 18 @ ENDIF 19 20 public class SimpleClass { 21 22 private String aStringOfChar; 23 private int anInt; 24 private Object aThing; 25 26 /* 27 * Get methods 28 */ 29 30 public String getAStringOfChar() { 31 return aStringOfChar; 32 } 33 34 public int getAnInt() { 35 return anInt; 36 } 37 38 public Object getAThing() { 39 $ trace(aThing) 40 return aThing; 41 } 42 43 /* 44 * Set methods 45 */ 46 47 public void setAStringOfChar( String aStringOfChar ) { 48 this.aStringOfChar = aStringOfChar; 49 } 50 51 public void setAnInt( int anInt ) { 52 this.anInt = anInt; 53 } 54 55 public void setAThing( Object aThing ) { 56 $ trace(aThing) 57 this.aThing = aThing; 58 } 59 60 } |
Code Example 2 - Code generated from SimpleClass.tj
Lines 1-3 and 70-72 contain a warning message automatically generated by tjpp. |
Source code - File "generated_code/subpackage/SimpleClass.java" |
1 // WARNING: file "subpackage/SimpleClass.java" generated from "subpackage/SimpleClass.tj" 2 // Changes should be applied on the source file. 3 4 package com.somusar.tjpptest.subpackage; 5 6 /** 7 * Class SimpleClass: 8 * 9 * A simple software entity. 10 */ 11 12 // begin include "header.tjh" 13 // 14 // Sample header file for Java preprocessor 15 // 16 // end include "header.tjh" 17 // begin include "subinc/subhdr.tjh" 18 // 19 // Sample header file for Java preprocessor from a subdirectory 20 // of include root directory "tjpp_inst/tjpp_include" 21 // 22 // end include "subinc/subhdr.tjh" 23 24 // DATE of preprocessing: timestamp for "date": Wed Dec 03 2003 25 // TIME of preprocessing: timestamp for "time": 17:35:16.844 26 27 public class SimpleClass { 28 29 private String aStringOfChar; 30 private int anInt; 31 private Object aThing; 32 33 /* 34 * Get methods 35 */ 36 37 public String getAStringOfChar() { 38 return aStringOfChar; 39 } 40 41 public int getAnInt() { 42 return anInt; 43 } 44 45 public Object getAThing() { 46 System.err.println("[T] File subpackage/SimpleClass.java, line 46 (src: subpackage/SimpleClass.tj, 39)"); 47 System.err.println("[T] [aThing = '" + aThing + "']"); 48 return aThing; 49 } 50 51 /* 52 * Set methods 53 */ 54 55 public void setAStringOfChar( String aStringOfChar ) { 56 this.aStringOfChar = aStringOfChar; 57 } 58 59 public void setAnInt( int anInt ) { 60 this.anInt = anInt; 61 } 62 63 public void setAThing( Object aThing ) { 64 System.err.println("[T] File subpackage/SimpleClass.java, line 64 (src: subpackage/SimpleClass.tj, 56)"); 65 System.err.println("[T] [aThing = '" + aThing + "']"); 66 this.aThing = aThing; 67 } 68 69 } 70 71 // WARNING: file "subpackage/SimpleClass.java" generated from "subpackage/SimpleClass.tj" 72 // Changes should be applied on the source file. |
Code Example 3 - A user-defined macro: timestamp
Line 1 defines the interface of this macro, which expects one parameter called "what". |
Source code - File "input_code/tjpp_lib/my_macros/timestamp" |
1 @ INTERFACE(what) 2 | 3 | Sample user-defined macro, returning a string 4 | with a time stamp, as requested via parameter "what" 5 | 6 @ IF what=date 7 @ SET TS=$DATE 8 @ ELSE 9 @ SET TS=$TIME 10 @ ENDIF 11 @ RETVALUE=timestamp for "what": TS |
Code Example 4 - Another user-defined macro: perc
This tjpp macro is equivalent to the following C #define:#define perc(a,b) ((a) * 100.0 / (b))A major advantage of tjpp macros is that they reside in individual files and are called by means of their file-system path name, relative to "tjpp_lib". Moreover, they can accept a variable number of arguments. This particular macro expects two arguments, referred to by means of local variables a and b, as specified on line 1. |
Source code - File "input_code/tjpp_lib/my_macros/perc" |
1 @ INTERFACE(a,b) 2 | 3 | Sample user-defined macro, returning a code string 4 | to compute the percentage on given arguments. 5 | 6 @ RETVALUE=((a) * 100.0 / (b)) |
Translation of "ComplexClass.tj" into "ComplexClass.java" provides a more complex example of code generated by tjpp. The most significant code fragments are described below.
Directive attach is similar to include, but
instructs tjpp to simply copy the contents of the attached file,
without processing it.
$attach(copyright.tjh)
Directive enumeration provides a means to define
enumerated types:
The above directive generates the following code:
$ enumeration(Color,%
RED, %
GREEN, %
BLUE %
)
The percent sign "%" is tjpp's line concatenation operator.
// Map enum 'Color' onto an int with a set of values
public static final int RED = 0;
public static final int GREEN = 1;
public static final int BLUE = 2;
User-defined numeric values can also be provided as follows:
$ enumeration(Color,%
RED=1, %
GREEN=2, %
BLUE=4 %
)
Directives property, getters, setters and to_string
allow to concisely define the set of properties of a
class and produce a toString method:
$ property(int, a_unique_id, readonly)
$ property(Object, a_thing)
$ getters
$ setters
$ to_string
Directive property accepts a Java type, an identifier
(in lower case letters, digits, and underscores) and an optional
readonly flag. The list of properties is then
scanned by getter and setter to generate the accessors
and mutators. No mutator is generated for properties declared
as readonly. In a similar way, directive to_string scans
the list of properties to generate the toString method.
The fragment above translates to the
following Java code:
private int aUniqueId; // read-only
private Object aThing;
/*
* Get methods
*/
public int getAUniqueId() {
return aUniqueId;
}
public Object getAThing() {
return aThing;
}
/*
* Set methods
*/
public void setAThing( Object aThing ) {
this.aThing = aThing;
}
public String toString() {
String s = "[" +
" aUniqueId = '" + aUniqueId + "'" +
" aThing = '" + aThing + "'" +
" ]";
return s;
}
The assert directive of tjpp provides a rather
mild implementation of assertions, in comparison with regular
Java assertions. The generated
code checks the assertion and prints a message similar to the
trace message if the asserted condition
evaluates to false, raising neither errors, nor exceptions.
The following fragments show the input to, and output from, tjpp.
Input:
$ assert(aRange >= 0 && aRange < 20000)
Output:
{
if (! (aRange >= 0 && aRange < 20000)) {
System.err.println("[A] -------------");
System.err.println("[A] --- File ComplexClass.java, line 153
(src: ComplexClass.tj, 54)");
System.err.println("[A] --- Assertion 'aRange >= 0 && aRange
< 20000' failed");
System.err.println("[A] -------------");
}
}
As for most tjpp directives, it
is also possible to customize this directive, for instance to add code
that prints a stack trace or raises an error. The macro source code
is commented at the end of this chapter.
Line 1 uses directive $attach to include a copyright file without any processing, ensuring that the contents of the include file is faithfully copied to the generated file. |
Source code - File "input_code/ComplexClass.tj" |
1 $attach(copyright.tjh) 2 $include(header.tjh) 3 $include(subinc/subhdr.tjh) 4 5 package PACKAGE_ROOT; 6 7 /** 8 * Class ComplexClass: 9 * 10 * A software entity with several fields and collections. 11 */ 12 13 import PACKAGE_ROOT.subpackage.SimpleClass; 14 import java.util.Date; 15 16 public class ComplexClass extends SimpleClass { 17 18 |--- 19 | This is a tjpp comment that will not appear in the 20 | generated Java file. The "%" in the lines below is 21 | tjpp's line-concatenation operator. 22 |--- 23 $ enumeration(Color,% 24 RED, % 25 GREEN, % 26 BLUE % 27 ) 28 29 $ property(boolean, a_bool) 30 $ property(int, a_color) 31 $ property(double, a_float) 32 $ property(int, a_range) 33 $ property(String, a_string) 34 $ property(Date, a_time) 35 $ property(int, a_unique_id, readonly) 36 $ property(int, an_int, readonly) 37 $ property(int, another_color, readonly) 38 $ property(Object, a_thing) 39 $ property(int [][], an_int_array) 40 41 $ getters 42 $ setters 43 44 /** 45 * Method 'A function' 46 */ 47 48 public boolean aFunction ( 49 int aRange, 50 int aColor 51 ) 52 { 53 $ trace(aRange,aColor) 54 $ assert(aRange >= 0 && aRange < 20000) 55 return true; 56 } 57 58 /** 59 * Method 'A function' 60 */ 61 62 public double aFunction ( 63 int anInt 64 ) 65 { 66 : TRACE_SWITCH=off 67 $ trace(anInt) 68 double d = $my_macros/perc(anInt,1000); 69 : TRACE_SWITCH=on 70 $ trace(d) 71 return d; 72 } 73 74 $ to_string 75 76 } |
Code Example 6 - Code generated from ComplexClass.tj
The $attached copyright file has been copied to lines 4-8. |
Source code - File "generated_code/ComplexClass.java" |
1 // WARNING: file "ComplexClass.java" generated from "ComplexClass.tj" 2 // Changes should be applied on the source file. 3 4 // 5 // Sample copyright file for Java preprocessor 6 // 7 // Copyright (c) _____________ , 2003 - All rights reserved. 8 // 9 // begin include "header.tjh" 10 // 11 // Sample header file for Java preprocessor 12 // 13 // end include "header.tjh" 14 // begin include "subinc/subhdr.tjh" 15 // 16 // Sample header file for Java preprocessor from a subdirectory 17 // of include root directory "tjpp_inst/tjpp_include" 18 // 19 // end include "subinc/subhdr.tjh" 20 21 package com.somusar.tjpptest; 22 23 /** 24 * Class ComplexClass: 25 * 26 * A software entity with several fields and collections. 27 */ 28 29 import com.somusar.tjpptest.subpackage.SimpleClass; 30 import java.util.Date; 31 32 public class ComplexClass extends SimpleClass { 33 34 // Map enum 'Color' onto an int with a set of values 35 public static final int RED = 0; 36 public static final int GREEN = 1; 37 public static final int BLUE = 2; 38 39 private boolean aBool; 40 private int aColor; 41 private double aFloat; 42 private int aRange; 43 private String aString; 44 private Date aTime; 45 private int aUniqueId; // read-only 46 private int anInt; // read-only 47 private int anotherColor; // read-only 48 private Object aThing; 49 private int anIntArray[][]; 50 51 /* 52 * Get methods 53 */ 54 55 public boolean getABool() { 56 return aBool; 57 } 58 59 public int getAColor() { 60 return aColor; 61 } 62 63 public double getAFloat() { 64 return aFloat; 65 } 66 67 public int getARange() { 68 return aRange; 69 } 70 71 public String getAString() { 72 return aString; 73 } 74 75 public Date getATime() { 76 return aTime; 77 } 78 79 public int getAUniqueId() { 80 return aUniqueId; 81 } 82 83 public int getAnInt() { 84 return anInt; 85 } 86 87 public int getAnotherColor() { 88 return anotherColor; 89 } 90 91 public Object getAThing() { 92 return aThing; 93 } 94 95 public int[][] getAnIntArray() { 96 return anIntArray; 97 } 98 99 /* 100 * Set methods 101 */ 102 103 public void setABool( boolean aBool ) { 104 this.aBool = aBool; 105 } 106 107 public void setAColor( int aColor ) { 108 this.aColor = aColor; 109 } 110 111 public void setAFloat( double aFloat ) { 112 this.aFloat = aFloat; 113 } 114 115 public void setARange( int aRange ) { 116 this.aRange = aRange; 117 } 118 119 public void setAString( String aString ) { 120 this.aString = aString; 121 } 122 123 public void setATime( Date aTime ) { 124 this.aTime = aTime; 125 } 126 127 public void setAThing( Object aThing ) { 128 this.aThing = aThing; 129 } 130 131 public void setAnIntArray( int anIntArray[][] ) { 132 this.anIntArray = anIntArray; 133 } 134 135 136 /** 137 * Method 'A function' 138 */ 139 140 public boolean aFunction ( 141 int aRange, 142 int aColor 143 ) 144 { 145 System.err.println("[T] File ComplexClass.java, line 145 (src: ComplexClass.tj, 53)"); 146 System.err.println("[T] [aRange = '" + aRange + "']"); 147 System.err.println("[T] [aColor = '" + aColor + "']"); 148 { 149 if (! (aRange >= 0 && aRange < 20000)) { 150 System.err.println("[A] -------------"); 151 System.err.println("[A] --- File ComplexClass.java, line 149 (src: ComplexClass.tj, 54)"); 152 System.err.println("[A] --- Assertion 'aRange >= 0 && aRange < 20000' failed"); 153 System.err.println("[A] -------------"); 154 } 155 } 156 return true; 157 } 158 159 /** 160 * Method 'A function' 161 */ 162 163 public double aFunction ( 164 int anInt 165 ) 166 { 167 double d = ((anInt) * 100.0 / (1000)); 168 System.err.println("[T] File ComplexClass.java, line 168 (src: ComplexClass.tj, 70)"); 169 System.err.println("[T] [d = '" + d + "']"); 170 return d; 171 } 172 173 public String toString() { 174 String s = "[" + 175 " aBool = '" + aBool + "'" + 176 " aColor = '" + aColor + "'" + 177 " aFloat = '" + aFloat + "'" + 178 " aRange = '" + aRange + "'" + 179 " aString = '" + aString + "'" + 180 " aTime = '" + aTime + "'" + 181 " aUniqueId = '" + aUniqueId + "'" + 182 " anInt = '" + anInt + "'" + 183 " anotherColor = '" + anotherColor + "'" + 184 " aThing = '" + aThing + "'" + 185 " anIntArray = '" + anIntArray + "'" + 186 " ]"; 187 return s; 188 } 189 190 } 191 192 // WARNING: file "ComplexClass.java" generated from "ComplexClass.tj" 193 // Changes should be applied on the source file. |
Code Example 7 - Implementation of assert
Generation of assertion code is controlled by tjpp's variable ASSERTION_SWITCH (lines 11-13). |
Source code - File "input_code/tjpp_lib/assert" |
1 @ INTERFACE(...) 2 | 3 | Generate a block of statements to check an assertion. 4 | The assertion expression is passed as one or more arguments 5 | and used below as REG_ALL. 6 | When an assertion evaluates to false, the generated code 7 | prints out a trace message with source file and line, then 8 | continues normal execution flow. 9 | No code is generated if ASSERTION_SWITCH is not "on". 10 | 11 @ IF ASSERTION_SWITCH#on 12 @ QUIT 13 @ ENDIF 14 @ SET ASSERTIONBANNER=[A] --- 15 { 16 @ SET FILELOC=$jfileloc 17 if (! (REG_ALL)) { 18 System.err.println("ASSERTIONBANNER----------"); 19 System.err.println("ASSERTIONBANNER FILELOC"); 20 System.err.println("ASSERTIONBANNER Assertion 'REG_ALL' failed"); 21 System.err.println("ASSERTIONBANNER----------"); 22 } 23 } |
A plain Java file, "TestJavapp.java", contains a test program for "SimpleClass.java" and "ComplexClass.java". Running the test produces the diagnostic System.err messages listed and commented in "stderr.txt".
Line 16 causes an assertion to fail and a trace message to be printed out. |
Source code - File "input_code/TestJavapp.java" |
1 package com.somusar.tjpptest; 2 3 import com.somusar.tjpptest.ComplexClass; 4 import com.somusar.tjpptest.subpackage.SimpleClass; 5 6 public class TestJavapp { 7 8 public static void main(String[] args) { 9 10 SimpleClass s = new SimpleClass(); 11 ComplexClass c = new ComplexClass(); 12 double d; 13 boolean b; 14 Object o; 15 16 b = c.aFunction(20000, ComplexClass.RED); 17 b = c.aFunction(10000, ComplexClass.GREEN); 18 d = c.aFunction(12); 19 s.setAThing(c); 20 o = s.getAThing(); 21 } 22 } |
Code Example 9 - Diagnostic messages: "stderr.txt"
Lines 1-7 result from line 16 of TestJavapp.java. |
Source code - File "generated_code/stderr.txt" |
1 [T] File ComplexClass.java, line 145 (src: ComplexClass.tj, 53) 2 [T] [aRange = '20000'] 3 [T] [aColor = '0'] 4 [A] ------------- 5 [A] --- File ComplexClass.java, line 149 (src: ComplexClass.tj, 54) 6 [A] --- Assertion 'aRange >= 0 && aRange < 20000' failed 7 [A] ------------- 8 [T] File ComplexClass.java, line 145 (src: ComplexClass.tj, 53) 9 [T] [aRange = '10000'] 10 [T] [aColor = '1'] 11 [T] File ComplexClass.java, line 168 (src: ComplexClass.tj, 70) 12 [T] [d = '1.2'] 13 [T] File subpackage/SimpleClass.java, line 64 (src: subpackage/SimpleClass.tj, 56) 14 [T] [aThing = '[ aBool = 'false' aColor = '0' aFloat = '0.0' aRange = '0' aString = 'null' aTime = 'null' aUniqueId = '0' anInt = '0' anotherColor = '0' aThing = 'null' anIntArray = 'null' ]'] 15 [T] File subpackage/SimpleClass.java, line 46 (src: subpackage/SimpleClass.tj, 39) 16 [T] [aThing = '[ aBool = 'false' aColor = '0' aFloat = '0.0' aRange = '0' aString = 'null' aTime = 'null' aUniqueId = '0' anInt = '0' anotherColor = '0' aThing = 'null' anIntArray = 'null' ]'] |
Multitier applications replicate the same
data item, such as a "Last Name", at various levels:
database tables, Java classes (for both business logic and system
infrastructure), user interface dialogs.
A familiar example of this is shown by the following
code fragment, where data items retrieved from a database
are copied to Java variables:
The new macro my_macro/get_results
is commented below, as are
the input "Results.tj" and output "Results.java" files. Input
and output fragments are listed below.
Input:
// Get results from "results" by column name
int rCustId = results.getInt("CUST_ID");
String rFirstName = results.getString("FIRST_NAME");
String rLastName = results.getString("LAST_NAME");
float rBalance = results.getFloat("BALANCE");
String rEmail = results.getString("EMAIL");
Similar code fragments are frequent and lend themselves
to be generated by a tjpp macro. The new user-defined
macro will directly generate a block of code, instead of returning
a short string of code as do my_macro/timestamp and
my_macro/perc.
: MY_MEMBERS=int/cust_id ,%
String/first_name ,%
String/last_name ,%
float/balance ,%
String/email
$ my_macros/get_results(BY_NUMBER,rs,MY_MEMBERS)
$ my_macros/get_results(BY_NAME,results,MY_MEMBERS)
Output:
int rCustId = rs.getInt( 1);
String rFirstName = rs.getString( 2);
String rLastName = rs.getString( 3);
float rBalance = rs.getFloat( 4);
String rEmail = rs.getString( 5);
int rCustId = results.getInt( "CUST_ID");
String rFirstName = results.getString( "FIRST_NAME");
String rLastName = results.getString( "LAST_NAME");
float rBalance = results.getFloat( "BALANCE");
String rEmail = results.getString( "EMAIL");
An alternative and more exhaustive solution to
the problems deriving from multitier data
redundancy is discussed in booklet
"somusar/SoProTech: A Sample Project".
Line 8 uses column numbers to get the query result values. |
Source code - File "input_code/Results.tj" |
1 : MY_MEMBERS=int/cust_id ,% 2 String/first_name ,% 3 String/last_name ,% 4 float/balance ,% 5 String/email ,% 6 wrongType/sthg_else 7 // Get results from "rs" by column number 8 $ my_macros/get_results(BY_NUMBER,rs,MY_MEMBERS) 9 10 // Get results from "results" by column name 11 $ my_macros/get_results(BY_NAME,results,MY_MEMBERS) |
Code Example 11 - Code generated from Results.tj
Lines 5-10 result from calling my_macro/get_results with mode BY_NUMBER. |
Source code - File "generated_code/Results.java" |
1 // WARNING: file "Results.java" generated from "Results.tj" 2 // Changes should be applied on the source file. 3 4 // Get results from "rs" by column number 5 int rCustId = rs.getInt( 1); 6 String rFirstName = rs.getString( 2); 7 String rLastName = rs.getString( 3); 8 float rBalance = rs.getFloat( 4); 9 String rEmail = rs.getString( 5); 10 wrongType rSthgElse = rs.get UNKNOWN ( 6); 11 12 // Get results from "results" by column name 13 int rCustId = results.getInt( "CUST_ID"); 14 String rFirstName = results.getString( "FIRST_NAME"); 15 String rLastName = results.getString( "LAST_NAME"); 16 float rBalance = results.getFloat( "BALANCE"); 17 String rEmail = results.getString( "EMAIL"); 18 wrongType rSthgElse = results.get UNKNOWN ( "STHG_ELSE"); 19 20 // WARNING: file "Results.java" generated from "Results.tj" 21 // Changes should be applied on the source file. |
Code Example 12 - A macro to generate result-get statements
This macro generates result-set getXXX statements from a parametric source variable for the type/id pairs supplied as arguments. |
Source code - File "input_code/tjpp_lib/my_macros/get_results" |
1 @ INTERFACE(mode,source) 2 | 3 | Generate statements in the form (mode = BY_NUMBER) 4 | int rCustId = source.getInt(1); 5 | or (mode = BY_NAME) 6 | int rCustId = source.getInt("CUST_ID"); 7 | Actually, more arguments are supplied, namely a 8 | list of type/id arguments, like in "int/cust_id". 9 | 10 @ DASH ^ 11 | Create a mapping between Java types and getXXX accessors 12 @ SET jmap^int=Int 13 @ SET jmap^float=Float 14 @ SET jmap^double=Double 15 @ SET jmap^String=String 16 @ SET jmap^boolean=Boolean 17 | Scan list of type/id pairs, skipping mode and source 18 @ SET I=2 19 @ WHILE I<REG_COUNT 20 @ SET FIELD=REG_^I 21 | Strip leading and trailing blanks 22 @ SET FIELD=$WORD(FIELD,0) 23 | Retrieve type 24 @ SET JTYPE=$FIELD(FIELD,0,/) 25 | Retrieve identifier 26 @ SET JID=$FIELD(FIELD,1,/) 27 | Check if type mapping is known, issue a warning otherwise 28 | and propagate error into Java code 29 @ SET JRESTYPE=$VALUE(jmap^JTYPE) 30 @ IF JRESTYPE~jmap 31 @ SET JRESTYPE= UNKNOWN 32 $ warning($jfileloc(src_only): don't know how to map type "JTYPE") 33 @ ENDIF 34 | Select mode of getXXX 35 @ IF mode=BY_NAME 36 @ SET JKEY="$MAKE_ID(JID,ABC_DEF)" 37 @ ELSE 38 @ SET JKEY=I 39 @ SUB JKEY 1 40 @ ENDIF 41 | Prepare a local identifier 42 @ SET JID=$MAKE_ID(r_^JID,abcDef) 43 | Prepare right-hand side of assignment 44 @ SET JVAL=source.get^JRESTYPE( JKEY) 45 | Generate tab-aligned code 46 @ ECHO $TABS( JTYPE JID = JVAL;,8,20,32,48) 47 @ ADD I 1 48 @ ENDWHILE 49 @ DASH |
To request any type of information concerning the SoProTech[tm] or the SoProMach[tm], please fill in the appropriate form at http://www.somusar.com/contact specifying, beside your question or questions, the requested contact data.
To request support for any problem concerning
tjpp, licensees should fill in form
http://www.somusar.com/contact/problem_report,
specifying, among other contact data, the following
information:
After validation of submitted support requests
a confirmation email is sent to the address of the
Somusar licensee. Additional information exchange
about problem resolution is generally
managed via email.
Additional information on the different aspects of the
Somusar/Software Production Technique[tm] can be found in the other volumes of
the Somusar/SoProTech[tm] Booklet Series, listed below.
Vol. I -
somusar/SoProTech: An Introduction
Vol. II -
somusar/SoProTech: A Sample Project
Vol. III -
somusar/Sisendel: A Tutorial Introduction
Vol. IV -
somusar/Tefigel: A Tutorial Introduction
Vol. V -
somusar/Sisendel: Reference Guide
Vol. VI -
somusar/Tefigel: Reference Guide
Vol. VII -
somusar/SoProMach: User's Guide
Vol. IX -
Code Generation Somusar Style
An introduction to the Somusar/Software Production Technique[tm], a new, fast, and efficient
technology to make high-quality multifacet software.
Description of a sample project, serving as a proof-of-concept
for the Somusar/Software Production Technique[tm], and the Somusar/Sisendel[tm] and Somusar/Tefigel[tm] languages.
A few code examples are provided and
demonstrate the practical applicability of the technique.
A tutorial introduction to Somusar/Sisendel[tm], describing all
features of the simple software entity design language. Several code examples
practically demonstrate the conciseness and flexibility
of the language.
An introduction to the syntax, semantics, and usage of Somusar/Tefigel[tm],
including a vast set of code examples, illustrating the powerful
features of the text file generation language.
Sisendel reference guide: official definition of syntax and semantics
of the Somusar/Sisendel[tm] language.
Tefigel reference guide: official definition of syntax and semantics
of the Somusar/Tefigel[tm] language.
The Somusar/Software Production Machine[tm] User's Guide. How to install and operate
SoProMach.
Proof-of-concept samples of what you can generate with Somusar/SoProMach[tm].
In summary, the current (December 2003) implementation of tjpp provides the directives and macros listed in the following tables.
Directive | Description |
---|---|
:IDENTIFIER=value | Defines a tjpp variable IDENTIFIER, setting it to the given value. Subsequent references to IDENTIFIER will be replaced by value, even within quotes |
@ IF ... @ ELSE @ ENDIF |
Conditional code block generation. This is a Tefigel construct, and is documented at http://somusar.com/doc/booklets/tefigel_ref. |
$include(filename) | Includes filename in the generated file, processing its contents |
$attach(filename) | Includes filename in the generated file, without processing its contents |
$trace(var1[,var2...]) | Generates code to print out on System.err the value of each variable var1, var2, ... |
$assert(expression) | Generates code to evaluate the assertion defined by the boolean expression and perform an action if it evaluates to false. By default the action is a tracing message printed out on System.err |
Generation of code for $asserts and $traces is controlled respectively by tjpp's variables ASSERTION_SWITCH and TRACE_SWITCH, which by default are both switched on.
Directive | Description |
---|---|
$property(type,id[,readonly]) |
Generates code to declare a class property of the given Java type, possibly non-modifiable (when readonly is specified). The identifier id should only contain lower case letters, decimal digits, and underscores, as in this_is_a_valid_identifier. If TJPP_PROPERTY_MAKES_GSETTERS is set to true, generates also a getter method, and a setter method for modifiable properties |
$getters | Generates getter methods for all properties declared via directive $property, unless TJPP_PROPERTY_MAKES_GSETTERS is set to true |
$setters | Generates setter methods for all modifiable properties declared via directive $property, unless TJPP_PROPERTY_MAKES_GSETTERS is set to true |
$to_string | Generates a toString method based on the property list |
$enumeration(enum_descr, % VALUE_1[=num_1], % VALUE_2[=num_2],...) |
Generates code to declare a pseudo-enumeration type described by enum_descr and defined by symbols VALUE_1, VALUE_2, ... Numeric values num_1, num_2, ..., can optionally be associated with the corresponding symbols |
Tjpp provides the library and user-defined macros listed
below. File names are relative to "tjpp_lib".
File and macro name | Description |
---|---|
checkhdr | Verifies that a header file complies with the ".tjh" naming convention |
eofinput | Tefigel HOOK routine for end-of-file condition |
fileprefix | Strips a given extension from a given pathname |
flatpath | Calls fileprefix and replaces "/" with "_" |
gen_warning | Generates a Java comment with a "generated-file" warning |
getset | Generates an accessor or a modifier for a given property |
jfileloc | Returns the file/line location of current ".tj" and (optionally) ".java" files |
newfile | Tefigel HOOK routine for beginning-of-file condition |
property_get | Generates the accessor for a given property |
property_id | Returns the identifier of a given property |
property_scan | Scans the list of properties applying a given property processor (another tjpp macro) |
property_set | Generates the modifier for a given property |
property_type | Returns the type of a given property |
warning | Issues a generation-time warning message |
File and macro name | Description |
---|---|
my_macros/get_results | Generate a block of result.getXXX statements |
my_macros/perc | Returns a code string that calculates the percentage of the given parameters |
my_macros/timestamp | Returns a time-stamp string |