program = { SOI ~ stmt_list ~ EOI }
stmt_list = { COMMENT* ~ stmt ~ ";" ~ (stmt ~ ";")* | "" }
stmt = { import | declaration | assignment | exception_handling | exception | return_stmt | expr }
import = { "include" ~ expr }
return_stmt = { "return" }
declaration = { "let" ~ identifier ~ "=" ~ expr }
exception_handling = { "try" ~ "{" ~ stmt_list ~ "}" ~ catch_list }
catch_list = { catch+ }
catch = { catch_as | catch_expr | catch_into }
catch_as = { "catch" ~ "as" ~ identifier ~ "{" ~ stmt_list ~ "}" }
catch_expr = { "catch" ~ "(" ~ expr ~ ")" ~ "{" ~ stmt_list ~ "}" }
catch_into = { "catch" ~ "into" ~ identifier }
exception = { toss_how ~ expr }
toss_how = { "toss" | "hurl" }
assignment = { identifier ~ "=" ~ expr }
expr = _{ expr0 }
expr0 = { expr1 ~ (cmp ~ expr0)? }
expr1 = { expr2 ~ (bin1 ~ expr1)? }
expr2 = { term ~ (bin2 ~ expr2)? }
cmp = _{ eq | neq | lt | leq | gt | geq | and | or }
eq = { "==" }
neq = { "~=" }
lt = { "<" }
leq = { "<=" }
gt = { ">" }
geq = { ">=" }
and = { "and" }
or = { "or" }
bin1 = _{ add | sub }
add = { "+" }
sub = { "-" }
bin2 = _{ mul | div | modu | pow }
mul = { "*" }
div = { "/" }
modu = { "%" }
pow = { "^" }
term = { index_access | literal | paren_expr | func_expr | function_call | identifier | not_expr | list_expr }
literal = { string | number | boolean }
paren_expr = { "(" ~ expr ~ ")" }
func_expr = { "func" ~ "(" ~ params ~ ")" ~ "{" ~ stmt_list ~ "}" }
params = { identifier ~ ("," ~ identifier)* | identifier | "" }
function_call = { identifier ~ "(" ~ argument_list? ~ ")" }
argument_list = { expr ~ ("," ~ expr)* }
identifier = @{ ASCII_ALPHA ~ (ASCII_ALPHA | ASCII_DIGIT | "_")* }
not_expr = { "~" ~ expr }
list_expr = { "[" ~ (expr ~ ("," ~ expr)*)? ~ "]" }
index_access = { identifier ~ "." ~ integer }
boolean = { "true" | "false" }
number = { float | integer }
integer = @{ ASCII_DIGIT+ }
float = @{ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
string = @{ "\"" ~ (!("\\" ~ ANY | "\"") ~ ANY | "\\\"" | "\\\\")* ~ "\"" }
COMMENT = { "#" ~ (!"\n" ~ ANY)* ~ "\n" }
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }