ikra 0.0.1 → 0.0.2

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ast/builder.rb +225 -77
  3. data/lib/ast/host_section_builder.rb +38 -0
  4. data/lib/ast/interpreter.rb +67 -0
  5. data/lib/ast/lexical_variables_enumerator.rb +3 -2
  6. data/lib/ast/nodes.rb +521 -31
  7. data/lib/ast/printer.rb +116 -18
  8. data/lib/ast/ssa_generator.rb +192 -0
  9. data/lib/ast/visitor.rb +235 -21
  10. data/lib/config/configuration.rb +28 -3
  11. data/lib/config/os_configuration.rb +62 -9
  12. data/lib/cpu/cpu_implementation.rb +39 -0
  13. data/lib/ikra.rb +13 -3
  14. data/lib/resources/cuda/allocate_device_memory.cpp +5 -0
  15. data/lib/resources/cuda/allocate_host_memory.cpp +1 -0
  16. data/lib/resources/cuda/allocate_memcpy_environment_to_device.cpp +11 -0
  17. data/lib/resources/cuda/ast/assignment.cpp +1 -0
  18. data/lib/resources/cuda/block_function_head.cpp +7 -1
  19. data/lib/resources/cuda/entry_point.cpp +47 -0
  20. data/lib/resources/cuda/env_builder_copy_array.cpp +8 -2
  21. data/lib/resources/cuda/free_device_memory.cpp +3 -0
  22. data/lib/resources/cuda/free_memory_for_command.cpp +24 -0
  23. data/lib/resources/cuda/header.cpp +23 -9
  24. data/lib/resources/cuda/header_structs.cpp +92 -0
  25. data/lib/resources/cuda/host_section_block_function_head.cpp +12 -0
  26. data/lib/resources/cuda/host_section_entry_point.cpp +55 -0
  27. data/lib/resources/cuda/host_section_free_device_memory.cpp +18 -0
  28. data/lib/resources/cuda/host_section_launch_parallel_section.cpp +14 -0
  29. data/lib/resources/cuda/host_section_malloc_memcpy_device_to_host.cpp +10 -0
  30. data/lib/resources/cuda/kernel.cpp +9 -2
  31. data/lib/resources/cuda/launch_kernel.cpp +5 -0
  32. data/lib/resources/cuda/memcpy_device_to_host.cpp +3 -0
  33. data/lib/resources/cuda/memcpy_device_to_host_expr.cpp +10 -0
  34. data/lib/resources/cuda/reduce_body.cpp +88 -0
  35. data/lib/resources/cuda/stencil_array_reconstruction.cpp +2 -0
  36. data/lib/resources/cuda/stencil_body.cpp +16 -0
  37. data/lib/resources/cuda/struct_definition.cpp +4 -0
  38. data/lib/ruby_core/array.rb +34 -0
  39. data/lib/ruby_core/array_command.rb +313 -0
  40. data/lib/ruby_core/core.rb +103 -0
  41. data/lib/ruby_core/interpreter.rb +16 -0
  42. data/lib/ruby_core/math.rb +32 -0
  43. data/lib/ruby_core/ruby_integration.rb +256 -0
  44. data/lib/symbolic/host_section.rb +115 -0
  45. data/lib/symbolic/input.rb +87 -0
  46. data/lib/symbolic/input_visitor.rb +68 -0
  47. data/lib/symbolic/symbolic.rb +793 -117
  48. data/lib/symbolic/visitor.rb +70 -8
  49. data/lib/translator/array_command_struct_builder.rb +163 -0
  50. data/lib/translator/ast_translator.rb +572 -0
  51. data/lib/translator/block_translator.rb +104 -48
  52. data/lib/translator/commands/array_combine_command.rb +41 -0
  53. data/lib/translator/commands/array_identity_command.rb +28 -0
  54. data/lib/translator/commands/array_index_command.rb +52 -0
  55. data/lib/translator/commands/array_reduce_command.rb +135 -0
  56. data/lib/translator/commands/array_stencil_command.rb +129 -0
  57. data/lib/translator/commands/array_zip_command.rb +30 -0
  58. data/lib/translator/commands/command_translator.rb +264 -0
  59. data/lib/translator/cuda_errors.rb +32 -0
  60. data/lib/translator/environment_builder.rb +263 -0
  61. data/lib/translator/host_section/array_host_section_command.rb +150 -0
  62. data/lib/translator/host_section/array_in_host_section_command.rb +41 -0
  63. data/lib/translator/host_section/ast_translator.rb +14 -0
  64. data/lib/translator/host_section/parallel_section_invocation_visitor.rb +20 -0
  65. data/lib/translator/host_section/program_builder.rb +89 -0
  66. data/lib/translator/input_translator.rb +226 -0
  67. data/lib/translator/kernel_builder.rb +137 -0
  68. data/lib/translator/kernel_launcher/for_loop_kernel_launcher.rb +40 -0
  69. data/lib/translator/kernel_launcher/kernel_launcher.rb +259 -0
  70. data/lib/translator/kernel_launcher/while_loop_kernel_launcher.rb +38 -0
  71. data/lib/translator/last_returns_visitor.rb +19 -10
  72. data/lib/translator/program_builder.rb +197 -0
  73. data/lib/translator/program_launcher.rb +273 -0
  74. data/lib/translator/struct_type.rb +55 -0
  75. data/lib/translator/translator.rb +34 -11
  76. data/lib/translator/variable_classifier_visitor.rb +56 -0
  77. data/lib/types/inference/ast_inference.rb +586 -0
  78. data/lib/types/inference/clear_types_visitor.rb +11 -0
  79. data/lib/types/inference/command_inference.rb +101 -0
  80. data/lib/types/inference/input_inference.rb +62 -0
  81. data/lib/types/{object_tracer.rb → inference/object_tracer.rb} +5 -6
  82. data/lib/types/inference/ruby_extension.rb +35 -0
  83. data/lib/types/inference/symbol_table.rb +131 -0
  84. data/lib/types/types.rb +14 -0
  85. data/lib/types/types/array_command_type.rb +123 -0
  86. data/lib/types/types/array_type.rb +137 -0
  87. data/lib/types/{class_type.rb → types/class_type.rb} +42 -18
  88. data/lib/types/{primitive_type.rb → types/primitive_type.rb} +20 -7
  89. data/lib/types/types/ruby_type.rb +88 -0
  90. data/lib/types/types/struct_type.rb +179 -0
  91. data/lib/types/types/union_type.rb +239 -0
  92. metadata +160 -18
  93. data/lib/ast/method_definition.rb +0 -37
  94. data/lib/ast/translator.rb +0 -264
  95. data/lib/resources/cuda/kernel_launcher.cpp +0 -28
  96. data/lib/scope.rb +0 -166
  97. data/lib/translator/command_translator.rb +0 -421
  98. data/lib/translator/local_variables_enumerator.rb +0 -35
  99. data/lib/translator/method_translator.rb +0 -24
  100. data/lib/types/array_type.rb +0 -51
  101. data/lib/types/ruby_extension.rb +0 -67
  102. data/lib/types/ruby_type.rb +0 -45
  103. data/lib/types/type_inference.rb +0 -382
  104. data/lib/types/union_type.rb +0 -155
