WHITESPACE = _{ " " | "\t" | NEWLINE } COMMENT = _{ "//" ~ (!"\n" ~ ANY)* } name_char = { ASCII_ALPHA_LOWER | ASCII_ALPHA_UPPER | "_" | "$" } name = @{ name_char ~ (name_char | ASCII_DIGIT)* } dec_number = @{ ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* } hex_number = ${ "0x" ~ ASCII_HEX_DIGIT+ } bin_number = ${ "0b" ~ ASCII_BIN_DIGIT+ } oct_number = ${ "0o" ~ ASCII_OCT_DIGIT+ } dec_zero = @{ "0" } number = { dec_number | hex_number | bin_number | oct_number | dec_zero } escape = @{ "\\" ~ ("t" | "r" | "n" | "0" | "\\" | "\"") } string_inner = ${ !("\"" | "\\") ~ ANY | escape } string = ${ "\"" ~ string_inner* ~ "\"" } assignment = { lvalue ~ "=" ~ rvalue } lvalue = { arrayref | name } rvalue = { expr | string } add = { "+" } sub = { "-" } mul = { "*" } div = { "/" } modulus = { "%" } log_and = { "&&" } log_or = { "||" } bit_and = { "&" } bit_or = { "|" } xor = { "^" } lt = { "<" } le = { "<=" } gt = { ">" } ge = { ">=" } eq = { "==" } ne = { "!=" } lshift = { "<<" } rshift = { ">>" } prefix = { "-" | "!" } operator = _{ add | sub | mul | div | modulus | log_and | log_or | bit_and | bit_or | xor | lshift | rshift | lt | le | gt | ge | eq | ne } expr = { prefix? ~ val ~ (operator ~ prefix? ~ val)* } val = { // These are what get evaluated and left on the stack: number | // Literal numbers ("(" ~ expr ~ ")") | // Nested parenthesized exprs // Bare literal ids, fn calls, array references // (call, or pointer arithmetic, since ids all reference addresses) // (multiple calls / subscripts aren't allowed; use CALL or collapse to one // subscript) call | arrayref | name | address } address = { "&" ~ name } // The address for a name arrayref = { name ~ subscript } // Subscripting is only literal IDs. Anything else can be pointer arithmetic call = { name ~ arglist } // Call syntax is only literal IDs. Calling things dynamically is done with a builtin; CALL(foo[3], 1, 2, 3) arglist = { "(" ~ (rvalue ~ ("," ~ rvalue)*)? ~ ")" } subscript = { "[" ~ expr ~ "]" } statement = { ((return_stmt | assignment | call | var_decl) ~ ";") | conditional | while_loop | repeat_loop } block = { "{" ~ statement* ~ "}" } function = { "fn" ~ name ~ annotations? ~ argnames ~ block } annotations = { "<" ~ (annotation ~ ("," ~ annotation)*) ~ ">" } annotation = { inline_annotation | org_annotation | type_annotation } inline_annotation = { "inline" } org_annotation = { "org=" ~ number } type_annotation = { "type=" ~ name } argnames = { "(" ~ (argname ~ ("," ~ argname)*)? ~ ")" } argname = { name ~ typename? } declaration = { function | global | struct_decl | const_decl } program = { (COMMENT | WHITESPACE)? ~ declaration* ~ EOI } return_stmt = { "return" ~ expr? } conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? } while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block } repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block } var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ expr)? } global = { "global" ~ name ~ varinfo ~ ";" } typename = { ":" ~ name } size = { "[" ~ expr ~ "]" } const_decl = { "const" ~ name ~ "=" ~ (expr | string) ~ ";" } struct_decl = { "struct" ~ name ~ "{" ~ members ~ "}" } member = { name ~ varinfo } members = { (member ~ ("," ~ member)*)? } varinfo = { typename? ~ size? }