// Google AIP-160 Filter Grammar
// Supports filtering expressions like:
// - name = "foo"
// - age > 18 AND active = true
// - (status = "active" OR status = "pending") AND created > "2024-01-01"
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
// Main entry point
filter = { SOI ~ expression ~ EOI }
// Expressions with precedence
expression = { term ~ (or_op ~ term)* }
term = { factor ~ (and_op ~ factor)* }
factor = { not_op? ~ (restriction | "(" ~ expression ~ ")") }
// Logical operators
and_op = { "AND" }
or_op = { "OR" }
not_op = { "NOT" | "-" }
// Restrictions (comparisons)
restriction = { comparable ~ comparator ~ arg }
// Sequence for member/function access (for future nested field support)
sequence = { member ~ (sequence_op)+ }
sequence_op = _{ "." ~ member }
// Comparators
comparator = {
">=" | "<=" | "!=" | "=" | ":" | ">" | "<"
}
// Comparable (left side of comparison)
comparable = { member }
// Member (field name)
member = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
// Argument (right side of comparison)
arg = { string | number | boolean | null_val }
// Value types
string = ${ "\"" ~ string_inner ~ "\"" | "'" ~ string_inner ~ "'" }
string_inner = @{ (!("\"" | "'") ~ ANY)* }
number = @{
"-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? ~ (^"e" ~ ("+" | "-")? ~ ASCII_DIGIT+)?
}
boolean = { "true" | "TRUE" | "false" | "FALSE" }
null_val = { "null" | "NULL" }