orbacle 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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