# Control Statements in Nickle

## Simple statements

    expr;

    ; /* null statement */

    { statement ... }

The simplest statement is merely an expression terminated by a semicolon; the expression is evaluated. A semicolon by itself is allowed but does nothing. One or more statements may be grouped inside curly braces to form one compound statement; each is executed in order. Any statements may compose the statement list, including control statements and other curly-bracketed lists.

## Conditionals

    if ( expr ) statement

    else statement

`if` is used to execute a section of code only under some condition: If `expr` is true, `statement` is executed; otherwise control skips over it. For example:

    if ( x == 0 )
            printf ( "x is zero.\n" );

In this case, the message will be printed only if `x` is zero.

`else` allows for a choice if the condition fails. It executes its `statement` if the most recent `if` or `twixt` (see below) did not. For example,

    if ( x == 0 )
            printf ( "x is zero.\n" );
    else
            printf ( "x is not zero.\n" );

More than one option may be presented by nesting further 'if's in 'else' statements like this:

    if ( x == 0 )
            printf ( "x is zero.\n" );
    else if ( x < 0 )
            printf ( "x is negative.\n" );
    else
            printf ( "x is positive.\n" );

## Twixt

    twixt ( expr; expr ) statement

Ensures that the the first `expr` will always have been evaluated whenever control flow passes into any part of `statement` and ensures that the second `expr` will be evaluated anytime control flow passes out of `statement`. That order is gauranteed. If a `long_jmp` target is inside `statement`, the first `expr` will be executed before control passes to the target. If `statement` throws an exception or `long_jmp`s out of the `twixt`, the second `expr` will be evaluated. Thus, `twixt` is useful in locked operations where the statement should only be executed under a lock and that lock must be released afterwards.

    twixt ( get_lock ( ); release_lock ( ) )
            locked_operation ( );

## Switch

    switch ( expr ) { case expr: statement-list ... default: statement-list }

Control jumps to the first `case` whose `expr` evaluates to the same value as the `expr` at the top. Unlike in C, these values do not have to be integers, or even constant. The optional case `default` matches any value. If nothing is matched and there is no `default`, control skips the `switch` entirely. This example prints out a number to the screen, replacing it by a letter as though it were a poker card:

    switch ( x ) {
            case 1:
                    printf ( "A\n" );       /* ace */
                    break;
            case 11:
                    printf ( "J\n" );       /* jack */
                    break;
            case 12:
                    printf ( "Q\n" );       /* queen */
                    break;
            case 13:
                    printf ( "K\n" );       /* king */
                    break;
            default:
                    printf ( "%d\n", x );   /* numeric */
                    break;
    }

Notice the `break`s in the example. Once control jumps to the matching case, it continues normally: Upon exhausting that `statement-list`, it does not jump out of the `switch`; it continues through the subsequent statement lists. Here is an example of this 'falling through':

    int x = 3;

    switch ( sign ( x ) ) {
            case -1:
                    printf ( "x is negative.\n" );
            case 1:
                    printf ( "x is positive.\n" );
            default:
                    printf ( "x is zero.\n" );
    }

This prints:

    x is positive.
    x is zero.

Falling through may be desirable if several cases are treated similarly; however, it should be used sparingly and probably commented so it is clear you are doing it on purpose. This is a difficult error to catch.

## Union switch

    union switch ( union ) { case name: statement-list ... default: statement-list }

`union switch` is similar to `switch`. It matches its `case`s based on what name currently applies to the union's value. As always, `default` matches everything. The following example chooses the best way to print the union:

    union {
            int a;
            string b;
    } u;

    u.b = "hello";

    union switch ( u ) {
            case a:
                    printf ( "%d\n", u.a );
                    break;
            case b:
                    printf ( "%s\n", u.b );
                    break;
    }

In this case, it prints 'hello'.

An additional name may follow that of a case; the union's value will be available inside the case by that name. The switch above could have been written:

    union switch ( u ) {
            case a num:
                    printf ( "%d\n", num );
                    break;
            case b str:
                    printf ( "%s\n", str );
                    break;
    }

## Loops

    while ( expr ) statement

    do statement while ( expr )

    for ( expr; expr; expr ) statement

`while` executes `statement` repeatedly as long as `expr` is true. Control continues outside the loop when `expression` becomes false. For example:

    int x = 0;
    while ( x < 10 ) {
            printf ( "%d\n", x );
            ++x;
    }

This prints the numbers from zero to nine.

`do-while` is like `while`, but tests the condition after each iteration rather than before. Thus, it is garaunteed to execute at least once. It is often used in input while testing for end-of-file:

    file f = File::open ( "test", "r" );

    do {
            printf ( "%s\n", File::fgets ( f ) );
    } while ( ! end ( f ) );

    close ( f );

`for` begins by evaluating the first `expr`, which often initializes a counter variable; since declarations are expressions in Nickle, they may be used here and the counter will be local to the loop. Then it executes `statement` as long as the second `expr` is true, like `while`. After each iteration, the third `expr` is evaluated, which usually increments or decrements the counter variable. The `while` example above can also be written as the following `for` loop:

    for ( int x = 0; x < 10; ++x )
            printf ( "%d\n", x );

## Flow control

    continue

    break

    return expr

`continue` restarts the nearest surrounding `do-while`, `while`, or `for` loop by jumping directly to the conditional test. The iterative statement of a `for` loop will be evaluated first.

`break` leaves the nearest surrounding `do-while`, `while`, `for`, or `switch` statement by jumping to its end. The iterative statement of a `for` loop will not be evaluated.

`return` returns from the nearest surrounding function with value `expr`.