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
@@ -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
|
data/lib/types/array_type.rb
DELETED
@@ -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
|
data/lib/types/ruby_extension.rb
DELETED
@@ -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
|
data/lib/types/ruby_type.rb
DELETED
@@ -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
|
data/lib/types/type_inference.rb
DELETED
@@ -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
|