Grammar overview

Here is the SPL grammar syntax, with references to the sections that contain the semantics.

For more information, see Lexical syntax and Grammar notation.

The compilation unit is the start symbol of the SPL grammar.

compilationUnit   ::= namespace? useDirective*  # Compile-time entities
                      ( compositeDef | functionDef | standAloneTypeDef )*
namespace         ::= ‘namespace' ID+. ‘;'
useDirective      ::= ‘use' ID+. ‘::' ( ‘*' | ID ) ‘;apos;
Composite operators are defined at the top level in a namespace.
compositeDef    ::= compositeHead compositeBody # Composite operators
compositeHead   ::= ‘public'?composite' ID ( ‘(' compositeInOut+; ‘)' )?
compositeInOut  ::= ( ‘input' | ‘output' ) ( streamType? ID )+,
streamType      ::= ‘stream' ‘<' tupleBody ‘>'
compositeBody   ::= ‘{'
                    ( ‘param' compositeFormal+ )?
                    ( ‘type' compositeTypeDef+ )?
                    ( ‘graph' opInvoke+        )?
                    ( ‘config' configuration+  )?}'
compositeFormal ::= expressionMode ID ( ‘:' opActual )? ‘; # Operator parameter modes
opInvokeActual  ::= ID ‘:' opActual ‘;'
opActual        ::= type | expr+,
configuration   ::= ID ‘:' expr+, ‘;'  # Config clause, Config clause
Streams are defined in a composite operator's graph clause.
opInvoke        ::= opInvokeHead opInvokeBody  # Operator invocations
opInvokeHead    ::= opOutputs ( ‘as' ID )? ‘=' ID opInputs  # Operator invocation head
opOutputs       ::= opOutput | ‘(' opOutput*; ‘)'
opOutput        ::= streamType ID ( ‘as' ID )?
opInputs        ::= ‘(' portInputs*; ‘)'
portInputs      ::= streamType? ID+, ( ‘as' ID )?
opInvokeBody    ::= ‘{'  # Operator invocations
                    ( ‘logic' opInvokeLogic+ )?
                    ( ‘window' opInvokeWindow+ )?
                    ( ‘param' opInvokeActual+ )?
                    ( ‘output' opInvokeOutput+ )?
                    ( ‘config' configuration+ )?
                    ‘}'
opInvokeLogic   ::= opInvokeCode | opInvokeState  # Logic clause
opInvokeCode    ::= 'onProcess' ':' stmt
                    | ( 'onTuple' | 'onPunct' ) ID ':' stmt
opInvokeState   ::= ‘state' ‘:' ( varDef | ‘{' varDef+ ‘}' )
opInvokeWindow  ::= ID ‘:' expr+, ‘;'  # Window clause
opInvokeOutput  ::= ID ‘:' ( ID ‘=' expr )+, ‘;'  # Output clause
SPL functions are defined at the top level in a namespace.
functionDef      ::= functionHead blockStmt  # SPL functions
functionHead     ::= functionModifier* type ID ‘(' functionFormal*, ‘)'
functionModifier ::= ‘public' | ‘stateful'
functionFormal   ::= ‘mutable'? type ID
Native function prototype declarations come from XML files, not regular SPL files.
functionPrototype    ::= genericFormals functionModifier*  # Native functions
                        type ID ‘(' protoFormal*, ‘)'
genericFormals       ::= ( ‘<' typeFormal+, ‘>' )? ( ‘[' boundsFormal+, ‘]' )?
typeFormal           ::= typeFormalConstraint ID
typeFormalConstraint ::= ‘any' | ‘collection' | ‘complex' | ‘composite'
                       | ‘decimal' | ‘enum' | ‘float' | ‘floatingpoint'
                       | ‘integral' | ‘list' | ‘map' | ‘numeric'  
                       | ‘optional' | ‘ordered'  | ‘primitive' | ‘set' 
                       | ‘string' | ‘tuple'
boundsFormal         ::= ID
protoFormal          ::= formalModifier* type ID?
Imperative statements can appear in function bodies or the logic clause of an operator invocation.
stmt          ::= varDef | blockStmt | exprStmt  # Statements
                | ifStmt | forStmt | whileStmt
                | breakStmt | continueStmt | returnStmt
varDef        ::= ‘mutable'? type  ( ID ( ‘=' expr )? )+, ‘;'
blockStmt     ::= ‘{' ( stmt | standAloneTypeDef )*}'
exprStmt      ::= expr ‘;'
ifStmt        ::= ‘if' ‘(' expr ‘)' stmt ( ‘else' stmt )?
forStmt       ::= ‘for' ‘(' type ID ‘in' expr ‘)' stmt
whileStmt     ::= ‘while' ‘(' expr ‘)' stmt
breakStmt     ::= ‘break' ‘;'
continueStmt  ::= ‘continue' ‘;'
returnStmt    ::= ‘return' expr? ‘;'
Expressions can appear in many places in the grammar. For precedence and associativity, see Expression operators.
expr            ::= prefixExpr | infixExpr | postfixExpr
                  | conditionalExpr | ‘(' expr ‘)' | ID 
                  | literal  # Expression language
prefixExpr      ::= prefixOp expr
prefixOp        ::= ‘!' | ‘-' | ‘~' | ‘++' | ‘--'
infixExpr       ::= expr ( infixOp | mappedOp | assignOp ) expr
infixOp         ::= ‘+' | ‘-' | ‘*' | ‘/' | ‘%' | ‘<<' | ‘>>' | ‘&' | ‘ˆ' | ‘|'
                  | ‘&&' | ‘||' | ‘in' | ‘<' | ‘<=' | ‘>' | ‘>=' | ‘!=' | ‘==' | ‘?:'
mappedOp        ::= ‘.+' | ‘.-' | ‘.*' | ‘./' | ‘.%' | ‘.<<' | ‘.>>' | ‘.&'
                  | ‘.^' | ‘.|' | ‘.<' | ‘.<=' | ‘.>' | ‘.>=' | ‘.!=' | ‘.=='
assignOp        ::= ‘=' | ‘+=' | ‘-=' | ‘*=' | ‘/=' | ‘%=' | ‘<<=' | ‘>>='
                  | ‘&=' | ‘^=' | ‘|='
postfixExpr     ::= ID ‘(' expr*, ‘)'
                  | type ‘(' expr ‘)'
                  | expr ‘[' subscript ‘]'
                  | expr ‘.' ID
                  | expr postfixOp
subscript       ::= expr | ( expr? ‘:' expr? )
postfixOp       ::= ‘++' | ‘--' | ‘??' | ‘!'
conditionalExpr ::= expr ‘?' expr ‘:' expr
Literals are the highest-precedence expressions that denote values.
literal           ::= primitiveLiteral | listLiteral | setLiteral | mapLiteral 
                      | nullLiteral | tupleLiteral # Expression language
listLiteral       ::= ‘[' expr*, ‘]'  # Collections
setLiteral        ::= ‘{' expr*, ‘}'
mapLiteral        ::= ‘{' ( expr ‘:' expr )*, ‘}'
nullLiteral       ::= ‘null'  # Optional types
tupleLiteral      ::= ‘{' ( ID ‘=' expr)*, ‘}'  # Tuples
primitiveLiteral  ::= ‘true' | ‘false' | STRING | FLOAT | INT  # Primitive types;
Types are defined in a composite operator's type clause, or in a block, or at the top level.
standAloneTypeDef ::= ‘type' ID=' ( type | tupleBody ) ‘;'
compositeTypeDef  ::= ‘static'? ID=' ( type | tupleBody ) ‘;'  # Type definitions
expressionMode  ::= ‘attribute' | ‘expression' typeArgs?  # Operator parameter modes
                  | ‘function' | ‘operator' | ‘type'
type            ::= ID | ‘void' | primitiveType | compositeType  # Types
typeArgs        ::= ‘<' type+, ‘>'
typeDims        ::= ‘[' expr ‘]'
Primitive types are types without other types as arguments.
primitiveType   ::= ‘boolean'  # Primitive types
                  | ‘enum' ‘{' ID*, ‘}'
                  | ‘int8' | ‘int16' | ‘int32' | ‘int64' | ‘int128'
                  | ‘uint8' | ‘uint16' | ‘uint3'| ‘uint64' | ‘uint128'
                  | ‘float32' | ‘float64'
                  | ‘decimal32' | ‘decimal64' | ‘decimal128'
                  | ‘complex32' | ‘complex64'
                  | ‘timestamp'
                  | ‘blob'
                  | ‘rstring' typeDims?
                  | ‘ustring'
                  | ‘xml' ('<' "schemaURI" '>')?
Composite types are type constructors for composing new types out of other types.
compositeType   ::= tupleType  # Composite types
                 | ‘list' typeArgs typeDims?
                 | ‘map' typeArgs typeDims?
                 | ‘set' typeArgs typeDims?
                 | ‘optional' typeArgs
tupleType       ::= ‘tuple' ‘<' tupleBody ‘>'  # Tuples
tupleBody       ::= attributeDecl+,
                 | ( ID | tupleType )+,
attributeDecl   ::= type ID