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.
- checksums.yaml +4 -4
- data/lib/ast/builder.rb +225 -77
- data/lib/ast/host_section_builder.rb +38 -0
- data/lib/ast/interpreter.rb +67 -0
- data/lib/ast/lexical_variables_enumerator.rb +3 -2
- data/lib/ast/nodes.rb +521 -31
- data/lib/ast/printer.rb +116 -18
- data/lib/ast/ssa_generator.rb +192 -0
- data/lib/ast/visitor.rb +235 -21
- data/lib/config/configuration.rb +28 -3
- data/lib/config/os_configuration.rb +62 -9
- data/lib/cpu/cpu_implementation.rb +39 -0
- data/lib/ikra.rb +13 -3
- data/lib/resources/cuda/allocate_device_memory.cpp +5 -0
- data/lib/resources/cuda/allocate_host_memory.cpp +1 -0
- data/lib/resources/cuda/allocate_memcpy_environment_to_device.cpp +11 -0
- data/lib/resources/cuda/ast/assignment.cpp +1 -0
- data/lib/resources/cuda/block_function_head.cpp +7 -1
- data/lib/resources/cuda/entry_point.cpp +47 -0
- data/lib/resources/cuda/env_builder_copy_array.cpp +8 -2
- data/lib/resources/cuda/free_device_memory.cpp +3 -0
- data/lib/resources/cuda/free_memory_for_command.cpp +24 -0
- data/lib/resources/cuda/header.cpp +23 -9
- data/lib/resources/cuda/header_structs.cpp +92 -0
- data/lib/resources/cuda/host_section_block_function_head.cpp +12 -0
- data/lib/resources/cuda/host_section_entry_point.cpp +55 -0
- data/lib/resources/cuda/host_section_free_device_memory.cpp +18 -0
- data/lib/resources/cuda/host_section_launch_parallel_section.cpp +14 -0
- data/lib/resources/cuda/host_section_malloc_memcpy_device_to_host.cpp +10 -0
- data/lib/resources/cuda/kernel.cpp +9 -2
- data/lib/resources/cuda/launch_kernel.cpp +5 -0
- data/lib/resources/cuda/memcpy_device_to_host.cpp +3 -0
- data/lib/resources/cuda/memcpy_device_to_host_expr.cpp +10 -0
- data/lib/resources/cuda/reduce_body.cpp +88 -0
- data/lib/resources/cuda/stencil_array_reconstruction.cpp +2 -0
- data/lib/resources/cuda/stencil_body.cpp +16 -0
- data/lib/resources/cuda/struct_definition.cpp +4 -0
- data/lib/ruby_core/array.rb +34 -0
- data/lib/ruby_core/array_command.rb +313 -0
- data/lib/ruby_core/core.rb +103 -0
- data/lib/ruby_core/interpreter.rb +16 -0
- data/lib/ruby_core/math.rb +32 -0
- data/lib/ruby_core/ruby_integration.rb +256 -0
- data/lib/symbolic/host_section.rb +115 -0
- data/lib/symbolic/input.rb +87 -0
- data/lib/symbolic/input_visitor.rb +68 -0
- data/lib/symbolic/symbolic.rb +793 -117
- data/lib/symbolic/visitor.rb +70 -8
- data/lib/translator/array_command_struct_builder.rb +163 -0
- data/lib/translator/ast_translator.rb +572 -0
- data/lib/translator/block_translator.rb +104 -48
- data/lib/translator/commands/array_combine_command.rb +41 -0
- data/lib/translator/commands/array_identity_command.rb +28 -0
- data/lib/translator/commands/array_index_command.rb +52 -0
- data/lib/translator/commands/array_reduce_command.rb +135 -0
- data/lib/translator/commands/array_stencil_command.rb +129 -0
- data/lib/translator/commands/array_zip_command.rb +30 -0
- data/lib/translator/commands/command_translator.rb +264 -0
- data/lib/translator/cuda_errors.rb +32 -0
- data/lib/translator/environment_builder.rb +263 -0
- data/lib/translator/host_section/array_host_section_command.rb +150 -0
- data/lib/translator/host_section/array_in_host_section_command.rb +41 -0
- data/lib/translator/host_section/ast_translator.rb +14 -0
- data/lib/translator/host_section/parallel_section_invocation_visitor.rb +20 -0
- data/lib/translator/host_section/program_builder.rb +89 -0
- data/lib/translator/input_translator.rb +226 -0
- data/lib/translator/kernel_builder.rb +137 -0
- data/lib/translator/kernel_launcher/for_loop_kernel_launcher.rb +40 -0
- data/lib/translator/kernel_launcher/kernel_launcher.rb +259 -0
- data/lib/translator/kernel_launcher/while_loop_kernel_launcher.rb +38 -0
- data/lib/translator/last_returns_visitor.rb +19 -10
- data/lib/translator/program_builder.rb +197 -0
- data/lib/translator/program_launcher.rb +273 -0
- data/lib/translator/struct_type.rb +55 -0
- data/lib/translator/translator.rb +34 -11
- data/lib/translator/variable_classifier_visitor.rb +56 -0
- data/lib/types/inference/ast_inference.rb +586 -0
- data/lib/types/inference/clear_types_visitor.rb +11 -0
- data/lib/types/inference/command_inference.rb +101 -0
- data/lib/types/inference/input_inference.rb +62 -0
- data/lib/types/{object_tracer.rb → inference/object_tracer.rb} +5 -6
- data/lib/types/inference/ruby_extension.rb +35 -0
- data/lib/types/inference/symbol_table.rb +131 -0
- data/lib/types/types.rb +14 -0
- data/lib/types/types/array_command_type.rb +123 -0
- data/lib/types/types/array_type.rb +137 -0
- data/lib/types/{class_type.rb → types/class_type.rb} +42 -18
- data/lib/types/{primitive_type.rb → types/primitive_type.rb} +20 -7
- data/lib/types/types/ruby_type.rb +88 -0
- data/lib/types/types/struct_type.rb +179 -0
- data/lib/types/types/union_type.rb +239 -0
- metadata +160 -18
- data/lib/ast/method_definition.rb +0 -37
- data/lib/ast/translator.rb +0 -264
- data/lib/resources/cuda/kernel_launcher.cpp +0 -28
- data/lib/scope.rb +0 -166
- data/lib/translator/command_translator.rb +0 -421
- data/lib/translator/local_variables_enumerator.rb +0 -35
- data/lib/translator/method_translator.rb +0 -24
- data/lib/types/array_type.rb +0 -51
- data/lib/types/ruby_extension.rb +0 -67
- data/lib/types/ruby_type.rb +0 -45
- data/lib/types/type_inference.rb +0 -382
- data/lib/types/union_type.rb +0 -155
@@ -0,0 +1,586 @@
|
|
1
|
+
# No explicit `require`s. This file should be includes via types.rb
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
require_relative "../../ast/nodes.rb"
|
6
|
+
require_relative "../../ast/visitor.rb"
|
7
|
+
require_relative "clear_types_visitor.rb"
|
8
|
+
|
9
|
+
module Ikra
|
10
|
+
module AST
|
11
|
+
class TreeNode
|
12
|
+
def get_type
|
13
|
+
@type ||= Types::UnionType.new
|
14
|
+
return @type.dup
|
15
|
+
end
|
16
|
+
|
17
|
+
def merge_union_type(union_type)
|
18
|
+
@type ||= Types::UnionType.new
|
19
|
+
|
20
|
+
if not @type.include_all?(union_type)
|
21
|
+
register_type_change
|
22
|
+
end
|
23
|
+
|
24
|
+
return @type.expand_return_type(union_type).dup
|
25
|
+
end
|
26
|
+
|
27
|
+
def symbol_table
|
28
|
+
return parent.symbol_table
|
29
|
+
end
|
30
|
+
|
31
|
+
def register_type_change
|
32
|
+
if parent != nil
|
33
|
+
parent.register_type_change
|
34
|
+
else
|
35
|
+
# This node is not part of a full AST, i.e., it does not have a [BehaviorNode]
|
36
|
+
# as a parent. Do nothing.
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class ClassDefNode
|
42
|
+
def get_type
|
43
|
+
return ruby_class.to_ikra_type
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class LVarWriteNode
|
48
|
+
attr_accessor :variable_type
|
49
|
+
end
|
50
|
+
|
51
|
+
class MethDefNode
|
52
|
+
attr_accessor :receiver_type
|
53
|
+
|
54
|
+
def initialize_types(receiver_type:, return_type: Types::UnionType.new)
|
55
|
+
@receiver_type = receiver_type
|
56
|
+
@type = return_type
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.new_with_types(
|
60
|
+
name:,
|
61
|
+
body:,
|
62
|
+
parameters_names_and_types:,
|
63
|
+
ruby_method:,
|
64
|
+
receiver_type:,
|
65
|
+
return_type: Types::UnionType.new,
|
66
|
+
method_binding: nil)
|
67
|
+
|
68
|
+
instance = new(name: name, body: body, ruby_method: ruby_method, method_binding: method_binding)
|
69
|
+
instance.initialize_types(receiver_type: receiver_type, return_type: return_type)
|
70
|
+
instance.parameters_names_and_types = parameters_names_and_types
|
71
|
+
return instance
|
72
|
+
end
|
73
|
+
|
74
|
+
def callers
|
75
|
+
@callers ||= []
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class BehaviorNode
|
80
|
+
def get_type
|
81
|
+
@type ||= Types::UnionType.new
|
82
|
+
end
|
83
|
+
|
84
|
+
def merge_union_type(union_type)
|
85
|
+
type = @type ||= Types::UnionType.new
|
86
|
+
|
87
|
+
if not @type.include_all?(union_type)
|
88
|
+
register_type_change
|
89
|
+
end
|
90
|
+
|
91
|
+
return type.expand_return_type(union_type).dup
|
92
|
+
end
|
93
|
+
|
94
|
+
# Mapping: parameter name -> UnionType
|
95
|
+
def parameters_names_and_types
|
96
|
+
@parameters_names_and_types ||= {}
|
97
|
+
end
|
98
|
+
|
99
|
+
def parameters_names_and_types=(value)
|
100
|
+
@parameters_names_and_types = value
|
101
|
+
end
|
102
|
+
|
103
|
+
# Mapping: lexical variable name -> UnionType
|
104
|
+
def lexical_variables_names_and_types
|
105
|
+
@lexical_variables_names_and_types ||= {}
|
106
|
+
end
|
107
|
+
|
108
|
+
# Mapping: local variable name -> UnionType
|
109
|
+
def local_variables_names_and_types
|
110
|
+
@local_variables_names_and_types ||= {}
|
111
|
+
end
|
112
|
+
|
113
|
+
def local_variables_names_and_types=(value)
|
114
|
+
@local_variables_names_and_types = value
|
115
|
+
end
|
116
|
+
|
117
|
+
def symbol_table
|
118
|
+
@symbol_table ||= TypeInference::SymbolTable.new
|
119
|
+
end
|
120
|
+
|
121
|
+
def types_changed?
|
122
|
+
return @types_changed ||= false
|
123
|
+
end
|
124
|
+
|
125
|
+
def reset_types_changed
|
126
|
+
@types_changed = false
|
127
|
+
end
|
128
|
+
|
129
|
+
def register_type_change
|
130
|
+
@types_changed = true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class SendNode
|
135
|
+
attr_writer :return_type_by_recv_type
|
136
|
+
|
137
|
+
# Mapping: Receiver type --> Return value of send
|
138
|
+
def return_type_by_recv_type
|
139
|
+
@return_type_by_recv_type ||= {}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
module TypeInference
|
145
|
+
class Visitor < AST::Visitor
|
146
|
+
|
147
|
+
# If this error is thrown, type inference should start from the beginning (with
|
148
|
+
# an empty symbol table).
|
149
|
+
class RestartTypeInferenceError < RuntimeError
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
attr_reader :classes
|
154
|
+
|
155
|
+
def initialize
|
156
|
+
# Ikra type -> ClassDefNode
|
157
|
+
@classes = {}
|
158
|
+
@classes.default_proc = proc do |hash, key|
|
159
|
+
hash[key] = AST::ClassDefNode.new(
|
160
|
+
name: key.cls.name,
|
161
|
+
ruby_class: key.cls)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Top of stack is the method that is currently processed
|
165
|
+
@work_stack = []
|
166
|
+
|
167
|
+
# Block/method definitions that must be processed
|
168
|
+
@worklist = Set.new
|
169
|
+
end
|
170
|
+
|
171
|
+
def all_methods
|
172
|
+
return classes.values.map do |class_|
|
173
|
+
class_.instance_methods
|
174
|
+
end.flatten
|
175
|
+
end
|
176
|
+
|
177
|
+
def symbol_table
|
178
|
+
current_method_or_block.symbol_table
|
179
|
+
end
|
180
|
+
|
181
|
+
def binding
|
182
|
+
current_method_or_block.binding
|
183
|
+
end
|
184
|
+
|
185
|
+
def current_method_or_block
|
186
|
+
@work_stack.last
|
187
|
+
end
|
188
|
+
|
189
|
+
# This is used as an entry point for the visitor
|
190
|
+
def process_block(block_def_node)
|
191
|
+
Log.info("Type inference: proceed into block(#{Types::UnionType.parameter_hash_to_s(block_def_node.parameters_names_and_types)})")
|
192
|
+
|
193
|
+
@work_stack.push(block_def_node)
|
194
|
+
body_ast = block_def_node.body
|
195
|
+
|
196
|
+
# Variables that are not defined inside the block
|
197
|
+
predefined_variables = []
|
198
|
+
|
199
|
+
# Add parameters to symbol table (name -> type)
|
200
|
+
block_def_node.parameters_names_and_types.each do |name, type|
|
201
|
+
symbol_table.declare_variable(name, type: type)
|
202
|
+
predefined_variables.push(name)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Add lexical variables to symbol table (name -> type)
|
206
|
+
block_def_node.lexical_variables_names_and_types.each do |name, type|
|
207
|
+
# Variable might be shadowed by parameter
|
208
|
+
symbol_table.ensure_variable_declared(name, type: type, kind: :lexical)
|
209
|
+
predefined_variables.push(name)
|
210
|
+
end
|
211
|
+
|
212
|
+
begin
|
213
|
+
# Infer types
|
214
|
+
body_ast.accept(self)
|
215
|
+
rescue RestartTypeInferenceError
|
216
|
+
# Reset all type information
|
217
|
+
symbol_table.clear!
|
218
|
+
block_def_node.accept(ClearTypesVisitor.new)
|
219
|
+
|
220
|
+
# Remove block from stack
|
221
|
+
@work_stack.pop
|
222
|
+
|
223
|
+
Log.info("Changed AST during type inference. Restarting type inference.")
|
224
|
+
|
225
|
+
# Restart inference
|
226
|
+
return process_block(block_def_node)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Get local variable definitons
|
230
|
+
for variable_name in symbol_table.read_and_written_variables
|
231
|
+
if !predefined_variables.include?(variable_name)
|
232
|
+
block_def_node.local_variables_names_and_types[variable_name] =
|
233
|
+
symbol_table[variable_name]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
return_value_type = symbol_table.return_type
|
238
|
+
Log.info("Type inference: block return type is #{return_value_type.to_s}")
|
239
|
+
|
240
|
+
@work_stack.pop
|
241
|
+
|
242
|
+
return_type = block_def_node.merge_union_type(return_value_type)
|
243
|
+
|
244
|
+
if block_def_node.types_changed?
|
245
|
+
# Types changed, do another pass. This is not efficient and there are better
|
246
|
+
# ways to do type inference (e.g., constraint solving), but it works for now.
|
247
|
+
block_def_node.reset_types_changed
|
248
|
+
return process_block(block_def_node)
|
249
|
+
else
|
250
|
+
return return_type
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# This is used as an entry point for the visitor
|
255
|
+
def process_method(method_def_node)
|
256
|
+
Log.info("Type inference: proceed into method #{method_def_node.receiver_type}.#{method_def_node.name}(#{Types::UnionType.parameter_hash_to_s(method_def_node.parameters_names_and_types)})")
|
257
|
+
|
258
|
+
@work_stack.push(method_def_node)
|
259
|
+
body_ast = method_def_node.body
|
260
|
+
|
261
|
+
# TODO: handle multiple receiver types
|
262
|
+
recv_type = method_def_node.receiver_type
|
263
|
+
|
264
|
+
# Variables that are not defined inside the method
|
265
|
+
predefined_variables = []
|
266
|
+
|
267
|
+
# Add parameters to symbol table (name -> type)
|
268
|
+
method_def_node.parameters_names_and_types.each do |name, type|
|
269
|
+
symbol_table.declare_variable(name, type: type)
|
270
|
+
predefined_variables.push(name)
|
271
|
+
end
|
272
|
+
|
273
|
+
# Add lexical variables to symbol table (name -> type)
|
274
|
+
method_def_node.lexical_variables_names_and_types.each do |name, type|
|
275
|
+
# Variable might be shadowed by parameter
|
276
|
+
symbol_table.ensure_variable_declared(name, type: type, kind: :lexical)
|
277
|
+
predefined_variables.push(name)
|
278
|
+
end
|
279
|
+
|
280
|
+
# Add return statements
|
281
|
+
body_ast.accept(Translator::LastStatementReturnsVisitor.new)
|
282
|
+
|
283
|
+
# Infer types
|
284
|
+
body_ast.accept(self)
|
285
|
+
|
286
|
+
# Get local variable definitons
|
287
|
+
for variable_name in symbol_table.read_and_written_variables
|
288
|
+
if !predefined_variables.include?(variable_name)
|
289
|
+
method_def_node.local_variables_names_and_types[variable_name] =
|
290
|
+
symbol_table[variable_name]
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
return_value_type = symbol_table.return_type
|
295
|
+
Log.info("Type inference: method return type is #{return_value_type.to_s}")
|
296
|
+
|
297
|
+
@work_stack.pop
|
298
|
+
|
299
|
+
return_type = method_def_node.merge_union_type(return_value_type)
|
300
|
+
|
301
|
+
if method_def_node.types_changed?
|
302
|
+
# Types changed, do another pass. This is not efficient and there are better
|
303
|
+
# ways to do type inference (e.g., constraint solving), but it works for now.
|
304
|
+
method_def_node.reset_types_changed
|
305
|
+
return process_method(method_def_node)
|
306
|
+
else
|
307
|
+
return return_type
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# This is not an actual Visitor method. It is called from visit_send_node.
|
312
|
+
def visit_method_call(send_node, recv_singleton_type)
|
313
|
+
selector = send_node.selector
|
314
|
+
|
315
|
+
if recv_singleton_type.is_primitive?
|
316
|
+
raise NotImplementedError.new("#{recv_singleton_type}.#{selector} not implemented (#{send_node.to_s})")
|
317
|
+
end
|
318
|
+
|
319
|
+
parameter_names = recv_singleton_type.method_parameters(selector)
|
320
|
+
arg_types = send_node.arguments.map do |arg| arg.get_type end
|
321
|
+
ast = recv_singleton_type.method_ast(selector)
|
322
|
+
method_visited_before = nil
|
323
|
+
|
324
|
+
if not @classes[recv_singleton_type].has_instance_method?(selector)
|
325
|
+
# This method was never visited before
|
326
|
+
method_def_node = AST::MethDefNode.new_with_types(
|
327
|
+
name: selector,
|
328
|
+
body: ast,
|
329
|
+
parameters_names_and_types: Hash[*parameter_names.zip(
|
330
|
+
Array.new(arg_types.size) do |arg_index|
|
331
|
+
Types::UnionType.new
|
332
|
+
end).flatten],
|
333
|
+
ruby_method: nil,
|
334
|
+
receiver_type: recv_singleton_type,
|
335
|
+
method_binding: recv_singleton_type.method_binding(selector))
|
336
|
+
@classes[recv_singleton_type].add_instance_method(method_def_node)
|
337
|
+
method_visited_before = false
|
338
|
+
else
|
339
|
+
method_visited_before = true
|
340
|
+
end
|
341
|
+
|
342
|
+
method_def_node = @classes[recv_singleton_type].instance_method(selector)
|
343
|
+
|
344
|
+
parameter_types_expanded = parameter_names.map.with_index do |name, index|
|
345
|
+
# returns true if expanded
|
346
|
+
method_def_node.parameters_names_and_types[name].expand(arg_types[index])
|
347
|
+
end.reduce(:|)
|
348
|
+
|
349
|
+
# Method needs processing if any parameter is expanded (or method was never visited before)
|
350
|
+
needs_processing = !method_visited_before or parameter_types_expanded
|
351
|
+
|
352
|
+
# Return value type from the last pass
|
353
|
+
# TODO: Have to make a copy here?
|
354
|
+
last_return_type = method_def_node.get_type
|
355
|
+
|
356
|
+
if needs_processing
|
357
|
+
process_method(method_def_node)
|
358
|
+
end
|
359
|
+
|
360
|
+
if not last_return_type.include_all?(method_def_node.get_type)
|
361
|
+
# Return type was expanded during this pass, reprocess all callers (except for current method)
|
362
|
+
@worklist += (method_def_node.callers - [current_method_or_block])
|
363
|
+
end
|
364
|
+
|
365
|
+
method_def_node.callers.push(current_method_or_block)
|
366
|
+
|
367
|
+
return method_def_node.get_type
|
368
|
+
end
|
369
|
+
|
370
|
+
def assert_singleton_type(union_type, expected_type)
|
371
|
+
if union_type.singleton_type != expected_type
|
372
|
+
raise AssertionError.new(
|
373
|
+
"Expected type #{expected_type} but found #{union_type.singleton_type}")
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def visit_const_node(node)
|
378
|
+
if not binding
|
379
|
+
raise AssertionError.new("Unable to resolve constants without Binding")
|
380
|
+
end
|
381
|
+
|
382
|
+
constant = binding.eval(node.identifier.to_s)
|
383
|
+
node.merge_union_type(constant.ikra_type.to_union_type)
|
384
|
+
end
|
385
|
+
|
386
|
+
def visit_root_node(node)
|
387
|
+
node.merge_union_type(node.single_child.accept(self))
|
388
|
+
end
|
389
|
+
|
390
|
+
def visit_lvar_read_node(node)
|
391
|
+
symbol_table.read!(node.identifier)
|
392
|
+
|
393
|
+
# Extend type of variable
|
394
|
+
return node.merge_union_type(symbol_table[node.identifier])
|
395
|
+
end
|
396
|
+
|
397
|
+
def visit_lvar_write_node(node)
|
398
|
+
type = node.value.accept(self)
|
399
|
+
|
400
|
+
# Declare/extend type in symbol table
|
401
|
+
symbol_table.ensure_variable_declared(node.identifier, type: type)
|
402
|
+
symbol_table.written!(node.identifier)
|
403
|
+
|
404
|
+
node.variable_type = symbol_table[node.identifier]
|
405
|
+
|
406
|
+
# Extend type of variable
|
407
|
+
# Note: Return value of this expression != type of the variable
|
408
|
+
node.merge_union_type(type)
|
409
|
+
end
|
410
|
+
|
411
|
+
def visit_ivar_read_node(node)
|
412
|
+
cls_type = node.enclosing_class.ruby_class.to_ikra_type
|
413
|
+
cls_type.inst_var_read!(node.identifier)
|
414
|
+
cls_type.inst_vars_types[node.identifier]
|
415
|
+
end
|
416
|
+
|
417
|
+
def visit_int_node(node)
|
418
|
+
node.merge_union_type(Types::UnionType.create_int)
|
419
|
+
end
|
420
|
+
|
421
|
+
def visit_nil_node(node)
|
422
|
+
node.merge_union_type(Types::UnionType.create_nil)
|
423
|
+
end
|
424
|
+
|
425
|
+
def visit_float_node(node)
|
426
|
+
node.merge_union_type(Types::UnionType.create_float)
|
427
|
+
end
|
428
|
+
|
429
|
+
def visit_bool_node(node)
|
430
|
+
node.merge_union_type(Types::UnionType.create_bool)
|
431
|
+
end
|
432
|
+
|
433
|
+
def visit_string_node(node)
|
434
|
+
# Use [Types::ClassType] for the moment
|
435
|
+
return node.value.ikra_type.to_union_type
|
436
|
+
end
|
437
|
+
|
438
|
+
def visit_symbol_node(node)
|
439
|
+
# Use [Types::ClassType] for the moment
|
440
|
+
return node.value.ikra_type.to_union_type
|
441
|
+
end
|
442
|
+
|
443
|
+
def visit_hash_node(node)
|
444
|
+
# Use [Types::ClassType] for the moment
|
445
|
+
return Hash.to_ikra_type.to_union_type
|
446
|
+
end
|
447
|
+
|
448
|
+
def visit_for_node(node)
|
449
|
+
assert_singleton_type(node.range_from.accept(self), Types::PrimitiveType::Int)
|
450
|
+
assert_singleton_type(node.range_to.accept(self), Types::PrimitiveType::Int)
|
451
|
+
|
452
|
+
changed = symbol_table.ensure_variable_declared(node.iterator_identifier, type: Types::UnionType.create_int)
|
453
|
+
symbol_table.written!(node.iterator_identifier)
|
454
|
+
|
455
|
+
super(node)
|
456
|
+
|
457
|
+
# TODO: Should return range
|
458
|
+
|
459
|
+
node.merge_union_type(Types::UnionType.create_int)
|
460
|
+
end
|
461
|
+
|
462
|
+
def visit_break_node(node)
|
463
|
+
Types::UnionType.create_void
|
464
|
+
end
|
465
|
+
|
466
|
+
def visit_if_node(node)
|
467
|
+
assert_singleton_type(node.condition.accept(self), Types::PrimitiveType::Bool)
|
468
|
+
|
469
|
+
type = Types::UnionType.new
|
470
|
+
type.expand(node.true_body_stmts.accept(self)) # Begin always has type of last stmt
|
471
|
+
|
472
|
+
if node.false_body_stmts == nil
|
473
|
+
type.expand(Types::UnionType.create_void)
|
474
|
+
else
|
475
|
+
type.expand(node.false_body_stmts.accept(self))
|
476
|
+
end
|
477
|
+
|
478
|
+
node.merge_union_type(type)
|
479
|
+
end
|
480
|
+
|
481
|
+
def visit_ternary_node(node)
|
482
|
+
assert_singleton_type(node.condition.accept(self), Types::PrimitiveType::Bool)
|
483
|
+
|
484
|
+
type = Types::UnionType.new
|
485
|
+
type.expand(node.true_val.accept(self))
|
486
|
+
type.expand(node.false_val.accept(self))
|
487
|
+
|
488
|
+
node.merge_union_type(type)
|
489
|
+
end
|
490
|
+
|
491
|
+
def visit_begin_node(node)
|
492
|
+
node.body_stmts[0...-1].each do |stmt|
|
493
|
+
stmt.accept(self)
|
494
|
+
end
|
495
|
+
|
496
|
+
if node.body_stmts.empty?
|
497
|
+
type = Types::UnionType.new
|
498
|
+
else
|
499
|
+
type = node.body_stmts.last.accept(self)
|
500
|
+
end
|
501
|
+
|
502
|
+
node.merge_union_type(type)
|
503
|
+
end
|
504
|
+
|
505
|
+
def visit_return_node(node)
|
506
|
+
type = node.value.accept(self)
|
507
|
+
symbol_table.expand_return_type(type)
|
508
|
+
node.merge_union_type(type)
|
509
|
+
end
|
510
|
+
|
511
|
+
def visit_source_code_expr_node(node)
|
512
|
+
# This is a synthetic node. No type inference. Return the type that was set
|
513
|
+
# manually before (if any).
|
514
|
+
return node.get_type
|
515
|
+
end
|
516
|
+
|
517
|
+
def visit_send_node_singleton_receiver(sing_type, node)
|
518
|
+
if RubyIntegration.is_interpreter_only?(sing_type)
|
519
|
+
return Types::InterpreterOnlyType.new.to_union_type
|
520
|
+
elsif RubyIntegration.has_implementation?(sing_type, node.selector)
|
521
|
+
arg_types = node.arguments.map do |arg| arg.get_type end
|
522
|
+
|
523
|
+
begin
|
524
|
+
return_type = RubyIntegration.get_return_type(
|
525
|
+
sing_type, node.selector, *arg_types, send_node: node)
|
526
|
+
return return_type
|
527
|
+
rescue RubyIntegration::CycleDetectedError => cycle_error
|
528
|
+
# Cannot do further symbolic execution, i.e., kernel fusion here,
|
529
|
+
# because we are in a loop.
|
530
|
+
|
531
|
+
# Invoke parallel section: change to `RECV` to `RECV.__call__.to_command`
|
532
|
+
node.replace_child(
|
533
|
+
node.receiver,
|
534
|
+
AST::SendNode.new(
|
535
|
+
receiver: AST::SendNode.new(
|
536
|
+
receiver: node.receiver, selector: :__call__),
|
537
|
+
selector: :to_command))
|
538
|
+
|
539
|
+
# Start fresh
|
540
|
+
raise RestartTypeInferenceError.new
|
541
|
+
end
|
542
|
+
elsif sing_type.is_a?(Types::StructType)
|
543
|
+
# This is a struct type, special type inference rules apply
|
544
|
+
return sing_type.get_return_type(node.selector, *node.arguments)
|
545
|
+
else
|
546
|
+
Log.info("Translate call to ordinary Ruby method #{sing_type}.#{node.selector}")
|
547
|
+
return visit_method_call(node, sing_type)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
def visit_send_node_union_type(receiver_type, node)
|
552
|
+
type = Types::UnionType.new
|
553
|
+
|
554
|
+
for sing_type in receiver_type
|
555
|
+
return_type = visit_send_node_singleton_receiver(sing_type, node)
|
556
|
+
node.return_type_by_recv_type[sing_type] = return_type
|
557
|
+
type.expand(return_type)
|
558
|
+
end
|
559
|
+
|
560
|
+
node.merge_union_type(type)
|
561
|
+
|
562
|
+
return type
|
563
|
+
end
|
564
|
+
|
565
|
+
def visit_send_node(node)
|
566
|
+
# TODO: handle self sends
|
567
|
+
receiver_type = nil
|
568
|
+
|
569
|
+
if node.receiver == nil
|
570
|
+
Logger.warn("No receiver given for node #{node.to_s}")
|
571
|
+
receiver_type = Types::UnionType.create_int
|
572
|
+
else
|
573
|
+
receiver_type = node.receiver.accept(self)
|
574
|
+
end
|
575
|
+
|
576
|
+
node.arguments.each do |arg|
|
577
|
+
arg.accept(self)
|
578
|
+
end
|
579
|
+
|
580
|
+
visit_send_node_union_type(receiver_type, node)
|
581
|
+
|
582
|
+
return node.get_type
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|