Statements
Statements largely work like in C, but with some additions.
Expression blocks
Expression blocks (delimited using {| |}
) are compound statements that opens their own function scope.
Jumps cannot be done into or out of a function block, and return
exits the block, rather than the function as a whole.
The function below prints World!
fn void test(){ int a = 0; {| if (!a) return; io::printf("Hello "); return; |}; io::printf("World!\n");}
Expression blocks may also return values:
fn void test(int x){ int a = {| if (x > 0) return x * 2; if (x == 0) return 100; return -x; |}; io::printfn("The result was %d", a);}
Labelled break and continue
Labelled break
and continue
lets you break out of an outer scope. Labels can be put on if
,
switch
, while
and do
statements.
fn void test(int i){ if FOO: (i > 0) { while (1) { io::printfn("%d", i); // Break out of the top if statement. if (i++ > 10) break FOO; } }}
Do-without-while
Do-while statements can skip the ending while
. In that case it acts as if the while
was while(0)
:
do{ io::printn("FOO");} while (0);
// Equivalent to the above.do{ io::printn("FOO");};
Nextcase and labelled nextcase
The nextcase
statement is used in switch
and if-catch
to jump to the next statement:
switch (i){ case 1: doSomething(); nextcase; // Jumps to case 2 case 2: doSomethingElse();}
It’s also possible to use nextcase
with an expression, to jump to an arbitrary case or between labeled switch statements:
switch MAIN: (enum_var) case FOO: switch (i) { case 1: doSomething(); nextcase 3; // Jump to case 3 case 2: doSomethingElse(); case 3: nextcase rand(); // Jump to random case default: io::printn("Ended"); nextcase MAIN: BAR; // Jump to outer (MAIN) switch } case BAR: io::printn("BAR"); default: break;}
Which can be used as structured goto
when creating state machines.
Switch cases with runtime evaluation
It’s possible to use switch
as an enhanced if-else chain:
switch (true){ case x < 0: xless(); case x > 0: xgreater(); default: xequals();}
The above would be equivalent to writing:
if (x < 0){ xless();}else if (x > 0){ xgreater();}else{ xequals();}
Note that because of this, the first match is always picked. Consider:
switch (true){ case x > 0: foo(); case x > 2: bar();}
Because of the evaluation order, only foo()
will be invoked for x > 0, even when x is greater than 2.
It’s also possible to omit the conditional after switch
. In that case it is implicitly assumed to be same as
writing (true)
switch{ case foo() > 0: bar(); case test() == 1: baz();}
Jumptable switches with “@jump”
Regular switch statements with only enum or integer cases may use the @jump
attribute. This attribute ensures that the switch is implemented as
a jump using a jumptable. In C this is possible to do manually using labels and
calculated gotos which are extensions available in GCC/Clang.
The behaviour of the switch itself does not change with a jumptable,
but some restrictions will apply. Typically used for situations
like bytecode interpreters, it might perform worse
or better than a regular switch depending on the situation.
nextcase
statements will also use jumptable dispatch when
@jump
is used.