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
@@ -1,24 +0,0 @@
1
- module Ikra
2
- module AST
3
- class MethodDefinition
4
- def to_c_source
5
- # TODO: merge with BlockTranslator
6
-
7
- method_params = (["environment_t * #{Translator::Constants::ENV_IDENTIFIER}", "#{type.to_c_type} #{Constants::SELF_IDENTIFIER}"] + parameter_variables.map do |name, type|
8
- "#{name} #{type.singleton_type.to_c_type}"
9
- end).join(", ")
10
-
11
- # TODO: load environment variables
12
-
13
- # Declare local variables
14
- local_variables_def = ""
15
- local_variables.each do |name, types|
16
- local_variables_def += "#{types.singleton_type.to_c_type} #{name};\n"
17
- end
18
-
19
- signature = "__device__ #{return_type.singleton_type.to_c_type} #{type.mangled_method_name(selector)}(#{method_params})"
20
- signature + "\n" + Translator.wrap_in_c_block(local_variables_def + ast.translate_statement)
21
- end
22
- end
23
- end
24
- end
@@ -1,51 +0,0 @@
1
- require_relative "ruby_type"
2
-
3
- module Ikra
4
- module Types
5
- class ArrayType
6
- include RubyType
7
-
8
- class << self
9
- # Ensure singleton per class
10
- def new(inner_type)
11
- if @cache == nil
12
- @cache = {}
13
- @cache.default_proc = Proc.new do |hash, key|
14
- hash[key] = super(key)
15
- end
16
- end
17
-
18
- @cache[inner_type]
19
- end
20
- end
21
-
22
- def initialize(inner_type)
23
- if not inner_type.is_union_type?
24
- raise "Union type expected"
25
- end
26
-
27
- @inner_type = inner_type
28
- end
29
-
30
- def to_c_type
31
- "#{@inner_type.to_c_type} *"
32
- end
33
-
34
- def to_ffi_type
35
- :pointer
36
- end
37
- end
38
- end
39
- end
40
-
41
- class Array
42
- def self.to_ikra_type_obj(object)
43
- inner_type = Ikra::Types::UnionType.new
44
-
45
- object.each do |element|
46
- inner_type.expand_with_singleton_type(element.class.to_ikra_type)
47
- end
48
-
49
- Ikra::Types::ArrayType.new(inner_type)
50
- end
51
- end
@@ -1,67 +0,0 @@
1
- require "set"
2
- require_relative "primitive_type"
3
- require_relative "union_type"
4
-
5
- class Fixnum
6
- class << self
7
- def to_ikra_type
8
- Ikra::Types::PrimitiveType::Int
9
- end
10
-
11
- def _ikra_t_to_f(receiver_type)
12
- Ikra::Types::UnionType.create_float
13
- end
14
-
15
- def _ikra_c_to_f(receiver)
16
- "(float) #{receiver}"
17
- end
18
-
19
- def _ikra_t_to_i(receiver_type)
20
- Ikra::Types::UnionType.create_int
21
- end
22
-
23
- def _ikra_c_to_i(receiver)
24
- "#{receiver}"
25
- end
26
- end
27
- end
28
-
29
- class Float
30
- class << self
31
- def to_ikra_type
32
- Ikra::Types::PrimitiveType::Float
33
- end
34
-
35
- def _ikra_t_to_f(receiver_type)
36
- Ikra::Types::UnionType.create_float
37
- end
38
-
39
- def _ikra_c_to_f(receiver)
40
- "#{receiver}"
41
- end
42
-
43
- def _ikra_t_to_i(receiver_type)
44
- Ikra::Types::UnionType.create_int
45
- end
46
-
47
- def _ikra_c_to_i(receiver)
48
- "(int) #{receiver}"
49
- end
50
- end
51
- end
52
-
53
- class TrueClass
54
- class << self
55
- def to_ikra_type
56
- Ikra::Types::PrimitiveType::Bool
57
- end
58
- end
59
- end
60
-
61
- class FalseClass
62
- class << self
63
- def to_ikra_type
64
- Ikra::Types::PrimitiveType::Bool
65
- end
66
- end
67
- end
@@ -1,45 +0,0 @@
1
-
2
- require "set"
3
-
4
- module Ikra
5
- module Types
6
-
7
- # Defines the minimal interface for Ikra types. Instances of {UnionType} are expected in most cases.
8
- module RubyType
9
- @@next_class_id = 0
10
-
11
- def to_ruby_type
12
- raise NotImplementedError
13
- end
14
-
15
- def to_c_type
16
- raise NotImplementedError
17
- end
18
-
19
- def is_primitive?
20
- false
21
- end
22
-
23
- def is_union_type?
24
- false
25
- end
26
-
27
- def class_id
28
- if @class_id == nil
29
- @class_id = @@next_class_id
30
- @@next_class_id += 1
31
- end
32
-
33
- @class_id
34
- end
35
- end
36
- end
37
- end
38
-
39
- class Array
40
- def to_type_array_string
41
- "[" + map do |set|
42
- set.to_s
43
- end.join(", ") + "]"
44
- end
45
- end
@@ -1,382 +0,0 @@
1
- require "set"
2
- require_relative "primitive_type"
3
- require_relative "union_type"
4
- require_relative "ruby_extension"
5
- require_relative "../ast/nodes.rb"
6
- require_relative "../ast/visitor.rb"
7
- require_relative "../ast/method_definition"
8
- require_relative "../scope.rb"
9
-
10
- module Ikra
11
- module AST
12
- class Node
13
- def get_type
14
- @type ||= Types::UnionType.new
15
- end
16
- end
17
- end
18
-
19
- module TypeInference
20
- class Visitor < AST::Visitor
21
- attr_reader :methods
22
-
23
- def initialize
24
- # methods: Ikra type x selector --> MethodDefinition
25
- @methods = Hash.new
26
- @methods.default_proc = proc do |hash, key|
27
- hash[key] = Hash.new
28
- end
29
-
30
- # Top of stack is the method that is currently processed
31
- @method_stack = []
32
-
33
- # Method definitions that must be processed
34
- @worklist = Set.new
35
- end
36
-
37
- def symbol_table
38
- current_method.symbol_table
39
- end
40
-
41
- def binding
42
- current_method.binding
43
- end
44
-
45
- def current_method
46
- @method_stack.last
47
- end
48
-
49
- # This is used as an entry point for the visitor
50
- def process_method(method_definition)
51
- Log.info("Type inference: proceed into method #{method_definition.type}.#{method_definition.selector}(#{Types::UnionType.parameter_hash_to_s(method_definition.parameter_variables)})")
52
-
53
- @method_stack.push(method_definition)
54
- ast = method_definition.ast
55
- # TODO: handle multiple types
56
- recv_type = method_definition.type
57
-
58
- # Set up new symbol table (pushing a frame is not sufficient here)
59
- return_value_type = nil
60
- symbol_table.new_frame do # lexical variables, parameters defined on this level
61
- # Add parameters to symbol table (name -> type)
62
- method_definition.parameter_variables.each do |name, type|
63
- symbol_table.declare_expand_type(name, type)
64
- end
65
- # Add lexical variables to symbol table (name -> type)
66
- method_definition.lexical_variables.each do |name, type|
67
- symbol_table.declare_expand_type(name, type)
68
- end
69
-
70
- symbol_table.new_function_frame do # local variables defined on this level
71
- # Add return statements
72
- ast.accept(Translator::LastStatementReturnsVisitor.new)
73
-
74
- # Infer types
75
- ast.accept(self)
76
- return_value_type = symbol_table.top_frame.return_type
77
-
78
- # Get local variable definitons
79
- local_variables_enumerator = Translator::LocalVariablesEnumerator.new
80
- ast.accept(local_variables_enumerator)
81
- method_definition.local_variables = local_variables_enumerator.local_variables.reject do |name, type|
82
- symbol_table.previous_frame.variable_names.include?(name) # no lexical vars or parameters
83
- end
84
- end
85
-
86
- # Determine read/written lexical variables
87
- (symbol_table.read_and_written_variables(-1) - method_definition.parameter_variables.keys).each do |var|
88
- method_definition.accessed_lexical_variables[var] = symbol_table.get_type(var)
89
- end
90
- end
91
-
92
- Log.info("Type inference: method return type is #{return_value_type.to_s}")
93
-
94
- @method_stack.pop
95
-
96
- method_definition.return_type = return_value_type
97
- return_value_type
98
- end
99
-
100
- def visit_method_call(send_node)
101
- recv_type = send_node.receiver.get_type
102
- selector = send_node.selector
103
- return_type = Types::UnionType.new
104
-
105
- recv_type.types.each do |recv_singleton_type|
106
- parameter_names = recv_singleton_type.method_parameters(selector)
107
- arg_types = send_node.arguments.map do |arg| arg.get_type end
108
- ast = recv_singleton_type.method_ast(selector)
109
- method_visited_before = nil
110
-
111
- if not @methods[recv_singleton_type].include?(selector)
112
- # This method was never visited before
113
- parameter_variables =
114
- @methods[recv_singleton_type][selector] = AST::MethodDefinition.new(
115
- type: recv_singleton_type,
116
- selector: selector,
117
- parameter_variables: Hash[*parameter_names.zip(
118
- Array.new(arg_types.size) do
119
- Types::UnionType.new
120
- end).flatten],
121
- return_type: Types::UnionType.new,
122
- ast: ast)
123
- method_visited_before = false
124
- else
125
- method_visited_before = true
126
- end
127
-
128
- method_def = @methods[recv_singleton_type][selector]
129
- # Method needs processing if any parameter is expanded (or method was never visited before)
130
- needs_processing = !method_visited_before or parameter_names.map.with_index do |name, index|
131
- method_def.parameter_variables[name].expand(arg_types[index]) # returns true if expanded
132
- end.reduce(:|)
133
-
134
- last_return_type = method_def.return_type # return value type from the last pass
135
-
136
- if needs_processing
137
- process_method(method_def)
138
- end
139
-
140
- if not last_return_type.include_all?(method_def.return_type)
141
- # Return type was expanded during this pass, reprocess all callers (except for current method)
142
- @worklist += (method_def.callers - [current_method])
143
- end
144
-
145
- method_def.callers.add(current_method)
146
-
147
- # Return value of all visit methods should be the type
148
- return_type.expand(method_def.return_type)
149
- end
150
-
151
- send_node.get_type.expand(return_type)
152
- return_type
153
- end
154
-
155
- def assert_singleton_type(union_type, expected_type)
156
- if union_type.singleton_type != expected_type
157
- raise "Expected type #{expected_type} but found #{union_type.singleton_type}"
158
- end
159
- end
160
-
161
- def visit_root_node(node)
162
- node.get_type.expand_return_type(node.child.accept(self))
163
- end
164
-
165
- def visit_const_node(node)
166
- if not @binding
167
- raise "Unable to resolve constants without Binding"
168
- end
169
-
170
- node.get_type.expand_return_type(
171
- Types::UnionType.new([@binding.eval(node.identifier.to_s).class.to_ikra_type]))
172
- end
173
-
174
- def visit_lvar_read_node(node)
175
- symbol_table.read!(node.identifier)
176
- node.get_type.expand_return_type(symbol_table.get_type(node.identifier))
177
- end
178
-
179
- def visit_lvar_write_node(node)
180
- type = node.value.accept(self)
181
- symbol_table.declare_expand_type(node.identifier, type)
182
- symbol_table.written!(node.identifier)
183
- node.get_type.expand_return_type(type)
184
- end
185
-
186
- def visit_ivar_read_node(node)
187
- cls_type = node.class_owner.to_ikra_type
188
- cls_type.inst_var_read!(node.identifier)
189
- cls_type.inst_vars_types[node.identifier]
190
- end
191
-
192
- def visit_int_node(node)
193
- node.get_type.expand_return_type(Types::UnionType.create_int)
194
- end
195
-
196
- def visit_float_node(node)
197
- node.get_type.expand_return_type(Types::UnionType.create_float)
198
- end
199
-
200
- def visit_bool_node(node)
201
- node.get_type.expand_return_type(Types::UnionType.create_bool)
202
- end
203
-
204
- def visit_for_node(node)
205
- assert_singleton_type(node.range_from.accept(self), Types::PrimitiveType::Int)
206
- assert_singleton_type(node.range_to.accept(self), Types::PrimitiveType::Int)
207
-
208
- changed = symbol_table.declare_expand_type(node.iterator_identifier, Types::UnionType.create_int)
209
-
210
- super(node)
211
-
212
- # TODO: Should return range
213
-
214
- node.get_type.expand_return_type(Types::UnionType.create_int)
215
- end
216
-
217
- def visit_break_node(node)
218
- Types::UnionType.create_void
219
- end
220
-
221
- def visit_if_node(node)
222
- assert_singleton_type(node.condition.accept(self), Types::PrimitiveType::Bool)
223
-
224
- type = Types::UnionType.new
225
- type.expand(node.true_body_stmts.accept(self)) # Begin always has type of last stmt
226
-
227
- if node.false_body_stmts == nil
228
- type.expand(Types::UnionType.create_void)
229
- else
230
- type.expand(node.false_body_stmts.accept(self))
231
- end
232
-
233
- node.get_type.expand_return_type(type)
234
- end
235
-
236
- def visit_begin_node(node)
237
- node.body_stmts[0...-1].each do |stmt|
238
- stmt.accept(self)
239
- end
240
-
241
- # TODO: need to handle empty BeginNode?
242
- type = node.body_stmts.last.accept(self)
243
- node.get_type.expand_return_type(type)
244
- end
245
-
246
- def visit_return_node(node)
247
- type = node.value.accept(self)
248
- symbol_table.add_return_type(type)
249
- node.get_type.expand_return_type(type)
250
- end
251
-
252
-
253
- ArithOperators = [:+, :-, :*, :/, :%]
254
- CompareOperators = [:<, :<=, :>, :>=]
255
- EqualityOperators = [:==, :!=]
256
- LogicOperators = [:&, :'&&', :|, :'||', :^]
257
- PrimitiveOperators = ArithOperators + CompareOperators + EqualityOperators + LogicOperators
258
-
259
- def visit_send_node(node)
260
- # TODO: handle self sends
261
- receiver_type = nil
262
-
263
- if node.receiver == nil
264
- receiver_type = Types::UnionType.create_int
265
- else
266
- receiver_type = node.receiver.accept(self)
267
- end
268
- type = Types::UnionType.new
269
-
270
- if PrimitiveOperators.include?(node.selector)
271
- if node.arguments.size != 1
272
- raise "Expected 1 argument for binary selector (#{node.arguments.size} given)"
273
- end
274
-
275
- # Process every combination of recv_type x operand_type
276
- operand_type = node.arguments.first.accept(self)
277
- for recv_type in receiver_type.types
278
- for op_type in operand_type.types
279
- type.expand(primitive_operator_type(node.selector, recv_type, op_type))
280
- end
281
- end
282
- else
283
- for recv_type in receiver_type.types
284
- if recv_type.to_ruby_type.singleton_methods.include?(("_ikra_t_" + node.selector.to_s).to_sym)
285
- # TODO: pass arguments
286
- type.expand(recv_type.to_ruby_type.send(("_ikra_t_" + node.selector.to_s).to_sym, receiver_type))
287
- else
288
- node.arguments.each do |arg|
289
- arg.accept(self)
290
- end
291
-
292
- type.expand(visit_method_call(node))
293
- end
294
- end
295
- end
296
-
297
- node.get_type.expand_return_type(type)
298
- end
299
-
300
- def primitive_operator_type(selector, receiver_type, operand_type)
301
- # receiver_type and operand_type are singleton types, return value is union type
302
-
303
- arg_types = [receiver_type, operand_type]
304
-
305
- if ArithOperators.include?(selector)
306
- type_mapping = {[Types::PrimitiveType::Int, Types::PrimitiveType::Int] => Types::UnionType.create_int,
307
- [Types::PrimitiveType::Int, Types::PrimitiveType::Float] => Types::UnionType.create_float,
308
- [Types::PrimitiveType::Float, Types::PrimitiveType::Float] => Types::UnionType.create_float}
309
-
310
- if type_mapping.has_key?(arg_types)
311
- return type_mapping[arg_types]
312
- elsif type_mapping.has_key?(arg_types.reverse)
313
- return type_mapping[arg_types.reverse]
314
- else
315
- raise "Types #{receiver_type} and #{operand_type} not applicable for primitive operator #{selector.to_s}"
316
- end
317
- elsif CompareOperators.include?(selector)
318
- type_mapping = {[Types::PrimitiveType::Int, Types::PrimitiveType::Int] => Types::UnionType.create_bool,
319
- [Types::PrimitiveType::Int, Types::PrimitiveType::Float] => Types::UnionType.create_bool,
320
- [Types::PrimitiveType::Float, Types::PrimitiveType::Float] => Types::UnionType.create_bool}
321
-
322
- if type_mapping.has_key?(arg_types)
323
- return type_mapping[arg_types]
324
- elsif type_mapping.has_key?(arg_types.reverse)
325
- return type_mapping[arg_types.reverse]
326
- else
327
- raise "Types #{receiver_type} and #{operand_type} not applicable for primitive operator #{selector.to_s}"
328
- end
329
- elsif EqualityOperators.include?(selector)
330
- type_mapping = {[Types::PrimitiveType::Bool, Types::PrimitiveType::Bool] => Types::UnionType.create_bool,
331
- [Types::PrimitiveType::Int, Types::PrimitiveType::Int] => Types::UnionType.create_bool,
332
- [Types::PrimitiveType::Int, Types::PrimitiveType::Float] => Types::UnionType.create_bool,
333
- [Types::PrimitiveType::Float, Types::PrimitiveType::Float] => Types::UnionType.create_bool}
334
-
335
- if type_mapping.has_key?(arg_types)
336
- return type_mapping[arg_types]
337
- elsif type_mapping.has_key?(arg_types.reverse)
338
- return type_mapping[arg_types.reverse]
339
- elsif not arg_types.include?(Types::PrimitiveType::Void) and receiver.type.is_primitive? and operand.type.is_primitive?
340
- # TODO: this should also return a translation result: selector == :== ? "false" : "true"
341
- return Types::UnionType.create_bool
342
- else
343
- raise "Types #{receiver_type} and #{operand_type} not applicable for primitive operator #{selector.to_s}"
344
- end
345
- elsif LogicOperators.include?(selector)
346
- # TODO: need proper implementation
347
- int_float = [Types::PrimitiveType::Int, Types::PrimitiveType::Float].to_set
348
- if selector == :'&&'
349
- if (int_float + arg_types).size == 2
350
- # Both are int/float
351
- # TODO: this should return the operand
352
- return Types::UnionType.new(operand_type)
353
- elsif operand_type == PrimitiveType::Bool and receiver_type == Types::PrimitiveType::Bool
354
- return Types::UnionType.create_bool
355
- else
356
- raise "Cannot handle types #{receiver_type} and #{operand_type} for primitive operator #{selector.to_s}"
357
- end
358
- elsif selector == :'||'
359
- if (int_float + arg_types).size == 2
360
- # Both are int/float
361
- # TODO: this should return the receiver
362
- return Types::UnionType.new(receiver_type)
363
- elsif operand_type == Types::PrimitiveType::Bool and receiver_type == Types::PrimitiveType::Bool
364
- return Types::UnionType.create_bool
365
- else
366
- raise "Cannot handle types #{receiver_type} and #{operand_type} for primitive operator #{selector.to_s}"
367
- end
368
- elsif selector == :& or selector == :| or selector == :^
369
- type_mapping = {[Types::PrimitiveType::Bool, Types::PrimitiveType::Bool] => Types::UnionType.create_bool,
370
- [Types::PrimitiveType::Int, Types::PrimitiveType::Int] => Types::UnionType.create_int}
371
-
372
- if type_mapping.has_key?(arg_types)
373
- return type_mapping[arg_types]
374
- else
375
- raise "Types #{receiver_type} and #{operand_type} not applicable for primitive operator #{selector.to_s}"
376
- end
377
- end
378
- end
379
- end
380
- end
381
- end
382
- end