class JMESPath::Parser
@api private
Constants
- AFTER_DOT
@api private
- CURRENT_NODE
Public Class Methods
new(options = {})
click to toggle source
@option options [Lexer] :lexer
# File lib/jmespath/parser.rb, line 21 def initialize(options = {}) @lexer = options[:lexer] || Lexer.new() end
Public Instance Methods
method_missing(method_name, *args)
click to toggle source
@api private
Calls superclass method
# File lib/jmespath/parser.rb, line 37 def method_missing(method_name, *args) if matches = method_name.match(/^(nud_|led_)(.*)/) raise Errors::SyntaxError, "unexpected token #{matches[2]}" else super end end
parse(expression)
click to toggle source
@param [String<JMESPath>] expression
# File lib/jmespath/parser.rb, line 26 def parse(expression) stream = TokenStream.new(expression, @lexer.tokenize(expression)) result = expr(stream) if stream.token.type != :eof raise Errors::SyntaxError, "expected :eof got #{stream.token.type}" else result end end
Private Instance Methods
expr(stream, rbp = 0)
click to toggle source
@param [TokenStream] stream @param [Integer] rbp Right binding power
# File lib/jmespath/parser.rb, line 49 def expr(stream, rbp = 0) left = send("nud_#{stream.token.type}", stream) while rbp < stream.token.binding_power left = send("led_#{stream.token.type}", stream, left) end left end
led_comparator(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 137 def led_comparator(stream, left) token = stream.token stream.next { type: :comparator, relation: token.value, children: [ left, expr(stream), ] } end
led_dot(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 150 def led_dot(stream, left) stream.next(match:AFTER_DOT) if stream.token.type == :star parse_wildcard_object(stream, left) else { type: :subexpression, children: [ left, parse_dot(stream, Token::BINDING_POWER[:dot]) ] } end end
led_filter(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 165 def led_filter(stream, left) stream.next expression = expr(stream) if stream.token.type != :rbracket raise Errors::SyntaxError, 'expected a closing rbracket for the filter' end stream.next rhs = parse_projection(stream, Token::BINDING_POWER[:filter]) { type: :projection, from: :array, children: [ left ? left : CURRENT_NODE, { type: :condition, children: [expression, rhs], } ] } end
led_flatten(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 186 def led_flatten(stream, left) stream.next { type: :projection, from: :array, children: [ { type: :flatten, children: [left] }, parse_projection(stream, Token::BINDING_POWER[:flatten]) ] } end
led_lbracket(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 198 def led_lbracket(stream, left) stream.next(match: Set.new([:number, :colon, :star])) type = stream.token.type if type == :number || type == :colon { type: :subexpression, children: [ left, parse_array_index_expression(stream) ] } else parse_wildcard_array(stream, left) end end
led_lparen(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 214 def led_lparen(stream, left) args = [] name = left[:key] stream.next while stream.token.type != :rparen args << expr(stream, 0) if stream.token.type == :comma stream.next end end stream.next { type: :function, fn: name, children: args, } end
led_or(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 232 def led_or(stream, left) stream.next { type: :or, children: [left, expr(stream, Token::BINDING_POWER[:or])] } end
led_pipe(stream, left)
click to toggle source
# File lib/jmespath/parser.rb, line 240 def led_pipe(stream, left) stream.next { type: :pipe, children: [left, expr(stream, Token::BINDING_POWER[:pipe])], } end
nud_current(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 57 def nud_current(stream) stream.next CURRENT_NODE end
nud_expref(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 62 def nud_expref(stream) stream.next { type: :expression, children: [expr(stream, 2)] } end
nud_filter(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 70 def nud_filter(stream) led_filter(stream, CURRENT_NODE) end
nud_flatten(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 74 def nud_flatten(stream) led_flatten(stream, CURRENT_NODE) end
nud_identifier(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 78 def nud_identifier(stream) token = stream.token stream.next { type: :field, key: token.value } end
nud_lbrace(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 84 def nud_lbrace(stream) valid_keys = Set.new([:quoted_identifier, :identifier]) stream.next(match:valid_keys) pairs = [] begin pairs << parse_key_value_pair(stream) if stream.token.type == :comma stream.next(match:valid_keys) end end while stream.token.type != :rbrace stream.next { type: :multi_select_hash, children: pairs } end
nud_lbracket(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 101 def nud_lbracket(stream) stream.next type = stream.token.type if type == :number || type == :colon parse_array_index_expression(stream) elsif type == :star && stream.lookahead(1).type == :rbracket parse_wildcard_array(stream) else parse_multi_select_list(stream) end end
nud_literal(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 113 def nud_literal(stream) value = stream.token.value stream.next { type: :literal, value: value } end
nud_quoted_identifier(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 122 def nud_quoted_identifier(stream) token = stream.token next_token = stream.next if next_token.type == :lparen msg = 'quoted identifiers are not allowed for function names' raise Errors::SyntaxError, msg else { type: :field, key: token[:value] } end end
nud_star(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 133 def nud_star(stream) parse_wildcard_object(stream, CURRENT_NODE) end
parse_array_index_expression(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 248 def parse_array_index_expression(stream) pos = 0 parts = [nil, nil, nil] begin if stream.token.type == :colon pos += 1 else parts[pos] = stream.token.value end stream.next(match:Set.new([:number, :colon, :rbracket])) end while stream.token.type != :rbracket stream.next if pos == 0 { type: :index, index: parts[0] } elsif pos > 2 raise Errors::SyntaxError, 'invalid array slice syntax: too many colons' else { type: :slice, args: parts } end end
parse_dot(stream, binding_power)
click to toggle source
# File lib/jmespath/parser.rb, line 269 def parse_dot(stream, binding_power) if stream.token.type == :lbracket stream.next parse_multi_select_list(stream) else expr(stream, binding_power) end end
parse_key_value_pair(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 278 def parse_key_value_pair(stream) key = stream.token.value stream.next(match:Set.new([:colon])) stream.next { type: :key_value_pair, key: key, children: [expr(stream)] } end
parse_multi_select_list(stream)
click to toggle source
# File lib/jmespath/parser.rb, line 289 def parse_multi_select_list(stream) nodes = [] begin nodes << expr(stream) if stream.token.type == :comma stream.next if stream.token.type == :rbracket raise Errors::SyntaxError, 'expression epxected, found rbracket' end end end while stream.token.type != :rbracket stream.next { type: :multi_select_list, children: nodes } end
parse_projection(stream, binding_power)
click to toggle source
# File lib/jmespath/parser.rb, line 307 def parse_projection(stream, binding_power) type = stream.token.type if stream.token.binding_power < 10 CURRENT_NODE elsif type == :dot stream.next(match:AFTER_DOT) parse_dot(stream, binding_power) elsif type == :lbracket || type == :filter expr(stream, binding_power) else raise Errors::SyntaxError, 'syntax error after projection' end end
parse_wildcard_array(stream, left = nil)
click to toggle source
# File lib/jmespath/parser.rb, line 321 def parse_wildcard_array(stream, left = nil) stream.next(match:Set.new([:rbracket])) stream.next { type: :projection, from: :array, children: [ left ? left : CURRENT_NODE, parse_projection(stream, Token::BINDING_POWER[:star]) ] } end
parse_wildcard_object(stream, left = nil)
click to toggle source
# File lib/jmespath/parser.rb, line 334 def parse_wildcard_object(stream, left = nil) stream.next { type: :projection, from: :object, children: [ left ? left : CURRENT_NODE, parse_projection(stream, Token::BINDING_POWER[:star]) ] } end