Scoped Code Blocks
ClassMaker
provides the following methods to create scoped code blocks.
public Labelled Begin() throws ClassMakerException public void End() throws ClassMakerException
A Begin
and End
pair create a code block that limits the scope of variables
declared within the code block. Other statements may include a code block of multiple statements
but they do not limit variable scope.
In the following code the variable a
is declared twice in different scoped code blocks.
Consequently, the variable can be declared as an integer in one code block and a character in the other.
Java code | ClassMaker code |
if (n > 0) { int a; a = n++; } else { char a; a = '0'; n = a - n; } |
If(GT(Get("n"), Literal(0))); Begin(); Declare("a", int.class, 0); Set("a", Inc("n")); End(); Else(); Begin(); Declare("a", char.class, 0); Set("a", Literal('0')); Set("n", Subt(Get("a"), Get("n"))); End(); EndIf(); |
Begin
and End
are also used to define the code block for a method, as described in the section
about [Methods].
If Statement
ClassMaker
provides the following methods to create if statements.
public Labelled If(Type condition) throws ClassMakerException; public void Else() throws ClassMakerException; public void EndIf() throws ClassMakerException;
There may be any number of statements between the If
, Else
and EndIf
method calls.
Unlike java, there is an implicit code block between each clause.
An exception will be thrown if the clauses do not balance, for example, if an Else
method is
called when not preceded by an If
call and followed by an EndIf
call.
Java code | ClassMaker code |
if (a<0) { a = 0; } |
If(LT(Get("a"), Literal(0))); Set("a", Literal(0)); EndIf(); |
if (a<0) { a = 0; } else { a = 1; } |
If(LT(Get("a"), Literal(0))); Set("a", Literal(0)); Else(); Set("a", Literal(1)); EndIf(); |
While loop
A while loop can be created using the following methods from ClassMaker
.
public Labelled Loop() throws ClassMakerException public void While(Type condition) throws ClassMakerException public void EndLoop() throws ClassMakerException
The While
clause can appear at the start or end of the loop, either after the Loop
clause or just before the EndLoop
clause. In actual fact it could appear anywhere in the loop
as ClassMaker places no restrictions on the placement of the While
clause, but the traditional
place is at the start of the loop or occasionally at the end.
Java code | ClassMaker code |
x = 1; while (n>0) { x = x * n; --n; } |
Eval(Set("x", Literal(1))); Loop(); While(GT(Get("n"), Literal(0))); Eval(Set("x", Mult(Get("x"), Get("n")))); Eval(Dec("n")); EndLoop(); |
For loop
The methods for generating a for loop in ClassMaker
look like this.
public ForWhile For(Type declare) throws ClassMakerException; interface ForWhile { ForStep While(Type condition) throws ClassMakerException; } interface ForStep { Labelled Step(Type step) throws ClassMakerException; } public void EndFor() throws ClassMakerException
While this looks daunting it actually comes down to this simple sequence.
For( <assignment> ).While( <condition> ).Step( <increment> );
The For
method expects an expression which is usually an assignment, although this is not enforced.
The While
method expects a boolean expression and will complain if it doesn't get one.
The Step method expects another expression which usually increments a value, although again, this is not enforced.
Any or all of the expressions may be omitted by providing null
.
The call to EndFor
terminates the loop.
The following code calculates factorial for a given n
.
Java code | ClassMaker code |
for (x=1; n>0; --n) { x = x * n; } |
For(Set("x", Literal(1))).While(GT(Get("n"), Literal(0))).Step(Dec("n")); Eval(Set("x", Mult(Get("x"), Get("n")))); EndFor(); |
Break & Continue
The usual way to shortcut evaluation in the middle of a loop in java is to use a break
or continue
statement. The equivalents in ClassMaker
are named similarly.
public void Break() throws ClassMakerException public void Continue() throws ClassMakerException
The While
clause in a loop is optional; a break
can be used instead. The following
code sums values up to n
, the second version excludes multiples of 2.
Java code | ClassMaker code |
// Sum all values up to n. x = 0; while (true) { if (n<=0) { break; } x = x + n; --n; } |
Eval(Set("x", Literal(0))); Loop(); If(LE(Get("n"), Literal(0))); Break(); EndIf(); Eval(Set("x", Add(Get("x"), Get("n")))); Eval(Dec("n")); EndLoop(); |
// Sum all values up to n, except multiples of 2 x = 0; while (true) { y = n--; if (y<=0) { break; } if ((y % 2) == 0) { continue; } x = x + y; } |
Eval(Set("x", Literal(0))); Loop(); Eval(Set("y", PostDec("n"))); If(LE(Get("y"), Literal(0))); Break(); EndIf(); If(EQ(Rem(Get("y"), Literal(2)), Literal(0))); Continue(); EndIf(); Eval(Set("x", Add(Get("x"), Get("y")))); EndLoop(); |
Switch
ClassMaker
provides the following methods to support the switch
statement.
public Labelled Switch(Type switchType) throws ClassMakerException; public void Case(int key) throws ClassMakerException; public void Break() throws ClassMakerException public void Break(String label) throws ClassMakerException public void Default() throws ClassMakerException; public void EndSwitch() throws ClassMakerException;
The Case(int key)
method will accept an int
, char
, short
or byte
type.
ClassMaker
will generate different byte-code for the switch depending upon whether the keys
are contiguous or non-contiguous. It will generate a table-switch in the former situation or a
lookup-switch in the latter.
Java code | ClassMaker code |
y = 0; switch (x) { case 0: y = 1; break; case 4: y = 2; break; case 2: y = 3; break; case 6: y = 4; break; default: y = 0; break; } |
Set("y", Literal(0)); Switch(Get("x")); { Case(0); Set("y", Literal(1)); Break(); Case(4); Set("y", Literal(3)); Break(); Case(2); Set("y", Literal(2)); Break(); Case(6); Set("y", Literal(4)); Break(); Default(); Set("y", Literal(0)); Break(); } EndSwitch(); |
Try catch finally
ClassMaker
provides the following methods to perform exception handling.
public Labelled Try(); public void Catch(Class javaClass, String name) throws ClassMakerException; public void Catch(String exceptionName, String name) public void Finally() throws ClassMakerException; public void EndTry() throws ClassMakerException;
There are two versions of the Catch
method. You will use the version that
takes a reflection Class
most of the time. The version that takes a
!String is necessary when you are catching an exception class
that you are generating at runtime.
The generated code in the Finally
clause is always executed, as you would expect.
The code is put in a subroutine and the subroutine is invoked:
Try
block completes normallyCatch
clause processes an exceptionBreak
, Continue
or Return
methods are calledJava code | ClassMaker code |
try { x = func.unary(x); } catch (FileNotFoundException ex1) { x = 10000; } catch (IllegalArgumentException ex1) { x = 20000; } finally { x = x + 100; } |
Try(); { Eval(Set("x", Call(Get("func"), "unary", Push(Get("x"))))); } Catch(FileNotFoundException.class, "ex1"); { Eval(Set("x", Literal(10000))); } Catch(IllegalArgumentException.class, "ex2"); { Eval(Set("x", Literal(20000))); } Finally() { Eval(Set("x", Add(Get("x"), Literal(100)))); } EndTry(); |
Labelled Break & Continue
ClassMaker provides the following interface and methods to support labelled Break and Continue.
public interface Labelled { void setLabel(String label); String getLabel(); } public void Break(String label) throws ClassMakerException public void Continue(String label) throws ClassMakerException
The Labelled
interface is returned by all !ClassMaker statements to allow
them to be labelled. It is then possible to Break
to the labelled
statement. Labelled loops can also be the target of a Continue
method.
Statements may be labelled as follows.
Begin().setLabel("HERE"); If(<cond>).setLabel("THERE"); Loop().setLabel("LOOP"); For(<expr>).While(<cond>).Step(<expr>).setLabel("FORLOOP"); Switch().setLabel("EXIT"); Try().setLabel("TRYING");
The following example demonstrates several of these uses.
Java code | ClassMaker code |
outer: { loop: for (j=1; j<=3; j++) { switch (i) { case 1: break; case 2: continue; case 3: break loop; case 4: continue loop; case 5: break outer; } n++; } } |
Begin().setLabel("outer"); For(Set("j", Literal(1))).While(LE(Get("j"), Literal(3))).Step(Inc("j")).setLabel("loop"); Switch(Get("i")); Case(1); Break(); Case(2); Continue(); Case(3); Break("loop"); Case(4); Continue("loop"); Case(5); Break("outer"); EndSwitch(); Eval(Inc("n")); EndFor(); End(); |