orbacle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +119 -0
  8. data/LICENSE +22 -0
  9. data/Makefile +57 -0
  10. data/README.md +53 -0
  11. data/circle.yml +82 -0
  12. data/exe/orbaclerun +6 -0
  13. data/index.html +106 -0
  14. data/lib/orbacle.rb +96 -0
  15. data/lib/orbacle/ast_utils.rb +35 -0
  16. data/lib/orbacle/bottom_type.rb +23 -0
  17. data/lib/orbacle/builder.rb +1414 -0
  18. data/lib/orbacle/builder/context.rb +71 -0
  19. data/lib/orbacle/builder/operator_assignment_processors.rb +80 -0
  20. data/lib/orbacle/class_type.rb +32 -0
  21. data/lib/orbacle/command_line_interface.rb +107 -0
  22. data/lib/orbacle/const_name.rb +33 -0
  23. data/lib/orbacle/const_ref.rb +53 -0
  24. data/lib/orbacle/constants_tree.rb +73 -0
  25. data/lib/orbacle/define_builtins.rb +139 -0
  26. data/lib/orbacle/engine.rb +74 -0
  27. data/lib/orbacle/find_definition_under_position.rb +76 -0
  28. data/lib/orbacle/generic_type.rb +35 -0
  29. data/lib/orbacle/global_tree.rb +280 -0
  30. data/lib/orbacle/graph.rb +126 -0
  31. data/lib/orbacle/indexer.rb +151 -0
  32. data/lib/orbacle/integer_id_generator.rb +13 -0
  33. data/lib/orbacle/lambda_type.rb +37 -0
  34. data/lib/orbacle/lang_server.rb +64 -0
  35. data/lib/orbacle/main_type.rb +23 -0
  36. data/lib/orbacle/nesting.rb +78 -0
  37. data/lib/orbacle/node.rb +23 -0
  38. data/lib/orbacle/nominal_type.rb +32 -0
  39. data/lib/orbacle/ruby_parser.rb +19 -0
  40. data/lib/orbacle/scope.rb +63 -0
  41. data/lib/orbacle/selfie.rb +41 -0
  42. data/lib/orbacle/type_pretty_printer.rb +24 -0
  43. data/lib/orbacle/typing_service.rb +816 -0
  44. data/lib/orbacle/union_type.rb +40 -0
  45. data/lib/orbacle/uuid_id_generator.rb +11 -0
  46. data/lib/orbacle/worklist.rb +51 -0
  47. data/orbacle.gemspec +33 -0
  48. metadata +258 -0
