sep = _{ "." }
segment = { (ASCII_ALPHANUMERIC | "_" | "-")+ }
segment_with_ws = { (ASCII_ALPHANUMERIC | WHITESPACE | "." | "_" | "-")+ }
field_path = ${ sep ~ ("\"" ~ segment_with_ws ~ "\"" | segment) ~ field_path* }
value_dq = @{ "\"" ~ (!("\"") ~ ANY)* ~ "\"" }
value_sq = @{ "'" ~ (!("'") ~ ANY)* ~ "'" }
_number = _{ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
number = @{ _number | ("'" ~ _number ~ "'") | ("\"" ~ _number ~ "\"") }
_hex = _{ "0x"? ~ ASCII_HEX_DIGIT+ }
hex = @{ _hex | ("'" ~ _hex ~ "'") | ("\"" ~ _hex ~ "\"") }
none = @{ "none" }
some = @{ "some" }
option = _{ none | some }
bool_true = @{ "true" }
bool_false = @{ "false" }
bool = _{ bool_false | bool_true }
value = { (option | bool | hex | number | value_dq | value_sq) }
// the order in which operators are evaluated is important
op = { eq | lte | lt | gte | gt | rex | flag }
eq = { "==" | "is" }
lt = { "<" }
lte = { "<=" }
gt = { ">" }
gte = { ">=" }
rex = { "~=" }
flag = { "&=" }
_direct_match = _{ SOI ~ "\""? ~ field_path ~ "\""? ~ op ~ value ~ EOI }
direct_match = { _direct_match }
// indirect match
at = _{ "@" }
indirect_field_path = @{ at ~ field_path }
indirect_match = { SOI ~ field_path ~ eq ~ indirect_field_path ~ EOI }
// rule match
rule_name = { (ASCII_ALPHANUMERIC | "." | "_" | "-")+ }
rule_match = { SOI ~ "rule(" ~ rule_name ~ ")" }
// matcher
matcher = { direct_match | indirect_match | rule_match }
WHITESPACE = _{ " " }