@@ -3,55 +3,344 @@ module Ikra
3
3
  class Node
4
4
  attr_accessor :parent
5
5
 
6
+ def eql?(other)
7
+ return self == other
8
+ end
9
+
10
+ def ==(other)
11
+ return self.class == other.class
12
+ end
13
+
14
+ def hash
15
+ return 1231
16
+ end
17
+ end
18
+
19
+ class ProgramNode < Node
20
+ # First block is program entry point
21
+ attr_reader :blocks
22
+ attr_reader :classes
23
+
24
+ def initialize(blocks: [], classes: [])
25
+ @blocks = blocks
26
+ @classes = classes
27
+ end
28
+
29
+ def clone
30
+ return ProgramNode.new(
31
+ blocks: @blocks.map do |b| b.clone end,
32
+ classes: @classes.map do |c| c.clone end)
33
+ end
34
+
35
+ def ==(other)
36
+ return super(other) && blocks == other.blocks && classes == other.classes
37
+ end
38
+
39
+ def hash
40
+ return (blocks.hash + classes.hash) % 4524321
41
+ end
42
+ end
43
+
44
+ class ClassDefNode < Node
45
+ attr_reader :name
46
+ attr_reader :instance_variables
47
+ attr_reader :instance_methods
48
+ attr_reader :ruby_class
49
+
50
+ # Class variables/methods are defined as instance variables/methods on the singleton
51
+ # class ClassDefNode
52
+
53
+ def initialize(
54
+ name:,
55
+ ruby_class:,
56
+ instance_variables: [],
57
+ instance_methods: [],
58
+ class_variables: [],
59
+ class_methods: [])
60
+ @name = name
61
+ @ruby_class = ruby_class
62
+ @instance_variables = instance_variables
63
+ @instance_methods = instance_methods
64
+ end
65
+
66
+ def clone
67
+ return ClassDefNode.new(
68
+ name: @name,
69
+ ruby_class: @ruby_class,
70
+ instance_variables: @instance_variables.map do |i| i.clone end,
71
+ instance_methods: @instance_methods.map do |i| i.clone end,
72
+ class_variables: @class_variables.map do |c| c.clone end,
73
+ class_methods: @class_methods.map do |c| c.clone end)
74
+ end
75
+
76
+ def add_instance_variable(inst_var)
77
+ instance_variables.push(inst_var)
78
+ inst_meth.parent = self
79
+ end
80
+
81
+ def add_instance_method(inst_meth)
82
+ instance_methods.push(inst_meth)
83
+ inst_meth.parent = self
84
+ end
85
+
86
+ def has_instance_method?(selector)
87
+ return instance_method(selector) != nil
88
+ end
89
+
90
+ def instance_method(selector)
91
+ return instance_methods.find do |meth|
92
+ meth.name == selector
93
+ end
94
+ end
95
+
96
+ def enclosing_class
97
+ return self
98
+ end
99
+
100
+ def ==(other)
101
+ return super(other) &&
102
+ name == other.name &&
103
+ ruby_class == other.ruby_class &&
104
+ instance_variables == other.instance_variables &&
105
+ instance_methods == other.instance_methods &&
106
+ class_variables == other.class_variables &&
107
+ class_methods == other.class_methods
108
+ end
109
+ end
110
+
111
+ class VarDefNode < Node
112
+ attr_reader :name
113
+ attr_accessor :read
114
+ attr_accessor :written
115
+
116
+ def initialize(name:, read: false, written: false)
117
+ @name = name
118
+ @read = read
119
+ @written = written
120
+ end
121
+
122
+ def clone
123
+ return VarDefNode.new(
124
+ name: @name,
125
+ read: @read,
126
+ written: @written)
127
+ end
128
+
129
+ def ==(other)
130
+ return super(other) &&
131
+ name == other.name &&
132
+ read == other.read &&
133
+ written == other.written
134
+ end
135
+ end
136
+
137
+ class BehaviorNode < Node
138
+ def find_behavior_node
139
+ return self
140
+ end
141
+ end
142
+
143
+ class MethDefNode < BehaviorNode
144
+ attr_reader :name
145
+ attr_reader :ruby_method
146
+ attr_reader :body
147
+
148
+ def initialize(name:, body:, ruby_method:, method_binding: nil)
149
+ @name = name
150
+ @body = body
151
+ @ruby_method = ruby_method
152
+ @binding = method_binding
153
+
154
+ body.parent = self
155
+ end
156
+
157
+ def clone
158
+ return MethodDefNode.new(
159
+ name: @name,
160
+ body: @body.clone,
161
+ ruby_method: @ruby_method)
162
+ end
163
+
164
+ def binding
165
+ if @binding != nil
166
+ return @binding
167
+ elsif ruby_method == nil
168
+ return nil
169
+ else
170
+ return ruby_method.send(:binding)
171
+ end
172
+ end
173
+
174
+ def ==(other)
175
+ return super(other) && name == other.name && body == other.body
176
+ end
177
+ end
178
+
179
+ class BlockDefNode < BehaviorNode
180
+ attr_reader :body
181
+ attr_reader :ruby_block
182
+ attr_reader :parameters
183
+
184
+ def initialize(body:, ruby_block:, parameters: nil)
185
+ @body = body
186
+ @ruby_block = ruby_block
187
+ @parameters = parameters
188
+
189
+ body.parent = self
190
+ end
191
+
192
+ def clone
193
+ return BlockDefNode.new(
194
+ body: @body.clone,
195
+ ruby_block: @ruby_block,
196
+ parameters: @parameters == nil ? nil : @parameters.dup)
197
+ end
198
+
199
+ def binding
200
+ return ruby_block.binding
201
+ end
202
+
203
+ def ==(other)
204
+ return super(other) && body == other.body && parameters == other.parameters
205
+ end
206
+ end
207
+
208
+ class TreeNode < Node
6
209
  def is_begin_node?
