Filter              = Or
Or                  = And {<'or'> And}
And                 = CompOr {<'and'> CompOr}
<CompOr>            = Comp | WS <'('> Or <')'> WS

Comp                = Attribute EqOp Value
                       | Attribute EqOp Values
                       | Attribute RelOp OrdinalValue
                       | Attribute PrefixOp StringValue
                       | Attribute FullTextOp StringValue
                       | Attribute  GeoOp WktValue
                       | Value EqOp Attribute
                       | Values EqOp Attribute
                       | OrdinalValue RelOp Attribute
                       | StringValue PrefixOp Attribute
                       | StringValue FullTextOp Attribute

FullTextOp          = '=='
PrefixOp            = '^='
EqOp                = '=' | '!='
RelOp               = '<' | '<=' | '>=' | '>'
GeoOp               = 'intersects' | 'disjoint' | 'within' | 'contains'


Attribute           = WS NamespaceTerm ('/' NamespaceTerm)* WS

<NamespaceTerm>     = (Term ':' Term) | Term
<Term>              = #'([a-zA-Z@][\w-]*[\w]+)|[a-zA-Z]'
<OrdinalValue>      = IntValue | DateValue | StringValue
<NominalValue>      = BoolValue | NullValue
<Value>             = OrdinalValue | NominalValue
Values              = <'['> [OrdinalValue {WS [<','>] WS OrdinalValue}] <']'> WS
IntValue            = WS #'\d+' WS
DateValue           = WS #'\d+-\d+(-\d+)?(T\d+:\d+:\d+(\.\d+)?(Z|[+-]\d+:\d+))?' WS
WktValue            = StringValue
StringValue         = WS (DoubleQuoteString | SingleQuoteString) WS
BoolValue           = WS ('true' | 'false') WS
NullValue           = WS 'null' WS

<WS>                = <#'\s*'>

<DoubleQuoteString> = #"\"[^\"\\]*(?:\\.[^\"\\]*)*\""
<SingleQuoteString> = #"'[^'\\]*(?:\\.[^'\\]*)*'"
