yadriggy 1.0.0
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 +7 -0
- data/.gitignore +13 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +108 -0
- data/Rakefile +10 -0
- data/lib/yadriggy.rb +32 -0
- data/lib/yadriggy/algebra.rb +497 -0
- data/lib/yadriggy/ast.rb +1839 -0
- data/lib/yadriggy/ast_location.rb +73 -0
- data/lib/yadriggy/ast_value.rb +428 -0
- data/lib/yadriggy/c.rb +11 -0
- data/lib/yadriggy/c/c.rb +220 -0
- data/lib/yadriggy/c/codegen.rb +481 -0
- data/lib/yadriggy/c/config.rb +51 -0
- data/lib/yadriggy/c/ctype.rb +118 -0
- data/lib/yadriggy/c/ctypecheck.rb +449 -0
- data/lib/yadriggy/c/ffi.rb +301 -0
- data/lib/yadriggy/c/opencl.rb +458 -0
- data/lib/yadriggy/c/program.rb +86 -0
- data/lib/yadriggy/c1.rb +10 -0
- data/lib/yadriggy/checker.rb +216 -0
- data/lib/yadriggy/eval.rb +200 -0
- data/lib/yadriggy/eval_all.rb +159 -0
- data/lib/yadriggy/pretty_print.rb +492 -0
- data/lib/yadriggy/printer.rb +82 -0
- data/lib/yadriggy/ruby_typecheck.rb +468 -0
- data/lib/yadriggy/ruby_typeinfer.rb +335 -0
- data/lib/yadriggy/source_code.rb +168 -0
- data/lib/yadriggy/syntax.rb +524 -0
- data/lib/yadriggy/type.rb +754 -0
- data/lib/yadriggy/typecheck.rb +277 -0
- data/lib/yadriggy/version.rb +5 -0
- data/yadriggy.gemspec +33 -0
- metadata +149 -0
@@ -0,0 +1,754 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
module Yadriggy
|
4
|
+
# @abstract
|
5
|
+
# Root of the classes representing a type.
|
6
|
+
# A {Type} object may consist of a chain of multiple {Type} objects.
|
7
|
+
#
|
8
|
+
# Don't use `is_a?` but use `has_role?` or `role`.
|
9
|
+
#
|
10
|
+
class Type
|
11
|
+
# @private
|
12
|
+
def self.get_instance_method_object(recv_type, method_name)
|
13
|
+
recv_type.get_method_object(method_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Raises an error.
|
17
|
+
# @param [String] msg an error message.
|
18
|
+
def self.error_found!(msg)
|
19
|
+
raise TypeChecker::CheckError.new(msg)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Obtains the name of this type.
|
23
|
+
# @return [String] the type name.
|
24
|
+
def name()
|
25
|
+
to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
# Makes a copy of self. Note that a {Type} object may consist of
|
29
|
+
# a chain of multiple {Type} objects. The copied chain does not
|
30
|
+
# contain an instance of `without_role`.
|
31
|
+
#
|
32
|
+
# @param [Class] without_role a subclass of {OptionalRole}.
|
33
|
+
# @return [Type] the copy.
|
34
|
+
def copy(without_role)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check the inequality.
|
39
|
+
# @return [Boolean] false if `self` and `t` represent the same type.
|
40
|
+
def != (t)
|
41
|
+
!(self == t)
|
42
|
+
end
|
43
|
+
|
44
|
+
# An alias to `==`.
|
45
|
+
# @return [Boolean] true if `self` and `t` represent the same type.
|
46
|
+
def eql?(t)
|
47
|
+
self == t
|
48
|
+
end
|
49
|
+
|
50
|
+
# Check the subtype relation.
|
51
|
+
# @param [Type] t the other type.
|
52
|
+
# @return [Boolean] true if `self` is equivalent to `t` or a subtpye of `t`
|
53
|
+
def <= (t)
|
54
|
+
self == t
|
55
|
+
end
|
56
|
+
|
57
|
+
# @private
|
58
|
+
# Only {DynType}, {UnionType} and {OptionalRole} override this method.
|
59
|
+
def is_super_of? (t)
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
# Finds an instance of the receiver class in the chain starting with
|
64
|
+
# the given {Type} object.
|
65
|
+
# If such an instance is not found, the method returns nil.
|
66
|
+
# Also see {OptionalRole}.
|
67
|
+
#
|
68
|
+
# @param [Type] type a Type object.
|
69
|
+
# @return [Type|nil] an instance of the receiver class.
|
70
|
+
def self.role(type)
|
71
|
+
if type.is_a?(Type)
|
72
|
+
type.has_role?(self)
|
73
|
+
else
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Finds an instance of the receiver class in the chain starting
|
79
|
+
# with `self`.
|
80
|
+
# If such an instance is not found, the method returns `nil`.
|
81
|
+
# Also see {OptionalRole}.
|
82
|
+
#
|
83
|
+
# @param [Module] a_role a subclass of Type.
|
84
|
+
# @return [Type|nil] an instance of `a_role`.
|
85
|
+
def has_role?(a_role)
|
86
|
+
if self.is_a?(a_role)
|
87
|
+
self
|
88
|
+
else
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Gets the Ruby class represented by this Type.
|
94
|
+
# @return [Module|DynType] the corresponding Ruby class or {DynType}.
|
95
|
+
def exact_type
|
96
|
+
DynType
|
97
|
+
end
|
98
|
+
|
99
|
+
# @private
|
100
|
+
# Gets a method with the given name declared in this type.
|
101
|
+
# `nil` is returned when the method is not exactly determined.
|
102
|
+
#
|
103
|
+
# @return [Method|nil]
|
104
|
+
def get_method_object(method_name)
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
|
108
|
+
# @return [Type] the type containing a wider range of values.
|
109
|
+
def supertype
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# @private
|
115
|
+
class NonRubyType < Type
|
116
|
+
def initialize(obj_name, type_name)
|
117
|
+
@obj_name = obj_name
|
118
|
+
@type_name = type_name
|
119
|
+
end
|
120
|
+
|
121
|
+
# Obtains the name of this type.
|
122
|
+
# @return [String] the type name.
|
123
|
+
def name
|
124
|
+
@type_name
|
125
|
+
end
|
126
|
+
|
127
|
+
# Checks the equality.
|
128
|
+
# @param [Type] t the other type.
|
129
|
+
# @return [Boolean] true if `self` and `t` represent the same type.
|
130
|
+
def == (t)
|
131
|
+
r = NonRubyType.role(t)
|
132
|
+
self.equal?(r)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Check the subtype relation.
|
136
|
+
# @param [Type] t the other type.
|
137
|
+
# @return [Boolean] true if `self` is equivalent to `t`.
|
138
|
+
def <= (t)
|
139
|
+
self == t || t.is_super_of?(self)
|
140
|
+
end
|
141
|
+
|
142
|
+
def role(t)
|
143
|
+
r = NonRubyType.role(t)
|
144
|
+
self.equal?(r) ? self : nil
|
145
|
+
end
|
146
|
+
|
147
|
+
def inspect()
|
148
|
+
@obj_name
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Dynamic type.
|
153
|
+
DynType = NonRubyType.new('#<Yadriggy::DynType>', 'DynType')
|
154
|
+
|
155
|
+
# @private
|
156
|
+
def DynType.is_super_of?(t)
|
157
|
+
true
|
158
|
+
end
|
159
|
+
|
160
|
+
# Void type.
|
161
|
+
Void = NonRubyType.new('#<Yadriggy::Void>', 'Void')
|
162
|
+
|
163
|
+
# Union type. A value of this type is a value of one of
|
164
|
+
# the given types.
|
165
|
+
class UnionType < Type
|
166
|
+
# @return [Array<Type>] the given types.
|
167
|
+
attr_reader :types
|
168
|
+
|
169
|
+
# Makes an instance of {UnionType}
|
170
|
+
# @param [Array<Type>] ts the types included in the union type.
|
171
|
+
# @return [UnionType|DynType] the instance.
|
172
|
+
def self.make(*ts)
|
173
|
+
fts = ts.flatten
|
174
|
+
fts.each do |e|
|
175
|
+
return DynType if DynType == e
|
176
|
+
end
|
177
|
+
|
178
|
+
t = UnionType.new(fts)
|
179
|
+
if t.types.size == 1
|
180
|
+
t.types[0]
|
181
|
+
else
|
182
|
+
t
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# @param [Array<Type>] ts the types included in the union type.
|
187
|
+
def initialize(*ts)
|
188
|
+
@types = ts.flatten.map {|e| UnionType.role(e)&.types || e }.flatten.uniq
|
189
|
+
end
|
190
|
+
|
191
|
+
# Checks equality.
|
192
|
+
# Ignores {OptionalRole} when comparing two {UnionType}s.
|
193
|
+
# @param [Type] t the other type.
|
194
|
+
# @return [Boolean] true if `self` is equivalent to `t`.
|
195
|
+
def == (t)
|
196
|
+
ut = UnionType.role(t)
|
197
|
+
!ut.nil? && @types.size == ut.types.size &&
|
198
|
+
(normalize(self) | normalize(ut)).size <= @types.size
|
199
|
+
end
|
200
|
+
|
201
|
+
# @private
|
202
|
+
def normalize(utype)
|
203
|
+
utype.types.map {|e| e.copy(OptionalRole) }
|
204
|
+
end
|
205
|
+
|
206
|
+
# @private
|
207
|
+
def hash
|
208
|
+
@types.hash
|
209
|
+
end
|
210
|
+
|
211
|
+
# @private
|
212
|
+
# Check the subtype relation.
|
213
|
+
# @param [Type] t the other type.
|
214
|
+
# @return [Boolean] true if `self` is equivalent to `t`
|
215
|
+
# or a subtype of `t`.
|
216
|
+
def <= (t)
|
217
|
+
DynType == t || @types.all? {|e| e <= t }
|
218
|
+
end
|
219
|
+
|
220
|
+
# @param [Type] t a type.
|
221
|
+
# @return [Boolean] true if `self` is a super type of `t`.
|
222
|
+
def is_super_of?(t)
|
223
|
+
@types.any? {|e| t <= e }
|
224
|
+
end
|
225
|
+
|
226
|
+
# Obtains the name of this type.
|
227
|
+
# @return [String] the type name.
|
228
|
+
def name
|
229
|
+
name = '(' << @types.map{|e| e.name }.join('|') << ')'
|
230
|
+
name
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# The most specific common super type.
|
235
|
+
# A value of this type is either an instance of `self.type`
|
236
|
+
# or a subclass of `self.type`.
|
237
|
+
#
|
238
|
+
class CommonSuperType < Type
|
239
|
+
# @return [Module] the common super type.
|
240
|
+
attr_reader :type
|
241
|
+
|
242
|
+
# @param [Module] t the type.
|
243
|
+
def initialize(t)
|
244
|
+
@type = t
|
245
|
+
end
|
246
|
+
|
247
|
+
# @private
|
248
|
+
def == (t)
|
249
|
+
CommonSuperType.role(t)&.type == @type
|
250
|
+
end
|
251
|
+
|
252
|
+
# @private
|
253
|
+
def hash
|
254
|
+
@type.hash + 1
|
255
|
+
end
|
256
|
+
|
257
|
+
# @private
|
258
|
+
# Check the subtype relation.
|
259
|
+
# @param [Type] t the other type.
|
260
|
+
# @return [Boolean] true if `self` is equivalent to `t`
|
261
|
+
# or a subtype of `t`.
|
262
|
+
def <= (t)
|
263
|
+
if t.is_super_of?(self)
|
264
|
+
true
|
265
|
+
else
|
266
|
+
ct = CommonSuperType.role(t)
|
267
|
+
!ct.nil? && (@type <= ct.type || @type == NilClass)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# @private
|
272
|
+
def get_method_object(method_name)
|
273
|
+
nil
|
274
|
+
end
|
275
|
+
|
276
|
+
# @return [CommonSuperType|nil] the {CommonSuperType} for the super class.
|
277
|
+
def supertype
|
278
|
+
if @type.is_a?(Class) && !@type.superclass.nil?
|
279
|
+
CommonSuperType.new(@type.superclass)
|
280
|
+
else
|
281
|
+
nil
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# Obtains the name of this type.
|
286
|
+
# @return [String] the type name.
|
287
|
+
def name
|
288
|
+
@type.name + '+'
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Type of immediate instances of a Ruby class.
|
293
|
+
# The instances of its subclass are excluded.
|
294
|
+
# A class type including its subclasses is represented
|
295
|
+
# by {CommonSuperType}.
|
296
|
+
#
|
297
|
+
class RubyClass < Type
|
298
|
+
# @private
|
299
|
+
Table = {}
|
300
|
+
|
301
|
+
# @private
|
302
|
+
def self.make(clazz)
|
303
|
+
obj = RubyClass.new(clazz)
|
304
|
+
Table[clazz] = obj
|
305
|
+
obj
|
306
|
+
end
|
307
|
+
|
308
|
+
# @private
|
309
|
+
def self.set_alias(clazz, ruby_class)
|
310
|
+
Table[clazz] = ruby_class
|
311
|
+
end
|
312
|
+
|
313
|
+
# @param [Module|Object] clazz a Ruby class or module.
|
314
|
+
# @return [RubyClass|Object] a {RubyClass} object for `clazz`
|
315
|
+
# if `clazz` is an instance of `Module`. Otherwise, `clazz`
|
316
|
+
# is returned. For example, `RubyClass[Void]` returns `Void`.
|
317
|
+
def self.[](clazz)
|
318
|
+
Table[clazz] || (clazz.is_a?(::Module) ? RubyClass.new(clazz) : clazz)
|
319
|
+
end
|
320
|
+
|
321
|
+
# @param [Module] clazz the Ruby class or module.
|
322
|
+
def initialize(clazz)
|
323
|
+
@ruby_class = clazz
|
324
|
+
end
|
325
|
+
|
326
|
+
# Checks the equality.
|
327
|
+
# @param [Type|Module] t the other object.
|
328
|
+
# @return [Boolean] true if `self` and `t` represent the same Ruby class.
|
329
|
+
def == (t)
|
330
|
+
RubyClass.role(t)&.exact_type == @ruby_class
|
331
|
+
end
|
332
|
+
|
333
|
+
# @private
|
334
|
+
def hash
|
335
|
+
@ruby_class.hash
|
336
|
+
end
|
337
|
+
|
338
|
+
# @private
|
339
|
+
# Check the subtype relation.
|
340
|
+
# @param [Type] t the other type.
|
341
|
+
# @return [Boolean] true if `self` is equivalent to `t`
|
342
|
+
# or a subtype of `t`.
|
343
|
+
def <= (t)
|
344
|
+
if t.is_super_of?(self)
|
345
|
+
true
|
346
|
+
else
|
347
|
+
rc = RubyClass.role(t)
|
348
|
+
if rc.nil?
|
349
|
+
CommonSuperType.new(@ruby_class) <= t
|
350
|
+
else
|
351
|
+
rc.exact_type == @ruby_class || @ruby_class == ::NilClass
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# @private
|
357
|
+
def get_method_object(method_name)
|
358
|
+
@ruby_class.instance_method(method_name)
|
359
|
+
rescue NameError
|
360
|
+
Type.error_found!("no such method: #{@ruby_class}\##{method_name}")
|
361
|
+
end
|
362
|
+
|
363
|
+
# @private
|
364
|
+
def exact_type
|
365
|
+
@ruby_class
|
366
|
+
end
|
367
|
+
|
368
|
+
# @return [CommonSuperType] the {CommonSuperType} for this class.
|
369
|
+
def supertype
|
370
|
+
CommonSuperType.new(@ruby_class)
|
371
|
+
end
|
372
|
+
|
373
|
+
# Obtains the name of this type.
|
374
|
+
# @return [String] the type name.
|
375
|
+
def name
|
376
|
+
@ruby_class.name
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
RubyClass::Symbol = RubyClass.make(Symbol)
|
381
|
+
RubyClass::String = RubyClass.make(String)
|
382
|
+
RubyClass::Integer = RubyClass.make(Integer)
|
383
|
+
RubyClass::Float = RubyClass.make(Float)
|
384
|
+
RubyClass::Range = RubyClass.make(Range)
|
385
|
+
RubyClass::Hash = RubyClass.make(Hash)
|
386
|
+
RubyClass::Array = RubyClass.make(Array)
|
387
|
+
RubyClass::Proc = RubyClass.make(Proc)
|
388
|
+
RubyClass::Exception = RubyClass.make(Exception)
|
389
|
+
RubyClass::TrueClass = RubyClass.make(TrueClass)
|
390
|
+
RubyClass::FalseClass = RubyClass.make(FalseClass)
|
391
|
+
|
392
|
+
# Fixnum is a subclass of Integer in Ruby earlier than 2.4.
|
393
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4')
|
394
|
+
RubyClass.set_alias(Fixnum, RubyClass::Integer)
|
395
|
+
end
|
396
|
+
|
397
|
+
# The type for `nil`. Although ::NilClass is not a subtype of
|
398
|
+
# other classes, RubyClass::NilClass is a subtype of {RubyClass::String},
|
399
|
+
# etc.
|
400
|
+
RubyClass::NilClass = RubyClass.make(NilClass)
|
401
|
+
|
402
|
+
# An instance of {UnionType}. It represents either `TrueClass` or
|
403
|
+
# `FalseClass`.
|
404
|
+
RubyClass::Boolean = UnionType.new([RubyClass::TrueClass,
|
405
|
+
RubyClass::FalseClass])
|
406
|
+
|
407
|
+
# An instance of {CommonSuperType}. It represents `::Numeric` class.
|
408
|
+
RubyClass::Numeric = CommonSuperType.new(Numeric)
|
409
|
+
|
410
|
+
# Type of a particular Ruby object.
|
411
|
+
#
|
412
|
+
class InstanceType < Type
|
413
|
+
# @return [Object] the Ruby object.
|
414
|
+
attr_reader :object
|
415
|
+
|
416
|
+
def initialize(obj)
|
417
|
+
@object = obj
|
418
|
+
end
|
419
|
+
|
420
|
+
# @private
|
421
|
+
def == (t)
|
422
|
+
InstanceType.role(t)&.object == @object
|
423
|
+
end
|
424
|
+
|
425
|
+
# @private
|
426
|
+
def hash
|
427
|
+
@object.hash
|
428
|
+
end
|
429
|
+
|
430
|
+
# @private
|
431
|
+
# Check the subtype relation.
|
432
|
+
# @param [Type] t the other type.
|
433
|
+
# @return [Boolean] true if `self` is equivalent to `t`
|
434
|
+
# or a subtype of `t`.
|
435
|
+
def <= (t)
|
436
|
+
if t.is_super_of?(self)
|
437
|
+
true
|
438
|
+
else
|
439
|
+
it = InstanceType.role(t)
|
440
|
+
(!it.nil? && it.object == @object) ||
|
441
|
+
RubyClass[exact_type] <= t
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
# @private
|
446
|
+
# Recall that `1.class` was `Fixnum` in Ruby earlier than 2.4.
|
447
|
+
def exact_type
|
448
|
+
@object.is_a?(Integer) ? Integer : @object.class
|
449
|
+
end
|
450
|
+
|
451
|
+
# @private
|
452
|
+
def get_method_object(method_name)
|
453
|
+
@object.method(method_name)
|
454
|
+
rescue NameError
|
455
|
+
Type.error_found!("no such method: #{@object.class}\##{method_name}")
|
456
|
+
end
|
457
|
+
|
458
|
+
# @return [RubyClass] the {RubyClass} for this class.
|
459
|
+
def supertype
|
460
|
+
RubyClass[exact_type]
|
461
|
+
end
|
462
|
+
|
463
|
+
# Obtains the name of this type.
|
464
|
+
# @return [String] the type name.
|
465
|
+
def name
|
466
|
+
@object.to_s
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
# Type of methods.
|
471
|
+
#
|
472
|
+
class MethodType < Type
|
473
|
+
# @param [Parameters|nil] method_def method definition.
|
474
|
+
# @param [Array<Type|Module>|DynType] param_type_array parameter types.
|
475
|
+
# `param_type_array` can be {DynType}.
|
476
|
+
# @param [Type|Module|DynType] result_type the result type.
|
477
|
+
def initialize(method_def=nil, param_type_array, result_type)
|
478
|
+
@param_types = if param_type_array.is_a?(Array)
|
479
|
+
param_type_array.map do |t|
|
480
|
+
t.is_a?(Type) ? t : RubyClass[t]
|
481
|
+
end
|
482
|
+
else
|
483
|
+
param_type_array
|
484
|
+
end
|
485
|
+
@result_type = if result_type.is_a?(Type)
|
486
|
+
result_type
|
487
|
+
else
|
488
|
+
RubyClass[result_type]
|
489
|
+
end
|
490
|
+
@method_def = method_def
|
491
|
+
end
|
492
|
+
|
493
|
+
# Gets an array of the parameter types.
|
494
|
+
# @return [Array<Type>|DynType] the parameter types.
|
495
|
+
def params() @param_types end
|
496
|
+
|
497
|
+
# @return [Type] the result type.
|
498
|
+
def result_type() @result_type end
|
499
|
+
|
500
|
+
# @return [Parameters] the method definition.
|
501
|
+
def method_def() @method_def end
|
502
|
+
|
503
|
+
# @private
|
504
|
+
def == (t)
|
505
|
+
mt = MethodType.role(t)
|
506
|
+
!mt.nil? && @result_type == mt.result_type && @param_types == mt.params
|
507
|
+
end
|
508
|
+
|
509
|
+
# @private
|
510
|
+
def hash
|
511
|
+
@result_type.hash + @param_types.hash
|
512
|
+
end
|
513
|
+
|
514
|
+
# @private
|
515
|
+
def <= (t)
|
516
|
+
if t.is_super_of?(self)
|
517
|
+
true
|
518
|
+
else
|
519
|
+
mt = MethodType.role(t)
|
520
|
+
!mt.nil? && @result_type <= mt.result_type &&
|
521
|
+
compare_params(mt.params, @param_types)
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
# @return [ResultType] the result type. Note that a {ResultType} object
|
526
|
+
# is always returned.
|
527
|
+
def result()
|
528
|
+
ResultType.new(@result_type, @method_def)
|
529
|
+
end
|
530
|
+
|
531
|
+
# Obtains the name of this type.
|
532
|
+
# @return [String] the type name.
|
533
|
+
def name
|
534
|
+
name = ''
|
535
|
+
if @param_types.is_a?(Array)
|
536
|
+
name << '(' << @param_types.map{|e| e.name }.join(',') << ')'
|
537
|
+
else
|
538
|
+
name << @param_types.name
|
539
|
+
end
|
540
|
+
name << '->' << @result_type.name
|
541
|
+
name
|
542
|
+
end
|
543
|
+
|
544
|
+
private
|
545
|
+
|
546
|
+
# @return [Boolean] true if p <= q
|
547
|
+
def compare_params(p, q)
|
548
|
+
if p.is_a?(Array) && q.is_a?(Array)
|
549
|
+
p.size == q.size &&
|
550
|
+
(0...p.size).reduce(true) {|b,i| b && p[i] <= q[i] }
|
551
|
+
else
|
552
|
+
DynType == q
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
# Parametric types.
|
558
|
+
#
|
559
|
+
class CompositeType < Type
|
560
|
+
# @return [Module] type name. The value is a Ruby class.
|
561
|
+
attr_reader :ruby_class
|
562
|
+
# @return [Array<Type>] type arguments.
|
563
|
+
attr_reader :args
|
564
|
+
|
565
|
+
# @param [Module] name type name.
|
566
|
+
# @param [Array<Type>|Type] args type arguments.
|
567
|
+
def initialize(name, args)
|
568
|
+
@ruby_class = name
|
569
|
+
@args = args.is_a?(Array) ? args : [ args ]
|
570
|
+
end
|
571
|
+
|
572
|
+
# @return [Type] the first type argument.
|
573
|
+
def first_arg
|
574
|
+
@args[0]
|
575
|
+
end
|
576
|
+
|
577
|
+
# Checks the equality.
|
578
|
+
# @param [Type|Module] t the other object.
|
579
|
+
# @return [Boolean] true if `self` and `t` represent the same type
|
580
|
+
# and their type arguments are equivalent.
|
581
|
+
def == (t)
|
582
|
+
ct = CompositeType.role(t)
|
583
|
+
!ct.nil? && ct.ruby_class == @ruby_class &&
|
584
|
+
ct.args == @args
|
585
|
+
end
|
586
|
+
|
587
|
+
# @private
|
588
|
+
def hash
|
589
|
+
@ruby_class.hash + @args.reduce(0) {|h,p| h + p.hash }
|
590
|
+
end
|
591
|
+
|
592
|
+
# @private
|
593
|
+
# Check the subtype relation.
|
594
|
+
# @param [Type] t the other type.
|
595
|
+
# @return [Boolean] true if `self` is equivalent to `t`
|
596
|
+
# or a subtype of `t`.
|
597
|
+
def <= (t)
|
598
|
+
if t.is_super_of?(self)
|
599
|
+
true
|
600
|
+
else
|
601
|
+
ct = CompositeType.role(t)
|
602
|
+
if ct.nil?
|
603
|
+
RubyClass[@ruby_class] <= t
|
604
|
+
else
|
605
|
+
ct.ruby_class == @ruby_class &&
|
606
|
+
@args.zip(ct.args).all? {|tt| tt[0] <= tt[1] }
|
607
|
+
end
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
# @private
|
612
|
+
def exact_type
|
613
|
+
@ruby_class
|
614
|
+
end
|
615
|
+
|
616
|
+
# @return [RubyClass] the {RubyClass} for this class.
|
617
|
+
def supertype
|
618
|
+
RubyClass[@ruby_class]
|
619
|
+
end
|
620
|
+
|
621
|
+
# Obtains the name of this type.
|
622
|
+
# @return [String] the type name.
|
623
|
+
def name
|
624
|
+
name = @ruby_class.name
|
625
|
+
name << '<' << @args.map{|e| e.name }.join(',') << '>'
|
626
|
+
name
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
# A role that can be attached to a {Type} object.
|
631
|
+
# It makes a chain of {Type} objects.
|
632
|
+
#
|
633
|
+
class OptionalRole < Type
|
634
|
+
# @param [Type] type a Type object that this role is added to.
|
635
|
+
def initialize(type)
|
636
|
+
@type = type
|
637
|
+
end
|
638
|
+
|
639
|
+
# @private
|
640
|
+
def copy(without_role)
|
641
|
+
chain = @type.copy(without_role)
|
642
|
+
if self.is_a?(without_role)
|
643
|
+
chain
|
644
|
+
else
|
645
|
+
if @type.equal?(chain)
|
646
|
+
self
|
647
|
+
else
|
648
|
+
new_self = self.clone()
|
649
|
+
new_self.update_type = chain
|
650
|
+
new_self
|
651
|
+
end
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
# @private
|
656
|
+
def update_type(t)
|
657
|
+
@type = t
|
658
|
+
end
|
659
|
+
|
660
|
+
# Checks the equality. The roles (a {OptionalRole} objects) in the chain
|
661
|
+
# are ignored when objects are compared.
|
662
|
+
def == (t)
|
663
|
+
@type == t
|
664
|
+
end
|
665
|
+
|
666
|
+
# @private
|
667
|
+
def hash
|
668
|
+
@type.hash
|
669
|
+
end
|
670
|
+
|
671
|
+
# @private
|
672
|
+
def <= (t)
|
673
|
+
@type <= t
|
674
|
+
end
|
675
|
+
|
676
|
+
# @private
|
677
|
+
def is_super_of?(t)
|
678
|
+
@type.is_super_of?(t)
|
679
|
+
end
|
680
|
+
|
681
|
+
# @private
|
682
|
+
def has_role?(a_role)
|
683
|
+
if self.is_a?(a_role)
|
684
|
+
self
|
685
|
+
else
|
686
|
+
@type.has_role?(a_role)
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
# @private
|
691
|
+
def exact_type
|
692
|
+
@type.exact_type
|
693
|
+
end
|
694
|
+
|
695
|
+
# @private
|
696
|
+
def get_method_object(method_name)
|
697
|
+
Type.get_instance_method_object(@type, method_name)
|
698
|
+
end
|
699
|
+
|
700
|
+
# @return [Type] the super type.
|
701
|
+
def supertype
|
702
|
+
@type.supertype
|
703
|
+
end
|
704
|
+
end # of OptionalRole
|
705
|
+
|
706
|
+
# Type of values returned by a method.
|
707
|
+
#
|
708
|
+
class ResultType < OptionalRole
|
709
|
+
# @return [Parameters] The definition of the method returning
|
710
|
+
# a value of this type.
|
711
|
+
attr_reader :method_def
|
712
|
+
|
713
|
+
# @param [Type] type a Type object that this role is added to.
|
714
|
+
# @param [Parameters] method_def the method.
|
715
|
+
def initialize(type, method_def)
|
716
|
+
super(type)
|
717
|
+
@method_def = method_def
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
# Type of the value of a local variable.
|
722
|
+
#
|
723
|
+
class LocalVarType < OptionalRole
|
724
|
+
# @return [ASTnode|Undef|nil] the AST node where the variable appears
|
725
|
+
# for the first time, in other words,
|
726
|
+
# where the variable's type is defined.
|
727
|
+
# `Undef` if a value is assigned to the variable
|
728
|
+
# more than once.
|
729
|
+
# `nil` if an initial value has not been assigned
|
730
|
+
# to the variable yet.
|
731
|
+
attr_reader :definition
|
732
|
+
|
733
|
+
# @param [Type] type a Type object that this role is added to.
|
734
|
+
# @param [ASTnode|nil] definition the AST node of the local variable.
|
735
|
+
# `nil` if an initial value is not set.
|
736
|
+
def initialize(type, definition)
|
737
|
+
super(type)
|
738
|
+
@definition = definition
|
739
|
+
end
|
740
|
+
|
741
|
+
# @param [ASTnode] ast the AST node of the local variable where
|
742
|
+
# a new value is assigned to it.
|
743
|
+
# @return [self]
|
744
|
+
def definition=(ast)
|
745
|
+
if @definition.nil?
|
746
|
+
@definition = ast
|
747
|
+
else
|
748
|
+
@definition = Undef
|
749
|
+
end
|
750
|
+
self
|
751
|
+
end
|
752
|
+
|
753
|
+
end
|
754
|
+
end
|