7
210
  false
8
211
  end
9
212
 
10
213
  def replace(another_node)
214
+ # Sometimes, this method does not work as expected, if the `parent` of the `self`
215
+ # is already modified before calling this method.
11
216
  parent.replace_child(self, another_node)
12
217
  end
13
218
 
14
219
  def replace_child(node, another_node)
15
220
  instance_variables.each do |inst_var|
16
- if instance_variable_get(inst_var) == node
221
+ if instance_variable_get(inst_var).equal?(node)
17
222
  instance_variable_set(inst_var, another_node)
18
223
  another_node.parent = self
19
224
  end
20
225
  end
21
226
  end
22
227
 
23
- def class_owner
24
- @parent.class_owner
228
+ def enclosing_class
229
+ @parent.enclosing_class
230
+ end
231
+
232
+ def find_behavior_node
233
+ return parent.find_behavior_node
234
+ end
235
+
236
+ TYPE_INFO_VARS = [:@return_type_by_recv_type, :@type]
237
+
238
+ def ==(other)
239
+ if self.class != other.class
240
+ return false
241
+ end
242
+
243
+ # Ignore types
244
+ if (instance_variables - TYPE_INFO_VARS) != (other.instance_variables - TYPE_INFO_VARS)
245
+
246
+ return false
247
+ end
248
+
249
+ for var_name in instance_variables
250
+ if var_name != :@parent && !TYPE_INFO_VARS.include?(var_name)
251
+ # Avoid cycles via :parent... There could still be other cycles though
252
+ if instance_variable_get(var_name) != other.instance_variable_get(var_name)
253
+ return false
254
+ end
255
+ end
256
+ end
257
+
258
+ return true
25
259
  end
