How to use UniT
Now we dive into the technical details, but since UniT
is so easy, after reading this text you should
know nearly everything about using UniT if you are already
familiar with similar technologies.
The remaining part introduces the main features of UniT
by giving a short description, a code example, and example output. Some of
these examples do not make much sense, they just demonstrate
the features. (Of course, all features, e.g., loops,
can be nested like in Java.)
Special UniT tags
|
name and description of the UniT feature
|
example syntax and example output of the UniT feature
|
start tag
Each UniT text template or program can be recognized by the start tag
in the first line and column. By the way, UniT source code is case
sensitive, of course! Every UniT source code
starts with the UniT start tag:
|
[UniT]
|
unit bracket escapes
A UniT is a text template, i.e., a mixture of text and UniT tags.
Tags allow the insertion of dynamic data.
Brackets ("[" and "]") are used to limit all the UniT tags.
Nevertheless, it should be possible to generate/output the usual brackets,
like those above. Therefore, bracket escapes are defined.
Double opening bracket ("[[") to output a single opening bracket: [;
double closing bracket ("]]") to output a single closing bracket: ].
They can be combined in any order and number:
|
]][[]][[]]
][][]
|
output expressions
As in other technologies, it is very easy to convert any expression
to a String object and direct it to output:
|
[= 1+1]
2
|
nestable comments
Of course, it is possible to include comments
that should not be part of the output.
Those comments are enclosed in brackets, too,
but with a (following/leading) star within them.
They can span a single or multiple lines and they can be nested:
|
short comment:
start-[*short comment*]-end
short comment:
start--end
multiple line comment:
start-[*
comment over
multiple lines
*]-end
multiple line comment:
start--end
nested comment:
start-[*
This is a [* nested *] comment
with some source code:
[= "hi, this will not be executed"]
*]-end
nested comment:
start--end
|
Expressions of the UniT programming language (only the easy parts of Java)
|
name and description of the UniT feature
|
example-syntax and example-result of the UniT feature
|
variable declarations
As in Java methods, you are allowed to declare any valid Java identifiers
as references to objects. Because UniT is realized with dynamic
type checking, type declarations and type casting are not needed.
The type is always Object.
|
[Object reference]
[= reference]
null
|
single declaration with immediate initialization
A reference can be initialized immediately at declaration with any expression.
|
[Object int1 = 1]
[= int1]
1
|
multiple declarations
Several references can be declared at once, separated by comma.
|
[Object oneDimIntArray,
twoDimIntArray,
initialized,
counter]
[=oneDimIntArray]
[=twoDimIntArray]
[=initialized]
[=counter]
[Object int2 = 1+1,
int3 = int2 +1,
test = new unit.Test(out)]
[=int2]
[=int3]
[=test]
null
null
null
null
called overloaded constructor Test()
2
3
unit.Test@a8e2e35c
|
strings
Strings are supported, of course.
|
[= "hello world"]
hello world
|
multiple line strings
Even this is possible:
|
[= "hello
world"]
hello
world
|
string concatenation
|
[= "hello" + " " + "world"]
[= 2 + " times"]
hello world
2 times
|
decimals/int, multiplication, division, modulo, addition,
subtraction, unay minus, parenthesis:
Calculation is supported, as is usual in Java.
|
[= 123]
[= 2*3]
[= 6/2]
[= 5%3]
[= 2+3]
[= 5-2]
[= -1]
[= (2 + 3) * 4]
123
6
3
2
5
3
-1
20
|
preferences
All operators have the usual preferences:
|
[= 2 + 3 * 4] = [= 2 + ( 3 * 4 )]
14 = 14
|
boolean literals, logic and, logic or, (unary) not:
Conditions are possible.
|
[= true]
[= false]
[= true && false]
[= false || true]
[= !false]
true
false
false
true
true
|
lower operator, lower equal, greater equal, greater,
equality of two operands, no equality:
Comparison:
|
[= 2 < 2]
[= 2 <= 2]
[= 2 >= 2]
[= 2 > 2]
[= 2 == 2]
[= 2 != 2]
false
true
true
false
true
false
|
any kind of references
Any locally declared identifier within the current scope,
any named argument as described below, and
even the null literal can be used in expressions:
|
[= int3]
[= int3 = 2]
[= int3]
[= null]
3
2
2
null
|
field access
Read and write any public static or non-static field of any class.
|
[= test.intField]
[= test.intField = 1]
[= test.intField]
[= unit.Test.staticIntField]
[= unit.Test.staticIntField = 2]
[= unit.Test.staticIntField]
0
1
1
0
2
2
|
object constructor with arguments and array constructor
|
[= new Integer(1)]
[= oneDimIntArray = new int[2]]
[= twoDimIntArray = new int[2][]]
1
[I@ce52e35c
[[I@c5c6e35c
|
array read and write access
|
[= oneDimIntArray[0]]
[= oneDimIntArray[0] = 1]
[= oneDimIntArray[0]]
0
1
1
|
call any public static or non-static method with any arguments,
Pass argument(s) that do not exactly match
with the method signature/parameter declaration(s)
(a dynamic method resolution will be applied).
All values/objects of the classes
-
java.lang.Boolean,
-
java.lang.Character,
-
java.lang.Byte,
-
java.lang.Short,
-
java.lang.Integer,
-
java.lang.Long,
-
java.lang.Float,
-
java.lang.Double
can be created and usually will be treated as/converted to
values of primitive types, automatically:
|
[System.out.println("hello world")]
[System.out.println(System.out)]
[unit.Test.staticMethod(1, out)]
[unit.Test.staticMethod(new Float("1.5"), out)]
[unit.Test.staticMethod("a".charAt(0), out)]
hello world
java.io.PrintStream@391b4be2
called static method with primitive int argument
called static method with primitive float argument
called static method with primitive char argument
|
operator instanceof
Runtime type information about objects and arrays:
|
[= "hello" instanceof String]
[= oneDimIntArray instanceof int[]]
true
true
|
type checking
Of course, UniT always checks the type of Boolean conditions and
expression operands and UniT throws appropriate RuntimeExceptions.
|
|
Control flow (only the easy parts of Java)
|
name and description of the UniT feature
|
example syntax and example result of the UniT feature
|
while loop with continue and break
The most important feature for a dynamic text generator language
like UniT is a loop.
UniT allows all the kinds of loops that are allowed in Java, too.
|
[counter = 1]
[while (counter < 5){]
[= counter]. iteration
[counter = counter +1]
[if (counter == 3) {]
continuing iteration
[continue]
[} else {]
[if (counter == 4) {]
breaking iteration
[break]
blabla
[}]
[}]
[}]
1. iteration
2. iteration
continuing iteration
3. iteration
breaking iteration
|
do loop
|
[do {]
within do
[break]
blabla
[} while(false)]
within do
|
for loop with declaration initialization
A for loop with declaration list in initialization that does NOT iterate.
|
[for ( Object a = 1, b = 2, c = 3;
false;
a = 1, b = 2) {]
within for
[break]
blabla
[}]
|
for loop with break
A for loop without condition usually never ends. But we use a break statement:
|
[for (;;) {]
within for
[break]
[}]
within for
|
conditionals
Often special conditions must be checked and handled differently.
|
[if (true) {]
within then
[}]
[if (false) {]
within then
[} else {]
within else
[}]
within then
within else
|
error handling
It is possible to generate and handle exceptions in UniT like in Java.
Of course, the finally block can be omitted. Or any catch block.
|
[try {]
within try with throw 1
[Object withinEHandling]
[withinEHandling = null]
[throw new RuntimeException("This is a stupidly provocated RuntimeException.")]
[} catch (RuntimeException exception) {]
caught RuntimeException: [=exception]
[Object withinEHandling]
[withinEHandling = null]
[} finally {]
within finally, e.g., for closing files
[Object withinEHandling]
[withinEHandling = null]
[}]
[Object withinEHandling]
[withinEHandling = null]
within try with throw 1
caught RuntimeException: java.lang.RuntimeException: This is a stupidly provocated RuntimeException.
within finally, e.g., for closing files
|
exit unit
A UniT program can be left at any location
(further text won't be generated anymore!):
|
[return]
|
Special features of UniT
The predefined identifier/reference "out":
All generated output is directed to an object called/referenced
by the identifier "out", which is always predefined
(with the System.out object wrapped in a Writer instance) and
can be reassigned at any time. It can even be passed to a unit
as a named argument (see below).
It must be an instance of the class java.io.Writer.
And because the identifier out always references a Writer object,
any file and anything else can be output to it.
First we save the current out object:
[Object savedOut = out]
The out object can be used to redirect output to a file or
to multiple targets or to install special filters,
like the following example illustrates.
We create and set a special output Writer
that replaces all white space sequences by one space and
that has special methods for reinserting white space explicitly.
This is a way having a nicely formatted UniT source code
and getting pretty output at the same time,
because you can indent and format the UniT source code and the output
as you like, completely independently/orthogonally.
After using such a WhiteSpaceStripper,
your indentation in the UniT source code, e.g., in loops,
has no effect on the output because all white space is stripped and
one space is inserted instead. But if the output needs to look nice, too,
or special white space is needed, it can be created explicitly
with some special methods.
[out = new unit.WhiteSpaceStripper(out)]
1. line 2. line 3. line
Now a method calls to create white space explicitly:
3 spaces([out.space()]): end of spaces
3 tabulators([out.tab()]): end of tabs
3 newlines([out.newline()]):
end of newlines
Now we restore the original out object: [out = savedOut]
Of course, a Java programmer can write his own filter that does anything
he wants, e.g.,
-
buffer all output text until a flush occurs,
to be able to stop output if an error occurs.
-
an HTML filter that replaces special characters with other special
characters, e.g., & by &,
-
or a filter that translates from one tag format to another tag format,
e.g., from HTML tags to a proprietary tag format or vice versa,
-
or a filter that passes the output to another transformation tool,
e.g., XML to an XSLT processor,
-
or a filter that replaces special tags with example text
(from the designer) by dynamically created text/tags
(from the programming expert),
-
or a filter that carries out even more complex actions.
Passing arguments to a UniT by name and the predefined identifier/reference "identifiers"
A Hashtable containing named objects can be passed to
a UniT. Those named objects can be accessed like local
references/variables. This is a way of passing any
argument by name to a UniT.
The Hashtable is an element of itself named "identifiers".
This way it can be passed to methods.
It can be passed to other UniTs that need to
have access to all current identifiers.
Include/reuse
Of course, it is possible to include other text files,
e.g., via file i/o and redirection to the out object or
to include/execute another UniT, e.g., as a header or footer.
This is analogous to Server Side Includes.
Even parameters can be passed to another UniT
by the identifiers that can be passed to a UniT as described above.
You can also parse a UniT file once and execute it multiple times
without parsing it again. It could even be executed in parallel threads.
Of course, this is a tricky topic. Did you find a bug? Contact me.
Of course, you can experiment with UniT and write your own programs to
get to know the functionality and use-cases of UniT. Enjoy and have fun!
|