program :=
	| statement*

statement :=
	| if_stmt
	| while_stmt
	| for_stmt
	| scope_stmt
	| function_def
	| call_stmt
	| let_stmt
	| uncache_stmt
	| break_stmt
	| continue_stmt
	| return_stmt
	| match_stmt
	| alias_stmt
	| try_stmt
	| until_stmt
	| error_stmt
	| delete_stmt
	| stop_stmt
	| import_stmt
	| define_stmt
	| command

if_stmt :=
	| `if` (argument|call_stmt) `then` program `end`
	| `if` (argument|call_stmt) `then` program else_stmt
	| `if` (argument|call_stmt) `then` program elif_stmt
	| `if` (argument|call_stmt) else_stmt

elif_stmt :=
	| `elif` program `end`
	| `elif` program elif_stmt
	| `elif` program else_stmt

else_stmt :=
	| `else` program `end`

while_stmt :=
	| `while` `do` program `end`
	| `while` argument `do` program `end`

for_stmt :=
	| `for` <text>+ `in` argument+ `do` program `end`

scope_stmt :=
	| `do` program `end`

delete_stmt :=
	| `delete` <text>+

function_def :=
	| `function` <text> program `end`

call_stmt :=
	| `call` <text>

let_stmt :=
	| `let` <variable> `{` `}` `=` argument+
	| `let` <variable> `{` expression `}` `{` `}` `=` argument+
	| `let` <variable> `{` expression `}` (`=`|`+=`|`-=`|`*=`|`/=`|`%=`|`%%=`|`&=`) argument+
	| `let` <variable>+ `=` argument+
	| `let` <variable>+
	| `let` <variable> (`+=`|`-=`|`*=`|`/=`|`%=`|`%%=`|`&=`) argument+
	| `initial` <variable> `=` argument+

uncache_stmt :=
	| `break` `cache` <text>

break_stmt :=
	| `break` argument?

continue_stmt :=
	| `continue` argument?

return_stmt :=
	| `return` argument?

match_stmt :=
	| `match` argument `do` match_if_stmt+ `end`
	| `match` argument `do` match_if_stmt+ else_smt

match_if_stmt :=
	| `if` match_argument `then` program `end`
	| terse_match_statement `if` match_argument

match_argument :=
	| <text>
	| string
	| `{` (`%`|`%%`|`>`|`<`|`>=`|`<=`|`=`|`!=`|`not`? `like`|`not`? `in`|`bitwise`? `and`|`bitwise`? `or`|`bitwise`? `xor`) expression `}`
	| `{` expression `}`
	| `${` inline_command `}`

terse_match_statement :=
	| call_stmt
	| let_stmt
	| uncache_stmt
	| break_stmt
	| continue_stmt
	| return_stmt
	| delete_stmt
	| stop_stmt
	| error_stmt
	| command

alias_stmt :=
	| `using` argument `as` argument
	| `using` argument

try_stmt :=
	| `try` program catch_block+ `end`

until_stmt :=
	| `until` text+ `do` program `end`

catch_block :=
	| `catch` text+
	| `catch` text+ as text

stop_stmt :=
	| `stop`

import_stmt :=
	| `require` text+

error_stmt :=
	| `error` argument `as` text
	| `error` argument

define_stmt :=
	| `define` argument+

command :=
	| (argument | pipeio)+

argument :=
	| <text>
	| string
	| `{` expression `}`
	| `${` inline_command `}`

pipeio :=
	| `|` command
	| stdio `>` (stdio | <text>)
	| `<` argument
	| `<<<` argument

stdio :=
	| `?`
	| `!`
	| `?!`

inline_command :=
	| call_stmt
	| command

expression :=
	| array

array :=
	| kv_pair `,` array
	| kv_pair `,`
	| kv_pair
	| `,`

kv_pair :=
	| ternary `=>` ternary
	| ternary
	| `=>`

ternary :=
	| list_comprehension `?` `else` ternary
	| list_comprehension `else` ternary
	| list_comprehension `?` `then` ternary
	| list_comprehension `then` ternary
	| list_comprehension `if` list_comprehension `else` ternary
	| list_comprehension

list_comprehension :=
	| boolean `for` <variable> `in` list_comprehension `if` list_comprehension
	| boolean `for` <variable> `in` list_comprehension
	| boolean

boolean :=
	| concat `bitwise`? `and` boolean
	| concat `bitwise`? `or` boolean
	| concat `bitwise`? `xor` boolean
	| concat `exists`
	| concat

concat :=
	| comparison+

comparison :=
	| add `>` comparison
	| add `<` comparison
	| add `>=` comparison
	| add `<=` comparison
	| add `=` comparison
	| add `!=` comparison
	| add `in` comparison
	| add `like` comparison
	| add `not` `in` comparison
	| add `not` `like` comparison
	| add

add :=
	| mult `+` add
	| mult `-` add
	| mult

mult :=
	| slice `*` mult
	| slice `/` mult
	| slice `//` mult
	| slice `%` mult
	| slice `%%` mult
	| slice

slice :=
	| unary `:` `:`
	| unary `:` unary `:` unary
	| unary `:` unary
	| unary

unary :=
	| `bitwise`? `not` exponent
	| `-` exponent

exponent :=
	| length `^` exponent
	| length

length :=
	| `&` dot_and_index
	| dot_and_index

dot_and_index :=
	| value `.` value
	| value `[` expression `]`
	| value `?` `.` value
	| value `?` `[` expression `]`
	| value

value :=
	| macro
	| func_call
	| <variable>
	| <number>
	| string
	| `true` | `false` | `null`
	| `(` expression `)`
	| `{` expression `}`
	| `${` inline_command `}`

macro :=
	| <exclamation> `[` expression `]`
	| <exclamation>

func_call :=
	| <variable> `(` expression `)`

string :=
	| `"` string_interp* `"`
	| `"""` string_interp* `"""`
	| `'` <text>? `'`
	| `'''` <text>? `'''`

string_interp :=
	| <text>
	| `{` expression `}`
	| `${` inline_command `}`
