Misty Programming Language:

Statements

The body of a function contains zero or more statements. This section describes the statement types.

statement
=> augment_statement
=> assignment_statement
=> break_statement
=> do_statement
=> for_statement
=> if_statement
=> invocation_statement
=> raise_statement
=> return_statement
=> while_statement

The augment statement

augment_statement
=> lvalue augmentation
=> self augmentation

lvalue
=> name [(subscription | invocation)* subscription]

The augment statement is a special case of the augment expression used as a statement. It can assign many values to an object at once.

Example:

$ {
    first : 'Moe'
    last : 'Howard'
}


# same result as
#    $.first : 'Moe'
#    $.last : 'Howard'

The assignment statement

assignment_statement
=> (lvalue ':')+ expression
=> lvalue ('+:' | '-:' | '~:' | '~~~:') expression
=> self subscription (':' | '+:' | '-:' | '~:' | '~~~:') expression

An assignment statement is of the form

lvalue   assignment_operator   expression

An lvalue is a variable name or parameter name or a dot expression or a subscript expression. An lvalue cannot be a literal or any other kind of expression. If the name was declared with define then a compile time error will result.

name
name.member
name[subscript]

The $ operator allows a method to modify its object even if the reference to the object is fixed. See Functions.

$.member : 2    # Change the value of the object's member property to 2.
var self : $    # Capture the self reference.
self.member : 3 # Throw a fix exception if the object is fixed.

The assignment operators are

:  +:   -:   ~:   ~~~:

The assignment operators cannot be used in expressions. They can only be used in assignment statements.

:

Normal assignment. These can be cascaded to assign a value of an expression to multiple lvalues.

In some programming languages, this operation has been associated with the = operator. In Misty, : is used for assignment, and = is used exclusively for comparison.

Example:

i : 5                # i is 5
x : y : z : 0      # x is 0 and y is 0 and z is 0
a[5] : temp : []    # a[5] and temp are the same empty array

+:

Increment. The lvalue is replaced by the sum of the lvalue and the value of the expression.

Example:

i : 2
i +: 1    # i is 3

-:

Decrement. The lvalue is replaced by the difference of the lvalue and the value of the expression.

Example:

i : 8
i -: 2    # i is 6

~:

Concatenate. The lvalue and the value of the expression are both converted to texts (using the ~ prefix operator) and then concatenated together, replacing the lvalue.

Example:

price : '$'
price ~: 3 + 4    # price is '$7' 

~~~:

Concatenate with space. The lvalue and the value of the expression are both converted to texts (using the ~ prefix operator) and then concatenated together with a space between them, replacing the lvalue.

Example:

price : '$'
price ~~~: 3 + 4    # price is '$ 7' 

The break statement

break_statement => 'break' [label]

The break statement is used to terminate loops. It can be used with the do, for, and while statements. It causes execution to continue with the statement following the od that closes the loop. The break can optionally be followed by a loop label, making it possible to break out of outer loops when loops are nested. The loop label must match a loop that contains the break.

Example:

variable i, j
variable found : false
outer : for i to n do
    for j to m do
        if a[i][j] = target then
            found : true
            break outer
        fi
    od
od 

The define or def statement

define_statement => ('define' | 'def') name (':' expression | parameter_list body)

The define statement defines a read-only variable within the current function. The variable is read-only, but the value it contains may be mutable. Names that are defined with the define statement cannot be changed with the assignment operators. If the value is mutable, then the value's members or elements can be changed with assignment operators.

The define statement cannot be used within a loop or if statement.

The define statement can be used to define functions (see Functions). Also see the variable statement below.

Example:

define pi : 3.1415926
define stack : []
stack.push(pi)    # Push pi onto the stack.
                  # stack is [3.1415926] # stack has been modified
stack : []       # Illegal statement, stack cannot be replaced.

define triple(n) {
    return n * 3
}

The do statement

do_statement => [label ':'] loop_body

loop_body => 'do' statement+ 'od'

label => name

The do statement defines a loop. Like all loop statements, it is bracketed with od. The body of the loop can contain one or more statements. It cannot contain a define or variable statement. The running of the loop must be terminated explicitly with a break, return, or raise statement.

Example:

variable a : []
do
    a.push(expression())
    if token.id = ')' then
        break
    fi
    advance(',')
od

The for statement

for_statement => [label ':'] 'for' induction for_clause loop_body

for_clause
=> 'in' expression
=> ['from' expression] ('to' | 'thru') expression ['by' expression]

induction => name

The for statement is like the do statement, but provides a great deal of convenience for writing common loops. The for statement makes use of an induction variable that changes on each iteration of the loop. The induction variable must have been declared as a variable in the same function as the for statement. The induction variable cannot be assigned to within the body of the loop. If the loop terminates early because of break, then the induction variable will retain its value as of the time of the break. Otherwise, after the loop completes its final interation, the induction variable will be null. The body cannot contain a define or variable statement.

for to

The for to statement makes it easy to step through a sequence of numbers.

for i from f to t by b do
    ...
od

The sample above is equivalent to

