Motoko grammar
This section describes the concrete syntax, or grammar, of Motoko. The specification is auto-generated with a tool.
<list(X, SEP)> ::= <empty> X X SEP <list(X, SEP)>
<list1(X, SEP)> ::= X X SEP <list(X, SEP)>
<implicit> ::= 'implicit'
<typ_obj_sort> ::= 'object' 'actor' 'module'
<obj_sort> ::= 'object' 'persistent'? 'actor' 'module'
<query> ::= 'query' 'composite' 'query'
<func_sort_opt> ::= <empty> 'shared' <query>? <query>
<shared_pat_opt> ::= <empty> 'shared' <query>? <pat_plain>? <query> <pat_plain>?
<typ_path> ::= <id> <id> ('.' <id>)* '.' <id>
<typ_obj> ::= '{' <list(<typ_field>, ';')> '}'
<typ_variant> ::= '{' '#' '}' '{' <list1(<typ_tag>, ';')> '}'
<typ_nullary> ::= '(' <list(<typ_item>, ',')> ')' <typ_path> <typ_args>? '[' 'var'? <typ> ']' <typ_obj> <typ_variant>
<typ_un> ::= <typ_nullary> '?' <typ_un> 'weak' <typ_un>
<typ_pre> ::= <typ_un> 'async' <typ_pre> 'async*' <typ_pre> <typ_obj_sort> <typ_obj>
<typ_nobin> ::= <typ_pre> <func_sort_opt> <typ_params_opt> <typ_un> '->' <typ_nobin>
<typ> ::= <typ_nobin> <typ> 'and' <typ> <typ> 'or' <typ>
<typ_item> ::= <implicit> ':' <typ> <id> ':' <typ> <typ>
<typ_args> ::= '<' <list(<typ>, ',')> '>'
<inst> ::= <empty> '<' <list(<typ>, ',')> '>' '<' 'system' (',' <typ>)* '>'
<typ_params_opt> ::= ('<' <list(<typ_bind>, ',')> '>')? '<' 'system' (',' <typ_bind>)* '>'
<typ_field> ::= 'type' <id> ('<' <list(<typ_bind>, ',')> '>')? '=' <typ> 'var'? <id> ':' <typ> <id> <typ_params_opt> <typ_nullary> ':' <typ>
<typ_tag> ::= '#' <id> (':' <typ>)?
<typ_bind> ::= <id> '<:' <typ> <id>
<lit> ::= 'null' <bool> <nat> <float> <char> <text>
<unop> ::= '+' '-' '^'
<binop> ::= '+' '-' '*' '/' '%' '**' '+%' '-%' '*%' '**%' '&' '|' '^' '<<' ' >>' '<<>' '<>>' '#'
<relop> ::= '==' '!=' ' < ' '<=' ' > ' '>='
<unassign> ::= '+=' '-=' '^='
<binassign> ::= '+=' '-=' '*=' '/=' '%=' '**-' '+%=' '-%=' '*%=' '**%=' '&=' '|=' '^=' '<<=' '>>=' '<<>=' '<>>=' '@='
<parenthetical> ::= '(' <exp_post>? 'with' <list(<exp_field>, ';')> ')'
<exp_obj> ::= '{' <list(<exp_field>, ';')> '}' '{' <exp_post> 'and' <exp_post> ('and' <exp_post>)* '}' '{' <exp_post> ('and' <exp_post>)* 'with' <list1(<exp_field>, ';')> '}'
<exp_plain> ::= <lit> '(' <list(<exp>, ',')> ')'
<exp_nullary> ::= <exp_obj> <exp_plain> <id> '_'
<exp_arg> ::= <ob> <lit> '(' <list(<exp>, ',')> ')' <id> '_'
<exp_post> ::= <exp_nullary> '[' 'var'? <list(<exp_nonvar>, ',')> ']' <exp_post> '[' <exp> ']' <exp_post> '.'<nat> <exp_post> '.' <id> <exp_post> <inst> <exp_arg> <exp_post> '!' '(' 'system' <exp_post> '.' <id> ')'
<exp_un> ::= <exp_post> <parenthetical> <exp_post> <inst> <exp_arg> '#' <id> '#' <id> <exp_nullary> '?' <exp_un> <unop> <exp_un> <unassign> <exp_un> 'actor' <exp_plain> 'not' <exp_un> 'debug_show' <exp_un> 'to_candid' '(' <list(<exp>, ',')> ')' 'from_candid' <exp_un>
<exp_bin> ::= <exp_un> <exp_bin> <binop> <exp_bin> <exp_bin> <relop> <exp_bin> <exp_bin> 'and' <exp_bin> <exp_bin> 'or' <exp_bin> <exp_bin> ':' <typ_nobin> <exp_bin> '|>' <exp_bin>
<exp_nondec> ::= <exp_bin> <exp_bin> ':=' <exp> <exp_bin> <binassign> <exp> 'return' <exp>? <parenthetical>? 'async' <exp_nest> 'async*' <exp_nest> 'await' <exp_nest> 'await?' <exp_nest> 'await*' <exp_nest> 'assert' <exp_nest> 'label' <id> (':' <typ>)? <exp_nest> 'break' <id> <exp_nullary>? 'break' 'continue' <id>? 'debug' <exp_nest> 'if' <exp_nullary> <exp_nest> 'if' <exp_nullary> <exp_nest> 'else' <exp_nest> 'try' <exp_nest> <catch> 'try' <exp_nest> <catch> 'finally' <exp_nest> 'try' <exp_nest> 'finally' <exp_nest> 'throw' <exp_nest> 'switch' <exp_nullary> '{' <list(<case>, ';')> '}' 'while' <exp_nullary> <exp_nest> 'loop' <exp_nest> 'loop' <exp_nest> 'while' <exp_nest> 'for' '(' <pat> 'in' <exp> ')' <exp_nest> 'ignore' <exp_nest> 'do' <block> 'do' '?' <block>
<exp_nonvar> ::= <exp_nondec> <dec_nonvar>
<exp> ::= <exp_nonvar> <dec_var>
<exp_nest> ::= <block> <exp>
<block> ::= '{' <list(<dec>, ';')> '}'
<case> ::= 'case' <pat_nullary> <exp_nest>
<catch> ::= 'catch' <pat_nullary> <exp_nest>
<exp_field> ::= 'var'? <id> (':' <typ>)? 'var'? <id> (':' <typ>)? '=' <exp>
<dec_field> ::= <vis> <stab> <dec>
<vis> ::= <empty> 'private' 'public' 'system'
<stab> ::= <empty> 'flexible' 'stable' 'transient'
<pat_plain> ::= '_' <id> <lit> '(' <list(<pat_bin>, ',')> ')'
<pat_nullary> ::= <pat_plain> '{' <list(<pat_field>, ';')> '}'
<pat_un> ::= <pat_nullary> '#' <id> '#' <id> <pat_nullary> '?' <pat_un> <unop> <lit>
<pat_bin> ::= <pat_un> <pat_bin> 'or' <pat_bin> <pat_bin> ':' <typ>
<pat> ::= <pat_bin>
<pat_field> ::= <id> (':' <typ>)? <id> (':' <typ>)? '=' <pat> 'type' <id>
<func_pat> ::= <id>? <typ_params_opt> <pat_plain>
<dec_var> ::= 'var' <id> (':' <typ>)? '=' <exp> 'var' <id> ':' <typ>
<dec_nonvar> ::= 'let' <pat> '=' <exp> 'let' <pat> 'type' <id> ('<' <list(<typ_bind>, ',')> '>')? '=' <typ> <shared_pat_opt> 'func' <func_pat> (':' <typ>)? <func_body> <parenthetical>? <obj_or_class_dec> 'mixin' <pat_plain> <obj_body> 'include' <id> <exp>
<obj_or_class_dec> ::= <obj_sort> <id>? (':' <typ>)? '='? <obj_body> <shared_pat_opt> <obj_sort>? 'class' <func_pat> (':' <typ>)? <class_body>
<dec> ::= <dec_var> <dec_nonvar> <exp_nondec> 'let' <pat> '=' <exp> 'else' <exp_nest>
<func_body> ::= '=' <exp> <block>
<obj_body> ::= '{' <list(<dec_field>, ';')> '}'
<class_body> ::= '=' <id>? <obj_body> <obj_body>
<imp> ::= 'import' <pat_nullary> '='? <text>
<prog> ::= <list(<imp>, ';')> <list(<dec>, ';')>