26
260
  end
27
-
28
- class RootNode < Node
29
- attr_reader :child
30
- attr_accessor :class_owner # @return [Class] The class where this method is defined
31
261
 
32
- def initialize(child:)
33
- @child = child
34
- child.parent = self
262
+ # Need to wrap block bodies in RootNode, so that the first node can be replaced if necessary (LastStatementReturnsVisitor)
263
+ class RootNode < TreeNode
264
+ attr_reader :single_child
265
+
266
+ def initialize(single_child:)
267
+ @single_child = single_child
268
+ single_child.parent = self
269
+ end
270
+
271
+ def clone
272
+ return RootNode.new(single_child: @single_child.clone)
273
+ end
274
+ end
275
+
276
+ class ArrayNode < TreeNode
277
+ attr_reader :values
278
+
279
+ def initialize(values:)
280
+ @values = values
281
+
282
+ for value in values
283
+ value.parent = self
284
+ end
285
+ end
286
+
287
+ def clone
288
+ return ArrayNode.new(
289
+ values: @values.map do |v| v.clone end)
35
290
  end
36
291
  end
37
292
 
38
- class ConstNode < Node
293
+ # A synthetic AST node. Contains its string translation directly.
294
+ class SourceCodeExprNode < TreeNode
295
+ attr_reader :code
296
+
297
+ def initialize(code:)
298
+ @code = code
299
+ end
300
+
301
+ def clone
302
+ return SourceCodeExprNode.new(code: @code)
303
+ end
304
+ end
305
+
306
+ class HashNode < TreeNode
307
+ attr_reader :hash
308
+
309
+ def initialize(hash:)
310
+ @hash = hash
311
+ end
312
+
313
+ def clone
314
+ # TODO: Clone properly
315
+ return HashNode.new(hash: @hash.clone)
316
+ end
317
+ end
318
+
319
+ class ConstNode < TreeNode
39
320
  attr_reader :identifier
