Class: Mirah::Typer::Simple
- Inherits:
-
Base
- Object
- Base
- Mirah::Typer::Simple
show all
- Defined in:
- lib/mirah/typer/simple.rb
Constant Summary
Constants included
from Mirah
Mirah::TransformError, VERSION
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#array_type ⇒ Object
-
#boolean_type ⇒ Object
-
#cycle(count) ⇒ Object
-
#cycling=(c) ⇒ Object
-
#cycling? ⇒ Boolean
-
#default_type ⇒ Object
-
#defer(node, error_message = nil) ⇒ Object
-
#deferred_nodes ⇒ Object
-
#define_type(scope, name, superclass, interfaces) ⇒ Object
-
#error(node, error_or_msg = nil, backtrace = nil) ⇒ Object
-
#field_type(cls, name) ⇒ Object
-
#field_type_hash(cls) ⇒ Object
-
#field_types ⇒ Object
-
#fixnum_type(value = 0) ⇒ Object
-
#float_type(value = 0) ⇒ Object
-
#get_method_type_hash(target_type, name, parameter_types) ⇒ Object
-
#hash_type ⇒ Object
-
#infer(node, expression = true) ⇒ Object
-
#infer_signature(method_def) ⇒ Object
-
#initialize(self_type) ⇒ Simple
constructor
A new instance of Simple.
-
#known_type(scope, name) ⇒ Object
-
#learn_field_type(cls, name, type) ⇒ Object
-
#learn_local_type(scope, name, type) ⇒ Object
-
#learn_method_type(target_type, name, parameter_types, type, exceptions) ⇒ Object
-
#learn_static_field_type(cls, name, type) ⇒ Object
-
#local_type(scope, name) ⇒ Object
-
#local_type_hash(scope) ⇒ Object
-
#local_types ⇒ Object
-
#method_type(target_type, name, parameter_types) ⇒ Object
-
#method_types ⇒ Object
-
#name ⇒ Object
-
#no_type ⇒ Object
-
#null_type ⇒ Object
-
#plugins ⇒ Object
-
#resolve(raise = false) ⇒ Object
-
#self_type ⇒ Object
-
#set_filename(scope, name) ⇒ Object
-
#static_field_type(cls, name) ⇒ Object
-
#static_field_type_hash(cls) ⇒ Object
-
#static_field_types ⇒ Object
-
#string_type ⇒ Object
-
#type_definition(scope, name, superclass, interfaces) ⇒ Object
-
#type_reference(scope, name, array = false, meta = false) ⇒ Object
Methods inherited from Base
#log, #to_s
Methods included from Mirah
compile, compiler_options, compiler_options=, dest_path, dest_path=, dest_paths, dest_to_source_path, find_dest, find_source, parse, plugins, print_error, reset, run, source_path, source_path=, source_paths, typer_plugins
Constructor Details
#initialize(self_type) ⇒ Simple
Returns a new instance of Simple.
24
25
26
27
28
29
30
31
32
33
|
# File 'lib/mirah/typer/simple.rb', line 24
def initialize(self_type)
@known_types = {}
@known_types["self"] = type_reference(nil, self_type)
@known_types["fixnum"] = type_reference(nil, "fixnum")
@known_types["float"] = type_reference(nil, "float")
@known_types["string"] = type_reference(nil, "string")
@known_types["boolean"] = type_reference(nil, "boolean")
@errors = []
end
|
Instance Attribute Details
#errors ⇒ Object
Returns the value of attribute errors.
22
23
24
|
# File 'lib/mirah/typer/simple.rb', line 22
def errors
@errors
end
|
#known_types ⇒ Object
Returns the value of attribute known_types.
22
23
24
|
# File 'lib/mirah/typer/simple.rb', line 22
def known_types
@known_types
end
|
#last_chance ⇒ Object
Returns the value of attribute last_chance.
22
23
24
|
# File 'lib/mirah/typer/simple.rb', line 22
def last_chance
@last_chance
end
|
Instance Method Details
#boolean_type ⇒ Object
61
62
63
|
# File 'lib/mirah/typer/simple.rb', line 61
def boolean_type
known_types["boolean"]
end
|
#cycle(count) ⇒ Object
231
232
233
234
235
236
237
238
239
240
241
242
243
|
# File 'lib/mirah/typer/simple.rb', line 231
def cycle(count)
@cycling = true
count.times do |i|
begin
log "[Cycle #{i}]: Started... (#{@deferred_nodes.size} nodes to resolve)"
yield i
ensure
log "[Cycle #{i}]: Complete!"
end
end
ensure
@cycling = false
end
|
#cycling=(c) ⇒ Object
227
228
229
|
# File 'lib/mirah/typer/simple.rb', line 227
def cycling=(c)
@cycling = c
end
|
#cycling? ⇒ Boolean
223
224
225
|
# File 'lib/mirah/typer/simple.rb', line 223
def cycling?
@cycling
end
|
#default_type ⇒ Object
45
46
47
|
# File 'lib/mirah/typer/simple.rb', line 45
def default_type
nil
end
|
#defer(node, error_message = nil) ⇒ Object
299
300
301
302
303
304
305
306
307
308
309
310
311
|
# File 'lib/mirah/typer/simple.rb', line 299
def defer(node, error_message=nil)
if @error_next
log "Marking #{node} as an error"
@error_next = false
error(node, error_message)
else
raise "Can't defer nil" if node.nil?
return if deferred_nodes.include? node
log "Deferring inference for #{node}"
deferred_nodes[node] = self_type
end
end
|
#deferred_nodes ⇒ Object
269
270
271
|
# File 'lib/mirah/typer/simple.rb', line 269
def deferred_nodes
@deferred_nodes ||= {}
end
|
#define_type(scope, name, superclass, interfaces) ⇒ Object
87
88
89
90
91
92
93
94
95
96
97
|
# File 'lib/mirah/typer/simple.rb', line 87
def define_type(scope, name, superclass, interfaces)
log "New type defined: '#{name}' < '#{superclass}'"
result = type_definition(scope, name, superclass, interfaces)
old_self, known_types["self"] = known_types["self"], result
yield
known_types["self"] = old_self
result
end
|
#error(node, error_or_msg = nil, backtrace = nil) ⇒ Object
284
285
286
287
288
289
290
291
292
293
294
295
296
297
|
# File 'lib/mirah/typer/simple.rb', line 284
def error(node, error_or_msg=nil, backtrace=nil)
if error_or_msg.kind_of? InferenceError
error = error_or_msg
elsif error_or_msg
error = InferenceError.new(error_or_msg, node)
error.set_backtrace(backtrace) if backtrace
else
error = InferenceError.new("Unable to infer type.", node)
end
@errors << error
node.resolve_if(self) do
AST.error_type
end
end
|
#field_type(cls, name) ⇒ Object
148
149
150
|
# File 'lib/mirah/typer/simple.rb', line 148
def field_type(cls, name)
field_type_hash(cls)[name]
end
|
#field_type_hash(cls) ⇒ Object
124
125
126
|
# File 'lib/mirah/typer/simple.rb', line 124
def field_type_hash(cls)
field_types[cls] ||= {}
end
|
#field_types ⇒ Object
120
121
122
|
# File 'lib/mirah/typer/simple.rb', line 120
def field_types
@field_types ||= {}
end
|
#fixnum_type(value = 0) ⇒ Object
49
50
51
|
# File 'lib/mirah/typer/simple.rb', line 49
def fixnum_type(value=0)
known_types["fixnum"]
end
|
#float_type(value = 0) ⇒ Object
53
54
55
|
# File 'lib/mirah/typer/simple.rb', line 53
def float_type(value=0)
known_types["float"]
end
|
#get_method_type_hash(target_type, name, parameter_types) ⇒ Object
249
250
251
252
253
254
255
256
257
258
259
|
# File 'lib/mirah/typer/simple.rb', line 249
def get_method_type_hash(target_type, name, parameter_types)
method_types[target_type] ||= {}
method_types[target_type][name] ||= {}
method_types[target_type][name][parameter_types.size] ||= {}
current = method_types[target_type][name][parameter_types.size]
parameter_types.each {|type| current[type] ||= {}; current = current[type]}
current
end
|
#infer(node, expression = true) ⇒ Object
273
274
275
276
277
278
279
280
281
282
|
# File 'lib/mirah/typer/simple.rb', line 273
def infer(node, expression=true)
begin
node.infer(self, expression)
rescue InferenceError => ex
ex.node ||= node
error(node, ex)
rescue Exception => ex
raise Mirah::InternalCompilerError.wrap(ex, node)
end
end
|
#infer_signature(method_def) ⇒ Object
136
137
|
# File 'lib/mirah/typer/simple.rb', line 136
def infer_signature(method_def)
end
|
#known_type(scope, name) ⇒ Object
83
84
85
|
# File 'lib/mirah/typer/simple.rb', line 83
def known_type(scope, name)
@known_types[name]
end
|
#learn_field_type(cls, name, type) ⇒ Object
139
140
141
142
143
144
145
146
|
# File 'lib/mirah/typer/simple.rb', line 139
def learn_field_type(cls, name, type)
log "Learned field type under #{cls} : #{name} = #{type}" if type
field_type_hash(cls)[name] ||= known_types[type] || type
type
end
|
#learn_local_type(scope, name, type) ⇒ Object
99
100
101
102
103
104
|
# File 'lib/mirah/typer/simple.rb', line 99
def learn_local_type(scope, name, type)
return if type.null? && !@last_chance
type = scope.learn_local_type(name, known_types[type] || type)
log "Learned local type under #{scope} : #{name} = #{type}" if type
type
end
|
#learn_method_type(target_type, name, parameter_types, type, exceptions) ⇒ Object
165
166
167
168
169
170
171
172
173
|
# File 'lib/mirah/typer/simple.rb', line 165
def learn_method_type(target_type, name, parameter_types, type, exceptions)
log "Learned method #{name} (#{parameter_types}) on #{target_type} = #{type}" if type
get_method_type_hash(target_type, name, parameter_types)[:type] = known_types[type] || type
imported_types = parameter_types.map {|param| known_types[param] || param}
get_method_type_hash(target_type, name, imported_types)[:type] = type
end
|
#learn_static_field_type(cls, name, type) ⇒ Object
152
153
154
155
156
157
158
159
|
# File 'lib/mirah/typer/simple.rb', line 152
def learn_static_field_type(cls, name, type)
log "Learned field type under #{cls} : #{name} = #{type}" if type
static_field_type_hash(cls)[name] ||= known_types[type] || type
type
end
|
#local_type(scope, name) ⇒ Object
106
107
108
109
110
|
# File 'lib/mirah/typer/simple.rb', line 106
def local_type(scope, name)
type = scope.local_type(name)
log "Retrieved local type in #{scope} : #{name} = #{type}" if type
type
end
|
#local_type_hash(scope) ⇒ Object
116
117
118
|
# File 'lib/mirah/typer/simple.rb', line 116
def local_type_hash(scope)
local_types[scope] ||= {}
end
|
#local_types ⇒ Object
112
113
114
|
# File 'lib/mirah/typer/simple.rb', line 112
def local_types
@local_types ||= {}
end
|
#method_type(target_type, name, parameter_types) ⇒ Object
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
# File 'lib/mirah/typer/simple.rb', line 175
def method_type(target_type, name, parameter_types)
if (target_type && target_type.error?) ||
parameter_types.any? {|t| t && t.error?}
return AST.error_type
end
constructor = (name == 'new' && target_type && target_type.meta?)
if constructor
simple_type = get_method_type_hash(target_type.unmeta, 'initialize', parameter_types)[:type]
else
simple_type = get_method_type_hash(target_type, name, parameter_types)[:type]
end
if !simple_type
log "Method type for \"#{name}\" #{parameter_types} on #{target_type} not found."
simple_type = plugins do |plugin|
plugin.method_type(self, target_type, name, parameter_types)
end
end
return nil unless simple_type
if constructor
log "Method type for \"#{name}\" #{parameter_types} on #{target_type} = #{target_type}"
target_type.unmeta
else
log "Method type for \"#{name}\" #{parameter_types} on #{target_type} = #{simple_type}"
simple_type
end
end
|
#method_types ⇒ Object
245
246
247
|
# File 'lib/mirah/typer/simple.rb', line 245
def method_types
@method_types ||= {}
end
|
#name ⇒ Object
35
36
37
|
# File 'lib/mirah/typer/simple.rb', line 35
def name
"Simple"
end
|
#plugins ⇒ Object
210
211
212
213
214
215
216
217
218
219
220
221
|
# File 'lib/mirah/typer/simple.rb', line 210
def plugins
if cycling?
Mirah.typer_plugins.each do |plugin|
log "Invoking plugin: #{plugin}"
result = yield plugin
return result if result
end
end
nil
end
|
#resolve(raise = false) ⇒ Object
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
|
# File 'lib/mirah/typer/simple.rb', line 313
def resolve(raise = false)
count = deferred_nodes.size + 1
log "Entering type inference cycle"
retried = false
cycle(count) do |i|
old_deferred = @deferred_nodes
@deferred_nodes = {}
old_deferred.each do |node, saved_type|
known_types["self"] = saved_type
type = infer(node)
log "[Cycle #{i}]: Inferred type for #{node}: #{type || 'FAILED'}"
if type == default_type
@deferred_nodes[node] = saved_type
end
end
if @deferred_nodes.empty?
log "[Cycle #{i}]: Resolved all types, exiting"
break
elsif old_deferred == @deferred_nodes
if @error_next || retried
log "[Cycle #{i}]: Made no progress, bailing out"
break
elsif @last_chance
retried = true
@error_next = true
redo
else
@last_chance = true
redo
end
end
retried = false
end
error_nodes = @errors.map {|e| e.node}
(deferred_nodes.keys - error_nodes).each do |deferred_node|
error_nodes << deferred_node
error(deferred_node)
end
if raise && !error_nodes.empty?
msg = "Could not infer typing for nodes:"
error_nodes.map do |e|
msg << "\n "
msg << "#{e.inspect} at line #{e.line_number} (child of #{e.parent})"
end
raise InferenceError.new(msg)
end
end
|
#self_type ⇒ Object
41
42
43
|
# File 'lib/mirah/typer/simple.rb', line 41
def self_type
known_types["self"]
end
|
#set_filename(scope, name) ⇒ Object
39
|
# File 'lib/mirah/typer/simple.rb', line 39
def set_filename(scope, name); end
|
#static_field_type(cls, name) ⇒ Object
161
162
163
|
# File 'lib/mirah/typer/simple.rb', line 161
def static_field_type(cls, name)
static_field_type_hash(cls)[name]
end
|
#static_field_type_hash(cls) ⇒ Object
132
133
134
|
# File 'lib/mirah/typer/simple.rb', line 132
def static_field_type_hash(cls)
static_field_types[cls] ||= {}
end
|
#static_field_types ⇒ Object
128
129
130
|
# File 'lib/mirah/typer/simple.rb', line 128
def static_field_types
@static_field_types ||= {}
end
|
#string_type ⇒ Object
57
58
59
|
# File 'lib/mirah/typer/simple.rb', line 57
def string_type
known_types["string"]
end
|
#type_definition(scope, name, superclass, interfaces) ⇒ Object
265
266
267
|
# File 'lib/mirah/typer/simple.rb', line 265
def type_definition(scope, name, superclass, interfaces)
AST::TypeDefinition.new(name, AST::TypeReference.new(superclass), interfaces)
end
|
#type_reference(scope, name, array = false, meta = false) ⇒ Object
261
262
263
|
# File 'lib/mirah/typer/simple.rb', line 261
def type_reference(scope, name, array=false, meta=false)
AST::TypeReference.new(name, array, meta)
end
|