﻿# Motoko grammar

> For the complete documentation index, see [llms.txt](/llms.txt)

This section describes the concrete syntax, or grammar, of Motoko. The specification is auto-generated with a tool.

```bnf
<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>
    '??' <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>
    '??' <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> '??' <exp_nest>
    <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>
    '??' <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>, ';')>
```
