rdl 1.1.1 → 2.0.0.rc1
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/CHANGES.md +6 -0
- data/README.md +211 -32
- data/gemfiles/Gemfile.travis +1 -1
- data/lib/rdl.rb +85 -18
- data/lib/rdl/info.rb +74 -0
- data/lib/rdl/query.rb +8 -9
- data/lib/rdl/typecheck.rb +1057 -0
- data/lib/rdl/types/annotated_arg.rb +5 -5
- data/lib/rdl/types/{nil.rb → bot.rb} +9 -13
- data/lib/rdl/types/dependent_arg.rb +5 -5
- data/lib/rdl/types/dots_query.rb +2 -0
- data/lib/rdl/types/finitehash.rb +67 -24
- data/lib/rdl/types/generic.rb +13 -21
- data/lib/rdl/types/intersection.rb +9 -8
- data/lib/rdl/types/method.rb +30 -32
- data/lib/rdl/types/nominal.rb +22 -16
- data/lib/rdl/types/optional.rb +8 -22
- data/lib/rdl/types/parser.racc +8 -3
- data/lib/rdl/types/parser.tab.rb +131 -118
- data/lib/rdl/types/singleton.rb +15 -10
- data/lib/rdl/types/structural.rb +6 -6
- data/lib/rdl/types/top.rb +6 -6
- data/lib/rdl/types/tuple.rb +56 -24
- data/lib/rdl/types/type.rb +9 -0
- data/lib/rdl/types/type_inferencer.rb +1 -1
- data/lib/rdl/types/union.rb +52 -26
- data/lib/rdl/types/var.rb +7 -6
- data/lib/rdl/types/vararg.rb +5 -6
- data/lib/rdl/types/wild_query.rb +9 -2
- data/lib/rdl/util.rb +9 -7
- data/lib/rdl/wrap.rb +90 -72
- data/lib/rdl_types.rb +2 -2
- data/rdl.gemspec +6 -8
- data/test/test_alias.rb +4 -3
- data/test/test_contract.rb +5 -4
- data/test/test_dsl.rb +2 -1
- data/test/test_generic.rb +30 -26
- data/test/test_intersection.rb +3 -3
- data/test/test_le.rb +129 -61
- data/test/test_lib_types.rb +3 -2
- data/test/test_member.rb +33 -46
- data/test/test_parser.rb +113 -116
- data/test/test_query.rb +2 -1
- data/test/test_rdl.rb +64 -6
- data/test/test_rdl_type.rb +3 -2
- data/test/test_type_contract.rb +30 -12
- data/test/test_typecheck.rb +893 -0
- data/test/test_types.rb +50 -54
- data/test/test_wrap.rb +2 -1
- data/types/ruby-2.x/_aliases.rb +13 -2
- data/types/ruby-2.x/bigdecimal.rb +60 -85
- data/types/ruby-2.x/bignum.rb +80 -119
- data/types/ruby-2.x/complex.rb +33 -40
- data/types/ruby-2.x/fixnum.rb +81 -120
- data/types/ruby-2.x/float.rb +79 -116
- data/types/ruby-2.x/integer.rb +187 -22
- data/types/ruby-2.x/nil.rb +12 -0
- data/types/ruby-2.x/numeric.rb +38 -38
- data/types/ruby-2.x/object.rb +3 -3
- data/types/ruby-2.x/random.rb +2 -0
- data/types/ruby-2.x/range.rb +20 -19
- data/types/ruby-2.x/rational.rb +40 -40
- data/types/ruby-2.x/regexp.rb +4 -4
- data/types/ruby-2.x/string.rb +15 -17
- metadata +17 -16
- data/lib/rdl/types/.#lexer.rex +0 -1
data/lib/rdl/types/wild_query.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative 'type_query'
|
2
|
-
|
3
1
|
module RDL::Type
|
4
2
|
class WildQuery < TypeQuery
|
5
3
|
@@cache = nil
|
@@ -18,9 +16,18 @@ module RDL::Type
|
|
18
16
|
end
|
19
17
|
|
20
18
|
def ==(other)
|
19
|
+
return false if other.nil?
|
20
|
+
other = other.canonical
|
21
21
|
return (other.instance_of? WildQuery)
|
22
22
|
end
|
23
23
|
|
24
|
+
alias eql? ==
|
25
|
+
|
26
|
+
def <=(other)
|
27
|
+
other = other.canonical
|
28
|
+
return self == other
|
29
|
+
end
|
30
|
+
|
24
31
|
def match(other)
|
25
32
|
return true
|
26
33
|
end
|
data/lib/rdl/util.rb
CHANGED
@@ -2,6 +2,7 @@ class RDL::Util
|
|
2
2
|
|
3
3
|
SINGLETON_MARKER = "[s]"
|
4
4
|
SINGLETON_MARKER_REGEXP = Regexp.escape(SINGLETON_MARKER)
|
5
|
+
GLOBAL_NAME = "_Globals" # something that's not a valid class name
|
5
6
|
|
6
7
|
def self.to_class(klass)
|
7
8
|
return klass if klass.class == Class
|
@@ -30,14 +31,15 @@ class RDL::Util
|
|
30
31
|
return SINGLETON_MARKER + klass
|
31
32
|
end
|
32
33
|
|
34
|
+
# Duplicate method...
|
33
35
|
# Klass should be a string and may have a singleton marker
|
34
|
-
def self.pretty_name(klass, meth)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
36
|
+
# def self.pretty_name(klass, meth)
|
37
|
+
# if klass =~ /^#{SINGLETON_MARKER_REGEXP}(.*)/
|
38
|
+
# return "#{$1}.#{meth}"
|
39
|
+
# else
|
40
|
+
# return "#{klass}##{meth}"
|
41
|
+
# end
|
42
|
+
# end
|
41
43
|
|
42
44
|
def self.method_defined?(klass, method)
|
43
45
|
begin
|
data/lib/rdl/wrap.rb
CHANGED
@@ -7,42 +7,14 @@ class RDL::Wrap
|
|
7
7
|
klass = klass.to_s
|
8
8
|
meth = meth.to_sym
|
9
9
|
while $__rdl_aliases[klass] && $__rdl_aliases[klass][meth]
|
10
|
-
|
10
|
+
if $__rdl_info.has_any?(klass, meth, [:pre, :post, :type])
|
11
|
+
raise RuntimeError, "Alias #{klass}\##{meth} has contracts. Contracts are only allowed on methods, not aliases."
|
12
|
+
end
|
11
13
|
meth = $__rdl_aliases[klass][meth]
|
12
14
|
end
|
13
15
|
return meth
|
14
16
|
end
|
15
17
|
|
16
|
-
def self.add_contract(klass, meth, kind, val)
|
17
|
-
klass = klass.to_s
|
18
|
-
meth = meth.to_sym
|
19
|
-
$__rdl_contracts[klass] = {} unless $__rdl_contracts[klass]
|
20
|
-
$__rdl_contracts[klass][meth] = {} unless $__rdl_contracts[klass][meth]
|
21
|
-
$__rdl_contracts[klass][meth][kind] = [] unless $__rdl_contracts[klass][meth][kind]
|
22
|
-
$__rdl_contracts[klass][meth][kind] << val
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.has_contracts?(klass, meth, kind)
|
26
|
-
klass = klass.to_s
|
27
|
-
meth = meth.to_sym
|
28
|
-
return ($__rdl_contracts.has_key? klass) &&
|
29
|
-
($__rdl_contracts[klass].has_key? meth) &&
|
30
|
-
($__rdl_contracts[klass][meth].has_key? kind)
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.has_any_contracts?(klass, meth)
|
34
|
-
klass = klass.to_s
|
35
|
-
meth = meth.to_sym
|
36
|
-
return ($__rdl_contracts.has_key? klass) &&
|
37
|
-
($__rdl_contracts[klass].has_key? meth)
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.get_contracts(klass, meth, kind)
|
41
|
-
klass = klass.to_s
|
42
|
-
meth = meth.to_sym
|
43
|
-
return $__rdl_contracts[klass][meth][kind]
|
44
|
-
end
|
45
|
-
|
46
18
|
def self.get_type_params(klass)
|
47
19
|
klass = klass.to_s
|
48
20
|
$__rdl_type_params[klass]
|
@@ -52,12 +24,13 @@ class RDL::Wrap
|
|
52
24
|
# [+meth+] may be a String or Symbol
|
53
25
|
#
|
54
26
|
# Wraps klass#method to check contracts and types. Does not rewrap
|
55
|
-
# if already wrapped.
|
27
|
+
# if already wrapped. Also records source location of method.
|
56
28
|
def self.wrap(klass_str, meth)
|
57
29
|
$__rdl_wrap_switch.off {
|
58
30
|
klass_str = klass_str.to_s
|
59
31
|
klass = RDL::Util.to_class klass_str
|
60
32
|
return if wrapped? klass, meth
|
33
|
+
$__rdl_info.set(klass_str, meth, :source_location, klass.instance_method(meth).source_location) # get locs for nowrap meths!
|
61
34
|
return if RDL::Config.instance.nowrap.member? klass
|
62
35
|
raise ArgumentError, "Attempt to wrap #{klass.to_s}\##{meth.to_s}" if klass.to_s =~ /^RDL::/
|
63
36
|
meth_old = wrapped_name(klass, meth) # meth_old is a symbol
|
@@ -79,24 +52,21 @@ class RDL::Wrap
|
|
79
52
|
inst = @__rdl_inst if defined? @__rdl_inst
|
80
53
|
inst = Hash[$__rdl_type_params[klass][0].zip []] if (not(inst) && $__rdl_type_params[klass])
|
81
54
|
inst = {} if not inst
|
82
|
-
#{if not(is_singleton_method) then "inst[:self] = RDL::Type::
|
55
|
+
#{if not(is_singleton_method) then "inst[:self] = RDL::Type::NominalType.new(self.class)" end}
|
83
56
|
# puts "Intercepted #{full_method_name}(\#{args.join(", ")}) { \#{blk} }, inst = \#{inst.inspect}"
|
84
57
|
meth = RDL::Wrap.resolve_alias(klass, #{meth.inspect})
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
if
|
90
|
-
types = RDL::Wrap.get_contracts(klass, meth, :type)
|
58
|
+
RDL::Typecheck.typecheck(klass, meth) if $__rdl_info.get(klass, meth, :typecheck)
|
59
|
+
pres = $__rdl_info.get(klass, meth, :pre)
|
60
|
+
RDL::Contract::AndContract.check_array(pres, self, *args, &blk) if pres
|
61
|
+
types = $__rdl_info.get(klass, meth, :type)
|
62
|
+
if types
|
91
63
|
matches,args,blk,bind = RDL::Type::MethodType.check_arg_types("#{full_method_name}", self, bind, types, inst, *args, &blk)
|
92
64
|
end
|
93
65
|
}
|
94
66
|
ret = send(#{meth_old.inspect}, *args, &blk)
|
95
67
|
$__rdl_wrap_switch.off {
|
96
|
-
|
97
|
-
|
98
|
-
RDL::Contract::AndContract.check_array(posts, self, ret, *args, &blk)
|
99
|
-
end
|
68
|
+
posts = $__rdl_info.get(klass, meth, :post)
|
69
|
+
RDL::Contract::AndContract.check_array(posts, self, ret, *args, &blk) if posts
|
100
70
|
if matches
|
101
71
|
ret = RDL::Type::MethodType.check_ret_types(self, "#{full_method_name}", types, inst, matches, ret, bind, *args, &blk)
|
102
72
|
end
|
@@ -213,6 +183,7 @@ class Object
|
|
213
183
|
# [+klass+] may be Class, Symbol, or String
|
214
184
|
# [+method+] may be Symbol or String
|
215
185
|
# [+contract+] must be a Contract
|
186
|
+
# [+wrap+] indicates whether the contract should be enforced (true) or just recorded (false)
|
216
187
|
#
|
217
188
|
# Add a precondition to a method. Possible invocations:
|
218
189
|
# pre(klass, meth, contract)
|
@@ -221,35 +192,39 @@ class Object
|
|
221
192
|
# pre(meth) { block } = pre(self, meth, FlatContract.new { block })
|
222
193
|
# pre(contract) = pre(self, next method, contract)
|
223
194
|
# pre { block } = pre(self, next method, FlatContract.new { block })
|
224
|
-
def pre(*args, &blk)
|
195
|
+
def pre(*args, wrap: true, &blk)
|
225
196
|
$__rdl_contract_switch.off { # Don't check contracts inside RDL code itself
|
226
197
|
klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Precondition", *args, &blk)
|
227
198
|
if meth
|
228
|
-
|
229
|
-
if
|
230
|
-
RDL::
|
231
|
-
|
232
|
-
|
199
|
+
$__rdl_info.add(klass, meth, :pre, contract)
|
200
|
+
if wrap
|
201
|
+
if RDL::Util.method_defined?(klass, meth) || meth == :initialize # there is always an initialize
|
202
|
+
RDL::Wrap.wrap(klass, meth)
|
203
|
+
else
|
204
|
+
$__rdl_to_wrap << [klass, meth]
|
205
|
+
end
|
233
206
|
end
|
234
207
|
else
|
235
|
-
$__rdl_deferred << [klass, :pre, contract]
|
208
|
+
$__rdl_deferred << [klass, :pre, contract, {wrap: wrap}]
|
236
209
|
end
|
237
210
|
}
|
238
211
|
end
|
239
212
|
|
240
213
|
# Add a postcondition to a method. Same possible invocations as pre.
|
241
|
-
def post(*args, &blk)
|
214
|
+
def post(*args, wrap: true, &blk)
|
242
215
|
$__rdl_contract_switch.off {
|
243
216
|
klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Postcondition", *args, &blk)
|
244
217
|
if meth
|
245
|
-
|
246
|
-
if
|
247
|
-
RDL::
|
248
|
-
|
249
|
-
|
218
|
+
$__rdl_info.add(klass, meth, :post, contract)
|
219
|
+
if wrap
|
220
|
+
if RDL::Util.method_defined?(klass, meth) || meth == :initialize
|
221
|
+
RDL::Wrap.wrap(klass, meth)
|
222
|
+
else
|
223
|
+
$__rdl_to_wrap << [klass, meth]
|
224
|
+
end
|
250
225
|
end
|
251
226
|
else
|
252
|
-
$__rdl_deferred << [klass, :post, contract]
|
227
|
+
$__rdl_deferred << [klass, :post, contract, {wrap: wrap}]
|
253
228
|
end
|
254
229
|
}
|
255
230
|
end
|
@@ -257,12 +232,14 @@ class Object
|
|
257
232
|
# [+klass+] may be Class, Symbol, or String
|
258
233
|
# [+method+] may be Symbol or String
|
259
234
|
# [+type+] may be Type or String
|
235
|
+
# [+wrap+] indicates whether the type should be enforced (true) or just recorded (false)
|
236
|
+
# [+typecheck+] indicates whether the method should be statically checked against this type (not yet implemented)
|
260
237
|
#
|
261
238
|
# Set a method's type. Possible invocations:
|
262
239
|
# type(klass, meth, type)
|
263
240
|
# type(meth, type)
|
264
241
|
# type(type)
|
265
|
-
def type(*args, &blk)
|
242
|
+
def type(*args, wrap: true, typecheck: false, typecheck_now: false, &blk)
|
266
243
|
$__rdl_contract_switch.off {
|
267
244
|
klass, meth, type = begin
|
268
245
|
RDL::Wrap.process_type_args(self, *args, &blk)
|
@@ -281,18 +258,37 @@ class Object
|
|
281
258
|
# if (meth.to_s[-1] == "?") && (type.ret != $__rdl_type_bool)
|
282
259
|
# warn "#{RDL::Util.pp_klass_method(klass, meth)}: methods that end in ? should have return type %bool"
|
283
260
|
# end
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
261
|
+
$__rdl_info.add(klass, meth, :type, type)
|
262
|
+
unless $__rdl_info.set(klass, meth, :typecheck, typecheck)
|
263
|
+
raise RuntimeError, "Inconsistent typecheck flag on #{klass}##{meth}"
|
264
|
+
end
|
265
|
+
if wrap
|
266
|
+
if RDL::Util.method_defined?(klass, meth) || meth == :initialize
|
267
|
+
RDL::Typecheck.typecheck(klass, meth) if typecheck_now
|
268
|
+
RDL::Wrap.wrap(klass, meth)
|
269
|
+
else
|
270
|
+
$__rdl_to_wrap << [klass, meth]
|
271
|
+
$__rdl_to_typecheck_now << [klass, meth] if typecheck_now
|
272
|
+
end
|
289
273
|
end
|
290
274
|
else
|
291
|
-
$__rdl_deferred << [klass, :type, type
|
275
|
+
$__rdl_deferred << [klass, :type, type, {wrap: wrap,
|
276
|
+
typecheck: typecheck,
|
277
|
+
typecheck_now: typecheck_now}]
|
292
278
|
end
|
293
279
|
}
|
294
280
|
end
|
295
281
|
|
282
|
+
def var_type(klass=self, var, typ)
|
283
|
+
raise RuntimeError, "Variable cannot begin with capital" if var.to_s =~ /^[A-Z]/
|
284
|
+
return if var.to_s =~ /^[a-z]/ # local variables handled specially, inside type checker
|
285
|
+
raise Runtimeerror, "Global variables can't be typed in a class" unless klass = self
|
286
|
+
klass = RDL::Util::GLOBAL_NAME if var.to_s =~ /^\$/
|
287
|
+
unless $__rdl_info.set(klass, var, :type, $__rdl_parser.scan_str("#T #{typ}"))
|
288
|
+
raise RuntimeError, "Type already declared for #{var}"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
296
292
|
def self.method_added(meth)
|
297
293
|
$__rdl_contract_switch.off {
|
298
294
|
klass = self.to_s
|
@@ -302,10 +298,15 @@ class Object
|
|
302
298
|
if $__rdl_deferred.size > 0
|
303
299
|
a = $__rdl_deferred
|
304
300
|
$__rdl_deferred = [] # Reset before doing more work to avoid infinite recursion
|
305
|
-
a.each { |prev_klass, kind, contract|
|
301
|
+
a.each { |prev_klass, kind, contract, h|
|
306
302
|
raise RuntimeError, "Deferred contract from class #{prev_klass} being applied in class #{klass}" if prev_klass != klass
|
307
|
-
|
308
|
-
RDL::Wrap.wrap(klass, meth)
|
303
|
+
$__rdl_info.add(klass, meth, kind, contract)
|
304
|
+
RDL::Wrap.wrap(klass, meth) if h[:wrap]
|
305
|
+
RDL::Typecheck.typecheck(klass, meth) if h[:typecheck_now]
|
306
|
+
unless $__rdl_info.set(klass, meth, :typecheck, h[:typecheck])
|
307
|
+
raise RuntimeError, "Inconsistent typecheck flag on #{klass}##{meth}"
|
308
|
+
end
|
309
|
+
|
309
310
|
# It turns out Ruby core/stdlib don't always follow this convention...
|
310
311
|
# if (kind == :type) && (meth.to_s[-1] == "?") && (contract.ret != $__rdl_type_bool)
|
311
312
|
# warn "#{RDL::Util.pp_klass_method(klass, meth)}: methods that end in ? should have return type %bool"
|
@@ -318,6 +319,12 @@ class Object
|
|
318
319
|
$__rdl_to_wrap.delete [klass, meth]
|
319
320
|
RDL::Wrap.wrap(klass, meth)
|
320
321
|
end
|
322
|
+
|
323
|
+
# Type check method if requested; must typecheck before wrap
|
324
|
+
if $__rdl_to_typecheck_now.member? [klass, meth]
|
325
|
+
$__rdl_to_typecheck_now.delete [klass, meth]
|
326
|
+
RDL::Typecheck.typecheck(klass, meth)
|
327
|
+
end
|
321
328
|
}
|
322
329
|
end
|
323
330
|
|
@@ -331,10 +338,14 @@ class Object
|
|
331
338
|
if $__rdl_deferred.size > 0
|
332
339
|
a = $__rdl_deferred
|
333
340
|
$__rdl_deferred = [] # Reset before doing more work to avoid infinite recursion
|
334
|
-
a.each { |prev_klass, kind, contract|
|
341
|
+
a.each { |prev_klass, kind, contract, h|
|
335
342
|
raise RuntimeError, "Deferred contract from class #{prev_klass} being applied in class #{klass}" if prev_klass != klass
|
336
|
-
|
337
|
-
RDL::Wrap.wrap(sklass, meth)
|
343
|
+
$__rdl_info.add(sklass, meth, kind, contract)
|
344
|
+
RDL::Wrap.wrap(sklass, meth) if h[:wrap]
|
345
|
+
RDL::Typecheck.typecheck(sklass, meth) if h[:typecheck_now]
|
346
|
+
unless $__rdl_info.set(klass, meth, :typecheck, h[:typecheck])
|
347
|
+
raise RuntimeError, "Inconsistent typecheck flag on #{klass}##{meth}"
|
348
|
+
end
|
338
349
|
}
|
339
350
|
end
|
340
351
|
|
@@ -343,6 +354,12 @@ class Object
|
|
343
354
|
$__rdl_to_wrap.delete [sklass, meth]
|
344
355
|
RDL::Wrap.wrap(sklass, meth)
|
345
356
|
end
|
357
|
+
|
358
|
+
# Type check method if requested
|
359
|
+
if $__rdl_to_typecheck_now.member? [sklass, meth]
|
360
|
+
$__rdl_to_typecheck_now.delete [sklass, meth]
|
361
|
+
RDL::Typecheck.typecheck(sklass, meth)
|
362
|
+
end
|
346
363
|
}
|
347
364
|
end
|
348
365
|
|
@@ -451,10 +468,11 @@ class Object
|
|
451
468
|
}
|
452
469
|
end
|
453
470
|
|
454
|
-
# Returns a new object that wraps self in a type cast.
|
455
|
-
def type_cast(typ)
|
471
|
+
# Returns a new object that wraps self in a type cast. If force is true this cast is *unchecked*, so use with caution
|
472
|
+
def type_cast(typ, force: false)
|
456
473
|
$__rdl_contract_switch.off {
|
457
474
|
new_typ = if typ.is_a? RDL::Type::Type then typ else $__rdl_parser.scan_str "#T #{typ}" end
|
475
|
+
raise RuntimeError, "type cast error: self not a member of #{new_typ}" unless force || typ.member?(self)
|
458
476
|
obj = SimpleDelegator.new(self)
|
459
477
|
obj.instance_variable_set('@__rdl_type', new_typ)
|
460
478
|
return obj
|
data/lib/rdl_types.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
dir = RUBY_VERSION.split('.')[0] + ".x"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_relative "../types/ruby-#{dir}/_aliases.rb" # load type aliases first
|
4
|
+
Dir[File.dirname(__FILE__) + "/../types/ruby-#{dir}/*.rb"].each { |f| require f }
|
data/rdl.gemspec
CHANGED
@@ -4,15 +4,13 @@
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'rdl'
|
7
|
-
s.version = '
|
8
|
-
s.date = '2016-
|
7
|
+
s.version = '2.0.0.rc1'
|
8
|
+
s.date = '2016-07-17'
|
9
9
|
s.summary = 'Ruby type and contract system'
|
10
10
|
s.description = <<-EOF
|
11
|
-
RDL is a gem that
|
12
|
-
|
13
|
-
|
14
|
-
RDL also includes extensive support for type contracts, which check the types of arguments and returns
|
15
|
-
when the method is called and when it returns, respectively.
|
11
|
+
RDL is a gem that adds types and contracts to Ruby. RDL includes extensive
|
12
|
+
support for specifying method types, which can either be enforced as
|
13
|
+
contracts or statically checked.
|
16
14
|
EOF
|
17
15
|
s.authors = ['Jeffrey S. Foster', 'Brianna M. Ren', 'T. Stephen Strickland', 'Alexander T. Yu', 'Milod Kazerounian']
|
18
16
|
s.email = ['rdl-users@googlegroups.com']
|
@@ -20,5 +18,5 @@ EOF
|
|
20
18
|
s.executables << 'rdl_query'
|
21
19
|
s.homepage = 'https://github.com/plum-umd/rdl'
|
22
20
|
s.license = 'BSD-3-Clause'
|
23
|
-
s.add_runtime_dependency '
|
21
|
+
s.add_runtime_dependency 'parser', '~>2.3', '>= 2.3.1.2'
|
24
22
|
end
|
data/test/test_alias.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
|
-
|
2
|
+
$LOAD_PATH << File.dirname(__FILE__) + "/../lib"
|
3
|
+
require 'rdl'
|
3
4
|
|
4
5
|
class TestAlias < Minitest::Test
|
5
6
|
|
@@ -62,5 +63,5 @@ class TestAlias < Minitest::Test
|
|
62
63
|
assert_equal 3, m10(3)
|
63
64
|
assert_raises(RDL::Contract::ContractError) { m10(-1) }
|
64
65
|
end
|
65
|
-
|
66
|
-
end
|
66
|
+
|
67
|
+
end
|
data/test/test_contract.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
|
-
|
2
|
+
$LOAD_PATH << File.dirname(__FILE__) + "/../lib"
|
3
|
+
require 'rdl'
|
3
4
|
|
4
5
|
class TestContract < Minitest::Test
|
5
6
|
include RDL::Contract
|
@@ -26,7 +27,7 @@ class TestContract < Minitest::Test
|
|
26
27
|
assert (posfivegt.check self, 5)
|
27
28
|
assert_raises(ContractError) { posfivegt.check self, 4 }
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
def test_or
|
31
32
|
pos = FlatContract.new("Positive") { |x| x > 0 }
|
32
33
|
zero = FlatContract.new("Zero") { |x| x == 0 }
|
@@ -58,7 +59,7 @@ class TestContract < Minitest::Test
|
|
58
59
|
proc = pc.wrap(self) { |x, &blk| blk.call(x) }
|
59
60
|
assert_equal 42, (proc.call(42) { |y| y })
|
60
61
|
end
|
61
|
-
|
62
|
+
|
62
63
|
def test_turn_off
|
63
64
|
foo = FlatContract.new("Foo") {
|
64
65
|
pos = FlatContract.new("Positive") { |x| x > 0 }
|
@@ -67,4 +68,4 @@ class TestContract < Minitest::Test
|
|
67
68
|
}
|
68
69
|
assert_equal true, foo.check(self)
|
69
70
|
end
|
70
|
-
end
|
71
|
+
end
|
data/test/test_dsl.rb
CHANGED
data/test/test_generic.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
|
-
|
2
|
+
$LOAD_PATH << File.dirname(__FILE__) + "/../lib"
|
3
|
+
require 'rdl'
|
3
4
|
|
4
5
|
class TestGeneric < Minitest::Test
|
5
6
|
|
@@ -32,22 +33,18 @@ class TestGeneric < Minitest::Test
|
|
32
33
|
nil
|
33
34
|
end
|
34
35
|
end
|
35
|
-
|
36
|
+
|
36
37
|
def setup
|
37
38
|
@ta = RDL::Type::NominalType.new "TestGeneric::A"
|
38
39
|
@th = RDL::Type::NominalType.new "TestGeneric::H"
|
39
|
-
@
|
40
|
-
@
|
41
|
-
@tfixnum = RDL::Type::NominalType.new "Fixnum"
|
42
|
-
@tas = RDL::Type::GenericType.new(@ta, @tstring)
|
43
|
-
@tao = RDL::Type::GenericType.new(@ta, @tobject)
|
40
|
+
@tas = RDL::Type::GenericType.new(@ta, $__rdl_string_type)
|
41
|
+
@tao = RDL::Type::GenericType.new(@ta, $__rdl_object_type)
|
44
42
|
@taas = RDL::Type::GenericType.new(@ta, @tas)
|
45
43
|
@taao = RDL::Type::GenericType.new(@ta, @tao)
|
46
|
-
@thss = RDL::Type::GenericType.new(@th,
|
47
|
-
@thoo = RDL::Type::GenericType.new(@th,
|
48
|
-
@thsf = RDL::Type::GenericType.new(@th,
|
44
|
+
@thss = RDL::Type::GenericType.new(@th, $__rdl_string_type, $__rdl_string_type)
|
45
|
+
@thoo = RDL::Type::GenericType.new(@th, $__rdl_object_type, $__rdl_object_type)
|
46
|
+
@thsf = RDL::Type::GenericType.new(@th, $__rdl_string_type, $__rdl_fixnum_type)
|
49
47
|
@tb = RDL::Type::NominalType.new "TestGeneric::B"
|
50
|
-
@tnil = RDL::Type::NilType.new
|
51
48
|
end
|
52
49
|
|
53
50
|
def test_le
|
@@ -71,10 +68,10 @@ class TestGeneric < Minitest::Test
|
|
71
68
|
assert (not (@thss <= @th))
|
72
69
|
|
73
70
|
# Check co- and contravariance using B
|
74
|
-
tbss = RDL::Type::GenericType.new(@tb,
|
75
|
-
tbso = RDL::Type::GenericType.new(@tb,
|
76
|
-
tbos = RDL::Type::GenericType.new(@tb,
|
77
|
-
tboo = RDL::Type::GenericType.new(@tb,
|
71
|
+
tbss = RDL::Type::GenericType.new(@tb, $__rdl_string_type, $__rdl_string_type)
|
72
|
+
tbso = RDL::Type::GenericType.new(@tb, $__rdl_string_type, $__rdl_object_type)
|
73
|
+
tbos = RDL::Type::GenericType.new(@tb, $__rdl_object_type, $__rdl_string_type)
|
74
|
+
tboo = RDL::Type::GenericType.new(@tb, $__rdl_object_type, $__rdl_object_type)
|
78
75
|
assert (tbss <= tbss)
|
79
76
|
assert (not (tbss <= tbso))
|
80
77
|
assert (tbss <= tbos)
|
@@ -94,10 +91,10 @@ class TestGeneric < Minitest::Test
|
|
94
91
|
end
|
95
92
|
|
96
93
|
def test_le_structural
|
97
|
-
tbss = RDL::Type::GenericType.new(@tb,
|
98
|
-
tma = RDL::Type::MethodType.new([], nil,
|
99
|
-
tmb = RDL::Type::MethodType.new([
|
100
|
-
tmc = RDL::Type::MethodType.new([
|
94
|
+
tbss = RDL::Type::GenericType.new(@tb, $__rdl_string_type, $__rdl_string_type)
|
95
|
+
tma = RDL::Type::MethodType.new([], nil, $__rdl_nil_type)
|
96
|
+
tmb = RDL::Type::MethodType.new([$__rdl_string_type], nil, $__rdl_nil_type)
|
97
|
+
tmc = RDL::Type::MethodType.new([$__rdl_fixnum_type], nil, $__rdl_nil_type)
|
101
98
|
ts1 = RDL::Type::StructuralType.new(m2: tma)
|
102
99
|
assert (tbss <= ts1)
|
103
100
|
ts2 = RDL::Type::StructuralType.new(m1: tmb)
|
@@ -109,18 +106,25 @@ class TestGeneric < Minitest::Test
|
|
109
106
|
ts5 = RDL::Type::StructuralType.new(m1: tmb, m2: tmc)
|
110
107
|
assert (tbss <= ts5)
|
111
108
|
end
|
112
|
-
|
109
|
+
|
113
110
|
class C
|
114
111
|
type "() -> self"
|
115
112
|
def m1() return self; end
|
116
113
|
type "() -> self"
|
117
114
|
def m2() return C.new; end
|
115
|
+
type "() -> self"
|
116
|
+
def m3() return Object.new; end
|
118
117
|
end
|
119
|
-
|
118
|
+
|
119
|
+
class D < C
|
120
|
+
end
|
121
|
+
|
120
122
|
def test_self_type
|
121
123
|
c = C.new
|
122
124
|
assert(c.m1)
|
123
|
-
|
125
|
+
assert(c.m2)
|
126
|
+
assert_raises(RDL::Type::TypeError) { c.m3 }
|
127
|
+
assert(D.new.m1)
|
124
128
|
end
|
125
129
|
|
126
130
|
def test_member
|
@@ -137,17 +141,17 @@ class TestGeneric < Minitest::Test
|
|
137
141
|
end
|
138
142
|
|
139
143
|
def test_instantiate
|
140
|
-
assert_raises(RuntimeError) { Object.new.instantiate!(
|
141
|
-
|
144
|
+
assert_raises(RuntimeError) { Object.new.instantiate!($__rdl_string_type) }
|
145
|
+
|
142
146
|
# Array<String>
|
143
147
|
assert (A.new([]).instantiate!('String'))
|
144
|
-
assert (A.new(["a", "b", "c"]).instantiate!(
|
148
|
+
assert (A.new(["a", "b", "c"]).instantiate!($__rdl_string_type))
|
145
149
|
assert (A.new(["a", "b", "c"]).instantiate!('String'))
|
146
150
|
assert_raises(RDL::Type::TypeError) { A.new([1, 2, 3]).instantiate!('String') }
|
147
151
|
|
148
152
|
# Array<Object>
|
149
153
|
assert (A.new([])).instantiate!('Object')
|
150
|
-
assert (A.new(["a", "b", "c"]).instantiate!(
|
154
|
+
assert (A.new(["a", "b", "c"]).instantiate!($__rdl_object_type))
|
151
155
|
assert (A.new(["a", "b", "c"]).instantiate!('Object'))
|
152
156
|
assert (A.new([1, 2, 3]).instantiate!('Object'))
|
153
157
|
|