40
321
 
41
322
  def initialize(identifier:)
42
323
  @identifier = identifier
43
324
  end
325
+
326
+ def clone
327
+ return ConstNode.new(identifier: @identifier)
328
+ end
44
329
  end
45
330
 
46
- class LVarReadNode < Node
331
+ class LVarReadNode < TreeNode
47
332
  attr_reader :identifier
48
333
 
49
334
  def initialize(identifier:)
50
335
  @identifier = identifier
51
336
  end
337
+
338
+ def clone
339
+ return LVarReadNode.new(identifier: @identifier)
340
+ end
52
341
  end
53
342
 
54
- class LVarWriteNode < Node
343
+ class LVarWriteNode < TreeNode
55
344
  attr_reader :identifier
56
345
  attr_reader :value
57
346
 
@@ -61,41 +350,91 @@ module Ikra
61
350
 
62
351
  value.parent = self
63
352
  end
353
+
354
+ def clone
355
+ return LVarWriteNode.new(
356
+ identifier: @identifier,
357
+ value: @value.clone)
358
+ end
64
359
  end
65
360
 
66
- class IVarReadNode < Node
361
+ class IVarReadNode < TreeNode
67
362
  attr_reader :identifier
68
363
 
69
364
  def initialize(identifier:)
70
365
  @identifier = identifier
71
366
  end
367
+
368
+ def clone
369
+ return IVarReadNode.new(identifier: @identifier)
370
+ end
72
371
  end
73
372
 
74
- class IntNode < Node
373
+ class IntLiteralNode < TreeNode
75
374
  attr_reader :value
76
375
 
77
376
  def initialize(value:)
78
377
  @value = value
79
378
  end
379
+
380
+ def clone
381
+ return IntLiteralNode.new(value: @value)
382
+ end
80
383
  end
81
384
 
82
- class FloatNode < Node
385
+ class FloatLiteralNode < TreeNode
83
386
  attr_reader :value
84
387
 
85
388
  def initialize(value:)
86
389
  @value = value
87
390
  end
391
+
392
+ def clone
393
+ return FloatLiteralNode.new(value: @value)
394
+ end
88
395
  end
89
396
 
90
- class BoolNode < Node
397
+ class BoolLiteralNode < TreeNode
91
398
  attr_reader :value
92
399
 
93
400
  def initialize(value:)
94
401
  @value = value
95
402
  end
403
+
404
+ def clone
405
+ return BoolLiteralNode.new(value: @value)
406
+ end
407
+ end
408
+
409
+ class NilLiteralNode < TreeNode
410
+
96
411
  end
97
412
 
98
- class ForNode < Node
413
+ class SymbolLiteralNode < TreeNode
414
+ attr_reader :value
415
+
416
+ def initialize(value:)
417
+ @value = value
418
+ end
419
+
420
+ def clone
421
+ return SymbolLiteralNode.new(value: @value)
422
+ end
423
+ end
424
+
425
+ class StringLiteralNode < TreeNode
426
+ attr_reader :value
427
+
428
+ def initialize(value:)
429
+ @value = value
430
+ end
431
+
432
+ def clone
433
+ return StringLiteralNode.new(value: @value)
434
+ end
435
+ end
436
+
437
+ class ForNode < TreeNode
99
438
  attr_reader :iterator_identifier
