Statements
Blocks
block :: ((lvar-def | statement) br)* statement :: expression | assignment-stmt | operator-assignment-stmt | if-stmt | switch-stmt | while-stmt | repeat-stmt | for-stmt | break-stmt | return-stmt | try-stmt | raise-stmt
A block contains any number of statements and local variable definitions. It is the basic building block of functions, methods and compound statements. A block is evaluated by evaluating its statements sequentially. If one of the statements either raises an exception or is a break or return statement, the execution of the block terminates and the rest of the statements are not evaluated.
Expression statement
Any expression is also a valid statement. An expression statement simply evaluates the expression and discards its result. Expression statements are typically used for calling functions or methods.
Assignment statement
assignment-stmt :: expression "=" expression
Assign the value of the expression on the right-hand side of the assignment operator to the lvalue on the left-hand side. The left-hand side must be a valid lvalue expression. Otherwise, a compile error is reported.
If the left expression is not an array constructor, assign the value of the expression like this:
- If the expression is a global or local variable reference, assign the value to that variable.
- If the expression is a member variable reference, call the setter method related to the referred member variable of the base object, with the value of the right-hand side expression as the argument.
- If the expression is a subscript expression, call the _set method of the subscripted object, with the value of the bracketed expression as the first argument and the value of the right-hand side expression as the second argument.
- If the expression is a superclass member variable reference (see Superclass member references), call the relevant setter method defined in the superclass. This is performed in a similar fashion as ordinary setter calls (see above).
- In a create method only: If the expression refers to an explicit member constant defined in the same class as the method, assign the value directly to the value slot associated with the constant.
If the left expression is a tuple or array constructor, the assignment is a multi-assignment. The right expression must evaluate to a tuple or array with the same number of items as in the lvalue, or otherwise a std::ValueError or std::TypeError exception will be raised. Each item expression in the left side will be assigned a value from the right side value, the first item getting the first array item, the second the second one, etc. These assignments are performed according to the rules in the above list.
If the setter or the _set method mentioned above is not defined, a std::MemberError exception will raised when evaluating the assignment statement.
Operator assignment statement
operator-assignment-stmt :: expression operator-assignment expression operator-assignment :: "+=" | "-=" | "*=" | "/=" | "**="
Evaluate the value of the expression on the left-hand side of the operator assignment token and the value of the right-hand-side expression. Evaluate the binary operation suggested by the operator assignment token, with the value of the left expression as the left operand, and the value of the right expression as the right operand, and assign the resulting value to the left expression, which is now interpreted as an lvalue. The subexpressions of the left expression are evaluated only once during the evaluation of the statement, however.
The semantics of the assignment are essentially identical to the assignment statement, but the left expression must not be an array constructor. The semantics of the binary operation are described in section Binary operations.
Local variable definition
lvar-def :: "var" id-list [ "=" expression ]
Define one or more local variables. If the optional initialization part is missing, the variables will be initialized to refer to the nil object. Otherwise, the initialization expression is evaluated and its results are assigned to the variables. The semantics are similar to the assignment statement: If there is a single variable, the result of the expression is assigned to that variable. If there are multiple variables, the result should be an Array object with as many items as there are variables. The array items will be assigned sequentially to the variables. If the result is not an Array object or contains a wrong number of items, an exception will be raised.
The local variables are visible and can be accessed only in the block that contains the definition and only in statements that follow the definition.
If statement
if-stmt :: "if" expression br block ( "elif" expression br block )* [ "else" br block ] "end"
An if statement tests the truth value of a condition expression or expressions, and executes at most a single block related to a true condition (or the else block if no conditions are true). All the condition expressions are evaluated in a boolean context.
First, the expression after if is evaluated. If it is true, the first block will be evaluated. Otherwise, if there are elif conditions, they are evaluated sequentially until one of them evaluates to true or until they have all been evaluated. If one of them evaluated to true, the block following that expression will be evaluated. If no condition evaluates to true and the else part is provided, the block in the else part will be evaluated. Otherwise, no blocks will be evaluated. After evaluating a block the evaluation of the statement is complete.
If any expression causes an exception to be raised, or any expression evaluates to a non-boolean value, the evaluation of the statement will be terminated.
Switch statement
switch-stmt :: "switch" expression br ( "case" expression-list br block )+ [ "else" br block ] "end" expression-list :: single-expression ("," single-expression)*
Switch statement first evaluates the expression after the switch keyword. Then, the expressions after the case keywords are evaluated sequentially. After evaluating each expression, the value of the expression is compared for equality with the value of the switch expression. If they compare equal, the block after the case expression is evaluated, and the statement finishes.
If no case expression is equal to the switch expression, the block following the else keyword is evaluated, if it exists. Otherwise, no block will be evaluated.
Loops
Loops are used to perform a block (the body of the loop) repeatedly until some condition is fulfilled.
Any loop will be terminated if an exception is raised within the body (and not caught within the body) or while evaluating the conditional expression, or if a break or return statement is used to break out of the loop.
While statement
while-stmt :: "while" expression br block "end"
The while statement is evaluated by evaluating the expression in a boolean context, and if the expression evaluates to True, the body of the statement is evaluated. The evaluation of the loop continues by evaluating the expression and body until the expression evaluates to False, after which the evaluation of the statement is finished.
Repeat statement
repeat-stmt :: "repeat" br block "until" expression
The repeat statement is evaluated by evaluating the body and then evaluating the expression in a boolean context. If the expression evaluates to True, the loop terminates. If it evaluates to False, evaluation of the loop continues by evaluating the body and the expression repeatedly until the expression evaluates to True.
For statement
for-stmt :: "for" id-list "in" expression br block "end"
The for statement is evaluated as follows:
- Evaluate the expression after in.
- Call the method iterator of the expression result value with no arguments. The result of the method call is the iterator object, and a reference to it is stored during the execution of the loop.
- Call the method hasNext of the iterator with no arguments in a boolean context. If the result is False, end the loop. Otherwise, continue to the next step.
- Call the method next of the iterator with no arguments. Assign the return value to the variable list located before in, using the semantics described above in Local variable definition. The variables in the list are visible only in the loop body. Unlike other local variables, they cannot be used as lvalues, i.e. they behave like constants.
- Evaluate the body of the loop.
- Return to step 3.
Break statement
break-stmt :: "break"
The break statements jumps out of the innermost enclosing for, while or repeat loop in the source file. After evaluation, execution continues in the next statement or expression to be evaluated after the loop statement, unless there are any try-finally statements between break and the loop. In the latter case, the finally block or blocks are evaluated before execution continues.
It is an error to use break outside a loop. You cannot break out of a loop defined in another, enclosing function.
Return statement
return-stmt :: "return" [ expression ]
Return from a function or method. If the expression is provided, evaluate the expression before returning and pass it to the caller as the return value of the function or method. If the expression is omitted, nil is provided as the return value.
In the presence of nested function definitions, this statement always returns from the innermost function or method that contains the statement. It is an error to use return outside a function.
If the return statement is within a try-finally block, the finally block or blocks will be evaluated before returning from the function.
Try statement
try-stmt :: "try" br block ( ("except" [ id "is" ] gvar br block)+ | "finally" br block ) "end"
The try statement actually refers to two different statements: try-except and try-finally. They are both used for dealing with raised exceptions. The try variant is determined by the keyword following the first block in the statement (except or finally).
Try-except
The try-except statement contains one or more except blocks after the statement body. Each except block contains a global variable reference that must refer to a class definition (a type), a block, and optionally an identifier before the is keyword that defines a local variable. The identifier, if present, must be a valid name for a local variable at that context.
The try-except statement evaluates the block after the try keyword. If no exception propagating outside the block is raised within the block, the evaluation of the statement ends there. Otherwise, the except blocks are consulted in the order they appear in the statement, and the type of the uncaught exception object is compared against the type references after each except keyword. If the exception object belongs to one of the types, the block after the except keyword is evaluated, and after this the statement evaluation is finished. In this case, the exception was caught, and the exception object is no longer active. If no types match, the exception will be propagated further as if the try statement did not exist.
If the except block that matches the exception contains a local variable definition (before is), the exception object will be assigned to that local variable before evaluating the block.
Try-finally
The try-finally statement contains an additional finally block after the finally keyword. The block after the try keyword is evaluated, as in the try-except variant. If no uncaught exception was raised within the block, the finally block will then be evaluated and the evaluation of the statement ends there. If an uncaught exception was raised, the finally block will be evaluated as well, but the original exception object will be raised again after evaluating the finally block, provided that no uncaught exception was raised within the finally block.
If a break statement is used to leave the body of the try-finally statement, the finally block will be evaluated before execution is continued normally outside the innermost loop.
Similarly, a return statement within the body causes the finally block to be evaluated before returning from the function or method.
Raise statement
raise-stmt :: "raise" expression
First, the expression is evaluated. It should evaluate to an instance of std::Exception or any subtype of std::Exception. In that case, the value of the expression will be raised as an exception. Otherwise if the type of the expression is invalid, a std::TypeError exception will be raised.