Interesting case. Technically requires a N:M (2:1) multi-mapping of bare_symbol and it's string to simple_symbol for a perfect solution.

This mapping is unfinished: 63 of 4586 nodes are still unmarked.

Before

1# frozen_string_literal: true
2
3require 'set'
4
5module JMESPath
6 # @api private
7 class Parser
8 AFTER_DOT = Set.new([
9 Lexer::T_IDENTIFIER, # foo.bar
10 Lexer::T_QUOTED_IDENTIFIER, # foo."bar"
11 Lexer::T_STAR, # foo.*
12 Lexer::T_LBRACE, # foo{a: 0}
13 Lexer::T_LBRACKET, # foo[1]
14 Lexer::T_FILTER # foo.[?bar==10]
15 ])
16
17 NUM_COLON_RBRACKET = Set.new([
18 Lexer::T_NUMBER,
19 Lexer::T_COLON,
20 Lexer::T_RBRACKET
21 ])
22
23 COLON_RBRACKET = Set.new([
24 Lexer::T_COLON,
25 Lexer::T_RBRACKET
26 ])
27
28 CURRENT_NODE = Nodes::Current.new
29
30 # @option options [Lexer] :lexer
31 def initialize(options = {})
32 @lexer = options[:lexer] || Lexer.new
…lines 33–56 unchanged (24 lines)
57 private
58
59 # @param [TokenStream] stream
60 # @param [Integer] rbp Right binding power
61 def expr(stream, rbp = 0)
62 left = send("nud_#{stream.token.type}", stream)
63 left = send("led_#{stream.token.type}", stream, left) while rbp < (stream.token.binding_power || 0)
64 left
65 end
66
67 def nud_current(stream)
68 stream.next
69 CURRENT_NODE
…lines 70–78 unchanged (9 lines)
79 Nodes::Not.new(expr(stream, Token::BINDING_POWER[:not]))
80 end
81
82 def nud_lparen(stream)
83 stream.next
84 result = expr(stream, 0)
85 raise Errors::SyntaxError, 'Unclosed `(`' if stream.token.type != Lexer::T_RPAREN
86
87 stream.next
88 result
89 end
90
91 def nud_filter(stream)
…lines 92–103 unchanged (12 lines)
104 else
105 Nodes::Field.new(token.value)
106 end
107 end
108
109 def nud_lbrace(stream)
110 valid_keys = Set.new(%i[quoted_identifier identifier])
111 stream.next(match: valid_keys)
112 pairs = []
113 loop do
114 pairs << parse_key_value_pair(stream)
115 stream.next(match: valid_keys) if stream.token.type == :comma
116 break unless stream.token.type != :rbrace
117 end
118 stream.next
119 Nodes::MultiSelectHash.new(pairs)
120 end
121
122 def nud_lbracket(stream)
123 stream.next
124 type = stream.token.type
125 if %i[number colon].include?(type)
126 parse_array_index_expression(stream)
127 elsif type == :star && stream.lookahead(1).type == :rbracket
128 parse_wildcard_array(stream)
129 else
130 parse_multi_select_list(stream)
131 end
132 end
…lines 133–172 unchanged (40 lines)
173 end
174 end
175
176 def led_filter(stream, left)
177 stream.next
178 expression = expr(stream)
179 raise Errors::SyntaxError, 'expected a closing rbracket for the filter' if stream.token.type != Lexer::T_RBRACKET
180
181 stream.next
182 rhs = parse_projection(stream, Token::BINDING_POWER[Lexer::T_FILTER])
183 left ||= CURRENT_NODE
184 right = Nodes::Condition.new(expression, rhs)
185 Nodes::ArrayProjection.new(left, right)
…lines 186–189 unchanged (4 lines)
190 left = Nodes::Flatten.new(left)
191 right = parse_projection(stream, Token::BINDING_POWER[:flatten])
192 Nodes::ArrayProjection.new(left, right)
193 end
194
195 def led_lbracket(stream, left)
196 stream.next(match: Set.new(%i[number colon star]))
197 type = stream.token.type
198 if %i[number colon].include?(type)
199 right = parse_array_index_expression(stream)
200 Nodes::Subexpression.new(left, right)
201 else
202 parse_wildcard_array(stream, left)
203 end
204 end
205
206 def led_lparen(stream, left)
207 args = []
208 if left.is_a?(Nodes::Function::FunctionName)
209 name = left.name
210 else
211 raise Errors::SyntaxError, 'invalid function invocation'
212 end
213 stream.next
214 while stream.token.type != :rparen
215 args << expr(stream, 0)
216 stream.next if stream.token.type == :comma
217 end
218 stream.next
219 Nodes::Function.create(name, args, disable_visit_errors: @disable_visit_errors)
220 end
221
222 def led_or(stream, left)
223 stream.next
224 right = expr(stream, Token::BINDING_POWER[:or])
225 Nodes::Or.new(left, right)
…lines 226–238 unchanged (13 lines)
239
240 # parse array index expressions, for example [0], [1:2:3], etc.
241 def parse_array_index_expression(stream)
242 pos = 0
243 parts = [nil, nil, nil]
244 expected = NUM_COLON_RBRACKET
245
246 loop do
247 case stream.token.type
248 when Lexer::T_COLON
249 pos += 1
250 expected = NUM_COLON_RBRACKET
251 when Lexer::T_NUMBER
252 parts[pos] = stream.token.value
253 expected = COLON_RBRACKET
254 end
255 stream.next(match: expected)
256 break unless stream.token.type != Lexer::T_RBRACKET
257 end
258
259 stream.next # consume the closing bracket
260
261 if pos.zero?
262 # no colons found, this is a single index extraction
263 Nodes::Index.new(parts[0])
264 elsif pos > 2
265 raise Errors::SyntaxError, 'invalid array slice syntax: too many colons'
266 else
267 Nodes::ArrayProjection.new(
…lines 268–285 unchanged (18 lines)
286 stream.next
287 Nodes::MultiSelectHash::KeyValuePair.new(key, expr(stream))
288 end
289
290 def parse_multi_select_list(stream)
291 nodes = []
292 loop do
293 nodes << expr(stream)
294 if stream.token.type == :comma
295 stream.next
296 raise Errors::SyntaxError, 'expression epxected, found rbracket' if stream.token.type == :rbracket
297 end
298 break unless stream.token.type != :rbracket
299 end
300 stream.next
301 Nodes::MultiSelectList.new(nodes)
302 end
303
304 def parse_projection(stream, binding_power)
305 type = stream.token.type
306 if stream.token.binding_power < 10
307 CURRENT_NODE
308 elsif type == :dot
309 stream.next(match: AFTER_DOT)
310 parse_dot(stream, binding_power)
311 elsif %i[lbracket filter].include?(type)
312 expr(stream, binding_power)
313 else
314 raise Errors::SyntaxError, 'syntax error after projection'
315 end
316 end
317
318 def parse_wildcard_array(stream, left = nil)
…lines 319–334 unchanged (16 lines)

After

1require 'set'
2
3module JMESPath
4 # @api private
5 class Parser
6
7 AFTER_DOT = Set.new([
8 Lexer::T_IDENTIFIER, # foo.bar
9 Lexer::T_QUOTED_IDENTIFIER, # foo."bar"
10 Lexer::T_STAR, # foo.*
11 Lexer::T_LBRACE, # foo{a: 0}
12 Lexer::T_LBRACKET, # foo[1]
13 Lexer::T_FILTER, # foo.[?bar==10]
14 ])
15
16 NUM_COLON_RBRACKET = Set.new([
17 Lexer::T_NUMBER,
18 Lexer::T_COLON,
19 Lexer::T_RBRACKET,
20 ])
21
22 COLON_RBRACKET = Set.new([
23 Lexer::T_COLON,
24 Lexer::T_RBRACKET,
25 ])
26
27 CURRENT_NODE = Nodes::Current.new
28
29 # @option options [Lexer] :lexer
30 def initialize(options = {})
31 @lexer = options[:lexer] || Lexer.new
…lines 32–55 unchanged (24 lines)
56 private
57
58 # @param [TokenStream] stream
59 # @param [Integer] rbp Right binding power
60 def expr(stream, rbp = 0)
61 left = send("nud_#{stream.token.type}", stream)
62 while rbp < (stream.token.binding_power || 0)
63 left = send("led_#{stream.token.type}", stream, left)
64 end
65 left
66 end
67
68 def nud_current(stream)
69 stream.next
70 CURRENT_NODE
…lines 71–79 unchanged (9 lines)
80 Nodes::Not.new(expr(stream, Token::BINDING_POWER[:not]))
81 end
82
83 def nud_lparen(stream)
84 stream.next
85 result = expr(stream, 0)
86 if stream.token.type != Lexer::T_RPAREN
87 raise Errors::SyntaxError, 'Unclosed `(`'
88 end
89 stream.next
90 result
91 end
92
93 def nud_filter(stream)
94 led_filter(stream, CURRENT_NODE)
…lines 95–105 unchanged (11 lines)
106 else
107 Nodes::Field.new(token.value)
108 end
109 end
110
111 def nud_lbrace(stream)
112 valid_keys = Set.new([:quoted_identifier, :identifier])
113 stream.next(match:valid_keys)
114 pairs = []
115 begin
116 pairs << parse_key_value_pair(stream)
117 if stream.token.type == :comma
118 stream.next(match:valid_keys)
119 end
120 end while stream.token.type != :rbrace
121 stream.next
122 Nodes::MultiSelectHash.new(pairs)
123 end
124
125 def nud_lbracket(stream)
126 stream.next
127 type = stream.token.type
128 if type == :number || type == :colon
129 parse_array_index_expression(stream)
130 elsif type == :star && stream.lookahead(1).type == :rbracket
131 parse_wildcard_array(stream)
132 else
133 parse_multi_select_list(stream)
134 end
135 end
…lines 136–175 unchanged (40 lines)
176 end
177 end
178
179 def led_filter(stream, left)
180 stream.next
181 expression = expr(stream)
182 if stream.token.type != Lexer::T_RBRACKET
183 raise Errors::SyntaxError, 'expected a closing rbracket for the filter'
184 end
185 stream.next
186 rhs = parse_projection(stream, Token::BINDING_POWER[Lexer::T_FILTER])
187 left ||= CURRENT_NODE
188 right = Nodes::Condition.new(expression, rhs)
189 Nodes::ArrayProjection.new(left, right)
190 end
191
192 def led_flatten(stream, left)
193 stream.next
194 left = Nodes::Flatten.new(left)
195 right = parse_projection(stream, Token::BINDING_POWER[:flatten])
196 Nodes::ArrayProjection.new(left, right)
197 end
198
199 def led_lbracket(stream, left)
200 stream.next(match: Set.new([:number, :colon, :star]))
201 type = stream.token.type
202 if type == :number || type == :colon
203 right = parse_array_index_expression(stream)
204 Nodes::Subexpression.new(left, right)
205 else
206 parse_wildcard_array(stream, left)
207 end
208 end
209
210 def led_lparen(stream, left)
211 args = []
212 if Nodes::Function::FunctionName === left
213 name = left.name
214 else
215 raise Errors::SyntaxError, 'invalid function invocation'
216 end
217 stream.next
218 while stream.token.type != :rparen
219 args << expr(stream, 0)
220 if stream.token.type == :comma
221 stream.next
222 end
223 end
224 stream.next
225 Nodes::Function.create(name, args, :disable_visit_errors => @disable_visit_errors)
226 end
227
228 def led_or(stream, left)
229 stream.next
230 right = expr(stream, Token::BINDING_POWER[:or])
231 Nodes::Or.new(left, right)
…lines 232–244 unchanged (13 lines)
245
246 # parse array index expressions, for example [0], [1:2:3], etc.
247 def parse_array_index_expression(stream)
248 pos = 0
249 parts = [nil, nil, nil]
250 expected = NUM_COLON_RBRACKET
251
252 begin
253 if stream.token.type == Lexer::T_COLON
254 pos += 1
255 expected = NUM_COLON_RBRACKET
256 elsif stream.token.type == Lexer::T_NUMBER
257 parts[pos] = stream.token.value
258 expected = COLON_RBRACKET
259 end
260 stream.next(match: expected)
261 end while stream.token.type != Lexer::T_RBRACKET
262
263 stream.next # consume the closing bracket
264
265 if pos == 0
266 # no colons found, this is a single index extraction
267 Nodes::Index.new(parts[0])
268 elsif pos > 2
269 raise Errors::SyntaxError, 'invalid array slice syntax: too many colons'
270 else
271 Nodes::ArrayProjection.new(
…lines 272–289 unchanged (18 lines)
290 stream.next
291 Nodes::MultiSelectHash::KeyValuePair.new(key, expr(stream))
292 end
293
294 def parse_multi_select_list(stream)
295 nodes = []
296 begin
297 nodes << expr(stream)
298 if stream.token.type == :comma
299 stream.next
300 if stream.token.type == :rbracket
301 raise Errors::SyntaxError, 'expression epxected, found rbracket'
302 end
303 end
304 end while stream.token.type != :rbracket
305 stream.next
306 Nodes::MultiSelectList.new(nodes)
307 end
308
309 def parse_projection(stream, binding_power)
310 type = stream.token.type
311 if stream.token.binding_power < 10
312 CURRENT_NODE
313 elsif type == :dot
314 stream.next(match:AFTER_DOT)
315 parse_dot(stream, binding_power)
316 elsif type == :lbracket || type == :filter
317 expr(stream, binding_power)
318 else
319 raise Errors::SyntaxError, 'syntax error after projection'
320 end
321 end
322
323 def parse_wildcard_array(stream, left = nil)
…lines 324–340 unchanged (17 lines)

Before

program
comment "# frozen_string_literal: true"
call
identifier "require"
argument_list
string
" "'"
string_content "set"
" "'"
module
module "module"
constant "JMESPath"
comment "# @api private"
body_statement
class
class "class"
constant "Parser"
body_statement
assignment
constant "AFTER_DOT"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
scope_resolution
constant "Lexer"
:: "::"
constant "T_IDENTIFIER"
, ","
comment "# foo.bar"
scope_resolution
constant "Lexer"
:: "::"
constant "T_QUOTED_IDENTIFIER"
, ","
comment "# foo.\"bar\""
scope_resolution
constant "Lexer"
:: "::"
constant "T_STAR"
, ","
comment "# foo.*"
scope_resolution
constant "Lexer"
:: "::"
constant "T_LBRACE"
, ","
comment "# foo{a: 0}"
scope_resolution
constant "Lexer"
:: "::"
constant "T_LBRACKET"
, ","
comment "# foo[1]"
scope_resolution
constant "Lexer"
:: "::"
constant "T_FILTER"
comment "# foo.[?bar==10]"
] "]"
) ")"
assignment
constant "NUM_COLON_RBRACKET"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
scope_resolution
constant "Lexer"
:: "::"
constant "T_NUMBER"
, ","
scope_resolution
constant "Lexer"
:: "::"
constant "T_COLON"
, ","
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
] "]"
) ")"
assignment
constant "COLON_RBRACKET"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
scope_resolution
constant "Lexer"
:: "::"
constant "T_COLON"
, ","
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
] "]"
) ")"
assignment
constant "CURRENT_NODE"
= "="
call
scope_resolution
constant "Nodes"
:: "::"
constant "Current"
. "."
identifier "new"
comment "# @option options [Lexer] :lexer"
method (+36 nodes collapsed)
comment "# @param [String<JMESPath>] expression"
method (+84 nodes collapsed)
comment "# @api private"
method (+57 nodes collapsed)
identifier "private"
comment "# @param [TokenStream] stream"
comment "# @param [Integer] rbp Right binding power"
method
def "def"
identifier "expr"
method_parameters
( "("
identifier "stream"
, ","
optional_parameter
identifier "rbp"
= "="
integer "0"
) ")"
body_statement
assignment (+24 nodes collapsed)
while_modifier
assignment (+26 nodes collapsed)
while "while"
binary
identifier "rbp"
< "<"
parenthesized_statements
( "("
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "binding_power"
|| "||"
integer "0"
) ")"
identifier "left"
end "end"
method
def "def"
identifier "nud_current"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
constant "CURRENT_NODE"
end "end"
method (+38 nodes collapsed)
method (+38 nodes collapsed)
method
def "def"
identifier "nud_lparen"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
assignment
identifier "result"
= "="
call
identifier "expr"
argument_list
( "("
identifier "stream"
, ","
integer "0"
) ")"
if_modifier
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "Unclosed `(`"
" "'"
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
scope_resolution
constant "Lexer"
:: "::"
constant "T_RPAREN"
call
identifier "stream"
. "."
identifier "next"
identifier "result"
end "end"
method
def "def"
identifier "nud_filter"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "led_filter"
argument_list
( "("
identifier "stream"
, ","
constant "CURRENT_NODE"
) ")"
end "end"
method
def "def"
identifier "nud_flatten"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "led_flatten"
argument_list
( "("
identifier "stream"
, ","
constant "CURRENT_NODE"
) ")"
end "end"
method (+67 nodes collapsed)
method
def "def"
identifier "nud_lbrace"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
assignment
identifier "valid_keys"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
symbol_array
%i( "%i["
bare_symbol
string_content "quoted_identifier"
bare_symbol
string_content "identifier"
) "]"
) ")"
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
identifier "valid_keys"
) ")"
assignment
identifier "pairs"
= "="
array
[ "["
] "]"
call
identifier "loop"
do_block
do "do"
body_statement
binary
identifier "pairs"
<< "<<"
call
identifier "parse_key_value_pair"
argument_list
( "("
identifier "stream"
) ")"
if_modifier
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
identifier "valid_keys"
) ")"
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":comma"
unless_modifier
break
break "break"
unless "unless"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
simple_symbol ":rbrace"
end "end"
call
identifier "stream"
. "."
identifier "next"
call
scope_resolution
constant "Nodes"
:: "::"
constant "MultiSelectHash"
. "."
identifier "new"
argument_list
( "("
identifier "pairs"
) ")"
end "end"
method
def "def"
identifier "nud_lbracket"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
assignment
identifier "type"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
if
if "if"
call
symbol_array
%i( "%i["
bare_symbol
string_content "number"
bare_symbol
string_content "colon"
) "]"
. "."
identifier "include?"
argument_list
( "("
identifier "type"
) ")"
then
call
identifier "parse_array_index_expression"
argument_list
( "("
identifier "stream"
) ")"
elsif (+37 nodes collapsed)
end "end"
end "end"
method (+34 nodes collapsed)
method (+67 nodes collapsed)
method
def "def"
identifier "nud_star"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "parse_wildcard_object"
argument_list
( "("
identifier "stream"
, ","
constant "CURRENT_NODE"
) ")"
end "end"
method (+34 nodes collapsed)
method (+58 nodes collapsed)
method (+77 nodes collapsed)
method
def "def"
identifier "led_filter"
method_parameters
( "("
identifier "stream"
, ","
identifier "left"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
assignment
identifier "expression"
= "="
call
identifier "expr"
argument_list
( "("
identifier "stream"
) ")"
if_modifier
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "expected a closing rbracket for the filter"
" "'"
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
call
identifier "stream"
. "."
identifier "next"
assignment (+21 nodes collapsed)
operator_assignment
identifier "left"
||= "||="
constant "CURRENT_NODE"
assignment
identifier "right"
= "="
call
scope_resolution
constant "Nodes"
:: "::"
constant "Condition"
. "."
identifier "new"
argument_list
( "("
identifier "expression"
, ","
identifier "rhs"
) ")"
call
scope_resolution
constant "Nodes"
:: "::"
constant "ArrayProjection"
. "."
identifier "new"
argument_list
( "("
identifier "left"
, ","
identifier "right"
) ")"
end "end"
method (+60 nodes collapsed)
method
def "def"
identifier "led_lbracket"
method_parameters
( "("
identifier "stream"
, ","
identifier "left"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
symbol_array
%i( "%i["
bare_symbol
string_content "number"
bare_symbol
string_content "colon"
bare_symbol
string_content "star"
) "]"
) ")"
) ")"
assignment
identifier "type"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
if
if "if"
call
symbol_array
%i( "%i["
bare_symbol
string_content "number"
bare_symbol
string_content "colon"
) "]"
. "."
identifier "include?"
argument_list
( "("
identifier "type"
) ")"
then (+23 nodes collapsed)
else
else "else"
call
identifier "parse_wildcard_array"
argument_list
( "("
identifier "stream"
, ","
identifier "left"
) ")"
end "end"
end "end"
method
def "def"
identifier "led_lparen"
method_parameters
( "("
identifier "stream"
, ","
identifier "left"
) ")"
body_statement
assignment
identifier "args"
= "="
array
[ "["
] "]"
if
if "if"
call
identifier "left"
. "."
identifier "is_a?"
argument_list
( "("
scope_resolution
scope_resolution
constant "Nodes"
:: "::"
constant "Function"
:: "::"
constant "FunctionName"
) ")"
then
assignment
identifier "name"
= "="
call
identifier "left"
. "."
identifier "name"
else
else "else"
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "invalid function invocation"
" "'"
end "end"
call
identifier "stream"
. "."
identifier "next"
while
while "while"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
simple_symbol ":rparen"
do
binary
identifier "args"
<< "<<"
call
identifier "expr"
argument_list
( "("
identifier "stream"
, ","
integer "0"
) ")"
if_modifier
call
identifier "stream"
. "."
identifier "next"
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":comma"
end "end"
call
identifier "stream"
. "."
identifier "next"
call
scope_resolution
constant "Nodes"
:: "::"
constant "Function"
. "."
identifier "create"
argument_list
( "("
identifier "name"
, ","
identifier "args"
, ","
pair
hash_key_symbol "disable_visit_errors"
: ":"
instance_variable "@disable_visit_errors"
) ")"
end "end"
method (+46 nodes collapsed)
method (+46 nodes collapsed)
method (+46 nodes collapsed)
comment "# parse array index expressions, for example [0], [1:2:3], e"...
method
def "def"
identifier "parse_array_index_expression"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
assignment
identifier "pos"
= "="
integer "0"
assignment
identifier "parts"
= "="
array
[ "["
nil
nil "nil"
, ","
nil
nil "nil"
, ","
nil
nil "nil"
] "]"
assignment
identifier "expected"
= "="
constant "NUM_COLON_RBRACKET"
call
identifier "loop"
do_block
do "do"
body_statement
case
case "case"
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
when
when "when"
pattern
scope_resolution
constant "Lexer"
:: "::"
constant "T_COLON"
then
operator_assignment
identifier "pos"
+= "+="
integer "1"
assignment
identifier "expected"
= "="
constant "NUM_COLON_RBRACKET"
when
when "when"
pattern
scope_resolution
constant "Lexer"
:: "::"
constant "T_NUMBER"
then
assignment
element_reference
identifier "parts"
[ "["
identifier "pos"
] "]"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "value"
assignment
identifier "expected"
= "="
constant "COLON_RBRACKET"
end "end"
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
identifier "expected"
) ")"
unless_modifier
break
break "break"
unless "unless"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
end "end"
call
identifier "stream"
. "."
identifier "next"
comment "# consume the closing bracket"
if
if "if"
call
identifier "pos"
. "."
identifier "zero?"
comment "# no colons found, this is a single index extraction"
then
call
scope_resolution
constant "Nodes"
:: "::"
constant "Index"
. "."
identifier "new"
argument_list
( "("
element_reference
identifier "parts"
[ "["
integer "0"
] "]"
) ")"
elsif (+63 nodes collapsed)
end "end"
end "end"
method (+45 nodes collapsed)
method (+65 nodes collapsed)
method
def "def"
identifier "parse_multi_select_list"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
assignment
identifier "nodes"
= "="
array
[ "["
] "]"
call
identifier "loop"
do_block
do "do"
body_statement
binary
identifier "nodes"
<< "<<"
call
identifier "expr"
argument_list
( "("
identifier "stream"
) ")"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":comma"
then
call
identifier "stream"
. "."
identifier "next"
if_modifier
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "expression epxected, found rbracket"
" "'"
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":rbracket"
end "end"
unless_modifier
break
break "break"
unless "unless"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
simple_symbol ":rbracket"
end "end"
call
identifier "stream"
. "."
identifier "next"
call
scope_resolution
constant "Nodes"
:: "::"
constant "MultiSelectList"
. "."
identifier "new"
argument_list
( "("
identifier "nodes"
) ")"
end "end"
method
def "def"
identifier "parse_projection"
method_parameters
( "("
identifier "stream"
, ","
identifier "binding_power"
) ")"
body_statement
assignment
identifier "type"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "binding_power"
< "<"
integer "10"
then
constant "CURRENT_NODE"
elsif
elsif "elsif"
binary
identifier "type"
== "=="
simple_symbol ":dot"
then
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
constant "AFTER_DOT"
) ")"
call
identifier "parse_dot"
argument_list
( "("
identifier "stream"
, ","
identifier "binding_power"
) ")"
elsif
elsif "elsif"
call
symbol_array
%i( "%i["
bare_symbol
string_content "lbracket"
bare_symbol
string_content "filter"
) "]"
. "."
identifier "include?"
argument_list
( "("
identifier "type"
) ")"
then
call
identifier "expr"
argument_list
( "("
identifier "stream"
, ","
identifier "binding_power"
) ")"
else
else "else"
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "syntax error after projection"
" "'"
end "end"
end "end"
method (+75 nodes collapsed)
method (+54 nodes collapsed)
end "end"
end "end"

