// Helpers
SP = _{ " " | "\t" }
NL = _{ "\r\n" | "\n" }
COMMENT = _{ "#" ~ (!NL ~ ANY)* }
_W = _{ (SP | NL)* } // 0 or more
_WS = _{ SP+ } // 1 or more
// Program
program = { SOI ~ _W ~ stmt_list ~ _W ~ EOI }
stmt_list = { stmt ~ (NL+ ~ _W ~ stmt)* }
stmt = { fn_def | let_stmt | print_stmt | expr }
// Statements
let_stmt = { "let" ~ _WS ~ ident ~ _W ~ "=" ~ _W ~ expr }
print_stmt = { "print" ~ _W ~ "(" ~ _W ~ ident ~ _W ~ ")" }
// Expressions
expr = { sum }
sum = { product ~ (_W ~ op_add ~ _W ~ product)* }
product = { postfix_expr ~ (_W ~ op_mul ~ _W ~ postfix_expr)* }
postfix_expr = { atom ~ postfix* }
postfix = {
"." ~ ident ~ _W ~ "(" ~ _W ~ method_arg ~ _W ~ ")"
| "." ~ ident
| "[" ~ _W ~ expr ~ _W ~ "]"
}
method_arg = { lambda_expr | expr }
call_expr = { ident ~ _W ~ "(" ~ _W ~ arg_list? ~ _W ~ ")" }
range_expr = { paren_expr }
paren_expr = { "(" ~ _W ~ expr ~ _W ~ ".." ~ _W ~ expr ~ _W ~ ")" }
// Atom Forms (ordered)
atom = {
paren_expr
| range_expr
| hashmap
| call_stmt
| call_expr
| lambda_expr
| array
| boolean
| number
| string
| ident
}
// Function
fn_def = {
"fn" ~ _WS ~ ident
~ _W ~ "(" ~ _W ~ param_list? ~ ")"
~ _W ~ block
}
lambda_expr = {
"|" ~ ident ~ "|" ~ _W ~ (block | expr)
}
block = { "{" ~ _W ~ stmt_list? ~ _W ~ "}" }
// Collections
array = { "[" ~ _W ~ expr_list? ~ _W ~ "]" }
expr_list = { expr ~ (_W ~ "," ~ _W ~ expr)* }
hashmap = { "{" ~ _W ~ key_val_pairs? ~ _W ~ "}" }
key_val_pairs = { key_val_pair ~ (_W ~ "," ~ _W ~ key_val_pair)* }
key_val_pair = { ident ~ _W ~ ":" ~ _W ~ expr }
param_list = { ident ~ (_W ~ "," ~ _W ~ ident)* ~ _W? }
arg_list = { expr ~ (_W ~ "," ~ _W ~ expr)* ~ _W? }
// Infix Operators
op_add = { "+" | "-" }
op_mul = { "*" | "/" }
// Lexical Tokens
ident = @{
ASCII_ALPHA_LOWER+
~ (ASCII_ALPHA_LOWER | ASCII_DIGIT | "_")*
}
number = @{ "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
boolean = { "true" | "false" }
// Shortcut Statement Helper
call_stmt = { ident ~ _W ~ "(" ~ _W ~ ident ~ _W ~ ")" }