ikra 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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,37 +0,0 @@
|
|
1
|
-
require "set"
|
2
|
-
require_relative "../scope"
|
3
|
-
|
4
|
-
module Ikra
|
5
|
-
module AST
|
6
|
-
class MethodDefinition
|
7
|
-
attr_accessor :type # receiver type
|
8
|
-
attr_accessor :selector
|
9
|
-
attr_accessor :ast
|
10
|
-
attr_accessor :return_type
|
11
|
-
attr_accessor :callers # method definitions calling this method
|
12
|
-
attr_accessor :symbol_table
|
13
|
-
attr_accessor :binding # needed for resolving constants
|
14
|
-
attr_accessor :local_variables # local variables defined in the method (name -> type)
|
15
|
-
attr_accessor :lexical_variables # lexical variables (defined outside; name -> type)
|
16
|
-
attr_accessor :accessed_lexical_variables # accessed lexical variables, only these variables are transferred to the GPU. TODO: Do we still need this? This is now determined in symbolic.rb
|
17
|
-
attr_accessor :parameter_variables # parameters of the method/block (name -> type)
|
18
|
-
|
19
|
-
def initialize(type:, selector:, parameter_variables:, return_type:, ast:)
|
20
|
-
@type = type
|
21
|
-
@selector = selector
|
22
|
-
@parameter_variables = parameter_variables
|
23
|
-
@return_type = return_type
|
24
|
-
@ast = ast
|
25
|
-
@callers = Set.new
|
26
|
-
@symbol_table = Scope.new
|
27
|
-
@local_variables = {}
|
28
|
-
@lexical_variables = {} # optional
|
29
|
-
@accessed_lexical_variables = {} # optional
|
30
|
-
end
|
31
|
-
|
32
|
-
def parameter_names
|
33
|
-
type.method_parameters(selector)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
data/lib/ast/translator.rb
DELETED
@@ -1,264 +0,0 @@
|
|
1
|
-
require_relative "nodes.rb"
|
2
|
-
require_relative "../translator/translator"
|
3
|
-
|
4
|
-
# Rule: every statement ends with newline
|
5
|
-
|
6
|
-
module Ikra
|
7
|
-
module AST
|
8
|
-
class Node
|
9
|
-
@@next_temp_identifier_id = 0
|
10
|
-
|
11
|
-
def translate_statement
|
12
|
-
translate_expression + ";\n"
|
13
|
-
end
|
14
|
-
|
15
|
-
protected
|
16
|
-
|
17
|
-
def statements_as_expression(str)
|
18
|
-
"[&]{ #{str} }()"
|
19
|
-
end
|
20
|
-
|
21
|
-
def indent_block(str)
|
22
|
-
str.split("\n").map do |line| " " + line end.join("\n")
|
23
|
-
end
|
24
|
-
|
25
|
-
def wrap_in_c_block(str)
|
26
|
-
"{\n" + indent_block(str) + "\n}\n"
|
27
|
-
end
|
28
|
-
|
29
|
-
def temp_identifier_id
|
30
|
-
@@next_temp_identifier_id += 1
|
31
|
-
@@next_temp_identifier_id
|
32
|
-
end
|
33
|
-
|
34
|
-
# Generates code that assigns the value of a node to a newly-defined variable.
|
35
|
-
def define_assign_variable(name, node)
|
36
|
-
type = node.get_type.to_c_type
|
37
|
-
"#{type} #{name} = #{node.translate_expression};"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class RootNode
|
42
|
-
def translate_statement
|
43
|
-
child.translate_statement
|
44
|
-
end
|
45
|
-
|
46
|
-
def translate_expression
|
47
|
-
child.translate_expression
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
class ConstNode
|
52
|
-
def translate_expression
|
53
|
-
raise "Not implemented"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
class LVarReadNode
|
58
|
-
def translate_expression
|
59
|
-
identifier.to_s
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class LVarWriteNode
|
64
|
-
def translate_expression
|
65
|
-
"#{identifier.to_s} = #{value.translate_expression}"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class IVarReadNode
|
70
|
-
def translate_expression
|
71
|
-
array_identifier = class_owner.to_ikra_type.inst_var_array_name(identifier)
|
72
|
-
"#{Translator::Constants::ENV_IDENTIFIER}->#{array_identifier}[#{Constants::SELF_IDENTIFIER}]"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class IntNode
|
77
|
-
def translate_expression
|
78
|
-
value.to_s
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class FloatNode
|
83
|
-
def translate_expression
|
84
|
-
value.to_s
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class BoolNode
|
89
|
-
def translate_expression
|
90
|
-
value.to_s
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
class ForNode
|
95
|
-
def translate_statement
|
96
|
-
loop_header = "for (#{iterator_identifier.to_s} = #{range_from.translate_expression}; #{iterator_identifier.to_s} <= #{range_to.translate_expression}; #{iterator_identifier.to_s}++)"
|
97
|
-
loop_header + "\n" + body_stmts.translate_statement + "#{iterator_identifier.to_s}--;\n"
|
98
|
-
end
|
99
|
-
|
100
|
-
def translate_expression
|
101
|
-
# TODO: return value should be range
|
102
|
-
loop_header = "for (#{iterator_identifier.to_s} = #{range_from.translate_expression}; #{iterator_identifier.to_s} <= #{range_to.translate_expression}; #{iterator_identifier.to_s}++)"
|
103
|
-
full_loop = loop_header + "\n" + body_stmts.translate_statement + "#{iterator_identifier.to_s}--;\nreturn 0;"
|
104
|
-
statements_as_expression(full_loop)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
class BreakNode
|
109
|
-
def translate_expression
|
110
|
-
raise "Not implemented yet"
|
111
|
-
end
|
112
|
-
|
113
|
-
def translate_statement
|
114
|
-
"break;\n"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class IfNode
|
119
|
-
def translate_statement
|
120
|
-
header = "if (#{condition.translate_expression})\n"
|
121
|
-
|
122
|
-
if false_body_stmts == nil
|
123
|
-
header + true_body_stmts.translate_statement
|
124
|
-
else
|
125
|
-
header + true_body_stmts.translate_statement + "else\n" + false_body_stmts.translate_statement
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def translate_expression
|
130
|
-
header = "if (#{condition.translate_expression})\n"
|
131
|
-
true_body_translated = nil
|
132
|
-
false_body_translated = nil
|
133
|
-
|
134
|
-
if true_body_stmts.is_begin_node?
|
135
|
-
true_body_translated = true_body_stmts.translate_statement_last_returns
|
136
|
-
else
|
137
|
-
true_body_translated = "return " + true_body_stmts.translate_expression + ";\n"
|
138
|
-
end
|
139
|
-
|
140
|
-
if false_body_stmts != nil
|
141
|
-
# Can be begin node or anything else
|
142
|
-
if false_body_stmts.is_begin_node?
|
143
|
-
false_body_translated = false_body_stmts.translate_statement_last_returns
|
144
|
-
else
|
145
|
-
false_body_translated = "return " + false_body_stmts.translate_expression + ";\n"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
if false_body_translated == nil
|
150
|
-
statements_as_expression(header + true_body_translated)
|
151
|
-
else
|
152
|
-
statements_as_expression(header + true_body_translated + "else\n" + false_body_translated)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
class BeginNode
|
158
|
-
def translate_statement
|
159
|
-
if body_stmts.size == 0
|
160
|
-
return ""
|
161
|
-
end
|
162
|
-
|
163
|
-
body_translated = body_stmts.map do |stmt|
|
164
|
-
stmt.translate_statement
|
165
|
-
end.join("")
|
166
|
-
|
167
|
-
wrap_in_c_block(body_translated)
|
168
|
-
end
|
169
|
-
|
170
|
-
def translate_statement_last_returns
|
171
|
-
if body_stmts.size == 0
|
172
|
-
raise "Cannot return empty BeginNode"
|
173
|
-
end
|
174
|
-
|
175
|
-
body_translated = BeginNode.new(body_stmts[0...-1]).translate_statement
|
176
|
-
body_translated + "return #{body_stmts.last.translate_expression};\n"
|
177
|
-
wrap_in_c_block(body_translated)
|
178
|
-
end
|
179
|
-
|
180
|
-
def translate_expression
|
181
|
-
if body_stmts.size == 0
|
182
|
-
raise "Empty BeginNode cannot be an expression"
|
183
|
-
elsif body_stmts.size == 1
|
184
|
-
# Preserve brackets
|
185
|
-
"(#{body_stmts.first.translate_expression})"
|
186
|
-
else
|
187
|
-
# Wrap in lambda
|
188
|
-
# Do not worry about scope of varibles, they will all be declared at the beginning of the function
|
189
|
-
statements_as_expression(translate_statement_last_returns)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
class SendNode
|
195
|
-
BinarySelectors = [:+, :-, :*, :/, :%, :<, :<=, :>, :>=, :==, :!=, :&, :'&&', :|, :'||', :^]
|
196
|
-
|
197
|
-
def translate_expression
|
198
|
-
if BinarySelectors.include?(selector)
|
199
|
-
if arguments.size != 1
|
200
|
-
raise "Expected 1 argument for binary selector (#{arguments.size} given)"
|
201
|
-
end
|
202
|
-
|
203
|
-
"(#{receiver.translate_expression} #{selector.to_s} #{arguments.first.translate_expression})"
|
204
|
-
else
|
205
|
-
if receiver.get_type.is_singleton? and
|
206
|
-
receiver.get_type.singleton_type.to_ruby_type.singleton_methods.include?(("_ikra_c_" + selector.to_s).to_sym)
|
207
|
-
# TODO: support multiple types for receiver
|
208
|
-
receiver.get_type.singleton_type.to_ruby_type.send(("_ikra_c_" + selector.to_s).to_sym, receiver.translate_expression)
|
209
|
-
else
|
210
|
-
# TODO: generate argument code only once
|
211
|
-
|
212
|
-
if receiver.get_type.is_singleton?
|
213
|
-
self_argument = []
|
214
|
-
if receiver.get_type.singleton_type.should_generate_type?
|
215
|
-
self_argument = [receiver]
|
216
|
-
end
|
217
|
-
|
218
|
-
args = ([Translator::Constants::ENV_IDENTIFIER] + (self_argument + arguments).map do |arg|
|
219
|
-
arg.translate_expression
|
220
|
-
end).join(", ")
|
221
|
-
|
222
|
-
"#{receiver.get_type.singleton_type.mangled_method_name(selector)}(#{args})"
|
223
|
-
else
|
224
|
-
# Polymorphic case
|
225
|
-
# TODO: This is not an expression anymore!
|
226
|
-
poly_id = temp_identifier_id
|
227
|
-
receiver_identifier = "_polytemp_recv_#{poly_id}"
|
228
|
-
result_identifier = "_polytemp_result_#{poly_id}"
|
229
|
-
header = "#{define_assign_variable(receiver_identifier, receiver)}\n#{get_type.to_c_type} #{result_identifier};\nswitch (#{receiver_identifier}.class_id)\n"
|
230
|
-
case_statements = []
|
231
|
-
|
232
|
-
receiver.get_type.types.each do |type|
|
233
|
-
self_argument = []
|
234
|
-
if type.should_generate_type?
|
235
|
-
# No need to pass type as subtypes are regarded as entirely new types
|
236
|
-
self_argument = ["#{receiver_identifier}.object_id"]
|
237
|
-
end
|
238
|
-
|
239
|
-
args = ([Translator::Constants::ENV_IDENTIFIER] + self_argument + arguments.map do |arg|
|
240
|
-
arg.translate_expression
|
241
|
-
end).join(", ")
|
242
|
-
|
243
|
-
case_statements.push("case #{type.class_id}: #{result_identifier} = #{type.mangled_method_name(selector)}(#{args}); break;")
|
244
|
-
end
|
245
|
-
|
246
|
-
# TODO: compound statements only work with the GNU C++ compiler
|
247
|
-
"(" + wrap_in_c_block(header + wrap_in_c_block(case_statements.join("\n")) + result_identifier + ";")[0..-2] + ")"
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
class ReturnNode
|
255
|
-
def translate_expression
|
256
|
-
raise "ReturnNode is never an expression"
|
257
|
-
end
|
258
|
-
|
259
|
-
def translate_statement
|
260
|
-
"return #{value.translate_expression};\n"
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
extern "C" EXPORT /*{result_type}*/ *launch_kernel(environment_t */*{host_env}*/)
|
2
|
-
{
|
3
|
-
printf("kernel launched\n");
|
4
|
-
|
5
|
-
/* Modify host environment to contain device pointers addresses */
|
6
|
-
/*{copy_env}*/
|
7
|
-
|
8
|
-
/* Allocate device environment and copy over struct */
|
9
|
-
environment_t */*{dev_env}*/;
|
10
|
-
checkCudaErrors(cudaMalloc(&/*{dev_env}*/, sizeof(environment_t)));
|
11
|
-
checkCudaErrors(cudaMemcpy(/*{dev_env}*/, /*{host_env}*/, sizeof(environment_t), cudaMemcpyHostToDevice));
|
12
|
-
|
13
|
-
/*{result_type}*/ *host_result = (/*{result_type}*/ *) malloc(sizeof(/*{result_type}*/) * /*{result_size}*/);
|
14
|
-
/*{result_type}*/ *device_result;
|
15
|
-
checkCudaErrors(cudaMalloc(&device_result, sizeof(/*{result_type}*/) * /*{result_size}*/));
|
16
|
-
|
17
|
-
dim3 dim_grid(/*{grid_dim[0]}*/, /*{grid_dim[1]}*/, /*{grid_dim[2]}*/);
|
18
|
-
dim3 dim_block(/*{block_dim[0]}*/, /*{block_dim[1]}*/, /*{block_dim[2]}*/);
|
19
|
-
|
20
|
-
kernel<<<dim_grid, dim_block>>>(/*{dev_env}*/, device_result);
|
21
|
-
|
22
|
-
checkCudaErrors(cudaThreadSynchronize());
|
23
|
-
|
24
|
-
checkCudaErrors(cudaMemcpy(host_result, device_result, sizeof(/*{result_type}*/) * /*{result_size}*/, cudaMemcpyDeviceToHost));
|
25
|
-
checkCudaErrors(cudaFree(/*{dev_env}*/));
|
26
|
-
|
27
|
-
return host_result;
|
28
|
-
}
|
data/lib/scope.rb
DELETED
@@ -1,166 +0,0 @@
|
|
1
|
-
require "set"
|
2
|
-
require_relative "types/union_type"
|
3
|
-
|
4
|
-
class Frame < Hash
|
5
|
-
def function_frame!
|
6
|
-
@is_function_frame = true
|
7
|
-
end
|
8
|
-
|
9
|
-
def is_function_frame?
|
10
|
-
@is_function_frame ||= false
|
11
|
-
@is_function_frame
|
12
|
-
end
|
13
|
-
|
14
|
-
def add_return_type(type)
|
15
|
-
if not is_function_frame?
|
16
|
-
raise "Return type allowed only for function frames"
|
17
|
-
end
|
18
|
-
|
19
|
-
if not type.is_union_type?
|
20
|
-
raise "Expected union type"
|
21
|
-
end
|
22
|
-
|
23
|
-
@return_type ||= Ikra::Types::UnionType.new
|
24
|
-
@return_type.expand(type)
|
25
|
-
end
|
26
|
-
|
27
|
-
def return_type
|
28
|
-
if not is_function_frame?
|
29
|
-
raise "Return type allowed only for function frames"
|
30
|
-
end
|
31
|
-
|
32
|
-
@return_type ||= Ikra::Types::UnionType.new
|
33
|
-
@return_type
|
34
|
-
end
|
35
|
-
|
36
|
-
def variable_names
|
37
|
-
keys
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class Scope < Array
|
42
|
-
class Variable
|
43
|
-
attr_reader :type
|
44
|
-
attr_accessor :read
|
45
|
-
attr_accessor :written
|
46
|
-
|
47
|
-
def initialize(type = Ikra::Types::UnionType.new)
|
48
|
-
@type = type
|
49
|
-
@read = false
|
50
|
-
@written = false
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def top_frame
|
55
|
-
last
|
56
|
-
end
|
57
|
-
|
58
|
-
def previous_frame
|
59
|
-
self[-2]
|
60
|
-
end
|
61
|
-
|
62
|
-
def push_frame
|
63
|
-
frame = Frame.new
|
64
|
-
frame.default_proc = Proc.new do |hash, key|
|
65
|
-
hash[key] = Variable.new
|
66
|
-
end
|
67
|
-
push(frame)
|
68
|
-
end
|
69
|
-
|
70
|
-
def push_function_frame
|
71
|
-
push_frame
|
72
|
-
top_frame.function_frame!
|
73
|
-
end
|
74
|
-
|
75
|
-
def pop_frame
|
76
|
-
pop
|
77
|
-
end
|
78
|
-
|
79
|
-
# TODO: maybe remove?
|
80
|
-
def define_shadowed(name, type)
|
81
|
-
if top_frame.has_key?(name)
|
82
|
-
raise "#{name} already defined"
|
83
|
-
end
|
84
|
-
|
85
|
-
top_frame[name] = Variable.new(type)
|
86
|
-
end
|
87
|
-
|
88
|
-
def is_defined?(name)
|
89
|
-
any? do |frame|
|
90
|
-
frame.has_key?(name)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def get_type(name)
|
95
|
-
reverse_each do |frame|
|
96
|
-
if frame.has_key?(name)
|
97
|
-
return frame[name].type
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
raise "#{name} not found in symbol table"
|
102
|
-
end
|
103
|
-
|
104
|
-
def declare_expand_type(name, type)
|
105
|
-
if not type.is_union_type?
|
106
|
-
raise "Expected union type"
|
107
|
-
end
|
108
|
-
|
109
|
-
top_frame[name].type.expand(type)
|
110
|
-
end
|
111
|
-
|
112
|
-
def add_return_type(type)
|
113
|
-
reverse_each.detect do |fr|
|
114
|
-
fr.add_return_type(type)
|
115
|
-
return self
|
116
|
-
end
|
117
|
-
|
118
|
-
raise "Function frame not found"
|
119
|
-
end
|
120
|
-
|
121
|
-
def read!(name)
|
122
|
-
frame = reverse_each.detect do |fr|
|
123
|
-
fr.has_key?(name)
|
124
|
-
end
|
125
|
-
|
126
|
-
frame[name].read = true
|
127
|
-
end
|
128
|
-
|
129
|
-
def written!(name)
|
130
|
-
frame = reverse_each.detect do |fr|
|
131
|
-
fr.has_key?(name)
|
132
|
-
end
|
133
|
-
|
134
|
-
frame[name].written = true
|
135
|
-
end
|
136
|
-
|
137
|
-
def read_variables(frame_position)
|
138
|
-
frame = self[frame_position]
|
139
|
-
frame.select do |name, var|
|
140
|
-
var.read
|
141
|
-
end.keys
|
142
|
-
end
|
143
|
-
|
144
|
-
def written_variables(frame_position)
|
145
|
-
frame = self[frame_position]
|
146
|
-
frame.select do |name, var|
|
147
|
-
var.written
|
148
|
-
end.keys
|
149
|
-
end
|
150
|
-
|
151
|
-
def read_and_written_variables(frame_position = -1)
|
152
|
-
read_variables(frame_position) + written_variables(frame_position)
|
153
|
-
end
|
154
|
-
|
155
|
-
def new_frame(&block)
|
156
|
-
push_frame
|
157
|
-
yield
|
158
|
-
pop_frame
|
159
|
-
end
|
160
|
-
|
161
|
-
def new_function_frame(&block)
|
162
|
-
push_function_frame
|
163
|
-
yield
|
164
|
-
pop_frame
|
165
|
-
end
|
166
|
-
end
|