module = {import} {declaration}
import = "import" path ["as" NAME] | "from" path "import" NAME {"," NAME}
declaration = ["pub"] (func | struct | enum | class | interface | alias | constant | test)
func = "func" NAME [generics] "(" [params] ")" ["->" type] ":" suite
struct = "struct" NAME [generics] [":" NAME {"," NAME}] ":" NEWLINE INDENT {field | func} DEDENT
class = "class" NAME [generics] [":" NAME {"," NAME}] ":" NEWLINE INDENT {field | func} DEDENT
enum = "enum" NAME [generics] [":" NAME {"," NAME}] ":" NEWLINE INDENT {case | func} DEDENT
interface = "interface" NAME [generics] ":" NEWLINE INDENT {signature} DEDENT
field = ("let" | "var") NAME ":" type ["=" expression]
case = NAME ["(" params ")"]
alias = "type" NAME "=" type
constant = "let" NAME [":" type] "=" expression
test = "test" STRING ":" suite
params = param {"," param} param = NAME ":" type ["=" expression]
generics = "[" generic {"," generic} "]" generic = NAME [":" NAME {"&" NAME}]
type = path ["[" type {"," type} "]"] | "(" [type {"," type}] ")"
| "func" "(" [type {"," type}] ")" ["->" type] | type "?" | type "!"
suite = simple NEWLINE | NEWLINE INDENT {statement} DEDENT
statement = simple NEWLINE | if | while | for | match | with
simple = binding | assignment | expression | "return" [expression] | "break" [NAME]
| "continue" [NAME] | "recover" expression | "error" "(" expression "," expression ")"
binding = ("let" | "var") (NAME | "(" NAME {"," NAME} ")") [":" type] "=" expression
if = "if" (expression | "let" NAME "=" expression) ":" suite
{"elif" ... ":" suite} ["else" ":" suite]
while = [NAME ":"] "while" (expression | "let" NAME "=" expression) ":" suite
for = [NAME ":"] "for" (NAME | "(" NAME {"," NAME} ")") "in" expression ":" suite
match = "match" expression ":" NEWLINE INDENT {pattern ["if" expression] ":" suite} DEDENT
with = "with" expression "as" NAME {"," expression "as" NAME} ":" suite
expression = lambda | conditional
lambda = "(" [params] ")" "=>" expression | "func" "(" [params] ")" ["->" type] ":" suite
conditional = or ["if" or "else" expression]
or = and {"or" and} and = not {"and" not} not = "not" not | compare
compare = range [("==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "is" | "is" "not") range]
range = add [("..<" | "..=") add]
add = mul {("+" | "-") mul} mul = unary {("*" | "/" | "//" | "%") unary}
unary = "-" unary | power power = postfix ["**" unary]
postfix = primary {"." NAME | "(" [args] ")" | "[" expression "]" | "[" [expression] ".." ["<" expression] "]"}
primary = literal | NAME | "self" | "." NAME | "(" expression ")" | tuple | list | map
| "try" expression | expression "catch" NAME ":" suite | expression "else" expression
| "match" expression ":" arms | "spawn" call | "wait" expression