WHITESPACE = _{ " " | "\t" | "\r\n" | "\n"}
boolean = {"true" | "false"}
null = {"null"}
min = _{"-"}
col = _{":"}
dot = _{ "." }
word = _{ ('a'..'z' | 'A'..'Z')+ }
specs = _{ "_" | "-" | "/" | "\\" | "#" }
number = @{"-"? ~ ("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) ~ ("." ~ ASCII_DIGIT+)? ~ (^"e" ~ ("+" | "-")? ~ ASCII_DIGIT+)?}
string_qt = ${ ("\'" ~ inner ~ "\'") | ("\"" ~ inner ~ "\"") }
inner = @{ char* }
char = _{
!("\"" | "\\" | "\'") ~ ANY
| "\\" ~ ("\"" | "\'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" | "(" | ")")
| "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4})
}
root = {"$"}
sign = { "==" | "!=" | "~=" | ">=" | ">" | "<=" | "<" | "in" | "nin" | "size" | "noneOf" | "anyOf" | "subsetOf"}
not = {"!"}
key_lim = {!"length()" ~ (word | ASCII_DIGIT | specs)+}
key_unlim = {"[" ~ string_qt ~ "]"}
key = ${key_lim | key_unlim}
descent = {dot ~ dot ~ key}
descent_w = {dot ~ dot ~ "*"} // refactor afterwards
wildcard = {dot? ~ "[" ~"*"~"]" | dot ~ "*"}
current = {"@" ~ chain?}
field = ${dot? ~ key_unlim | dot ~ key_lim }
function = { dot ~ "length" ~ "(" ~ ")"}
unsigned = {("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*)}
signed = {min? ~ unsigned}
start_slice = {signed}
end_slice = {signed}
step_slice = {col ~ unsigned}
slice = {start_slice? ~ col ~ end_slice? ~ step_slice? }
unit_keys = { string_qt ~ ("," ~ string_qt)+ }
unit_indexes = { number ~ ("," ~ number)+ }
filter = {"?"~ "(" ~ logic_or ~ ")"}
logic_or = {logic_and ~ ("||" ~ logic_and)*}
logic_and = {logic_not ~ ("&&" ~ logic_not)*}
logic_not = {not? ~ logic_atom}
logic_atom = {atom ~ (sign ~ atom)? | "(" ~ logic_or ~ ")"}
atom = {chain | string_qt | number | boolean | null}
index = {dot? ~ "["~ (unit_keys | unit_indexes | slice | unsigned |filter) ~ "]" }
chain = {(root | descent | descent_w | wildcard | current | field | index | function)+}
path = {SOI ~ chain ~ EOI }