After

program
call
identifier "require"
argument_list
string
" "'"
string_content "set"
" "'"
module
module "module"
constant "JMESPath"
comment "# @api private"
body_statement
class
class "class"
constant "Parser"
body_statement
assignment
constant "AFTER_DOT"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
scope_resolution
constant "Lexer"
:: "::"
constant "T_IDENTIFIER"
, ","
comment "# foo.bar"
scope_resolution
constant "Lexer"
:: "::"
constant "T_QUOTED_IDENTIFIER"
, ","
comment "# foo.\"bar\""
scope_resolution
constant "Lexer"
:: "::"
constant "T_STAR"
, ","
comment "# foo.*"
scope_resolution
constant "Lexer"
:: "::"
constant "T_LBRACE"
, ","
comment "# foo{a: 0}"
scope_resolution
constant "Lexer"
:: "::"
constant "T_LBRACKET"
, ","
comment "# foo[1]"
scope_resolution
constant "Lexer"
:: "::"
constant "T_FILTER"
, ","
comment "# foo.[?bar==10]"
] "]"
) ")"
assignment
constant "NUM_COLON_RBRACKET"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
scope_resolution
constant "Lexer"
:: "::"
constant "T_NUMBER"
, ","
scope_resolution
constant "Lexer"
:: "::"
constant "T_COLON"
, ","
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
, ","
] "]"
) ")"
assignment
constant "COLON_RBRACKET"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
scope_resolution
constant "Lexer"
:: "::"
constant "T_COLON"
, ","
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
, ","
] "]"
) ")"
assignment
constant "CURRENT_NODE"
= "="
call
scope_resolution
constant "Nodes"
:: "::"
constant "Current"
. "."
identifier "new"
comment "# @option options [Lexer] :lexer"
method (+36 nodes collapsed)
comment "# @param [String<JMESPath>] expression"
method (+84 nodes collapsed)
comment "# @api private"
method (+57 nodes collapsed)
identifier "private"
comment "# @param [TokenStream] stream"
comment "# @param [Integer] rbp Right binding power"
method
def "def"
identifier "expr"
method_parameters
( "("
identifier "stream"
, ","
optional_parameter
identifier "rbp"
= "="
integer "0"
) ")"
body_statement
assignment (+24 nodes collapsed)
while
while "while"
binary
identifier "rbp"
< "<"
parenthesized_statements
( "("
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "binding_power"
|| "||"
integer "0"
) ")"
do
assignment (+26 nodes collapsed)
end "end"
identifier "left"
end "end"
method
def "def"
identifier "nud_current"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
constant "CURRENT_NODE"
end "end"
method (+38 nodes collapsed)
method (+38 nodes collapsed)
method
def "def"
identifier "nud_lparen"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
assignment
identifier "result"
= "="
call
identifier "expr"
argument_list
( "("
identifier "stream"
, ","
integer "0"
) ")"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
scope_resolution
constant "Lexer"
:: "::"
constant "T_RPAREN"
then
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "Unclosed `(`"
" "'"
end "end"
call
identifier "stream"
. "."
identifier "next"
identifier "result"
end "end"
method
def "def"
identifier "nud_filter"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "led_filter"
argument_list
( "("
identifier "stream"
, ","
constant "CURRENT_NODE"
) ")"
end "end"
method
def "def"
identifier "nud_flatten"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "led_flatten"
argument_list
( "("
identifier "stream"
, ","
constant "CURRENT_NODE"
) ")"
end "end"
method (+67 nodes collapsed)
method
def "def"
identifier "nud_lbrace"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
assignment
identifier "valid_keys"
= "="
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
simple_symbol ":quoted_identifier"
, ","
simple_symbol ":identifier"
] "]"
) ")"
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
identifier "valid_keys"
) ")"
assignment
identifier "pairs"
= "="
array
[ "["
] "]"
while_modifier
begin
begin "begin"
binary
identifier "pairs"
<< "<<"
call
identifier "parse_key_value_pair"
argument_list
( "("
identifier "stream"
) ")"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":comma"
then
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
identifier "valid_keys"
) ")"
end "end"
end "end"
while "while"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
simple_symbol ":rbrace"
call
identifier "stream"
. "."
identifier "next"
call
scope_resolution
constant "Nodes"
:: "::"
constant "MultiSelectHash"
. "."
identifier "new"
argument_list
( "("
identifier "pairs"
) ")"
end "end"
method
def "def"
identifier "nud_lbracket"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
assignment
identifier "type"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
if
if "if"
binary
binary
identifier "type"
== "=="
simple_symbol ":number"
|| "||"
binary
identifier "type"
== "=="
simple_symbol ":colon"
then
call
identifier "parse_array_index_expression"
argument_list
( "("
identifier "stream"
) ")"
elsif (+37 nodes collapsed)
end "end"
end "end"
method (+34 nodes collapsed)
method (+67 nodes collapsed)
method
def "def"
identifier "nud_star"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
call
identifier "parse_wildcard_object"
argument_list
( "("
identifier "stream"
, ","
constant "CURRENT_NODE"
) ")"
end "end"
method (+34 nodes collapsed)
method (+58 nodes collapsed)
method (+77 nodes collapsed)
method
def "def"
identifier "led_filter"
method_parameters
( "("
identifier "stream"
, ","
identifier "left"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
assignment
identifier "expression"
= "="
call
identifier "expr"
argument_list
( "("
identifier "stream"
) ")"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
then
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "expected a closing rbracket for the filter"
" "'"
end "end"
call
identifier "stream"
. "."
identifier "next"
assignment (+21 nodes collapsed)
operator_assignment
identifier "left"
||= "||="
constant "CURRENT_NODE"
assignment
identifier "right"
= "="
call
scope_resolution
constant "Nodes"
:: "::"
constant "Condition"
. "."
identifier "new"
argument_list
( "("
identifier "expression"
, ","
identifier "rhs"
) ")"
call
scope_resolution
constant "Nodes"
:: "::"
constant "ArrayProjection"
. "."
identifier "new"
argument_list
( "("
identifier "left"
, ","
identifier "right"
) ")"
end "end"
method (+60 nodes collapsed)
method
def "def"
identifier "led_lbracket"
method_parameters
( "("
identifier "stream"
, ","
identifier "left"
) ")"
body_statement
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
call
constant "Set"
. "."
identifier "new"
argument_list
( "("
array
[ "["
simple_symbol ":number"
, ","
simple_symbol ":colon"
, ","
simple_symbol ":star"
] "]"
) ")"
) ")"
assignment
identifier "type"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
if
if "if"
binary
binary
identifier "type"
== "=="
simple_symbol ":number"
|| "||"
binary
identifier "type"
== "=="
simple_symbol ":colon"
then (+23 nodes collapsed)
else
else "else"
call
identifier "parse_wildcard_array"
argument_list
( "("
identifier "stream"
, ","
identifier "left"
) ")"
end "end"
end "end"
method
def "def"
identifier "led_lparen"
method_parameters
( "("
identifier "stream"
, ","
identifier "left"
) ")"
body_statement
assignment
identifier "args"
= "="
array
[ "["
] "]"
if
if "if"
binary
scope_resolution
scope_resolution
constant "Nodes"
:: "::"
constant "Function"
:: "::"
constant "FunctionName"
=== "==="
identifier "left"
then
assignment
identifier "name"
= "="
call
identifier "left"
. "."
identifier "name"
else
else "else"
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "invalid function invocation"
" "'"
end "end"
call
identifier "stream"
. "."
identifier "next"
while
while "while"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
simple_symbol ":rparen"
do
binary
identifier "args"
<< "<<"
call
identifier "expr"
argument_list
( "("
identifier "stream"
, ","
integer "0"
) ")"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":comma"
then
call
identifier "stream"
. "."
identifier "next"
end "end"
end "end"
call
identifier "stream"
. "."
identifier "next"
call
scope_resolution
constant "Nodes"
:: "::"
constant "Function"
. "."
identifier "create"
argument_list
( "("
identifier "name"
, ","
identifier "args"
, ","
pair
simple_symbol ":disable_visit_errors"
=> "=>"
instance_variable "@disable_visit_errors"
) ")"
end "end"
method (+46 nodes collapsed)
method (+46 nodes collapsed)
method (+46 nodes collapsed)
comment "# parse array index expressions, for example [0], [1:2:3], e"...
method
def "def"
identifier "parse_array_index_expression"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
assignment
identifier "pos"
= "="
integer "0"
assignment
identifier "parts"
= "="
array
[ "["
nil
nil "nil"
, ","
nil
nil "nil"
, ","
nil
nil "nil"
] "]"
assignment
identifier "expected"
= "="
constant "NUM_COLON_RBRACKET"
while_modifier
begin
begin "begin"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
scope_resolution
constant "Lexer"
:: "::"
constant "T_COLON"
then
operator_assignment
identifier "pos"
+= "+="
integer "1"
assignment
identifier "expected"
= "="
constant "NUM_COLON_RBRACKET"
elsif
elsif "elsif"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
scope_resolution
constant "Lexer"
:: "::"
constant "T_NUMBER"
then
assignment
element_reference
identifier "parts"
[ "["
identifier "pos"
] "]"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "value"
assignment
identifier "expected"
= "="
constant "COLON_RBRACKET"
end "end"
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
identifier "expected"
) ")"
end "end"
while "while"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
scope_resolution
constant "Lexer"
:: "::"
constant "T_RBRACKET"
call
identifier "stream"
. "."
identifier "next"
comment "# consume the closing bracket"
if
if "if"
binary
identifier "pos"
== "=="
integer "0"
comment "# no colons found, this is a single index extraction"
then
call
scope_resolution
constant "Nodes"
:: "::"
constant "Index"
. "."
identifier "new"
argument_list
( "("
element_reference
identifier "parts"
[ "["
integer "0"
] "]"
) ")"
elsif (+63 nodes collapsed)
end "end"
end "end"
method (+45 nodes collapsed)
method (+65 nodes collapsed)
method
def "def"
identifier "parse_multi_select_list"
method_parameters
( "("
identifier "stream"
) ")"
body_statement
assignment
identifier "nodes"
= "="
array
[ "["
] "]"
while_modifier
begin
begin "begin"
binary
identifier "nodes"
<< "<<"
call
identifier "expr"
argument_list
( "("
identifier "stream"
) ")"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":comma"
then
call
identifier "stream"
. "."
identifier "next"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
== "=="
simple_symbol ":rbracket"
then
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "expression epxected, found rbracket"
" "'"
end "end"
end "end"
end "end"
while "while"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
!= "!="
simple_symbol ":rbracket"
call
identifier "stream"
. "."
identifier "next"
call
scope_resolution
constant "Nodes"
:: "::"
constant "MultiSelectList"
. "."
identifier "new"
argument_list
( "("
identifier "nodes"
) ")"
end "end"
method
def "def"
identifier "parse_projection"
method_parameters
( "("
identifier "stream"
, ","
identifier "binding_power"
) ")"
body_statement
assignment
identifier "type"
= "="
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "type"
if
if "if"
binary
call
call
identifier "stream"
. "."
identifier "token"
. "."
identifier "binding_power"
< "<"
integer "10"
then
constant "CURRENT_NODE"
elsif
elsif "elsif"
binary
identifier "type"
== "=="
simple_symbol ":dot"
then
call
identifier "stream"
. "."
identifier "next"
argument_list
( "("
pair
hash_key_symbol "match"
: ":"
constant "AFTER_DOT"
) ")"
call
identifier "parse_dot"
argument_list
( "("
identifier "stream"
, ","
identifier "binding_power"
) ")"
elsif
elsif "elsif"
binary
binary
identifier "type"
== "=="
simple_symbol ":lbracket"
|| "||"
binary
identifier "type"
== "=="
simple_symbol ":filter"
then
call
identifier "expr"
argument_list
( "("
identifier "stream"
, ","
identifier "binding_power"
) ")"
else
else "else"
call
identifier "raise"
argument_list
scope_resolution
constant "Errors"
:: "::"
constant "SyntaxError"
, ","
string
" "'"
string_content "syntax error after projection"
" "'"
end "end"
end "end"
method (+75 nodes collapsed)
method (+54 nodes collapsed)
end "end"
end "end"