Class: Duby::Typer::Simple
Direct Known Subclasses
JVM
Constant Summary
Constants included
from Duby
Duby::TransformError
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#alias_type(short, long) ⇒ Object
-
#array_type ⇒ Object
-
#boolean_type ⇒ Object
-
#cycle(count) ⇒ Object
-
#cycling=(c) ⇒ Object
-
#cycling? ⇒ Boolean
-
#default_type ⇒ Object
-
#defer(node) ⇒ Object
-
#deferred_nodes ⇒ Object
-
#define_type(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 ⇒ Object
-
#float_type ⇒ Object
-
#get_method_type_hash(target_type, name, parameter_types) ⇒ Object
-
#hash_type ⇒ Object
-
#infer(node) ⇒ Object
-
#infer_signature(method_def) ⇒ Object
-
#initialize(self_type) ⇒ Simple
constructor
A new instance of Simple.
-
#known_type(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
-
#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
-
#string_type ⇒ Object
-
#type_definition(name, superclass, interfaces) ⇒ Object
-
#type_reference(name, array = false, meta = false) ⇒ Object
Methods inherited from BaseTyper
#log, #to_s
Methods included from Duby
compile, parse, plugins, print_error, reset, run, typer_plugins
Constructor Details
#initialize(self_type) ⇒ Simple
Returns a new instance of Simple.
35
36
37
38
39
40
41
42
43
44
|
# File 'lib/duby/typer.rb', line 35
def initialize(self_type)
@known_types = {}
@known_types["self"] = type_reference(self_type)
@known_types["fixnum"] = type_reference("fixnum")
@known_types["float"] = type_reference("float")
@known_types["string"] = type_reference("string")
@known_types["boolean"] = type_reference("boolean")
@errors = []
end
|
Instance Attribute Details
#errors ⇒ Object
Returns the value of attribute errors.
33
34
35
|
# File 'lib/duby/typer.rb', line 33
def errors
@errors
end
|
#known_types ⇒ Object
Returns the value of attribute known_types.
33
34
35
|
# File 'lib/duby/typer.rb', line 33
def known_types
@known_types
end
|
#last_chance ⇒ Object
Returns the value of attribute last_chance.
33
34
35
|
# File 'lib/duby/typer.rb', line 33
def last_chance
@last_chance
end
|
Instance Method Details
#alias_type(short, long) ⇒ Object
262
263
264
265
|
# File 'lib/duby/typer.rb', line 262
def alias_type(short, long)
@known_types[type_reference(short, false, false)] = type_reference(long, false, false)
@known_types[type_reference(short, false, true)] = type_reference(long, false, true)
end
|
#boolean_type ⇒ Object
70
71
72
|
# File 'lib/duby/typer.rb', line 70
def boolean_type
known_types["boolean"]
end
|
#cycle(count) ⇒ Object
224
225
226
227
228
229
230
231
232
233
234
235
236
|
# File 'lib/duby/typer.rb', line 224
def cycle(count)
@cycling = true
count.times do |i|
begin
log "[Cycle #{i}]: Started..."
yield i
ensure
log "[Cycle #{i}]: Complete!"
end
end
ensure
@cycling = false
end
|
#cycling=(c) ⇒ Object
220
221
222
|
# File 'lib/duby/typer.rb', line 220
def cycling=(c)
@cycling = c
end
|
#cycling? ⇒ Boolean
216
217
218
|
# File 'lib/duby/typer.rb', line 216
def cycling?
@cycling
end
|
#default_type ⇒ Object
54
55
56
|
# File 'lib/duby/typer.rb', line 54
def default_type
nil
end
|
#defer(node) ⇒ Object
297
298
299
300
301
302
303
304
305
306
307
308
|
# File 'lib/duby/typer.rb', line 297
def defer(node)
if @error_next
log "Marking #{node} as an error"
@error_next = false
error(node)
else
return if deferred_nodes.include? node
log "Deferring inference for #{node}"
deferred_nodes[node] = self_type
end
end
|
#deferred_nodes ⇒ Object
267
268
269
|
# File 'lib/duby/typer.rb', line 267
def deferred_nodes
@deferred_nodes ||= {}
end
|
#define_type(name, superclass, interfaces) ⇒ Object
96
97
98
99
100
101
102
103
104
105
|
# File 'lib/duby/typer.rb', line 96
def define_type(name, superclass, interfaces)
log "New type defined: '#{name}' < '#{superclass}'"
known_types[name] = type_definition(name, superclass, interfaces)
old_self, known_types["self"] = known_types["self"], known_types[name]
yield
known_types["self"] = old_self
known_types[name]
end
|
#error(node, error_or_msg = nil, backtrace = nil) ⇒ Object
282
283
284
285
286
287
288
289
290
291
292
293
294
295
|
# File 'lib/duby/typer.rb', line 282
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
154
155
156
|
# File 'lib/duby/typer.rb', line 154
def field_type(cls, name)
field_type_hash(cls)[name]
end
|
#field_type_hash(cls) ⇒ Object
138
139
140
|
# File 'lib/duby/typer.rb', line 138
def field_type_hash(cls)
field_types[cls] ||= {}
end
|
#field_types ⇒ Object
134
135
136
|
# File 'lib/duby/typer.rb', line 134
def field_types
@field_types ||= {}
end
|
#fixnum_type ⇒ Object
58
59
60
|
# File 'lib/duby/typer.rb', line 58
def fixnum_type
known_types["fixnum"]
end
|
#float_type ⇒ Object
62
63
64
|
# File 'lib/duby/typer.rb', line 62
def float_type
known_types["float"]
end
|
#get_method_type_hash(target_type, name, parameter_types) ⇒ Object
242
243
244
245
246
247
248
249
250
251
252
|
# File 'lib/duby/typer.rb', line 242
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) ⇒ Object
271
272
273
274
275
276
277
278
279
280
|
# File 'lib/duby/typer.rb', line 271
def infer(node)
begin
node.infer(self)
rescue InferenceError => ex
ex.node ||= node
error(node, ex)
rescue Exception => ex
error(node, ex.message, ex.backtrace)
end
end
|
#infer_signature(method_def) ⇒ Object
142
143
|
# File 'lib/duby/typer.rb', line 142
def infer_signature(method_def)
end
|
#known_type(name) ⇒ Object
92
93
94
|
# File 'lib/duby/typer.rb', line 92
def known_type(name)
@known_types[name]
end
|
#learn_field_type(cls, name, type) ⇒ Object
145
146
147
148
149
150
151
152
|
# File 'lib/duby/typer.rb', line 145
def learn_field_type(cls, name, type)
log "Learned field type under #{cls} : #{name} = #{type}"
field_type_hash(cls)[name] ||= known_types[type] || type
type
end
|
#learn_local_type(scope, name, type) ⇒ Object
107
108
109
110
111
112
113
114
115
116
117
|
# File 'lib/duby/typer.rb', line 107
def learn_local_type(scope, name, type)
existing_type = local_type_hash(scope)[name]
if existing_type
existing_type
elsif type
log "Learned local type under #{scope} : #{name} = #{type}"
local_type_hash(scope)[name] = known_types[type] || type
end
end
|
#learn_method_type(target_type, name, parameter_types, type, exceptions) ⇒ Object
158
159
160
161
162
163
164
165
166
|
# File 'lib/duby/typer.rb', line 158
def learn_method_type(target_type, name, parameter_types, type, exceptions)
log "Learned method #{name} (#{parameter_types}) on #{target_type} = #{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
|
#local_type(scope, name) ⇒ Object
119
120
121
122
123
124
|
# File 'lib/duby/typer.rb', line 119
def local_type(scope, name)
type = local_type_hash(scope)[name]
log "Retrieved local type in #{scope} : #{name} = #{type}" if type
type
end
|
#local_type_hash(scope) ⇒ Object
130
131
132
|
# File 'lib/duby/typer.rb', line 130
def local_type_hash(scope)
local_types[scope] ||= {}
end
|
#local_types ⇒ Object
126
127
128
|
# File 'lib/duby/typer.rb', line 126
def local_types
@local_types ||= {}
end
|
#method_type(target_type, name, parameter_types) ⇒ Object
168
169
170
171
172
173
174
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
|
# File 'lib/duby/typer.rb', line 168
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
238
239
240
|
# File 'lib/duby/typer.rb', line 238
def method_types
@method_types ||= {}
end
|
#name ⇒ Object
46
47
48
|
# File 'lib/duby/typer.rb', line 46
def name
"Simple"
end
|
#plugins ⇒ Object
203
204
205
206
207
208
209
210
211
212
213
214
|
# File 'lib/duby/typer.rb', line 203
def plugins
if cycling?
Duby.typer_plugins.each do |plugin|
log "Invoking plugin: #{plugin}"
result = yield plugin
return result if result
end
end
nil
end
|
#resolve(raise = false) ⇒ Object
310
311
312
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
|
# File 'lib/duby/typer.rb', line 310
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.size == 0
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
50
51
52
|
# File 'lib/duby/typer.rb', line 50
def self_type
known_types["self"]
end
|
#string_type ⇒ Object
66
67
68
|
# File 'lib/duby/typer.rb', line 66
def string_type
known_types["string"]
end
|
#type_definition(name, superclass, interfaces) ⇒ Object
#type_reference(name, array = false, meta = false) ⇒ Object
254
255
256
|
# File 'lib/duby/typer.rb', line 254
def type_reference(name, array=false, meta=false)
AST::TypeReference.new(name, array, meta)
end
|