Statements
Statements are the traditional building blocks of imperative languages. As a streaming language, SPL does not need statements most of the time, but they are permitted inside operator logic and function definitions as a convenience.
SPL's assortment of statements is deliberately simple; this simplicity makes it easy to optimize and easy to map to target languages, leading to better performance and portability.
A variable definition consists of an optional mutable modifier and a type, followed by a comma-separated list of variable identifiers with optional initializer expressions, followed by a semicolon:
varDef ::= ‘mutable'? type ( ID ( ‘=' expr )? )+, ‘;'
An example variable definition is mutable int32 i=2, j=3;. An immutable variable is deep-immutable: even if it has a composite value, all parts of that value are immutable too, recursively. The variable definition syntax is similar to C or Java™, except that the type does not get tangled up with the variable. For example, SPL does not have variable definitions like int32 x,y[],z;. Immutable local variables (without mutable modifier) must be initialized upon declaration. All variables must be initialized before use.
A block consists of zero or more statements or type definitions, surrounded by curly braces:
blockStmt ::= ‘{' ( stmt | standAloneTypeDef )* ‘}'
An example block is {type T=int32; T i=0; foo(i,2);}. Local types and variables that are defined in a block are in scope for the entire block. Blocks are often used as bodies for control statements like if/while/for, or as function bodies.
An expression statement consists of an expression followed by a semicolon:
exprStmt ::= expr ‘;'
An example expression statement is foo(i,2);. Obviously, the purpose of an expression statement is its side-effect. The only operators that have non-error side-effects are assignments, certain function calls, and increment/decrement (++/−−) operators.
An if statement can have an optional else clause:
ifStmt ::= ‘if' ‘(' expr ‘)' stmt ( ‘else' stmt )?
Dangling else is resolved to the innermost if; you can override this with blocks. SPL does not have a C-style switch statement.
A for statement loops over the elements of a string, list, set, or map:
forStmt ::= ‘for' ‘(' typeID ‘in' expr ‘)' stmt
SPL's for loops are similar to for (type ID : expr) loops in Java 5, but use the Python-style in instead of the colon (:). SPL does not have a C-style 3-part for loop, and the iterated-over collection becomes immutable during the loop. This means that SPL for loops are countable loops, which are less error-prone and permit more optimization opportunities than traditional loops. A for loop over a string or list iterates over the elements or characters in index order. A for loop over a set or map has an implementation-specific iteration order. In a for loop over a map, the loop variable ID iterates over the keys; a common idiom is to retrieve the associated value from the collection in the loop body.
for (int32 i in range(listVar)) // i is set to 0..size(listVar)-1
for (int32 i in range(limit)) // i is set to 0..limit-1
for (int32 i in range(start, limit)) // i is set to start..limit-1
for (int32 i in range(start, limit, step)) // i is set to start..limit-1 (by step).
// step can be positive or negative.
A while statement looks just like in C or Java:
whileStmt ::= ‘while' ‘(' expr ‘)' stmt
A break statement abruptly exits a while or for loop:
breakStmt ::= ‘break' ‘;'
A continue statement abruptly jumps to the next iteration of a while or for loop:
continueStmt ::= ‘continue' ‘;'
A return statement abruptly exits a function, optionally returning a value:
returnStmt ::= ‘return' expr? ‘;'
To summarize, SPL supports the following assortment of statements:
stmt ::= varDef | blockStmt | exprStmt | ifStmt | forStmt
| whileStmt | breakStmt | continueStmt | returnStmt