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)>
<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_obj> ::= 
    '{' <list(<typ_field>, ';')> '}'
<typ_variant> ::= 
    '{' '#' '}'
    '{' <list1(<typ_tag>, ';')> '}'
<typ_nullary> ::= 
    '(' <list(<typ_item>, ',')> ')'
    <id> ('.' <id>)* <typ_args>?
    '[' 'var'? <typ> ']'
    <typ_obj>
    <typ_variant>
<typ_un> ::= 
    <typ_nullary>
    '?' <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> ::= 
    <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_post> ::= 
    <exp_nullary>
    '[' 'var'? <list(<exp_nonvar>, ',')> ']'
    <exp_post> '[' <exp> ']'
    <exp_post> '.'<nat>
    <exp_post> '.' <id>
    <exp_post> <inst> <exp_nullary>
    <exp_post> '!'
    '(' 'system' <exp_post> '.' <id> ')'
<exp_un> ::= 
    <exp_post>
    <parenthetical> <exp_post> <inst> <exp_nullary>
    '#' <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>
    'assert' <exp_nest>
    'label' <id> (':' <typ>)? <exp_nest>
    'break' <id> <exp_nullary>?
    '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>
<dec_var> ::= 
    'var' <id> (':' <typ>)? '=' <exp>
<dec_nonvar> ::= 
    'let' <pat> '=' <exp>
    'type' <id> ('<' <list(<typ_bind>, ',')> '>')? '=' <typ>
    <shared_pat_opt> 'func' <id>? <typ_params_opt> <pat_plain> (':' <typ>)? <func_body>
    <parenthetical>? <obj_or_class_dec>
<obj_or_class_dec> ::= 
    <obj_sort> <id>? (':' <typ>)? '='? <obj_body>
    <shared_pat_opt> <obj_sort>? 'class' <id>? <typ_params_opt> <pat_plain> (':' <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>, ';')>