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,273 @@
|
|
1
|
+
require "ffi"
|
2
|
+
|
3
|
+
module Ikra
|
4
|
+
module Translator
|
5
|
+
class CommandTranslator
|
6
|
+
class ProgramBuilder
|
7
|
+
class Launcher
|
8
|
+
class CommandNotifier < Symbolic::Visitor
|
9
|
+
# This visitor executes the post_execute function on every Array Command
|
10
|
+
# That way the responsible command node will recieve the adress of the computed result that will be kept on GPU
|
11
|
+
|
12
|
+
attr_reader :environment
|
13
|
+
|
14
|
+
def initialize(environment)
|
15
|
+
@environment = environment
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_array_command(command)
|
19
|
+
super(command)
|
20
|
+
command.post_execute(environment)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class FixedSizeArrayStruct < FFI::Struct
|
25
|
+
layout :content, :pointer,
|
26
|
+
:size, :int32
|
27
|
+
end
|
28
|
+
|
29
|
+
class UnionTypeValue < FFI::Union
|
30
|
+
# There are some values missing here, but we don't need them at the moment
|
31
|
+
layout :int_, :int32,
|
32
|
+
:variable_size_array, FixedSizeArrayStruct
|
33
|
+
end
|
34
|
+
|
35
|
+
class UnionTypeStruct < FFI::Struct
|
36
|
+
layout :class_id, :int32,
|
37
|
+
:value, UnionTypeValue
|
38
|
+
end
|
39
|
+
|
40
|
+
class KernelUnionResultStruct < FFI::Struct
|
41
|
+
layout :result, UnionTypeStruct,
|
42
|
+
:error_code, :int32,
|
43
|
+
:time_setup_cuda, :uint64,
|
44
|
+
:time_prepare_env, :uint64,
|
45
|
+
:time_kernel, :uint64,
|
46
|
+
:time_free_memory, :uint64,
|
47
|
+
:time_transfer_memory, :uint64,
|
48
|
+
:time_allocate_memory, :uint64
|
49
|
+
end
|
50
|
+
|
51
|
+
class KernelResultStruct < FFI::Struct
|
52
|
+
layout :result, FixedSizeArrayStruct,
|
53
|
+
:error_code, :int32,
|
54
|
+
:time_setup_cuda, :uint64,
|
55
|
+
:time_prepare_env, :uint64,
|
56
|
+
:time_kernel, :uint64,
|
57
|
+
:time_free_memory, :uint64,
|
58
|
+
:time_transfer_memory, :uint64,
|
59
|
+
:time_allocate_memory, :uint64
|
60
|
+
end
|
61
|
+
|
62
|
+
attr_reader :root_command
|
63
|
+
attr_reader :source
|
64
|
+
attr_reader :environment_builder
|
65
|
+
attr_reader :result_type
|
66
|
+
|
67
|
+
class << self
|
68
|
+
attr_accessor :last_time_setup_cuda
|
69
|
+
attr_accessor :last_time_prepare_env
|
70
|
+
attr_accessor :last_time_kernel
|
71
|
+
attr_accessor :last_time_free_memory
|
72
|
+
attr_accessor :last_time_transfer_memory
|
73
|
+
attr_accessor :last_time_allocate_memory
|
74
|
+
attr_accessor :last_time_total_external
|
75
|
+
attr_accessor :last_time_compiler
|
76
|
+
attr_accessor :last_time_read_result_ffi
|
77
|
+
|
78
|
+
def reset_time
|
79
|
+
@last_time_setup_cuda = 0
|
80
|
+
@last_time_prepare_env = 0
|
81
|
+
@last_time_kernel = 0
|
82
|
+
@last_time_free_memory = 0
|
83
|
+
@last_time_transfer_memory = 0
|
84
|
+
@last_time_allocate_memory = 0
|
85
|
+
@last_time_total_external = 0
|
86
|
+
@last_time_compiler = 0
|
87
|
+
@last_time_read_result_ffi = 0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def initialize(source:, environment_builder:, result_type:, root_command:)
|
92
|
+
@source = source
|
93
|
+
@environment_builder = environment_builder
|
94
|
+
@result_type = result_type
|
95
|
+
@root_command = root_command
|
96
|
+
end
|
97
|
+
|
98
|
+
def compile
|
99
|
+
# Generate debug output with line numbers
|
100
|
+
line_no_digits = Math.log(source.lines.count, 10).ceil
|
101
|
+
source_with_line_numbers = source.lines.each_with_index.map do |line, num|
|
102
|
+
"[#{(num + 1).to_s.rjust(line_no_digits, "0")}] #{line}"
|
103
|
+
end.join("")
|
104
|
+
|
105
|
+
Log.info("Generated source code:\n#{source_with_line_numbers}")
|
106
|
+
|
107
|
+
# Write source code to temporary file
|
108
|
+
file = Tempfile.new(["ikra_kernel", ".cu"])
|
109
|
+
file.write(source)
|
110
|
+
file.close
|
111
|
+
|
112
|
+
# Write to codegen_expect
|
113
|
+
if Configuration.codegen_expect_file_name != nil
|
114
|
+
expect_file = File.new(Configuration.codegen_expect_file_name, "w+")
|
115
|
+
expect_file.write(source)
|
116
|
+
expect_file.close
|
117
|
+
end
|
118
|
+
|
119
|
+
# Run compiler
|
120
|
+
@so_filename = "#{file.path}.#{Configuration.so_suffix}"
|
121
|
+
nvcc_command = Configuration.nvcc_invocation_string(
|
122
|
+
file.path, @so_filename)
|
123
|
+
Log.info("Compiling kernel: #{nvcc_command}")
|
124
|
+
time_before = Time.now
|
125
|
+
compile_status = %x(#{nvcc_command})
|
126
|
+
Log.info("Done, took #{Time.now - time_before} s")
|
127
|
+
self.class.last_time_compiler = Time.now - time_before
|
128
|
+
|
129
|
+
if $? != 0
|
130
|
+
Log.fatal("nvcc failed: #{compile_status}")
|
131
|
+
raise RuntimeError.new("nvcc failed: #{compile_status}")
|
132
|
+
else
|
133
|
+
Log.info("nvcc successful: #{compile_status}")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Attaches the compiled shared library via Ruby FFI and invokes the kernel.
|
138
|
+
def execute
|
139
|
+
if !File.exist?(@so_filename)
|
140
|
+
compile
|
141
|
+
end
|
142
|
+
|
143
|
+
time_before = Time.now
|
144
|
+
ffi_interface = Module.new
|
145
|
+
ffi_interface.extend(FFI::Library)
|
146
|
+
ffi_interface.ffi_lib(@so_filename)
|
147
|
+
ffi_interface.attach_function(:launch_kernel, [:pointer], :pointer)
|
148
|
+
environment_object = environment_builder.build_ffi_object
|
149
|
+
Log.info("FFI transfer time: #{Time.now - time_before} s")
|
150
|
+
|
151
|
+
time_before = Time.now
|
152
|
+
kernel_result = ffi_interface.launch_kernel(environment_object)
|
153
|
+
total_time_external = Time.now - time_before
|
154
|
+
Log.info("Kernel time: #{total_time_external} s")
|
155
|
+
|
156
|
+
# Update command
|
157
|
+
root_command.accept(CommandNotifier.new(environment_builder.ffi_struct))
|
158
|
+
|
159
|
+
# TODO: Currently, this only works if result_type.is_singleton?
|
160
|
+
if result_type.is_singleton?
|
161
|
+
result_t_struct = KernelResultStruct.new(kernel_result)
|
162
|
+
else
|
163
|
+
result_t_struct = KernelUnionResultStruct.new(kernel_result)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Extract error code and return value
|
167
|
+
error_code = result_t_struct[:error_code]
|
168
|
+
|
169
|
+
# Extract time measurements
|
170
|
+
self.class.last_time_setup_cuda += result_t_struct[:time_setup_cuda] * 0.000001
|
171
|
+
self.class.last_time_prepare_env += result_t_struct[:time_prepare_env] * 0.000001
|
172
|
+
self.class.last_time_kernel += result_t_struct[:time_kernel] * 0.000001
|
173
|
+
self.class.last_time_free_memory += result_t_struct[:time_free_memory] * 0.000001
|
174
|
+
self.class.last_time_transfer_memory += result_t_struct[:time_transfer_memory] * 0.000001
|
175
|
+
self.class.last_time_allocate_memory += result_t_struct[:time_allocate_memory] * 0.000001
|
176
|
+
self.class.last_time_total_external += total_time_external
|
177
|
+
|
178
|
+
if error_code != 0
|
179
|
+
# Kernel failed
|
180
|
+
Errors.raiseCudaError(error_code)
|
181
|
+
end
|
182
|
+
|
183
|
+
time_before = Time.now
|
184
|
+
|
185
|
+
# Check type of result: It should be one of `result_type`
|
186
|
+
if result_type.is_singleton?
|
187
|
+
array_type = result_type.singleton_type
|
188
|
+
|
189
|
+
if !array_type.is_a?(Types::ArrayType)
|
190
|
+
raise AssertionError.new(
|
191
|
+
"ArrayType expected, but #{array_type} found")
|
192
|
+
end
|
193
|
+
|
194
|
+
result = result_t_struct[:result][:content]
|
195
|
+
result_size = result_t_struct[:result][:size]
|
196
|
+
else
|
197
|
+
array_type = result_type.find do |sing_type|
|
198
|
+
sing_type.class_id == result_t_struct[:result][:class_id]
|
199
|
+
end
|
200
|
+
|
201
|
+
if array_type == nil
|
202
|
+
raise AssertionError.new(
|
203
|
+
"Unknown class_id: #{result_t_struct[:result][:class_id]}")
|
204
|
+
end
|
205
|
+
|
206
|
+
if !array_type.is_a?(Types::ArrayType)
|
207
|
+
raise AssertionError.new(
|
208
|
+
"ArrayType expected, but #{array_type} found")
|
209
|
+
end
|
210
|
+
|
211
|
+
result = result_t_struct[:result][:value][:variable_size_array][:content]
|
212
|
+
result_size = result_t_struct[:result][:value][:variable_size_array][:size]
|
213
|
+
end
|
214
|
+
|
215
|
+
inner_type = array_type.inner_type
|
216
|
+
|
217
|
+
if inner_type.is_singleton?
|
218
|
+
# Read in entire array
|
219
|
+
if inner_type.singleton_type == Types::PrimitiveType::Int
|
220
|
+
computation_result = result.read_array_of_int(result_size)
|
221
|
+
elsif inner_type.singleton_type == Types::PrimitiveType::Float
|
222
|
+
computation_result = result.read_array_of_float(result_size)
|
223
|
+
elsif inner_type.singleton_type == Types::PrimitiveType::Bool
|
224
|
+
computation_result = result.read_array_of_uint8(result_size).map do |v|
|
225
|
+
v == 1
|
226
|
+
end
|
227
|
+
elsif inner_type.singleton_type == Types::PrimitiveType::Nil
|
228
|
+
computation_result = [nil] * result_size
|
229
|
+
elsif inner_type.singleton_type.is_a?(Types::ZipStructType)
|
230
|
+
result_struct_type = inner_type.singleton_type.to_ruby_type
|
231
|
+
computation_result = Array.new(result_size) do |index|
|
232
|
+
result_struct_type.new(result + index * result_struct_type.size)
|
233
|
+
end
|
234
|
+
else
|
235
|
+
raise NotImplementedError.new("Type not implemented")
|
236
|
+
end
|
237
|
+
|
238
|
+
self.class.last_time_read_result_ffi = Time.now - time_before
|
239
|
+
return computation_result
|
240
|
+
else
|
241
|
+
# Read union type struct
|
242
|
+
# Have to read one by one and assemble object
|
243
|
+
result_values = Array.new(result_size)
|
244
|
+
|
245
|
+
for index in 0...result_size
|
246
|
+
# TODO: Size of union type (12 bytes) should not be hard-coded here
|
247
|
+
s = Constants::UNION_TYPE_SIZE
|
248
|
+
o = Constants::UNION_TYPE_VALUE_OFFSET
|
249
|
+
next_type = (result + (s * index)).read_int
|
250
|
+
|
251
|
+
if next_type == Types::PrimitiveType::Int.class_id
|
252
|
+
result_values[index] = (result + s * index + o).read_int
|
253
|
+
elsif next_type == Types::PrimitiveType::Float.class_id
|
254
|
+
result_values[index] = (result + s * index + o).read_float
|
255
|
+
elsif next_type == Types::PrimitiveType::Bool.class_id
|
256
|
+
result_values[index] = (result + s * index + o).read_uint8 == 1
|
257
|
+
elsif next_type == Types::PrimitiveType::Nil.class_id
|
258
|
+
result_values[index] = nil
|
259
|
+
else
|
260
|
+
raise NotImplementedError.new("Implement class objs for \##{index}: #{next_type}")
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
self.class.last_time_read_result_ffi = Time.now - time_before
|
265
|
+
return result_values
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Ikra
|
2
|
+
module Types
|
3
|
+
class StructType
|
4
|
+
def generate_definition
|
5
|
+
raise NotImplementedError.new("ZipStructType is the only implementation")
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class ZipStructType < StructType
|
10
|
+
# Generates a source code expression that creates and initializes an instance of
|
11
|
+
# this struct.
|
12
|
+
def generate_inline_initialization(*input)
|
13
|
+
field_init = input.join(", ")
|
14
|
+
return "((#{to_c_type}) {#{field_init}})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_definition
|
18
|
+
fields_def = @fields.map do |field_name, type|
|
19
|
+
"#{type.to_c_type} #{field_name};"
|
20
|
+
end
|
21
|
+
|
22
|
+
all_fields = fields_def.join("\n")
|
23
|
+
|
24
|
+
return Translator.read_file(file_name: "struct_definition.cpp", replacements: {
|
25
|
+
"name" => to_c_type,
|
26
|
+
"fields" => all_fields})
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generates a source code expression that reads a fields of this struct by index.
|
30
|
+
def generate_read(receiver, selector, index)
|
31
|
+
# Type inference already ensured that there is exactly one parameter which is
|
32
|
+
# an IntLiteral.
|
33
|
+
|
34
|
+
return "#{receiver}.field_#{index}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def generate_non_constant_read(receiver, selector, index_expression_identifier)
|
38
|
+
expression = ""
|
39
|
+
|
40
|
+
for index in 0...@fields.size
|
41
|
+
expression = expression + "(#{index_expression_identifier} == #{index} ? #{receiver}.field_#{index} : "
|
42
|
+
end
|
43
|
+
|
44
|
+
# Out of bounds case should throw and exception
|
45
|
+
expression = expression + "NULL"
|
46
|
+
|
47
|
+
for index in 0...@fields.size
|
48
|
+
expression = expression + ")"
|
49
|
+
end
|
50
|
+
|
51
|
+
return expression
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,18 +1,47 @@
|
|
1
|
+
require_relative "../config/configuration"
|
2
|
+
|
3
|
+
require_relative "ast_translator"
|
1
4
|
require_relative "block_translator"
|
2
|
-
require_relative "
|
5
|
+
require_relative "cuda_errors"
|
6
|
+
require_relative "environment_builder"
|
7
|
+
require_relative "commands/command_translator"
|
3
8
|
require_relative "last_returns_visitor"
|
4
|
-
require_relative "
|
5
|
-
require_relative "
|
6
|
-
require_relative "../config/configuration"
|
9
|
+
require_relative "struct_type"
|
10
|
+
require_relative "array_command_struct_builder"
|
7
11
|
|
8
12
|
module Ikra
|
9
13
|
|
10
14
|
# This module contains functionality for translating Ruby code to CUDA (C++) code.
|
11
15
|
module Translator
|
12
16
|
module Constants
|
17
|
+
ENV_TYPE = "environment_t"
|
13
18
|
ENV_IDENTIFIER = "_env_"
|
14
19
|
ENV_DEVICE_IDENTIFIER = "dev_env"
|
15
20
|
ENV_HOST_IDENTIFIER = "host_env"
|
21
|
+
LEXICAL_VAR_PREFIX = "lex_"
|
22
|
+
RESULT_IDENTIFIER = "_result_"
|
23
|
+
NUM_THREADS_TYPE = "int"
|
24
|
+
NUM_THREADS_IDENTIFIER = "_num_threads_"
|
25
|
+
TEMP_RESULT_IDENTIFIER = "_temp_result_"
|
26
|
+
ODD_TYPE = "bool"
|
27
|
+
ODD_IDENTIFIER = "_odd_"
|
28
|
+
PROGRAM_RESULT_TYPE = "result_t"
|
29
|
+
PROGRAM_RESULT_IDENTIFIER = "program_result"
|
30
|
+
SELF_IDENTIFIER = "_self_"
|
31
|
+
|
32
|
+
# Make sure that these constants keep in sync with header declaration CPP file
|
33
|
+
UNION_TYPE_SIZE = 24
|
34
|
+
UNION_TYPE_VALUE_OFFSET = 8
|
35
|
+
end
|
36
|
+
|
37
|
+
class Variable
|
38
|
+
attr_reader :type
|
39
|
+
attr_reader :name
|
40
|
+
|
41
|
+
def initialize(name:, type:)
|
42
|
+
@name = name
|
43
|
+
@type = type
|
44
|
+
end
|
16
45
|
end
|
17
46
|
|
18
47
|
class << self
|
@@ -26,7 +55,7 @@ module Ikra
|
|
26
55
|
def read_file(file_name:, replacements: {})
|
27
56
|
full_name = Ikra::Configuration.resource_file_name(file_name)
|
28
57
|
if !File.exist?(full_name)
|
29
|
-
raise "File does not exist: #{full_name}"
|
58
|
+
raise AssertionError.new("File does not exist: #{full_name}")
|
30
59
|
end
|
31
60
|
|
32
61
|
contents = File.open(full_name, "rb").read
|
@@ -40,10 +69,4 @@ module Ikra
|
|
40
69
|
end
|
41
70
|
end
|
42
71
|
end
|
43
|
-
|
44
|
-
module AST
|
45
|
-
module Constants
|
46
|
-
SELF_IDENTIFIER = "_self_"
|
47
|
-
end
|
48
|
-
end
|
49
72
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative "../ast/nodes"
|
2
|
+
require_relative "../ast/visitor"
|
3
|
+
require_relative "../types/types"
|
4
|
+
|
5
|
+
module Ikra
|
6
|
+
module AST
|
7
|
+
class LVarReadNode
|
8
|
+
attr_accessor :variable_kind
|
9
|
+
|
10
|
+
def mangled_identifier
|
11
|
+
if variable_kind == :lexical
|
12
|
+
return Translator::Constants::LEXICAL_VAR_PREFIX + identifier.to_s
|
13
|
+
else
|
14
|
+
return identifier
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class LVarWriteNode
|
20
|
+
attr_accessor :variable_kind
|
21
|
+
|
22
|
+
def mangled_identifier
|
23
|
+
if variable_kind == :lexical
|
24
|
+
return Translator::Constants::LEXICAL_VAR_PREFIX + identifier.to_s
|
25
|
+
else
|
26
|
+
return identifier
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module Translator
|
33
|
+
class VariableClassifier < AST::Visitor
|
34
|
+
def initialize(lexical_variable_names:)
|
35
|
+
@lexical_variable_names = lexical_variable_names
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit_lvar_read_node(node)
|
39
|
+
node.variable_kind = var_type(node.identifier)
|
40
|
+
end
|
41
|
+
|
42
|
+
def visit_lvar_write_node(node)
|
43
|
+
node.variable_kind = var_type(node.identifier)
|
44
|
+
super(node)
|
45
|
+
end
|
46
|
+
|
47
|
+
def var_type(identifier)
|
48
|
+
if @lexical_variable_names.include?(identifier)
|
49
|
+
return :lexical
|
50
|
+
else
|
51
|
+
return :local
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|