WHITESPACE = _{ " " | "\t" }
COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" ~ NEWLINE? }
ARROW = _{ "->" }
LPAREN = _{ "(" }
RPAREN = _{ ")" }
LSQUARE = _{ "[" }
RSQUARE = _{ "]" }
COLON = _{ ":" }
EQ = _{ "=" }
COMMA = _{ "," }
name_char = _{ ASCII_ALPHA | "_" }
name = @{ name_char+ }
module_name = @{ (name_char | "::")+ }
fn_name_char = _{ "!" | "#" | "$" | "%" | "&" | "*" | "+" | "-" | "/" | "<" | ">" | "=" | "^" | "|" | "~" | "@" | "?" | "_" | name_char }
fn_name = @{ fn_name_char+ }
// Types
type_char = _{ name_char | ASCII_DIGIT }
firework_type = @{ type_char+ }
type_signature = { COLON ~ firework_type }
int = @{ "-"? ~ ASCII_DIGIT+ }
boolean = { "true" | "false" }
string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
char = @{ "'" ~ (!"'" ~ ANY)? ~ "'" }
list = @{ LSQUARE ~ literal ~ ( COMMA ~ literal )+? ~ RSQUARE }
enum_type = @{ "enum" ~ name ~ EQ ~ name ~ ("|" ~ name)+?}
literal = { precedence | int | boolean | string | char | list | anon_fn }
identifier = { fn_name ~ LPAREN ~ expr ~ (COMMA ~ expr)+? ~ RPAREN | fn_name }
precedence = { LPAREN ~ expr ~ RPAREN }
// Functions
fn_args = { (name ~ type_signature)+ }
declaration = { "let" ~ fn_name ~ (LPAREN ~ fn_args ~ RPAREN)? ~ type_signature ~ EQ ~ expr }
anon_fn = { LPAREN ~ fn_args? ~ RPAREN ~ type_signature ~ ARROW ~ expr }
// Modules
module_import = { "import" ~ module_name }
module_declaration = { "module" ~ module_name }
// If statements
if_statement = { "if" ~ expr ~ "do" ~ expr ~ "else" ~ expr }
// File
expr = _{ (precedence | if_statement | literal | identifier) }
stmt = _{ (declaration | module_declaration | module_import | enum_type) }
repl = !{ SOI ~ (stmt | expr ~ NEWLINE?)? ~ EOI }
program = _{ SOI ~ ((stmt ~ NEWLINE?) | NEWLINE)* ~ EOI }