i : f
var temp_to : t
var temp_by : b
do
    if i >= temp_to then
        break
    fi
    ...
    i +: temp_by
od

The from part is optional. The default is 0.

The by part is optional. The default is 1. It must be greater than zero.

Notice that the loop will stop before the index variable reaches the to value. The to value and by value are only computed once, at the beginning of the loop. (This is different than the practice in the C for statement, which can recalculate the limit and increment on every iteration.)

Example:

variable counter
variable digits : ''
for counter to 10 do
    digits ~: counter
od
    # digits is '0123456789'

for thru

The for thru statement is similar to the for to statement. The difference is in the test that breaks the loop.

for i from f thru t by b do
    ...
od

is equivalent to

var i : f
temp_thru : t
temp_by : b
do
    if i > temp_thru then
        break
    fi
    ...
    i +: temp_by
od

The from part is optional; the default is 0. The by part is optional; the default is 1.

The index variable must be local to the current function.

Notice that the loop will stop when the index variable exceeds the thru value.

Example:

variable counter
variable result : ''
for counter from 1 thru 10 do
    result ~~~: counter
od
# result is '1 2 3 4 5 6 7 8 9 10'
result : []
for i from 0 to 10 by 3 do
    result.append(i)
od
    # result is [0, 3, 6, 9]

for in

The for in statement loops through the values of an array or a function.

label : for value in collection do
    ...
od

If the collection is an array, it loops on the range of subscripts contained in the array. If the collection is a function, then the function is called once per iteration and the value it returns is assigned to the loop variable. The loop ends when the function returns null. If the collection is neither an array nor a function, then a 'type' exception is raised.

It is equivalent to

if collection is array then

    temp_value : null
    temp_length : length collection
    variable temp_counter : 0

    do
        if temp_counter >= temp_length then
            break
        fi
        value : collection[temp_counter]
        ...
        temp_counter +: 1
    od
elif collection is function then
    function () {
        do
            temp_value : collection()
            if temp_value is null then
                exit
            fi
            value : temp_value
            ...
        od
    exception e
        if e = 'done' then
            return
        else
            raise e
        fi
    }()
else
    raise 'type'
fi

The if statement

if_statement => 'if' expression consequence
('elif' expression consequence)*
['else' statement*]
'fi'

consequence
=> 'then' statement*
=> case+

case => 'case' expression (',' expression)* 'then' statement*

The if statement allows for the conditional execution of statements.

if expression
case value1, value2 then
    ...matching...
else
    ...not matching...
fi

The case part can have one or more expressions, separated by commas. If any of the expressions are eq (equal) to the first expression, then the following statements are executed. Multiple cases can be listed. If no cases match, then the else statements are executed. The else part is optional.

Example:

if first_name
case 'Curly', 'Moe', 'Shemp' then
    last_name : 'Howard'
case 'Larry' then
    last_name : 'Fine'
else
    last_name : '(unknown)'
fi

Unlike the switch statement in some languages, the break statement is not needed to prevent fallthru. The break statement is only used to break out of loops.

If there is a single case, the if can be simplified. If the first expression is falsy (false, null, or the empty text) then the else statements are executed. Otherwise, if the first expression is truthy then the then statements are executed.

Example:

if d = 0 then
    raise 'range'
else
    return int(q / d)
fi

The else part can be replaced with an elif part. This makes it possible to have alternatives without deeply nested ifs.

Example:

if char list[k].op = 'j' then
list[k].yz -: 1
elif list[k].op = 'opx' then
list[k].yz -: 1
k +: 1
fi

The if statement creates forks in the control flow of a function. An if statement cannot contain variable and define statements.

The invocation statement

invocation_statement
=> lvalue invocation
=> self subscription+ invocation (subscription* invocation)*

The invocation statement is used to call a function or method and discard its return value. See Functions.

The raise statement

raise_statement => 'raise' (text | exception_constant)

The raise statement raises an exception, sending control to an exception handler. The operand must be a non-empty text (the type of the exception).

The raise statement causes control to go to the exception part of the function. If control is already in the exception part, or if there is no exception part, then control goes to the most recent function in the calling chain that has an exception part. See Functions.

The return statement

return_statement => 'return' [expression]

The return statement provides for the normal exit of a function and the specification of its return value. If the function does not create any function objects and if the function does not have an exception handler, and if the expression is a function invocation, then the tail recursion optimization will be performed. This can have a significant performance advantage.

Example:

define double(number) {
    return number * 2
}

The variable or var statement

variable_statement => ('variable' | 'var') name (':' expression)

The variable statement defines a name within the current function. That name can be used to hold any value. If an initial value is not specified, then the initial value is null. It differs from the define statement in that the value can be replaced by an assignment operator. Thevariable statement cannot be placed within a loop or if statement.

Example:

variable total : 0
variable i
variable j
variable k

The while statement

while_statement => [label ':'] 'while' expression loop_body

The while statement is a slightly more convenient form of do statement. Testing at the top, the loop continues as long as the condition is true. The body cannot contain a define or variable statement.

label : while condition do
    ...
od

It is equivalent to

label : do
    if not condition then
        break
    fi
    ...
od