100
439
  attr_reader :range_from
101
440
  attr_reader :range_to
@@ -111,32 +450,153 @@ module Ikra
111
450
  range_to.parent = self
112
451
  body_stmts.parent = self
113
452
  end
453
+
454
+ def clone
455
+ return ForNode.new(
456
+ iterator_identifier: @iterator_identifier,
457
+ range_from: @range_from.clone,
458
+ range_to: @range_to.clone,
459
+ body_stmts: @body_stmts.clone)
460
+ end
114
461
  end
115
462
 
116
- class BreakNode < Node
463
+ class WhileNode < TreeNode
464
+ attr_reader :condition
465
+ attr_reader :body_stmts
466
+
467
+ def initialize(condition:, body_stmts:)
468
+ @condition = condition
469
+ @body_stmts = body_stmts
470
+
471
+ condition.parent = self
472
+ body_stmts.parent = self
473
+ end
474
+
475
+ def clone
476
+ return WhileNode.new(
477
+ condition: @condition.clone,
478
+ body_stmts: @body_stmts.clone)
479
+ end
480
+ end
117
481
 
482
+ class WhilePostNode < TreeNode
483
+ attr_reader :condition
484
+ attr_reader :body_stmts
485
+
486
+ def initialize(condition:, body_stmts:)
487
+ @condition = condition
488
+ @body_stmts = body_stmts
489
+
490
+ condition.parent = self
491
+ body_stmts.parent = self
492
+ end
493
+
494
+ def clone
495
+ return WhilePostNode.new(
496
+ condition: @condition.clone,
497
+ body_stmts: @body_stmts.clone)
498
+ end
118
499
  end
119
500
 
120
- class IfNode < Node
501
+ class UntilNode < TreeNode
502
+ attr_reader :condition
503
+ attr_reader :body_stmts
504
+
505
+ def initialize(condition:, body_stmts:)
506
+ @condition = condition
507
+ @body_stmts = body_stmts
508
+
509
+ condition.parent = self
510
+ body_stmts.parent = self
511
+ end
512
+
513
+ def clone
514
+ return UntilNode.new(
515
+ condition: @condition.clone,
516
+ body_stmts: @body_stmts.clone)
517
+ end
518
+ end
519
+
520
+ class UntilPostNode < TreeNode
521
+ attr_reader :condition
522
+ attr_reader :body_stmts
523
+
524
+ def initialize(condition:, body_stmts:)
525
+ @condition = condition
526
+ @body_stmts = body_stmts
527
+
528
+ condition.parent = self
529
+ body_stmts.parent = self
530
+ end
531
+
532
+ def clone
533
+ return UntilPostNode.new(
534
+ condition: @condition.clone,
535
+ body_stmts: @body_stmts.clone)
536
+ end
537
+ end
538
+
539
+ class BreakNode < TreeNode
540
+
541
+ end
542
+
543
+ class IfNode < TreeNode
121
544
  attr_reader :condition
122
545
  attr_reader :true_body_stmts
123
546
  attr_reader :false_body_stmts
124
547
 
125
548
  def initialize(condition:, true_body_stmts:, false_body_stmts: nil)
549
+ if true_body_stmts == nil
550
+ # Handle empty `true` block
551
+ true_body_stmts = BeginNode.new
552
+ end
553
+
554
+ if false_body_stmts == nil
555
+ # Handle empty `false` block
556
+ false_body_stmts = BeginNode.new
557
+ end
558
+
126
559
  @condition = condition
127
560
  @true_body_stmts = true_body_stmts
128
561
  @false_body_stmts = false_body_stmts
129
562
 
130
563
  condition.parent = self
131
- true_body_stmts.parent = self
564
+ true_body_stmts.parent = self
565
+ false_body_stmts.parent = self
566
+ end
132
567
 
