class SCIM::Query::Filter::Parser
Constants
- IsOperator
- NextToken
- Op
- Ops
- Paren
Tokenizing regexen:
- Sep
- Str
- Unary
- Word
Attributes
rpn[RW]
Public Instance Methods
assert_close()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 144 def assert_close return true if peek == ')' parse_error "Unexpected token '%s'. Expected ')'" end
assert_eos()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 149 def assert_eos return true if eos parse_error "Unexpected token '%s'. Expected EOS" end
assert_not_op()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 139 def assert_not_op return true if ! peek_operator parse_error "Unexpected operator '%s'" end
assert_op()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 134 def assert_op return true if peek_operator parse_error "Unexpected token '%s'. Expected operator" end
eos()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 122 def eos; @tokens.empty? end
get_tree()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 107 def get_tree tree = [] if not @stack.empty? op = tree[0] = @stack.pop tree[1] = Ops[@stack.last] ? get_tree : @stack.pop tree.insert 1, Ops[@stack.last] ? get_tree : @stack.pop \ if not Unary[op] end tree end
lex(input)
click to toggle source
Split input into tokens
# File lib/scim/query/filter/parser.rb, line 70 def lex input input = input.clone tokens = [] while ! input.empty? do input.sub! NextToken, '' \ or fail "Can't lex input here: '#{input}'" tokens.push $1 end tokens end
parse(input)
click to toggle source
# File lib/scim/query/filter/parser.rb, line 35 def parse input @input = input # Save for error msgs @tokens = lex input @rpn = parse_expr assert_eos self end
parse_error(msg)
click to toggle source
Error handling methods:
# File lib/scim/query/filter/parser.rb, line 130 def parse_error msg fail "#{sprintf(msg, *@tokens, 'EOS')}.\nInput: '#{@input}'\n" end
parse_expr()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 43 def parse_expr ast = [] until eos or peek == ')' assert_not_op ast.push(start_group ? parse_group : pop.downcase) break if (eos or peek == ')') assert_op ast.push pop.downcase if !Unary[ast.last] assert_not_op ast.push(start_group ? parse_group : pop) end break if eos or peek == ')' assert_op ast.push pop.downcase end to_rpn ast end
parse_group()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 62 def parse_group pop # pop '(' token ast = parse_expr assert_close && pop # pop ')' token ast end
peek()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 120 def peek; @tokens.first end
peek_operator()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 124 def peek_operator not(eos) and peek.downcase.match IsOperator end
pop()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 121 def pop; @tokens.shift end
start_group()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 123 def start_group; peek == '(' end
to_rpn(ast)
click to toggle source
Turn parsed tokens into an RPN stack en.wikipedia.org/wiki/Shunting_yard_algorithm
# File lib/scim/query/filter/parser.rb, line 83 def to_rpn ast out, ops = [], [] out.push ast.shift if not ast.empty? while not ast.empty? do op = ast.shift precedence = Ops[op] \ or fail "Unknown operator '#{op}'" while not ops.empty? do break if precedence > Ops[ops.first] out.push ops.shift end ops.unshift op out.push ast.shift if not Unary[op] end (out.concat ops).flatten end
tree()
click to toggle source
# File lib/scim/query/filter/parser.rb, line 102 def tree @stack = @rpn.clone get_tree end