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
loops
to generate very efficient code: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