§Tiro Reference Documentation
§Basics
Tiro accepts UTF-8 encoded source files as input. Source files must conform to the rules outlined in this document to form a valid program.
This section describes the lexical structure of tokens accepted by the language.
§Whitespace
Whitespace tokens consists of a sequence of characters having the Pattern_White_Space Unicode property (see (see Unicode® Standard Annex #31). Whitespace is not significant: its only use is to separate characters of adjacent tokens that would otherwise be parsed as a single token.
§Comments
Comments are used to annotate source code, but they have no meaning of their own. They are simply treated as whitespace.
- Comment
- LineComment | BlockComment
- LineComment
//
(~\n
)*- BlockComment
/*
(BlockComment | ~*/
*)**/
Line comments are introduced by //
and continue until the end of the line.
Block comments are delimited by /*
and */
and may be nested.
§Keywords
The following words have special meaning in the Tiro programming language:
assert | break | const | continue | defer |
else | export | false | for | func |
if | import | in | null | return |
true | var | while |
§Reserved keywords
The following keywords are reserved for future use:
as | catch | class | interface | is |
package | protocol | scope | struct | switch |
throw | try | yield |
§Identifiers
Identifiers are used to name items. They consist of one or more identifier characters as defined by the XID_Start and XID_Continue Unicode properties (see Unicode® Standard Annex #31). Keywords cannot be used as identifiers.
- Identifier
- KeywordOrIdentifierExcluding keywords
- KeywordOrIdentifier
- (XID_Start |
_
) XID_Continue*
§Number literals
- Integer
- DecInteger | BinInteger | OctInteger | HexInteger
- DecDigit
0
-9
- BinDigit
0
|1
- OctDigit
0
-7
- HexDigit
0
-9
|a
-f
|A
-F
§String literals
Strings are sequences of characters enclosed by matching quote characters ("
or '
).
Within a string, variables can be interpolated when prefixed with a $
sign and full expressions can be interpolated when enclosed within a
block started with ${
and closed with a }
sign.
- String
- StringDelimiter (PlainStringContent | EscapeSequence | InterpolatedValue)* StringDelimitermatches starting delimiter
- StringDelimiter
"
|'
- PlainStringContent
- ~(
\
|$
| StringDelimitermatches starting delimiter)*
§Escape sequences
- EscapeSequence
- EscapedCharacter | AsciiEscape | UnicodeEscape
- EscapedCharacter
\\
|\n
|\r
|\t
|\"
|\'
|\$
- UnicodeEscape
\u{
HexDigit+}
Escape sequences produce the following string content:
Escape Sequence | Production | |
---|---|---|
\\ | Literal \ | |
\n | Newline | |
\r | Carriage return | |
\t | Tabulator | |
\" | Literal " | |
\' | Literal ' | |
\$ | Literal $ | |
\x digits.. | A single byte | The numeric value of the two hex digits is produced as a byte (TODO: Must be valid utf-8?) |
\u{ digits.. } | A single unicode code point | The sequence of hex digits is interpreted as the value of a unicode code point. |
§Symbol literals
- Symbol
#
Identifier
§Grammar
This section describes higher level syntax constructions based on tokens.
§Items
- File
- Item*
- Item
export
? (ImportDecl;
| VarDecl;
| FuncDecl)
A Tiro source file is a sequence of Items.
An item containing the export
modifier will be exported from the current module.
Exported items are visible to other modules and may be imported.
§Imports
- ImportDecl
import
ImportPath (as
Identifier)?- ImportPath
- Identifier (
.
Identifier)*
An import
item imports the module referenced by the ImportPath and introduces it into the current scope.
The last Identifier in the ImportPath serves as the name of the imported reference by default.
A custom name may be provided by using the as
keyword.
§Variables
- Binding
- BindingPattern (
=
Expr)? - BindingPattern
- Identifier | TupleBindingPattern
- TupleBindingPattern
(
Identifier (,
Identifier)*)
Variable declarations introduce one or more variables into the current scope. A variable declaration contains Bindings, which may provide an initializer expression for the Identifier or Identifiers mentioned in the BindingPattern.
Bindings introduce a single new variable when the BindingPattern consists of a single identifier. The optional initializer expression may yield any value in this case.
A TupleBindingPattern introduces multiple variables at once. The optional initializer for a tuple pattern must yield a tuple value with a compatible size (at least the number of declared variable names).
Using the var
keyword creates a mutable variable, while a variable declared using the const
keyword cannot be reassigned after its initialization.
Constants must have an initializer.
Declaration kind | Example | Meaning |
---|---|---|
Simple declaration | var x; | Declares the initialized variable x in the current scope |
Multiple variables | var x, y; | Declares x and y in the current scope |
With initializer | var x = 3.14; | Declares x and with the initial value 3.14 |
Constant declaration | const x = 3.14; | Like the above, but x cannot be reassigned anymore |
Tuple unpacking | var (x, y) = (1, 2); | Unpacks the right hand side tuple into the new variables x and y |
§Functions
- FuncDecl
func
Identifier?(
ParamList?)
FuncBody- ParamList
- Identifier (
,
Identifier)*
A function declaration creates a new function. Functions may have a name, a set of parameters and a body. When a function is invoked, values passed as arguments in the function call expression will be bound to the declared parameters of that function.
The body of a function may be specified as either a BlockExpr or as a single expression introduced by a =
sign.
The shorthand syntax is useful for very simple functions.
§Statements
- Stmt
- VarDecl
;
| AssertStmt;
| DeferStmt;
| WhileStmt | ForEachStmt | ForStmt | IfExpr | BlockExpr | Expr;
|;
Statements are constructs used in block expressions such as function bodies.
Most statements must be terminated by a semicolon.
The semicolon is optional for block-like statements, where the end of the statement is obvious from the position of the closing }
.
§Assertions
An assertion verifies that the expression yields a truthful value. A failed assertion results in a panic.
An optional message argument may be specified; it will be included in the panic's diagnostic error message.
§Defer statements
- DeferStmt
defer
Expr
The defer statement registers an expression to be evaluated when the program leaves the current scope. It's main use is to ensure that resources are cleaned up properly.
Defer statements that have been visited by the program will run even if the scope is being left abruptly, such as by an early return
, break
, continue
or a panic.
§While loops
A while loop consists of a condition expression and a loop body. The condition will be repeatedly evaluated, and while it is truthful, the loop body will also be executed. The loop's execution stops as soon as the condition is false.
§For-each loops
- ForEachStmt
for
BindingPatternin
ExprExcluding BlockExpr BlockExpr
The for-each loop allows iteration over a collection or sequence such as an array. It requires a BindingPattern that specifies the variable names used for iteration and an expression that yields an iterable sequence.
§Classic for loops
The classic for loop allows iteration using one or more control variables, a condition expression and an update step.
When the loop starts its execution, the optional control variables are defined and possibly initialized.
Before every iteration, the optional condition expression is evaluated, and if it is truthful, the loop body is executed. If the condition is false, loop execution stops. If the condition is not defined, it is implicitly truthful.
The optional update expression is evaluated after every completed loop iteration.
§Expressions
- Expr
- VarExpr | FieldExpr | TupleFieldExpr | IndexExpr | CallExpr | UnaryExpr | BinaryExpr | AssignExpr | ContinueExpr | BreakExpr | ReturnExpr | GroupedExpr | IfExpr | FuncExpr | BlockExpr
Expressions are syntax constructs that yield a value. Tiro is an expression-oriented language; most syntax constructions are expressions.
§Evaluation order
All expressions are evaluated strictly from left to right.
§Variable expressions
- VarExpr
- Identifier
A variable expression yields the current value of the variable identified by the given identifier. Tiro is a lexically scoped language: variables may only be referenced from within the scope in which they have been defined. If there are multiple variable declarations for the same identifier in scope, the closest variable declaration is referenced.
§Field expressions
- FieldExpr
- Expr (
.
|?.
) Identifier - TupleFieldExpr
- Expr (
.
|?.
) NonNegativeInt
A field expression evaluates the expression left to the .
symbol and yields the specified field of that value.
The ?.
token can be used to make the field lookup optional.
If the left hand side is null
, the field expression will also yield null
.
The tuple field expression is a variant of the above that allows to lookup a tuple member instead. The left hand side expression must yield a tuple value and the right hand side token must be a non negative integer.
§Index expressions
Index expressions are used to lookup a value within a container by its index.
The ?[
token can be used to make the value lookup optional.
If the left hand side is null
, the index expression will also yield null
and the expression between brackets will not be evaluated.
§Call expressions
- CallExpr
- Expr (
(
|?(
) CallArguments?)
A Call expression invokes a function with a set of arguments.
The first expression must yield a function. Expressions passed as arguments (between parentheses) will be evaluated, then control will be passed to function with all arguments bound to the corresponding function parameter. The call expression yields the return value of the invoked function.
The ?(
token can be used to make the function call optional.
If the function value yields null
, the arguments will not be evaluated and the entire expression will also yield null
.
§Unary expressions
- UnaryOp
+
|-
|!
|~
Unary expressions evaluate the right hand side expression and then apply the specified operator to its result.
Operator | Description |
---|---|
+ | Unary plus. Requires a number operand. Yields the number as-is. |
- | Unary minus. Requires a number operand. Yields the arithmetic negative of its operand. |
! | Unary NOT. Returns the logical negative of its operand: false for all truthful values, true otherwise. |
~ | Bitwise NOT. Requires an integer operand. Yields an integer with all bits inverted. |
§Binary expressions
- BinaryOp
+
|-
|*
|**
|/
|%
|&
||
|<<
|>>
|^
|==
|!=
|<
|>
|<=
|>=
|&&
|||
|??
Binary expressions apply an operation to the left hand and right hand side expressions.
§Arithmetic operators
These operators require two numeric operands and apply the specified arithmetic operation on them.
Operator | Name | Description |
---|---|---|
a + b | Addition | Yields the sum of a and b. |
a - b | Subtraction | Yields the difference of a and b. |
a * b | Multiplication | Yields the product of a and b. |
a ** b | Power | Yields a raised to the power of b. |
a / b | Division | Yields a divided by b. |
a % b | Modulo | Yields the remainder after dividing a by b. |
§Binary operators
Operators that operate on the bits of their operands.
Operator | Name | Description |
---|---|---|
a & b | Binary AND | TODO |
a | b | Binary OR | TODO |
a ^ b | Binary XOR | TODO |
a << b | Bitwise left shift. | TODO |
a >> b | Bitwise right shift. | TODO |
§Relational operators
Relational operators compare their two operands and yield a boolean value depending on the comparison's result.
Operator | Name | Description |
---|---|---|
a == b | Equal to | Yields true if a is equal to b, false otherwise. |
a != b | Not equal to | Yields false if a is equal to b, true otherwise. |
a < b | Less than | Requires both operands to be numbers. Yields true if a is less than b, false otherwise. |
a > b | Greater than | Requires both operands to be numbers. Yields true if a is greater than b, false otherwise. |
a <= b | Less than or equal to | Requires both operands to be numbers. Yields true if a is less than or equal to b, false otherwise. |
a >= b | Greater than or equal to | Requires both operands to be numbers. Yields true if a is greater than or equal to b, false otherwise. |
§Logical operators
Operator | Name | Description |
---|---|---|
a && b | Logical AND | Yields a if is not truthful. Otherwise yields b. Note that b is only evaluated if a is truthful. |
a || b | Logical OR | Yields a if it is truthful. Otherwise yields b. Note that b is only evaluated if a is not truthful. |
§Other operators
Operator | Name | Description |
---|---|---|
a ?? b | Null coalescing | Yields a if it is not null. Otherwise yields b. Note that b is only evaluated if a is null . |
§Assignment expressions
- AssignOp
=
|+=
|-=
|*=
|**=
|/=
|%=
Assignment expressions evaluate their operands and assign the result to the location specified at the left hand side.
The =
assignment operator simply evaluates its right hand side and assigns it to the target location.
The other compound assignment operators take the current value of the left hand side expression into account:
Compound operator | Equivalent Expression |
---|---|
a += b | a = a + b |
a -= b | a = a - b |
a *= b | a = a * b |
a **= b | a = a ** b |
a /= b | a = a / b |
a %= b | a = a % b |
Not all kinds of expression are valid targets for assignments. The following expressions are valid:
- Var expressions. The result is written to the specified variable.
- (Tuple) field expressions. The result is written to the specified (tuple) field.
- Element expressions. The result is written to the specified element.
- Tuple expressions containing expressions of the previously mentioned kind. The result should be a tuple that will be decomposed and assigned to the specified locations.
The left hand side of an assignment expression may not use the optional variants of the field-, element- and call expressions.
§Break expressions
- BreakExpr
break
Aborts execution of the current (most nested) for, for each or while loop. Execution resumes directly after the loop statement.
Note that pending defer statements will be executed before execution resumes after the loop.
§Continue expressions
- ContinueExpr
continue
Jumps directly to the end of the current (most nested) for, for each or while loop's body.
Note that pending defer statements will be executed before execution of the loop resumes.
§Return expressions
- ReturnExpr
return
Expr?
Returns from the current (most nested) function. Program execution will continue in that function's caller.
An optional expression may be specified.
The value yielded by that expression will be come the function's return value.
If the expression is omitted, null
is returned.
Note that pending defer statements will be executed when returning from a function.
§Grouped expressions
- GroupedExpr
(
Expr)
Parentheses can be used to group expressions, for example to override the default precedence rules within expressions:
§If expressions
If expressions provide support for conditional execution. They consist of a mandatory condition, a then block expression, an optional series of else if expressions with additional conditions and finally an optional else block.
If the condition yields a truthful value, the then block is executed and all other blocks are skipped. Otherwise, conditions of any else if expressions are attempted in order, and the block expression after the first truthful condition will be executed. If no condition yielded a truthful value, the optional else block is executed instead.
If expressions may be used in positions where a value is expected. If that is the case, then the expression must have an else block and all blocks must yield a value as well.
§Function expressions
- FuncExpr
- FuncDecl
Function expressions yield the declared function as a value.
§Block expressions
- BlockExpr
{
Stmt*}
Block expressions contain a sequence of statements. When a block expression is evaluated, all its statements are evaluated in order.
Block expressions may be used in positions where a value is expected. If that is the case, there must be at least one statement and the last statement must yield a value. That value will then be yielded by the block expression.
§Literals
- Literal
true
|false
|null
| Integer | Float | String | Symbol | TupleLiteral | RecordLiteral | ArrayLiteral | MapLiteral | SetLiteral
Literals are expressions are source code representations of concrete values. Literals themselves do not require and additional context to evaluate (although nested expressions might).
§Tuple literals
- TupleLiteral
(
TupleElements?)
Creates a tuple containing the values yielded by the nested expressions in their written order.
In order to avoid ambiguity with grouped expressions, a one-element tuple must be contain a trailing comma.
§Record literals
- RecordLiteral
(
(RecordElements |:
))
- RecordElements
- RecordEntry (
,
RecordEntry)*,
? - RecordEntry
- Identifier
:
Expr
Creates a record containing the values yielded by the nested expressions associated with the declared field names.
In order to avoid ambiguity with empty tuples, an empty record must be spelled (:)
.
§Array literals
- ArrayLiteral
[
ArrayElements?]
Creates an array containing the values yielded by the nested expressions in their written order.
§Map literals
- MapLiteral
map
{
MapElements?}
- MapElements
- MapElement (
,
MapElement)*,
?
Creates a map with the specified elements.
Every element is specified using two expressions.
The expression to the right of the :
specifies the value, and the left expression specifies the associated key.
§Set literals
- SetLiteral
set
{
SetElements?}
Creates a set with the specified elements.