num = @{ int ~ ("." ~ ASCII_DIGIT*)? ~ (^"e" ~ int)? }
    int = @{ ("+" | "-")? ~ ASCII_DIGIT+ }

raw_string = @{ (!("\\" | "\"") ~ ANY)+ }
predefined = @{ "n" | "r" | "t" | "\\" | "0" | "\"" | "'" }
escape = @{ "\\" ~ predefined }
str = @{ "\"" ~ (raw_string | escape)* ~ "\"" }

ident_char = @{ ASCII_ALPHANUMERIC | "-" }
sub_ident = _{ sub_ident_regular | sub_ident_index | sub_ident_any | sub_ident_all | sub_ident_fn }
    sub_ident_regular = { sub_ident_regular_base | sub_ident_regular_expr }
    sub_ident_regular_base = @{ ASCII_ALPHA ~ ident_char* }
    sub_ident_regular_expr = ${ "[" ~ str_expr ~ "]" }
    sub_ident_index = { sub_ident_index_base | sub_ident_index_expr }
    sub_ident_index_base = @{ ASCII_DIGIT+ }
    sub_ident_index_expr = ${ "[" ~ num_expr ~ "]" }
    sub_ident_any = @{ "*" }
    sub_ident_all = @{ "&" }
    sub_ident_fn = ${ "[" ~ list_access_function ~ "]"}
        list_access_function = _{ list_access_function_first | list_access_function_last | list_access_function_any | list_access_function_all }
        list_access_function_first = !{ "first" ~ "(" ~ sub_ident_regular ~ "=>" ~ bool_expr ~ ")" }
        list_access_function_last = !{ "last" ~ "(" ~ sub_ident_regular ~ "=>" ~ bool_expr ~ ")" }
        list_access_function_any = !{ "any" ~ "(" ~ sub_ident_regular ~ "=>" ~ bool_expr ~ ")" }
        list_access_function_all = !{ "all" ~ "(" ~ sub_ident_regular ~ "=>" ~ bool_expr ~ ")" }

app_id = ${ "[" ~ sub_ident_regular ~ "]" }
ident = _{ (app_id ~ ".")? ~ sub_ident_regular ~ ("." ~ sub_ident)* }
bool_var = ${ ident ~ "?" }
num_var = ${ "#" ~ ident }
str_var = ${ "'" ~ ident }
any_var = ${ ident }

bool_op = _{ and | or | xor }
    and = { "AND" }
    or  = { "OR" }
    xor = { "XOR" }

num_cmp_op = _{ lt | lte | eq | neq | gt | gte }
str_cmp_op = _{ lt | lte | eq | neq | gt | gte }
    lt  = { "<" }
    lte = { "<=" }
    eq  = { "=" }
    neq = { "!=" }
    gt  = { ">" }
    gte = { ">=" }

num_op = _{ add | sub | mul | div | pow }
str_op = _{ add }
    add = { "+" }
    sub = { "-" }
    mul = { "*" }
    div = { "/" }
    pow = { "^" }

num_expr = !{ num_term ~ (num_op ~ num_term)* }
num_term = _{ num | num_var | "(" ~ num_expr ~ ")" }

str_expr = !{ str_term ~ (str_op ~ str_term)* }
str_term = _{ str | str_var | "(" ~ str_expr ~ ")" }

num_cmp_expr = { num_expr ~ num_cmp_op ~ num_expr }
str_cmp_expr = { str_expr ~ str_cmp_op ~ str_expr }

bool_expr = !{ bool_term ~ (bool_op ~ bool_term)* }
inv_bool_expr = { "!(" ~ bool_expr ~ ")" }
bool_term = _{ bool_var | "(" ~ bool_expr ~ ")" | inv_bool_expr | num_cmp_expr | str_cmp_expr }

val_expr = _{ any_var | str_expr | num_expr | bool_expr }

rule = _{ SOI ~ bool_expr ~ EOI }
reference = _{ SOI ~ any_var ~ EOI }
value = _{ SOI ~ val_expr ~ EOI }
del_action = _{ SOI ~ "FROM" ~ any_var ~ "AS" ~ sub_ident_regular ~ "WHERE" ~ bool_expr ~ EOI }
obj_key = _{ SOI ~ sub_ident_regular ~ EOI }

WHITESPACE = _{ " " | "\t" }