data/lib/orbacle.rb ADDED
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orbacle
4
+ Position = Struct.new(:line, :character)
5
+ PositionRange = Struct.new(:start, :end) do
6
+ def include_position?(position)
7
+ if (start_line+1..end_line-1).include?(position.line)
8
+ true
9
+ elsif start_line == position.line && end_line == position.line
10
+ (start_character <= position.character) && (position.character <= end_character)
11
+ elsif start_line == position.line
12
+ start_character <= position.character
13
+ elsif end_line == position.line
14
+ end_character >= position.character
15
+ end
16
+ end
17
+
18
+ def end_line
19
+ self.end.line
20
+ end
21
+
22
+ def start_line
23
+ self.start.line
24
+ end
25
+
26
+ def start_character
27
+ self.start.character
28
+ end
29
+
30
+ def end_character
31
+ self.end.character
32
+ end
33
+ end
34
+ class Location < Struct.new(:uri, :position_range, :span)
35
+ def start
36
+ position_range&.start
37
+ end
38
+
39
+ def start_line
40
+ start&.line
41
+ end
42
+
43
+ def start_character
44
+ start&.character
45
+ end
46
+
47
+ def end
48
+ position_range&.end
49
+ end
50
+
51
+ def end_line
52
+ self.end&.line
53
+ end
54
+
55
+ def end_character
56
+ self.end&.character
57
+ end
58
+ end
59
+
60
+ BIG_VALUE = 0b111111100100000010110010110011101010000101010100001100100110001
61
+ end
62
+
63
+ require 'parser/current'
64
+
65
+ require 'orbacle/ast_utils'
66
+ require 'orbacle/bottom_type'
67
+ require 'orbacle/builder/context'
68
+ require 'orbacle/builder/operator_assignment_processors'
69
+ require 'orbacle/builder'
70
+ require 'orbacle/class_type'
71
+ require 'orbacle/command_line_interface'
72
+ require 'orbacle/const_name'
73
+ require 'orbacle/const_ref'
74
+ require 'orbacle/constants_tree'
75
+ require 'orbacle/define_builtins'
76
+ require 'orbacle/engine'
77
+ require 'orbacle/find_definition_under_position'
78
+ require 'orbacle/generic_type'
79
+ require 'orbacle/global_tree'
80
+ require 'orbacle/graph'
81
+ require 'orbacle/indexer'
82
+ require 'orbacle/integer_id_generator'
83
+ require 'orbacle/lambda_type'
84
+ require 'orbacle/lang_server'
85
+ require 'orbacle/main_type'
86
+ require 'orbacle/nesting'
87
+ require 'orbacle/node'
88
+ require 'orbacle/nominal_type'
89
+ require 'orbacle/ruby_parser'
90
+ require 'orbacle/scope'
91
+ require 'orbacle/selfie'
92
+ require 'orbacle/type_pretty_printer'
93
+ require 'orbacle/typing_service'
94
+ require 'orbacle/union_type'
95
+ require 'orbacle/uuid_id_generator'
96
+ require 'orbacle/worklist'
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orbacle
4
+ module AstUtils
5
+ def self.const_to_string(const_ast)
6
+ get_nesting(const_ast).flatten.join("::")
7
+ end
8
+
9
+ def self.const_prename_and_name_to_string(prename_ast, name_ast)
10
+ (prename(prename_ast) + [name_ast.to_s]).compact.join("::")
11
+ end
12
+
13
+ def self.get_nesting(ast_const)
14
+ [prename(ast_const.children[0]), ast_const.children[1].to_s]
15
+ end
16
+
17
+ def self.prename(ast_const)
18
+ if ast_const.nil?
19
+ []
20
+ else
21
+ prename(ast_const.children[0]) + [ast_const.children[1].to_s]
22
+ end
23
+ end
24
+
25
+ def build_position_range_from_ast(ast)
26
+ build_position_range_from_parser_range(ast.loc.expression)
27
+ end
28
+
29
+ def build_position_range_from_parser_range(parser_range)
30
+ PositionRange.new(
31
+ Position.new(parser_range.begin.line - 1, parser_range.begin.column),
32
+ Position.new(parser_range.end.line - 1, parser_range.end.column - 1))
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orbacle
4
+ class BottomType
5
+ def ==(other)
6
+ other.class == self.class
7
+ end
8
+
9
+ def hash
10
+ [
11
+ self.class,
12
+ ].hash ^ BIG_VALUE
13
+ end
14
+ alias eql? ==
15
+
16
+ def each_possible_type
17
+ end
18
+
19
+ def bottom?
20
+ true
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,1414 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orbacle
4
+ class Builder
5
+ include AstUtils
6
+ BuilderError = Class.new(StandardError)
7
+ class Result
8
+ def initialize(node, context, data = {})
9
+ @node = node
10
+ @context = context.freeze
11
+ @data = data.freeze
12
+ end
13
+ attr_reader :node, :context, :data
14
+ end
15
+
16
+ def initialize(graph, worklist, tree, id_generator)
17
+ @graph = graph
18
+ @worklist = worklist
19
+ @tree = tree
20
+ @id_generator = id_generator
21
+ end
22
+
23
+ def process_file(ast, filepath)
24
+ initial_context = Context.new(filepath, Selfie.main, Nesting.empty, Context::AnalyzedKlass.new(nil, :public), nil, {})
25
+ result = process(ast, initial_context)
26
+ return result
27
+ end
28
+
29
+ private
30
+ attr_reader :id_generator
31
+
32
+ def process(ast, context)
33
+ return Result.new(nil, context) if ast.nil?
34
+
35
+ process_result = case ast.type
36
+
37
+ # primitives
38
+ when :int
39
+ handle_int(ast, context)
40
+ when :float
41
+ handle_float(ast, context)
42
+ when :rational
43
+ handle_rational(ast, context)
44
+ when :complex
45
+ handle_complex(ast, context)
46
+ when :true
47
+ handle_bool(ast, context)
48
+ when :false
49
+ handle_bool(ast, context)
50
+ when :nil
51
+ handle_nil(ast, context)
52
+ when :str
53
+ handle_str(ast, context)
54
+ when :dstr
55
+ handle_dstr(ast, context)
56
+ when :xstr
57
+ handle_xstr(ast, context)
58
+ when :sym
59
+ handle_sym(ast, context)
60
+ when :dsym
61
+ handle_dsym(ast, context)
62
+ when :regexp
63
+ handle_regexp(ast, context)
64
+
65
+ # arrays
66
+ when :array
67
+ handle_array(ast, context)
68
+ when :splat
69
+ handle_splat(ast, context)
70
+
71
+ # ranges
72
+ when :irange
73
+ handle_irange(ast, context)
74
+ when :erange
75
+ handle_erange(ast, context)
76
+
77
+ # hashes
78
+ when :hash
79
+ handle_hash(ast, context)
80
+
81
+ # local variables
82
+ when :lvar
83
+ handle_lvar(ast, context)
84
+ when :lvasgn
85
+ handle_lvasgn(ast, context)
86
+
87
+ # global variables
88
+ when :gvar
89
+ handle_gvar(ast, context)
90
+ when :gvasgn
91
+ handle_gvasgn(ast, context)
92
+
93
+ # instance variables
94
+ when :ivar
95
+ handle_ivar(ast, context)
96
+ when :ivasgn
97
+ handle_ivasgn(ast, context)
98
+
99
+ when :self
100
+ handle_self(ast, context)
101
+ when :back_ref
102
+ handle_ref(ast, context, :backref)
103
+ when :nth_ref
104
+ handle_ref(ast, context, :nthref)
105
+ when :defined?
106
+ handle_defined(ast, context)
107
+ when :undef
108
+ handle_undef(ast, context)
109
+ when :begin
110
+ handle_begin(ast, context)
111
+ when :kwbegin
112
+ handle_begin(ast, context)
113
+ when :cvar
114
+ handle_cvar(ast, context)
115
+ when :cvasgn
116
+ handle_cvasgn(ast, context)
117
+ when :send
118
+ handle_send(ast, context, false)
119
+ when :csend
120
+ handle_send(ast, context, true)
121
+ when :block
122
+ handle_block(ast, context)
123
+ when :def
124
+ handle_def(ast, context)
125
+ when :defs
126
+ handle_defs(ast, context)
127
+ when :class
128
+ handle_class(ast, context)
129
+ when :sclass
130
+ handle_sclass(ast, context)
131
+ when :module
132
+ handle_module(ast, context)
133
+ when :casgn
134
+ handle_casgn(ast, context)
135
+ when :const
136
+ handle_const(ast, context)
137
+ when :and
138
+ handle_and(ast, context)
139
+ when :or
140
+ handle_or(ast, context)
141
+ when :if
142
+ handle_if(ast, context)
143
+ when :return
144
+ handle_return(ast, context)
145
+ when :masgn
146
+ handle_masgn(ast, context)
147
+ when :alias
148
+ handle_alias(ast, context)
149
+ when :super
150
+ handle_super(ast, context)
151
+ when :zsuper
152
+ handle_zsuper(ast, context)
153
+ when :case
154
+ handle_case(ast, context)
155
+ when :yield
156
+ handle_yield(ast, context)
157
+ when :block_pass
158
+ handle_block_pass(ast, context)
159
+
160
+ when :while then handle_while(ast, context)
161
+ when :until then handle_while(ast, context)
162
+ when :while_post then handle_while(ast, context)
163
+ when :until_post then handle_while(ast, context)
164
+ when :for then handle_for(ast, context)
165
+ when :break then handle_loop_operator(ast, context)
166
+ when :next then handle_loop_operator(ast, context)
167
+ when :redo then handle_loop_operator(ast, context)
168
+
169
+ when :rescue then handle_rescue(ast, context)
170
+ when :resbody then handle_resbody(ast, context)
171
+ when :retry then handle_retry(ast, context)
172
+ when :ensure then handle_ensure(ast, context)
173
+
174
+ when :op_asgn then handle_op_asgn(ast, context)
175
+ when :or_asgn then handle_or_asgn(ast, context)
176
+ when :and_asgn then handle_and_asgn(ast, context)
177
+
178
+ when :match_with_lvasgn then handle_match_with_lvasgn(ast, context)
179
+ when :match_current_line then handle_match_current_line(ast, context)
180
+ when :iflipflop then handle_flipflop(ast, context)
181
+ when :eflipflop then handle_flipflop(ast, context)
182
+
183
+ when :preexe then handle_preexe(ast, context)
184
+ when :postexe then handle_preexe(ast, context)
185
+
186
+ else raise ArgumentError.new(ast.type)
187
+ end
188
+
189
+ if process_result.node && !process_result.node.location
190
+ process_result.node.location = build_location_from_ast(context, ast)
191
+ end
192
+ return process_result
193
+ rescue BuilderError
194
+ raise
195
+ rescue => e
196
+ puts "Error #{e} happened when parsing file #{context.filepath}"
197
+ puts ast
198
+ puts e.backtrace
199
+ raise BuilderError
200
+ end
201
+
202
+ include OperatorAssignmentProcessors
203
+
204
+ def handle_lvasgn(ast, context)
205
+ var_name = ast.children[0].to_s
206
+ expr = ast.children[1]
207
+
208
+ node_lvasgn = add_vertex(Node.new(:lvasgn, { var_name: var_name }, build_location_from_ast(context, ast)))
209
+
210
+ if expr
211
+ expr_result = process(expr, context)
212
+ @graph.add_edge(expr_result.node, node_lvasgn)
213
+ final_context = expr_result.context.merge_lenv(var_name => [node_lvasgn])
214
+ else
215
+ final_context = context.merge_lenv(var_name => [node_lvasgn])
216
+ end
217
+
218
+ return Result.new(node_lvasgn, final_context)
219
+ end
220
+
221
+ def handle_int(ast, context)
222
+ value = one(ast.children)
223
+ n = add_vertex(Node.new(:int, { value: value }))
224
+
225
+ Result.new(n, context)
226
+ end
227
+
228
+ def handle_float(ast, context)
229
+ value = one(ast.children)
230
+ n = add_vertex(Node.new(:float, { value: value }))
231
+
232
+ Result.new(n, context)
233
+ end
234
+
235
+ def handle_rational(_ast, context)
236
+ n = add_vertex(Node.new(:rational, {}))
237
+
238
+ Result.new(n, context)
239
+ end
240
+
241
+ def handle_complex(_ast, context)
242
+ n = add_vertex(Node.new(:complex, {}))
243
+
244
+ Result.new(n, context)
245
+ end
246
+
247
+ def handle_bool(_ast, context)
248
+ n = add_vertex(Node.new(:bool, {}))
249
+
250
+ Result.new(n, context)
251
+ end
252
+
253
+ def handle_nil(ast, context)
254
+ n = add_vertex(Node.new(:nil, {}, build_location_from_ast(context, ast)))
255
+
256
+ return Result.new(n, context)
257
+ end
258
+
259
+ def handle_str(ast, context)
260
+ value = ast.children[0]
261
+ n = add_vertex(Node.new(:str, { value: value }, build_location_from_ast(context, ast)))
262
+
263
+ return Result.new(n, context)
264
+ end
265
+
266
+ def handle_dstr(ast, context)
267
+ node_dstr = add_vertex(Node.new(:dstr, {}, build_location_from_ast(context, ast)))
268
+
269
+ final_context, nodes = fold_context(ast.children, context)
270
+ add_edges(nodes, node_dstr)
271
+
272
+ return Result.new(node_dstr, final_context)
273
+ end
274
+
275
+ def handle_xstr(ast, context)
276
+ node_xstr = add_vertex(Node.new(:xstr, {}, build_location_from_ast(context, ast)))
277
+
278
+ final_context, nodes = fold_context(ast.children, context)
279
+ add_edges(nodes, node_xstr)
280
+
281
+ return Result.new(node_xstr, final_context)
282
+ end
283
+
284
+ def handle_sym(ast, context)
285
+ value = ast.children[0]
286
+ n = add_vertex(Node.new(:sym, { value: value }, build_location_from_ast(context, ast)))
287
+
288
+ return Result.new(n, context)
289
+ end
290
+
291
+ def handle_dsym(ast, context)
292
+ node_dsym = add_vertex(Node.new(:dsym, {}, build_location_from_ast(context, ast)))
293
+
294
+ final_context, nodes = fold_context(ast.children, context)
295
+ add_edges(nodes, node_dsym)
296
+
297
+ return Result.new(node_dsym, final_context)
298
+ end
299
+
300
+ def handle_array(ast, context)
301
+ node_array = add_vertex(Node.new(:array, {}, build_location_from_ast(context, ast)))
302
+
303
+ final_context, nodes = fold_context(ast.children, context)
304
+ add_edges(nodes, node_array)
305
+
306
+ return Result.new(node_array, final_context)
307
+ end
308
+
309
+ def handle_splat(ast, context)
310
+ expr = ast.children[0]
311
+
312
+ expr_result = process(expr, context)
313
+
314
+ node_splat = Node.new(:splat_array, {}, build_location_from_ast(context, ast))
315
+ @graph.add_edge(expr_result.node, node_splat)
316
+
317
+ return Result.new(node_splat, expr_result.context)
318
+ end
319
+
320
+ def handle_regexp(ast, context)
321
+ expr_nodes = ast.children[0..-2]
322
+ regopt = ast.children[-1]
323
+
324
+ node_regexp = Node.new(:regexp, { regopt: regopt.children }, build_location_from_ast(context, ast))
325
+
326
+ final_context, nodes = fold_context(expr_nodes, context)
327
+ add_edges(nodes, node_regexp)
328
+
329
+ return Result.new(node_regexp, final_context)
330
+ end
331
+
332
+ def handle_irange(ast, context)
333
+ common_range(ast, context, true)
334
+ end
335
+
336
+ def handle_erange(ast, context)
337
+ common_range(ast, context, false)
338
+ end
339
+
340
+ def common_range(ast, context, inclusive)
341
+ range_from_ast = ast.children[0]
342
+ range_to_ast = ast.children[1]
343
+
344
+ range_node = Node.new(:range, { inclusive: inclusive }, build_location_from_ast(context, ast))
345
+
346
+ range_from_ast_result = process(range_from_ast, context)
347
+ from_node = Node.new(:range_from, {})
348
+ @graph.add_edge(range_from_ast_result.node, from_node)
349
+ @graph.add_edge(from_node, range_node)
350
+
351
+ range_to_ast_result = process(range_to_ast, range_from_ast_result.context)
352
+ to_node = Node.new(:range_to, {})
353
+ @graph.add_edge(range_to_ast_result.node, to_node)
354
+ @graph.add_edge(to_node, range_node)
355
+
356
+ return Result.new(range_node, range_to_ast_result.context)
357
+ end
358
+
359
+ def handle_ref(ast, context, node_type)
360
+ ref = if node_type == :backref
361
+ ast.children[0].to_s[1..-1]
362
+ elsif node_type == :nthref
363
+ ast.children[0].to_s
364
+ else
365
+ raise
366
+ end
367
+ node = add_vertex(Node.new(node_type, { ref: ref }, build_location_from_ast(context, ast)))
368
+ return Result.new(node, context)
369
+ end
370
+
371
+ def handle_defined(ast, context)
372
+ _expr = ast.children[0]
373
+
374
+ node = add_vertex(Node.new(:defined, {}, build_location_from_ast(context, ast)))
375
+
376
+ return Result.new(node, context)
377
+ end
378
+
379
+ def handle_undef(ast, context)
380
+ node = add_vertex(Node.new(:nil, {}))
381
+
382
+ Result.new(node, context)
383
+ end
384
+
385
+ def handle_begin(ast, context)
386
+ final_context, nodes = fold_context(ast.children, context)
387
+ if ast.children.empty?
388
+ return Result.new(add_vertex(Node.new(:nil, {}, ast)), context)
389
+ else
390
+ return Result.new(nodes.last, final_context)
391
+ end
392
+ end
393
+
394
+ def handle_lvar(ast, context)
395
+ var_name = ast.children[0].to_s
396
+
397
+ node_lvar = add_vertex(Node.new(:lvar, { var_name: var_name }, build_location_from_ast(context, ast)))
398
+
399
+ context.lenv_fetch(var_name).each do |var_definition_node|
400
+ @graph.add_edge(var_definition_node, node_lvar)
401
+ end
402
+
403
+ return Result.new(node_lvar, context)
404
+ end
405
+
406
+ def handle_ivar(ast, context)
407
+ ivar_name = ast.children.first.to_s
408
+
409
+ ivar_definition_node = if context.selfie.klass?
410
+ @graph.get_class_level_ivar_definition_node(context.scope, ivar_name)
411
+ elsif context.selfie.instance?
412
+ @graph.get_ivar_definition_node(context.scope, ivar_name)
413
+ elsif context.selfie.main?
414
+ @graph.get_main_ivar_definition_node(ivar_name)
415
+ else
416
+ raise
417
+ end
418
+
419
+ node = Node.new(:ivar, { var_name: ivar_name }, build_location_from_ast(context, ast))
420
+ @graph.add_edge(ivar_definition_node, node)
421
+
422
+ return Result.new(node, context)
423
+ end
424
+
425
+ def handle_ivasgn(ast, context)
426
+ ivar_name = ast.children[0].to_s
427
+ expr = ast.children[1]
428
+
429
+ node_ivasgn = add_vertex(Node.new(:ivasgn, { var_name: ivar_name }, build_location_from_ast(context, ast)))
430
+
431
+ if expr
432
+ expr_result = process(expr, context)
433
+ @graph.add_edge(expr_result.node, node_ivasgn)
434
+ context_after_expr = expr_result.context
435
+ else
436
+ context_after_expr = context
437
+ end
438
+
439
+ ivar_definition_node = if context.selfie.klass?
440
+ @graph.get_class_level_ivar_definition_node(context.scope, ivar_name)
441
+ elsif context.selfie.instance?
442
+ @graph.get_ivar_definition_node(context_after_expr.scope, ivar_name)
443
+ elsif context.selfie.main?
444
+ @graph.get_main_ivar_definition_node(ivar_name)
445
+ else
446
+ raise
447
+ end
448
+ @graph.add_edge(node_ivasgn, ivar_definition_node)
449
+
450
+ return Result.new(node_ivasgn, context_after_expr)
451
+ end
452
+
453
+ def handle_cvasgn(ast, context)
454
+ cvar_name = ast.children[0].to_s
455
+ expr = ast.children[1]
456
+
457
+ node_cvasgn = add_vertex(Node.new(:cvasgn, { var_name: cvar_name }, build_location_from_ast(context, ast)))
458
+
459
+ if expr
460
+ expr_result = process(expr, context)
461
+ @graph.add_edge(expr_result.node, node_cvasgn)
462
+ context_after_expr = expr_result.context
463
+ else
464
+ context_after_expr = context
465
+ end
466
+
467
+ node_cvar_definition = @graph.get_cvar_definition_node(context.scope, cvar_name)
468
+ @graph.add_edge(node_cvasgn, node_cvar_definition)
469
+
470
+ return Result.new(node_cvasgn, context_after_expr)
471
+ end
472
+
473
+ def handle_cvar(ast, context)
474
+ cvar_name = ast.children.first.to_s
475
+
476
+ cvar_definition_node = @graph.get_cvar_definition_node(context.scope, cvar_name)
477
+
478
+ node = Node.new(:cvar, { var_name: cvar_name }, build_location_from_ast(context, ast))
479
+ @graph.add_edge(cvar_definition_node, node)
480
+
481
+ return Result.new(node, context)
482
+ end
483
+
484
+ def handle_gvasgn(ast, context)
485
+ gvar_name = ast.children[0].to_s
486
+ expr = ast.children[1]
487
+
488
+ node_gvasgn = add_vertex(Node.new(:gvasgn, { var_name: gvar_name }, build_location_from_ast(context, ast)))
489
+
490
+ expr_result = process(expr, context)
491
+ @graph.add_edge(expr_result.node, node_gvasgn)
492
+
493
+ node_gvar_definition = @graph.get_gvar_definition_node(gvar_name)
494
+ @graph.add_edge(node_gvasgn, node_gvar_definition)
495
+
496
+ return Result.new(node_gvasgn, expr_result.context)
497
+ end
498
+
499
+ def handle_gvar(ast, context)
500
+ gvar_name = ast.children.first.to_s
501
+
502
+ gvar_definition_node = @graph.get_gvar_definition_node(gvar_name)
503
+
504
+ node = add_vertex(Node.new(:gvar, { var_name: gvar_name }, build_location_from_ast(context, ast)))
505
+ @graph.add_edge(gvar_definition_node, node)
506
+
507
+ return Result.new(node, context)
508
+ end
509
+
510
+ def transform_symbol_shorthand(obj_expr, message_name, arg_exprs, csend, context)
511
+ block_message_block_pass = arg_exprs.last
512
+ block_message_name = block_message_block_pass.children.last.children.last
513
+ normal_arg_exprs = arg_exprs[0..-2]
514
+ send_ast_type = csend ? :csend : :send
515
+ send_ast = Parser::AST::Node.new(send_ast_type, [obj_expr, message_name.to_sym, *normal_arg_exprs])
516
+ arg_ast = Parser::AST::Node.new(:args, [Parser::AST::Node.new(:arg, [:__orbacle__x])])
517
+ block_body_ast = Parser::AST::Node.new(:send, [Parser::AST::Node.new(:lvar, [:__orbacle__x]), block_message_name])
518
+ block_ast = Parser::AST::Node.new(:block, [send_ast, arg_ast, block_body_ast])
519
+ handle_block(block_ast, context)
520
+ end
521
+
522
+ def transform_symbol_shorthand_applies?(arg_exprs)
523
+ arg_exprs.last &&
524
+ arg_exprs.last.type == :block_pass &&
525
+ arg_exprs.last.children.last &&
526
+ arg_exprs.last.children.last.type == :sym
527
+ end
528
+
529
+ def handle_send(ast, context, csend)
530
+ obj_expr = ast.children[0]
531
+ message_name = ast.children[1].to_s
532
+ arg_exprs = ast.children[2..-1]
533
+
534
+ return transform_symbol_shorthand(obj_expr, message_name, arg_exprs, csend, context) if transform_symbol_shorthand_applies?(arg_exprs)
535
+
536
+ if obj_expr.nil?
537
+ obj_node = add_vertex(Node.new(:self, { selfie: context.selfie }))
538
+ obj_context = context
539
+ else
540
+ expr_result = process(obj_expr, context)
541
+ obj_node = expr_result.node
542
+ obj_context = expr_result.context
543
+ end
544
+
545
+ final_context, call_arg_nodes, block_node = prepare_argument_nodes(obj_context, arg_exprs)
546
+
547
+ return handle_changing_visibility(context, message_name.to_sym, arg_exprs) if obj_expr.nil? && ["public", "protected", "private"].include?(message_name)
548
+ return handle_custom_attr_reader_send(context, arg_exprs, ast) if obj_expr.nil? && message_name == "attr_reader"
549
+ return handle_custom_attr_writer_send(context, arg_exprs, ast) if obj_expr.nil? && message_name == "attr_writer"
550
+ return handle_custom_attr_accessor_send(context, arg_exprs, ast) if obj_expr.nil? && message_name == "attr_accessor"
551
+
552
+ call_obj_node = add_vertex(Node.new(:call_obj, {}))
553
+ @graph.add_edge(obj_node, call_obj_node)
554
+
555
+ call_result_node = add_vertex(Node.new(:call_result, { csend: csend }))
556
+
557
+ message_send = Worklist::MessageSend.new(message_name, call_obj_node, call_arg_nodes, call_result_node, block_node, build_location_from_ast(context, ast))
558
+ @worklist.add_message_send(message_send)
559
+
560
+ return Result.new(call_result_node, final_context, { message_send: message_send })
561
+ end
562
+
563
+ def prepare_argument_nodes(context, arg_exprs)
564
+ call_arg_nodes = []
565
+ block_node = nil
566
+ final_context = arg_exprs.reduce(context) do |current_context, ast_child|
567
+ case ast_child.type
568
+ when :block_pass
569
+ block_pass_result = process(ast_child.children[0], current_context)
570
+ block_node = Worklist::BlockNode.new(block_pass_result.node)
571
+ block_pass_result.context
572
+ when :splat
573
+ ast_child_result = process(ast_child.children[0], current_context)
574
+ call_arg_node = add_vertex(Node.new(:call_splatarg, {}))
575
+ call_arg_nodes << call_arg_node
576
+ @graph.add_edge(ast_child_result.node, call_arg_node)
577
+ ast_child_result.context
578
+ else
579
+ ast_child_result = process(ast_child, current_context)
580
+ call_arg_node = add_vertex(Node.new(:call_arg, {}))
581
+ call_arg_nodes << call_arg_node
582
+ @graph.add_edge(ast_child_result.node, call_arg_node)
583
+ ast_child_result.context
584
+ end
585
+ end
586
+ return final_context, call_arg_nodes, block_node
587
+ end
588
+
589
+ def handle_changing_visibility(context, new_visibility, arg_exprs)
590
+ if context.analyzed_klass_id && arg_exprs.empty?
591
+ final_node = add_vertex(Node.new(:definition_by_id, { id: context.analyzed_klass_id }))
592
+ return Result.new(final_node, context.with_visibility(new_visibility))
593
+ elsif context.analyzed_klass_id
594
+ methods_to_change_visibility = arg_exprs.map do |arg_expr|
595
+ [:sym, :str].include?(arg_expr.type) ? arg_expr.children[0].to_s : nil
596
+ end.compact
597
+ methods_to_change_visibility.each do |name|
598
+ @tree.change_method_visibility(context.analyzed_klass_id, name, new_visibility)
599
+ end
600
+
601
+ final_node = add_vertex(Node.new(:definition_by_id, { id: context.analyzed_klass_id }))
602
+ return Result.new(final_node, context)
603
+ else
604
+ final_node = add_vertex(Node.new(:const, { const_ref: ConstRef.from_full_name("Object", Nesting.empty) }))
605
+ return Result.new(final_node, context)
606
+ end
607
+ end
608
+
609
+ def handle_custom_attr_reader_send(context, arg_exprs, ast)
610
+ location = build_location_from_ast(context, ast)
611
+ ivar_names = arg_exprs.select {|s| [:sym, :str].include?(s.type) }.map {|s| s.children.first }.map(&:to_s)
612
+ ivar_names.each do |ivar_name|
613
+ define_attr_reader_method(context, ivar_name, location)
614
+ end
615
+
616
+ return Result.new(Node.new(:nil, {}), context)
617
+ end
618
+
619
+ def handle_custom_attr_writer_send(context, arg_exprs, ast)
620
+ location = build_location_from_ast(context, ast)
621
+ ivar_names = arg_exprs.select {|s| [:sym, :str].include?(s.type) }.map {|s| s.children.first }.map(&:to_s)
622
+ ivar_names.each do |ivar_name|
623
+ define_attr_writer_method(context, ivar_name, location)
624
+ end
625
+
626
+ return Result.new(Node.new(:nil, {}), context)
627
+ end
628
+
629
+ def handle_custom_attr_accessor_send(context, arg_exprs, ast)
630
+ location = build_location_from_ast(context, ast)
631
+ ivar_names = arg_exprs.select {|s| [:sym, :str].include?(s.type) }.map {|s| s.children.first }.map(&:to_s)
632
+ ivar_names.each do |ivar_name|
633
+ define_attr_reader_method(context, ivar_name, location)
634
+ define_attr_writer_method(context, ivar_name, location)
635
+ end
636
+
637
+ return Result.new(Node.new(:nil, {}), context)
638
+ end
639
+
640
+ def define_attr_reader_method(context, ivar_name, location)
641
+ ivar_definition_node = @graph.get_ivar_definition_node(context.scope, "@#{ivar_name}")
642
+
643
+ metod = @tree.add_method(
644
+ id_generator.call,
645
+ context.analyzed_klass_id,
646
+ ivar_name,
647
+ location,
648
+ context.analyzed_klass.method_visibility,
649
+ GlobalTree::ArgumentsTree.new([], [], nil))
650
+ @graph.store_metod_nodes(metod.id, {})
651
+ @graph.add_edge(ivar_definition_node, @graph.get_metod_nodes(metod.id).result)
652
+ end
653
+
654
+ def define_attr_writer_method(context, ivar_name, location)
655
+ ivar_definition_node = @graph.get_ivar_definition_node(context.scope, "@#{ivar_name}")
656
+
657
+ arg_name = "_attr_writer"
658
+ arg_node = add_vertex(Node.new(:formal_arg, { var_name: arg_name }))
659
+ metod = @tree.add_method(
660
+ id_generator.call,
661
+ context.analyzed_klass_id,
662
+ "#{ivar_name}=",
663
+ location,
664
+ context.analyzed_klass.method_visibility,
665
+ GlobalTree::ArgumentsTree.new([GlobalTree::ArgumentsTree::Regular.new(arg_name)], [], nil))
666
+ @graph.store_metod_nodes(metod.id, { arg_name => arg_node })
667
+ @graph.add_edge(arg_node, ivar_definition_node)
668
+ @graph.add_edge(ivar_definition_node, @graph.get_metod_nodes(metod.id).result)
669
+ end
670
+
671
+ def handle_self(ast, context)
672
+ node = add_vertex(Node.new(:self, { selfie: context.selfie }, build_location_from_ast(context, ast)))
673
+ return Result.new(node, context)
674
+ end
675
+
676
+ def handle_block(ast, context)
677
+ send_expr = ast.children[0]
678
+ args_ast = ast.children[1]
679
+ block_expr = ast.children[2]
680
+
681
+ if send_expr == Parser::AST::Node.new(:send, [nil, :lambda])
682
+ send_context = context
683
+ else
684
+ send_expr_result = process(send_expr, context)
685
+ message_send = send_expr_result.data[:message_send]
686
+ if message_send
687
+ send_node = send_expr_result.node
688
+ send_context = send_expr_result.context
689
+ else
690
+ return Result.new(Node.new(:nil, {}), context)
691
+ end
692
+ end
693
+
694
+ arguments_tree, context_with_args, args_ast_nodes = build_def_arguments(args_ast.children, send_context)
695
+
696
+ # It's not exactly good - local vars defined in blocks are not available outside (?),
697
+ # but assignments done in blocks are valid.
698
+ if block_expr
699
+ block_expr_result = process(block_expr, context_with_args)
700
+ block_final_node = block_expr_result.node
701
+ block_result_context = block_expr_result.context
702
+ else
703
+ block_final_node = Node.new(:nil, {})
704
+ block_result_context = context_with_args
705
+ end
706
+ block_result_node = add_vertex(Node.new(:block_result, {}))
707
+ @graph.add_edge(block_final_node, block_result_node)
708
+
709
+
710
+ lamba = @tree.add_lambda(arguments_tree)
711
+ @graph.store_lambda_nodes(lamba.id, args_ast_nodes, block_result_node)
712
+
713
+ if lambda_ast?(send_expr)
714
+ lambda_node = add_vertex(Node.new(:lambda, { id: lamba.id }))
715
+ return Result.new(lambda_node, block_result_context)
716
+ else
717
+ message_send.block = Worklist::BlockLambda.new(lamba.id)
718
+ return Result.new(send_node, block_result_context)
719
+ end
720
+ end
721
+
722
+ def handle_def(ast, context)
723
+ method_name = ast.children[0]
724
+ formal_arguments = ast.children[1]
725
+ method_body = ast.children[2]
726
+
727
+ arguments_tree, arguments_context, arguments_nodes = build_def_arguments(formal_arguments.children, context)
728
+
729
+ metod = @tree.add_method(
730
+ id_generator.call,
731
+ context.analyzed_klass_id,
732
+ method_name.to_s,
733
+ build_location_from_ast(context, ast),
734
+ context.analyzed_klass.method_visibility,
735
+ arguments_tree)
736
+ @graph.store_metod_nodes(metod.id, arguments_nodes)
737
+
738
+ context.with_analyzed_method(metod.id).tap do |context2|
739
+ if method_body
740
+ context2.with_selfie(Selfie.instance_from_scope(context2.scope)).tap do |context3|
741
+ final_node = process(method_body, context3.merge_lenv(arguments_context.lenv)).node
742
+ @graph.add_edge(final_node, @graph.get_metod_nodes(context3.analyzed_method).result)
743
+ end
744
+ else
745
+ final_node = add_vertex(Node.new(:nil, {}))
746
+ @graph.add_edge(final_node, @graph.get_metod_nodes(context2.analyzed_method).result)
747
+ end
748
+ end
749
+
750
+ node = add_vertex(Node.new(:sym, { value: method_name }, build_location_from_ast(context, ast)))
751
+
752
+ return Result.new(node, context)
753
+ end
754
+
755
+ def handle_hash(ast, context)
756
+ node_hash_keys = add_vertex(Node.new(:hash_keys, {}))
757
+ node_hash_values = add_vertex(Node.new(:hash_values, {}))
758
+ node_hash = add_vertex(Node.new(:hash, {}))
759
+ @graph.add_edge(node_hash_keys, node_hash)
760
+ @graph.add_edge(node_hash_values, node_hash)
761
+
762
+ final_context = ast.children.reduce(context) do |current_context, ast_child|
763
+ case ast_child.type
764
+ when :pair
765
+ hash_key, hash_value = ast_child.children
766
+ hash_key_result = process(hash_key, current_context)
767
+ hash_value_result = process(hash_value, hash_key_result.context)
768
+ @graph.add_edge(hash_key_result.node, node_hash_keys)
769
+ @graph.add_edge(hash_value_result.node, node_hash_values)
770
+ hash_value_result.context
771
+ when :kwsplat
772
+ kwsplat_expr = ast_child.children[0]
773
+
774
+ kwsplat_expr_result = process(kwsplat_expr, context)
775
+
776
+ node_unwrap_hash_keys = Node.new(:unwrap_hash_keys, {})
777
+ node_unwrap_hash_values = Node.new(:unwrap_hash_values, {})
778
+
779
+ @graph.add_edge(kwsplat_expr_result.node, node_unwrap_hash_keys)
780
+ @graph.add_edge(kwsplat_expr_result.node, node_unwrap_hash_values)
781
+
782
+ @graph.add_edge(node_unwrap_hash_keys, node_hash_keys)
783
+ @graph.add_edge(node_unwrap_hash_values, node_hash_values)
784
+
785
+ kwsplat_expr_result.context
786
+ else raise ArgumentError.new(ast)
787
+ end
788
+ end
789
+
790
+ return Result.new(node_hash, final_context)
791
+ end
792
+
793
+ def handle_class(ast, context)
794
+ klass_name_ast, parent_klass_name_ast, klass_body = ast.children
795
+ klass_name_ref = ConstRef.from_ast(klass_name_ast, context.nesting)
796
+ parent_name_ref = if parent_klass_name_ast.nil? || !simple_constant?(parent_klass_name_ast)
797
+ nil
798
+ elsif simple_constant?(parent_klass_name_ast)
799
+ ConstRef.from_ast(parent_klass_name_ast, context.nesting)
800
+ end
801
+
802
+ klass = @tree.add_klass(parent_name_ref)
803
+ klass_constant = @tree.add_constant(
804
+ GlobalTree::Constant.new(klass_name_ref.name, context.scope.increase_by_ref(klass_name_ref).decrease, build_location_from_ast(context, ast), klass.id))
805
+
806
+ new_context = context
807
+ .with_analyzed_klass(klass.id)
808
+ .with_nesting(context.nesting.increase_nesting_const(klass_name_ref))
809
+ .with_selfie(Selfie.klass_from_scope(context.scope))
810
+ if klass_body
811
+ process(klass_body, new_context)
812
+ end
813
+
814
+ node = add_vertex(Node.new(:nil, {}))
815
+
816
+ return Result.new(node, context)
817
+ end
818
+
819
+ def handle_module(ast, context)
820
+ module_name_ast = ast.children[0]
821
+ module_body = ast.children[1]
822
+
823
+ module_name_ref = ConstRef.from_ast(module_name_ast, context.nesting)
824
+
825
+ mod = @tree.add_mod
826
+ @tree.add_constant(
827
+ GlobalTree::Constant.new(
828
+ module_name_ref.name, context.scope.increase_by_ref(module_name_ref).decrease, build_location_from_ast(context, ast), mod.id))
829
+
830
+ if module_body
831
+ context
832
+ .with_analyzed_klass(mod.id)
833
+ .with_nesting(context.nesting.increase_nesting_const(module_name_ref)).tap do |context2|
834
+ process(module_body, context2)
835
+ end
836
+ end
837
+
838
+ return Result.new(Node.new(:nil, {}), context)
839
+ end
840
+
841
+ def handle_sclass(ast, context)
842
+ self_name = ast.children[0]
843
+ sklass_body = ast.children[1]
844
+
845
+ new_context = if self_name == Parser::AST::Node.new(:self) && context.analyzed_klass_id
846
+ eigenclass_of_analyzed_definition = @tree.get_eigenclass_of_definition(context.analyzed_klass_id)
847
+ context
848
+ .with_nesting(context.nesting.increase_nesting_self)
849
+ .with_analyzed_klass(eigenclass_of_analyzed_definition.id)
850
+ else
851
+ context
852
+ end
853
+ process(sklass_body, new_context)
854
+
855
+ return Result.new(Node.new(:nil, {}), context)
856
+ end
857
+
858
+ def handle_defs(ast, context)
859
+ method_receiver = ast.children[0]
860
+ method_name = ast.children[1]
861
+ formal_arguments = ast.children[2]
862
+ method_body = ast.children[3]
863
+
864
+ arguments_tree, arguments_context, arguments_nodes = build_def_arguments(formal_arguments.children, context)
865
+
866
+ if context.analyzed_klass_id
867
+ eigenclass_of_analyzed_definition = @tree.get_eigenclass_of_definition(context.analyzed_klass_id)
868
+ place_of_definition_id = eigenclass_of_analyzed_definition.id
869
+ else
870
+ place_of_definition_id = nil
871
+ end
872
+ metod = @tree.add_method(
873
+ id_generator.call,
874
+ place_of_definition_id,
875
+ method_name.to_s,
876
+ build_location_from_ast(context, ast),
877
+ context.analyzed_klass.method_visibility,
878
+ arguments_tree)
879
+ @graph.store_metod_nodes(metod.id, arguments_nodes)
880
+
881
+ context.with_analyzed_method(metod.id).tap do |context2|
882
+ if method_body
883
+ context2.with_selfie(Selfie.klass_from_scope(context2.scope)).tap do |context3|
884
+ final_node = process(method_body, context3.merge_lenv(arguments_context.lenv)).node
885
+ @graph.add_edge(final_node, @graph.get_metod_nodes(context3.analyzed_method).result)
886
+ end
887
+ else
888
+ final_node = add_vertex(Node.new(:nil, {}))
889
+ @graph.add_edge(final_node, @graph.get_metod_nodes(context2.analyzed_method).result)
890
+ end
891
+ end
892
+
893
+ node = add_vertex(Node.new(:sym, { value: method_name }))
894
+
895
+ return Result.new(node, context)
896
+ end
897
+
898
+ def handle_casgn(ast, context)
899
+ const_prename, const_name, expr = ast.children
900
+ return handle_dynamic_casgn(ast, context) if !simple_const_prename?(const_prename)
901
+
902
+ const_name_ref = ConstRef.from_full_name(AstUtils.const_prename_and_name_to_string(const_prename, const_name), context.nesting)
903
+
904
+ if expr_is_class_definition?(expr)
905
+ parent_klass_name_ast = expr.children[2]
906
+ parent_name_ref = parent_klass_name_ast.nil? ? nil : ConstRef.from_ast(parent_klass_name_ast, context.nesting)
907
+ klass = @tree.add_klass(parent_name_ref)
908
+ @tree.add_constant(
909
+ GlobalTree::Constant.new(
910
+ const_name_ref.name, context.scope.increase_by_ref(const_name_ref).decrease, build_location_from_ast(context, ast), klass.id))
911
+
912
+ return Result.new(Node.new(:nil, {}), context)
913
+ elsif expr_is_module_definition?(expr)
914
+ mod = @tree.add_mod
915
+ @tree.add_constant(
916
+ GlobalTree::Constant.new(
917
+ const_name_ref.name, context.scope.increase_by_ref(const_name_ref).decrease, build_location_from_ast(context, ast), mod.id))
918
+
919
+ return Result.new(Node.new(:nil, {}), context)
920
+ else
921
+ @tree.add_constant(
922
+ GlobalTree::Constant.new(
923
+ const_name_ref.name, context.scope.increase_by_ref(const_name_ref).decrease, build_location_from_ast(context, ast)))
924
+
925
+ expr_result = process(expr, context)
926
+
927
+ final_node = Node.new(:casgn, { const_ref: const_name_ref })
928
+ @graph.add_edge(expr_result.node, final_node)
929
+
930
+ const_name = context.scope.increase_by_ref(const_name_ref).to_const_name
931
+ node_const_definition = @graph.get_constant_definition_node(const_name.to_string)
932
+ @graph.add_edge(final_node, node_const_definition)
933
+
934
+ return Result.new(final_node, expr_result.context)
935
+ end
936
+ end
937
+
938
+ def handle_dynamic_casgn(ast, context)
939
+ _const_prename, _const_name, expr = ast.children
940
+ return process(expr, context)
941
+ end
942
+
943
+ def simple_const_prename?(const_prename)
944
+ const_prename.nil? ||
945
+ (const_prename.type == :const && simple_const_prename?(const_prename.children[0])) ||
946
+ const_prename.type == :cbase
947
+ end
948
+
949
+ def handle_const(ast, context)
950
+ if simple_constant?(ast)
951
+ const_ref = ConstRef.from_ast(ast, context.nesting)
952
+
953
+ node = add_vertex(Node.new(:const, { const_ref: const_ref }))
954
+
955
+ return Result.new(node, context)
956
+ else
957
+ node = add_vertex(Node.new(:dynamic_const, {}))
958
+
959
+ return Result.new(node, context)
960
+ end
961
+ end
962
+
963
+ def handle_and(ast, context)
964
+ handle_binary_operator(:and, ast.children[0], ast.children[1], context)
965
+ end
966
+
967
+ def handle_or(ast, context)
968
+ handle_binary_operator(:or, ast.children[0], ast.children[1], context)
969
+ end
970
+
971
+ def handle_binary_operator(node_type, expr_left, expr_right, context)
972
+ expr_left_result = process(expr_left, context)
973
+ expr_right_result = process(expr_right, expr_left_result.context)
974
+
975
+ node_or = add_vertex(Node.new(node_type, {}))
976
+ @graph.add_edge(expr_left_result.node, node_or)
977
+ @graph.add_edge(expr_right_result.node, node_or)
978
+
979
+ return Result.new(node_or, expr_right_result.context)
980
+ end
981
+
982
+ def handle_if(ast, context)
983
+ expr_cond = ast.children[0]
984
+ expr_iftrue = ast.children[1]
985
+ expr_iffalse = ast.children[2]
986
+
987
+ expr_cond_result = process(expr_cond, context)
988
+
989
+ if expr_iftrue
990
+ expr_iftrue_result = process(expr_iftrue, expr_cond_result.context)
991
+
992
+ node_iftrue = expr_iftrue_result.node
993
+ context_after_iftrue = expr_iftrue_result.context
994
+ else
995
+ node_iftrue = add_vertex(Node.new(:nil, {}))
996
+ context_after_iftrue = context
997
+ end
998
+
999
+ if expr_iffalse
1000
+ expr_iffalse_result = process(expr_iffalse, expr_cond_result.context)
1001
+
1002
+ node_iffalse = expr_iffalse_result.node
1003
+ context_after_iffalse = expr_iffalse_result.context
1004
+ else
1005
+ node_iffalse = add_vertex(Node.new(:nil, {}))
1006
+ context_after_iffalse = context
1007
+ end
1008
+
1009
+ node_if_result = add_vertex(Node.new(:if_result, {}))
1010
+ @graph.add_edge(node_iftrue, node_if_result)
1011
+ @graph.add_edge(node_iffalse, node_if_result)
1012
+
1013
+ return Result.new(node_if_result, expr_cond_result.context.with_merged_lenvs(context_after_iftrue.lenv, context_after_iffalse.lenv))
1014
+ end
1015
+
1016
+ def handle_return(ast, context)
1017
+ exprs = ast.children
1018
+
1019
+ if exprs.size == 0
1020
+ node_expr = add_vertex(Node.new(:nil, {}))
1021
+ final_context = context
1022
+ elsif exprs.size == 1
1023
+ expr_result = process(exprs[0], context)
1024
+ node_expr = expr_result.node
1025
+ final_context = expr_result.context
1026
+ else
1027
+ node_expr = add_vertex(Node.new(:array, {}))
1028
+ final_context, nodes = fold_context(ast.children, context)
1029
+ add_edges(nodes, node_expr)
1030
+ end
1031
+
1032
+ if context.analyzed_method
1033
+ @graph.add_edge(node_expr, @graph.get_metod_nodes(context.analyzed_method).result)
1034
+ end
1035
+
1036
+ return Result.new(node_expr, final_context)
1037
+ end
1038
+
1039
+ def handle_masgn(ast, context)
1040
+ mlhs_expr = ast.children[0]
1041
+ rhs_expr = ast.children[1]
1042
+
1043
+ rhs_expr_result = process(rhs_expr, context)
1044
+ node_rhs = rhs_expr_result.node
1045
+ context_after_rhs = rhs_expr_result.context
1046
+
1047
+ mlhs_result = handle_mlhs_for_masgn(mlhs_expr, context, rhs_expr)
1048
+
1049
+ return mlhs_result
1050
+ end
1051
+
1052
+ def handle_mlhs_for_masgn(ast, context, rhs_expr)
1053
+ result_node = add_vertex(Node.new(:array, {}))
1054
+
1055
+ i = 0
1056
+ final_context = ast.children.reduce(context) do |current_context, ast_child|
1057
+ if ast_child.type == :mlhs
1058
+ new_rhs_expr = Parser::AST::Node.new(:send, [rhs_expr, :[], Parser::AST::Node.new(:int, [i])])
1059
+ ast_child_result = handle_mlhs_for_masgn(ast_child, current_context, new_rhs_expr)
1060
+ node_child = ast_child_result.node
1061
+ context_after_child = ast_child_result.context
1062
+ else
1063
+ new_ast_child = ast_child.append(Parser::AST::Node.new(:send, [rhs_expr, :[], Parser::AST::Node.new(:int, [i])]))
1064
+ new_ast_child_result = process(new_ast_child, current_context)
1065
+ node_child = new_ast_child_result.node
1066
+ context_after_child = new_ast_child_result.context
1067
+ end
1068
+
1069
+ @graph.add_edge(node_child, result_node)
1070
+ i += 1
1071
+ context_after_child
1072
+ end
1073
+
1074
+ return Result.new(result_node, final_context)
1075
+ end
1076
+
1077
+ def handle_alias(ast, context)
1078
+ node = add_vertex(Node.new(:nil, {}))
1079
+ return Result.new(node, context)
1080
+ end
1081
+
1082
+ def handle_super(ast, context)
1083
+ arg_exprs = ast.children
1084
+
1085
+ final_context, call_arg_nodes, block_node = prepare_argument_nodes(context, arg_exprs)
1086
+
1087
+ call_result_node = add_vertex(Node.new(:call_result, {}))
1088
+
1089
+ super_send = Worklist::SuperSend.new(call_arg_nodes, call_result_node, block_node, final_context.analyzed_method, build_location_from_ast(context, ast))
1090
+ @worklist.add_message_send(super_send)
1091
+
1092
+ return Result.new(call_result_node, final_context, { message_send: super_send })
1093
+ end
1094
+
1095
+ def handle_zsuper(ast, context)
1096
+ call_result_node = add_vertex(Node.new(:call_result, {}))
1097
+
1098
+ if context.analyzed_method
1099
+ method_nodes = @graph.get_metod_nodes(context.analyzed_method)
1100
+ zsuper = Graph::ZSuper.new(call_result_node, nil)
1101
+ method_nodes.zsupers << zsuper
1102
+ end
1103
+
1104
+ return Result.new(call_result_node, context, { message_send: zsuper })
1105
+ end
1106
+
1107
+ def handle_while(ast, context)
1108
+ expr_cond = ast.children[0]
1109
+ expr_body = ast.children[1]
1110
+
1111
+ new_context = process(expr_cond, context).context
1112
+ final_context = process(expr_body, new_context).context
1113
+
1114
+ node = add_vertex(Node.new(:nil, {}))
1115
+
1116
+ return Result.new(node, final_context)
1117
+ end
1118
+
1119
+ def handle_for(ast, context)
1120
+ expr_asgn = ast.children[0]
1121
+ expr_collection = ast.children[1]
1122
+ expr_body = ast.children[2]
1123
+
1124
+ collection_result = process(expr_collection, context)
1125
+ final_context = process(expr_body, collection_result.context).context
1126
+
1127
+ node = add_vertex(Node.new(:for, {}))
1128
+ add_edges(collection_result.node, node)
1129
+
1130
+ return Result.new(node, final_context)
1131
+ end
1132
+
1133
+ def handle_case(ast, context)
1134
+ expr_cond = ast.children[0]
1135
+ expr_branches = ast.children[1..-1].compact
1136
+
1137
+ new_context = process(expr_cond, context).context
1138
+
1139
+ node_case_result = add_vertex(Node.new(:case_result, {}))
1140
+ final_context = expr_branches.reduce(new_context) do |current_context, expr_when|
1141
+ if expr_when.type == :when
1142
+ expr_cond, expr_body = expr_when.children
1143
+ context_after_cond = process(expr_cond, current_context).context
1144
+
1145
+ if expr_body.nil?
1146
+ @graph.add_edge(Node.new(:nil, {}), node_case_result)
1147
+ context_after_cond
1148
+ else
1149
+ expr_body_result = process(expr_body, context_after_cond)
1150
+ @graph.add_edge(expr_body_result.node, node_case_result)
1151
+ expr_body_result.context
1152
+ end
1153
+ else
1154
+ expr_body_result = process(expr_when, current_context)
1155
+ @graph.add_edge(expr_body_result.node, node_case_result)
1156
+ expr_body_result.context
1157
+ end
1158
+ end
1159
+
1160
+ return Result.new(node_case_result, final_context)
1161
+ end
1162
+
1163
+ def handle_yield(ast, context)
1164
+ exprs = ast.children
1165
+
1166
+ final_context, call_arg_nodes, _block_node = prepare_argument_nodes(context, exprs)
1167
+
1168
+ result_node = add_vertex(Node.new(:yield_result, {}))
1169
+ if context.analyzed_method
1170
+ method_nodes = @graph.get_metod_nodes(context.analyzed_method)
1171
+ method_nodes.yields << Graph::Yield.new(call_arg_nodes, result_node)
1172
+ end
1173
+
1174
+ return Result.new(result_node, final_context)
1175
+ end
1176
+
1177
+ def handle_loop_operator(ast, context)
1178
+ return Result.new(Node.new(:loop_operator, {}), context)
1179
+ end
1180
+
1181
+ def handle_resbody(ast, context)
1182
+ error_array_expr = ast.children[0]
1183
+ assignment_expr = ast.children[1]
1184
+ rescue_body_expr = ast.children[2]
1185
+
1186
+ error_array_expr ||= Parser::AST::Node.new(:array, [Parser::AST::Node.new(:const, [nil, :StandardError])])
1187
+ error_array_expr_result = process(error_array_expr, context)
1188
+ unwrap_node = add_vertex(Node.new(:unwrap_error_array, {}))
1189
+ @graph.add_edge(error_array_expr_result.node, unwrap_node)
1190
+ context_after_errors = error_array_expr_result.context
1191
+
1192
+ context_after_assignment = if assignment_expr
1193
+ assignment_expr_result = process(assignment_expr, context_after_errors)
1194
+ @graph.add_edge(unwrap_node, assignment_expr_result.node) if unwrap_node
1195
+ assignment_expr_result.context
1196
+ else
1197
+ context
1198
+ end
1199
+
1200
+ if rescue_body_expr
1201
+ rescue_body_expr_result = process(rescue_body_expr, context_after_assignment)
1202
+ node_rescue_body = rescue_body_expr_result.node
1203
+ final_context = rescue_body_expr_result.context
1204
+ else
1205
+ node_rescue_body = add_vertex(Node.new(:nil, {}))
1206
+ final_context = context
1207
+ end
1208
+
1209
+ return Result.new(node_rescue_body, final_context)
1210
+ end
1211
+
1212
+ def handle_rescue(ast, context)
1213
+ try_expr = ast.children[0]
1214
+ resbody = ast.children[1]
1215
+ elsebody = ast.children[2]
1216
+
1217
+ if try_expr
1218
+ try_expr_result = process(try_expr, context)
1219
+ node_try = try_expr_result.node
1220
+ context_after_try = try_expr_result.context
1221
+ else
1222
+ node_try = add_vertex(Node.new(:nil, {}))
1223
+ context_after_try = context
1224
+ end
1225
+
1226
+ resbody_result = process(resbody, context_after_try)
1227
+ node_resbody = resbody_result.node
1228
+ context_after_resbody = resbody_result.context
1229
+
1230
+ node = add_vertex(Node.new(:rescue, {}))
1231
+ @graph.add_edge(node_resbody, node)
1232
+
1233
+ if elsebody
1234
+ elsebody_result = process(elsebody, context_after_try)
1235
+ node_else = elsebody_result.node
1236
+ context_after_else = elsebody_result.context
1237
+ @graph.add_edge(node_else, node)
1238
+ return Result.new(node, context_after_try.with_merged_lenvs(context_after_resbody.lenv, context_after_else.lenv))
1239
+ else
1240
+ @graph.add_edge(node_try, node)
1241
+ return Result.new(node, context_after_resbody)
1242
+ end
1243
+ end
1244
+
1245
+ def handle_retry(ast, context)
1246
+ return Result.new(add_vertex(Node.new(:retry, {})), context)
1247
+ end
1248
+
1249
+ def handle_ensure(ast, context)
1250
+ expr_pre = ast.children[0]
1251
+ expr_ensure_body = ast.children[1]
1252
+
1253
+ node_ensure = add_vertex(Node.new(:ensure, {}))
1254
+
1255
+ expr_pre_result = process(expr_pre, context)
1256
+ @graph.add_edge(expr_pre_result.node, node_ensure) if expr_pre_result.node
1257
+
1258
+ expr_ensure_body_result = process(expr_ensure_body, expr_pre_result.context)
1259
+
1260
+ return Result.new(node_ensure, expr_ensure_body_result.context)
1261
+ end
1262
+
1263
+ def expr_is_class_definition?(expr)
1264
+ expr.type == :send &&
1265
+ expr.children[0] == Parser::AST::Node.new(:const, [nil, :Class]) &&
1266
+ expr.children[1] == :new
1267
+ end
1268
+
1269
+ def expr_is_module_definition?(expr)
1270
+ expr.type == :send &&
1271
+ expr.children[0] == Parser::AST::Node.new(:const, [nil, :Module]) &&
1272
+ expr.children[1] == :new
1273
+ end
1274
+
1275
+ def build_def_arguments(formal_arguments, context)
1276
+ args = []
1277
+ kwargs = []
1278
+ blockarg = nil
1279
+
1280
+ nodes = {}
1281
+
1282
+ final_context = formal_arguments.reduce(context) do |current_context, arg_ast|
1283
+ arg_name = arg_ast.children[0]&.to_s
1284
+ maybe_arg_default_expr = arg_ast.children[1]
1285
+ location = build_location_from_ast(current_context, arg_ast)
1286
+
1287
+ case arg_ast.type
1288
+ when :arg
1289
+ args << GlobalTree::ArgumentsTree::Regular.new(arg_name)
1290
+ nodes[arg_name] = add_vertex(Node.new(:formal_arg, { var_name: arg_name }, location))
1291
+ current_context.merge_lenv(arg_name => [nodes[arg_name]])
1292
+ when :optarg
1293
+ args << GlobalTree::ArgumentsTree::Optional.new(arg_name)
1294
+ maybe_arg_default_expr_result = process(maybe_arg_default_expr, current_context)
1295
+ nodes[arg_name] = add_vertex(Node.new(:formal_optarg, { var_name: arg_name }, location))
1296
+ @graph.add_edge(maybe_arg_default_expr_result.node, nodes[arg_name])
1297
+ maybe_arg_default_expr_result.context.merge_lenv(arg_name => [nodes[arg_name]])
1298
+ when :restarg
1299
+ args << GlobalTree::ArgumentsTree::Splat.new(arg_name)
1300
+ nodes[arg_name] = add_vertex(Node.new(:formal_restarg, { var_name: arg_name }, location))
1301
+ current_context.merge_lenv(arg_name => [nodes[arg_name]])
1302
+ when :kwarg
1303
+ kwargs << GlobalTree::ArgumentsTree::Regular.new(arg_name)
1304
+ nodes[arg_name] = add_vertex(Node.new(:formal_kwarg, { var_name: arg_name }, location))
1305
+ current_context.merge_lenv(arg_name => [nodes[arg_name]])
1306
+ when :kwoptarg
1307
+ kwargs << GlobalTree::ArgumentsTree::Optional.new(arg_name)
1308
+ maybe_arg_default_expr_result = process(maybe_arg_default_expr, current_context)
1309
+ nodes[arg_name] = add_vertex(Node.new(:formal_kwoptarg, { var_name: arg_name }, location))
1310
+ @graph.add_edge(maybe_arg_default_expr_result.node, nodes[arg_name])
1311
+ maybe_arg_default_expr_result.context.merge_lenv(arg_name => [nodes[arg_name]])
1312
+ when :kwrestarg
1313
+ kwargs << GlobalTree::ArgumentsTree::Splat.new(arg_name)
1314
+ nodes[arg_name] = add_vertex(Node.new(:formal_kwrestarg, { var_name: arg_name }, location))
1315
+ current_context.merge_lenv(arg_name => [nodes[arg_name]])
1316
+ when :mlhs
1317
+ nested_arg, next_context = build_def_arguments_nested(arg_ast.children, nodes, current_context)
1318
+ args << nested_arg
1319
+ next_context
1320
+ when :blockarg
1321
+ blockarg = arg_name
1322
+ nodes[arg_name] = add_vertex(Node.new(:formal_blockarg, { var_name: arg_name }, location))
1323
+ current_context.merge_lenv(arg_name => [nodes[arg_name]])
1324
+ else raise
1325
+ end
1326
+ end
1327
+
1328
+ return GlobalTree::ArgumentsTree.new(args, kwargs, blockarg), final_context, nodes
1329
+ end
1330
+
1331
+ def build_def_arguments_nested(arg_asts, nodes, context)
1332
+ args = []
1333
+
1334
+ final_context = arg_asts.reduce(context) do |current_context, arg_ast|
1335
+ arg_name = arg_ast.children[0]&.to_s
1336
+
1337
+ case arg_ast.type
1338
+ when :arg
1339
+ args << GlobalTree::ArgumentsTree::Regular.new(arg_name)
1340
+ nodes[arg_name] = add_vertex(Node.new(:formal_arg, { var_name: arg_name }))
1341
+ current_context.merge_lenv(arg_name => [nodes[arg_name]])
1342
+ when :restarg
1343
+ args << GlobalTree::ArgumentsTree::Splat.new(arg_name)
1344
+ nodes[arg_name] = add_vertex(Node.new(:formal_restarg, { var_name: arg_name }))
1345
+ current_context.merge_lenv(arg_name => [nodes[arg_name]])
1346
+ when :mlhs
1347
+ nested_arg, next_context = build_def_arguments_nested(arg_ast.children, nodes, current_context)
1348
+ args << nested_arg
1349
+ next_context
1350
+ else raise
1351
+ end
1352
+ end
1353
+
1354
+ return GlobalTree::ArgumentsTree::Nested.new(args), final_context
1355
+ end
1356
+
1357
+ def handle_match_with_lvasgn(ast, context)
1358
+ return Result.new(add_vertex(Node.new(:int, {})), context)
1359
+ end
1360
+
1361
+ def handle_match_current_line(ast, context)
1362
+ Result.new(add_vertex(Node.new(:bool, {})), context)
1363
+ end
1364
+
1365
+ def handle_flipflop(ast, context)
1366
+ Result.new(add_vertex(Node.new(:bool, {})), context)
1367
+ end
1368
+
1369
+ def handle_preexe(ast, context)
1370
+ body = ast.children[0]
1371
+ body_result = process(body, context)
1372
+ Result.new(add_vertex(Node.new(:nil, {})), body_result.context)
1373
+ end
1374
+
1375
+ def fold_context(exprs, context)
1376
+ nodes = []
1377
+ final_context = exprs.reduce(context) do |current_context, ast_child|
1378
+ child_result = process(ast_child, current_context)
1379
+ nodes << child_result.node
1380
+ child_result.context
1381
+ end
1382
+ return final_context, nodes
1383
+ end
1384
+
1385
+ def build_location_from_ast(context, ast)
1386
+ if ast.loc
1387
+ Location.new(
1388
+ context.filepath,
1389
+ build_position_range_from_ast(ast),
1390
+ ast.loc.expression.length)
1391
+ end
1392
+ end
1393
+
1394
+ def add_vertex(v)
1395
+ @graph.add_vertex(v)
1396
+ end
1397
+
1398
+ def add_edges(xs, ys)
1399
+ @graph.add_edges(xs, ys)
1400
+ end
1401
+
1402
+ def simple_constant?(c)
1403
+ c.type == :const && simple_const_prename?(c.children[0])
1404
+ end
1405
+
1406
+ def lambda_ast?(send_expr)
1407
+ send_expr == Parser::AST::Node.new(:send, [nil, :lambda])
1408
+ end
1409
+
1410
+ def one(arr)
1411
+ arr[0]
1412
+ end
1413
+ end
1414
+ end