WHITESPACE = _{ " " }
RANGE_SEPARATOR = _{ ":" }
// Parses positional arg inside tag and functions
digits = @{ ASCII_DIGIT+}
integer = @{ ("+" | "-")? ~ digits }
// Modifiers that can be applied to args, kwargs and env_var
optional = { "?" }
index = { integer }
range_from = { integer }
range_to = { integer }
range = { range_from? ~ RANGE_SEPARATOR ~ range_to? }
slice = { "[" ~ (range | index) ~ "]"}
// Positonal arg, i.e. $1 $2
arg = ${"$" ~ digits }
// Star inside tag, i.e. * or *?
all_args = ${ "$@" }
// Parses named arguments inside tag and functions
kwarg_name = { ( "_" | ASCII_ALPHA ) ~ ("_" | "-" | ASCII_ALPHANUMERIC )* }
kwarg = ${ kwarg_name }
// Parses env var inside tag
env_var_name = @{ ( "_" | ASCII_ALPHA ) ~ ( "_" | "-" | ASCII_ALPHANUMERIC )*}
env_var = ${ "$" ~ env_var_name }
// Parses fun inside tag
fun_name = @{ ( "_" | ASCII_ALPHA ) ~ ( "_" | ASCII_ALPHANUMERIC )* }
expression_inner = ${ all_args | fun | kwarg | arg | env_var | string }
expression = { expression_inner ~ slice* ~ optional? }
fun_params = { expression ~ (WHITESPACE* ~ "," ~ WHITESPACE* ~ expression)* }
fun = ${ fun_name ~ "(" ~ WHITESPACE* ~ fun_params? ~ WHITESPACE* ~ ")" }
// Tag, that can contain either a fun, arg, kwarg, end_var or star
tag = { "{" ~ WHITESPACE* ~ expression ~ WHITESPACE* ~ "}" }
// Escape values inside string
special_val = { "n" | "r" | "t" | "\\" | "0" | "'" | "\"" }
escape = { "\\" ~ special_val }
// Parses string inside tag
string_content = { (!("\\" | PEEK | NEWLINE ) ~ ANY)+ }
string = ${ PUSH("'" | "\"") ~ (string_content | escape)* ~ POP }
// Escape open and close brackets in literal
esc_ob = { "{{" }
esc_cb = { "}}" }
literal_content = {(!("{" | "}") ~ ANY)+}
// values outside tag
literal = { literal_content | ( esc_ob | esc_cb )}
// Multiline comment outside tag
comment = _{ "{/" ~ (!"/}" ~ ANY)* ~ "/}" }
// Parses the whole string, empty strings allowed
all = ${ SOI ~ (comment | tag | literal)* ~ EOI }
// Matches a task argument, which can be either a task or literal, or empty
task_arg = ${ SOI ~ (tag | literal+)? ~ EOI }