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,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
|