133
- if false_body_stmts != nil
134
- false_body_stmts.parent = self
135
- end
568
+ def clone
569
+ return IfNode.new(
570
+ condition: @condition.clone,
571
+ true_body_stmts: @true_body_stmts.clone,
572
+ false_body_stmts: @false_body_stmts.clone)
136
573
  end
137
574
  end
138
575
 
139
- class BeginNode < Node
576
+ class TernaryNode < TreeNode
577
+ attr_reader :condition
578
+ attr_reader :true_val
579
+ attr_reader :false_val
580
+
581
+ def initialize(condition:, true_val:, false_val:)
582
+ @condition = condition
583
+ @true_val = true_val
584
+ @false_val = false_val
585
+
586
+ condition.parent = self
587
+ true_val.parent = self
588
+ false_val.parent = self
589
+ end
590
+
591
+ def clone
592
+ return TernaryNode.new(
593
+ condition: @condition.clone,
594
+ true_val: @true_val.clone,
595
+ false_val: @false_val.clone)
596
+ end
597
+ end
598
+
599
+ class BeginNode < TreeNode
140
600
  attr_reader :body_stmts
141
601
 
142
602
  def initialize(body_stmts: [])
@@ -146,10 +606,20 @@ module Ikra
146
606
  stmt.parent = self
147
607
  end
148
608
  end
609
+
610
+ def clone
611
+ return BeginNode.new(
612
+ body_stmts: @body_stmts.map do |s| s.clone end)
613
+ end
614
+
615
+ def add_statement(node)
616
+ body_stmts.push(node)
617
+ node.parent = self
618
+ end
149
619
 
150
620
  def replace_child(node, another_node)
151
621
  @body_stmts = @body_stmts.map do |stmt|
152
- if node == stmt
622
+ if node.equal?(stmt)
153
623
  another_node.parent = self
154
624
  another_node
155
625
  else
@@ -163,15 +633,17 @@ module Ikra
163
633
  end
164
634
  end
165
635
 
166
- class SendNode < Node
636
+ class SendNode < TreeNode
167
637
  attr_reader :receiver
168
638
  attr_reader :selector
169
639
  attr_reader :arguments
640
+ attr_reader :block_argument
170
641
 
171
- def initialize(receiver:, selector:, arguments: [])
642
+ def initialize(receiver:, selector:, arguments: [], block_argument: nil)
172
643
  @receiver = receiver
173
644
  @selector = selector
174
645
  @arguments = arguments
646
+ @block_argument = block_argument
175
647
 
176
648
  receiver.parent = self
177
649
  arguments.each do |arg|
@@ -179,13 +651,22 @@ module Ikra
179
651
  end
180
652
  end
181
653
 
654
+ def clone
655
+ return SendNode.new(
656
+ receiver: @receiver.clone,
657
+ selector: @selector,
658
+ arguments: @arguments.map do |a| a.clone end,
659
+ block_argument: block_argument == nil ? nil : block_argument.clone)
660
+ end
661
+
182
662
  def replace_child(node, another_node)
183
- if @receiver == node
663
+ if @receiver.equal?(node)
184
664
  @receiver = another_node
665
+ another_node.parent = self
185
666
  end
186
667
 
187
668
  @arguments = @arguments.map do |arg|
188
- if node == arg
669
+ if node.equal?(arg)
189
670
  another_node.parent = self
190
671
  another_node
191
672
  else
@@ -193,9 +674,14 @@ module Ikra
193
674
  end
194
675
  end
195
676
  end
677
+
678
+ # Setter required for [HostSectionBuilder]
679
+ def block_argument=(value)
680
+ @block_argument = value
681
+ end
196
682
  end
197
683
 
198
- class ReturnNode < Node
684
+ class ReturnNode < TreeNode
199
685
  attr_reader :value
200
686
 
201
687
  def initialize(value:)
@@ -203,6 +689,10 @@ module Ikra
203
689
 
204
690
  value.parent = self
205
691
  end
692
+
693
+ def clone
694
+ return ReturnNode.new(value: value.clone)
695
+ end
206
696
  end
207
697
  end
208
698
  end