lib/scim2/filter/parser.racc
class Scim2::Filter::Parser
token EQ NE GT GE LT LE CO SW EW PR AND OR NOT LPAREN RPAREN LBRACKET RBRACKET
token NULL BOOLEAN NUMBER STRING ATTRNAME SCHEMA DOT
rule
#
# We must separate OR and AND filter rules in order to ensure the order of operations
# is properly followed. Specifically, the following two filters are the same:
#
# w AND x OR y AND z
# (w AND x) OR (y AND z)
#
# Separating the rules the parser will aggressively gobble up AND rules first, leaving
# OR rules for the very last as it bubbles back up the recursion stack
#
filter
: non_or_filter
| filter OR non_or_filter
{
filter1, op, filter2 = val
result = handler.on_logical_filter(filter1, filter2, op: op, context: result)
}
non_or_filter
: non_boolean_filter
| non_or_filter AND non_boolean_filter
{
filter1, op, filter2 = val
result = handler.on_logical_filter(filter1, filter2, op: op, context: result)
}
non_boolean_filter
: attribute_filter
| nested_filter
| grouped_filter
| not_filter
attribute_filter
: attr_path PR
{
attr, op = val
result = handler.on_attribute_filter(attr[:path], nil, op: op, schema: attr[:schema], context: result)
}
| attr_path comp_op comp_value
{
attr, op, v = val
result = handler.on_attribute_filter(attr[:path], v, op: op, schema: attr[:schema], context: result)
}
nested_filter
: nested_filter_start filter RBRACKET
{
attr, filter, _ = val
result = handler.on_nested_filter(attr[:path], filter, schema: attr[:schema], context: result)
}
nested_filter_start
: attr_path LBRACKET
{
attr, _ = val
handler.before_nested_filter(attr[:path], schema: attr[:schema], context: result) if handler.respond_to?(:before_nested_filter)
result = attr
}
grouped_filter
: LPAREN filter RPAREN
{
result = val[1]
}
not_filter
: NOT grouped_filter
{
_, filter = val
result = handler.on_not_filter(filter, context: result)
}
attr_path
: SCHEMA attr_path_elements
{
schema, path = val
result = { schema: schema, path: path }
}
| attr_path_elements
{
result = { path: val.last }
}
attr_path_elements
: attr_path_elements DOT ATTRNAME
{
result = [*val.first, val.last]
}
| ATTRNAME
{
result = [val.last]
}
comp_op
: EQ
| NE
| GT
| GE
| LT
| LE
| CO
| SW
| EW
comp_value
: BOOLEAN
| NULL
| NUMBER
| STRING
end