duby 0.0.1
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.
- data/History.txt +4 -0
- data/Manifest.txt +68 -0
- data/README.txt +31 -0
- data/Rakefile +37 -0
- data/bin/duby +9 -0
- data/bin/dubyc +9 -0
- data/bin/dubyp +9 -0
- data/examples/appengine/src/com/google/appengine/ext/duby/db/Model.duby +132 -0
- data/examples/appengine/src/com/ribrdb/DubyApp.duby +28 -0
- data/examples/bench_fractal.duby +57 -0
- data/examples/construction.duby +8 -0
- data/examples/edb.duby +3 -0
- data/examples/fib.duby +24 -0
- data/examples/fields.duby +22 -0
- data/examples/java_thing.duby +13 -0
- data/examples/simple_class.duby +12 -0
- data/examples/swing.duby +20 -0
- data/examples/tak.duby +15 -0
- data/javalib/JRubyParser.jar +0 -0
- data/lib/duby.rb +170 -0
- data/lib/duby/ast.rb +340 -0
- data/lib/duby/ast/call.rb +73 -0
- data/lib/duby/ast/class.rb +145 -0
- data/lib/duby/ast/flow.rb +328 -0
- data/lib/duby/ast/intrinsics.rb +46 -0
- data/lib/duby/ast/literal.rb +93 -0
- data/lib/duby/ast/local.rb +77 -0
- data/lib/duby/ast/method.rb +187 -0
- data/lib/duby/ast/structure.rb +44 -0
- data/lib/duby/ast/type.rb +93 -0
- data/lib/duby/c/compiler.rb +134 -0
- data/lib/duby/compiler.rb +261 -0
- data/lib/duby/jvm/compiler.rb +684 -0
- data/lib/duby/jvm/method_lookup.rb +185 -0
- data/lib/duby/jvm/source_compiler.rb +516 -0
- data/lib/duby/jvm/source_generator/builder.rb +368 -0
- data/lib/duby/jvm/source_generator/loops.rb +132 -0
- data/lib/duby/jvm/source_generator/precompile.rb +154 -0
- data/lib/duby/jvm/source_generator/typer.rb +11 -0
- data/lib/duby/jvm/typer.rb +118 -0
- data/lib/duby/jvm/types.rb +326 -0
- data/lib/duby/jvm/types/basic_types.rb +18 -0
- data/lib/duby/jvm/types/boolean.rb +11 -0
- data/lib/duby/jvm/types/factory.rb +151 -0
- data/lib/duby/jvm/types/floats.rb +70 -0
- data/lib/duby/jvm/types/integers.rb +110 -0
- data/lib/duby/jvm/types/intrinsics.rb +157 -0
- data/lib/duby/jvm/types/literals.rb +82 -0
- data/lib/duby/jvm/types/methods.rb +344 -0
- data/lib/duby/jvm/types/number.rb +92 -0
- data/lib/duby/nbcompiler.rb +29 -0
- data/lib/duby/old/compiler_old.rb +845 -0
- data/lib/duby/old/declaration.rb +72 -0
- data/lib/duby/old/mapper.rb +72 -0
- data/lib/duby/old/signature.rb +52 -0
- data/lib/duby/old/typer_old.rb +163 -0
- data/lib/duby/plugin/edb.rb +25 -0
- data/lib/duby/plugin/java.rb +42 -0
- data/lib/duby/plugin/math.rb +84 -0
- data/lib/duby/transform.rb +908 -0
- data/lib/duby/typer.rb +359 -0
- data/test/test_ast.rb +391 -0
- data/test/test_compilation.rb +98 -0
- data/test/test_java_typer.rb +199 -0
- data/test/test_javac_compiler.rb +57 -0
- data/test/test_jvm_compiler.rb +1459 -0
- data/test/test_math_plugin.rb +87 -0
- data/test/test_typer.rb +246 -0
- metadata +155 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
module Duby::AST
|
2
|
+
class FunctionalCall < Node
|
3
|
+
include Named
|
4
|
+
attr_accessor :parameters, :block, :cast
|
5
|
+
alias cast? cast
|
6
|
+
|
7
|
+
def initialize(parent, line_number, name, &kids)
|
8
|
+
super(parent, line_number, &kids)
|
9
|
+
@parameters, @block = children
|
10
|
+
@name = name
|
11
|
+
@cast = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def infer(typer)
|
15
|
+
@self_type ||= typer.self_type
|
16
|
+
|
17
|
+
unless @inferred_type
|
18
|
+
receiver_type = @self_type
|
19
|
+
should_defer = false
|
20
|
+
|
21
|
+
parameter_types = parameters.map do |param|
|
22
|
+
typer.infer(param) || should_defer = true
|
23
|
+
end
|
24
|
+
|
25
|
+
unless should_defer
|
26
|
+
if parameters.size == 1 && typer.known_types[name]
|
27
|
+
# cast operation
|
28
|
+
resolved!
|
29
|
+
self.cast = true
|
30
|
+
@inferred_type = typer.known_types[name]
|
31
|
+
else
|
32
|
+
@inferred_type = typer.method_type(receiver_type, name,
|
33
|
+
parameter_types)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@inferred_type ? resolved! : typer.defer(self)
|
38
|
+
end
|
39
|
+
|
40
|
+
@inferred_type
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Call < Node
|
45
|
+
include Named
|
46
|
+
attr_accessor :target, :parameters, :block
|
47
|
+
|
48
|
+
def initialize(parent, line_number, name, &kids)
|
49
|
+
super(parent, line_number, children, &kids)
|
50
|
+
@target, @parameters, @block = children
|
51
|
+
@name = name
|
52
|
+
end
|
53
|
+
|
54
|
+
def infer(typer)
|
55
|
+
unless @inferred_type
|
56
|
+
receiver_type = typer.infer(target)
|
57
|
+
should_defer = false
|
58
|
+
parameter_types = parameters.map do |param|
|
59
|
+
typer.infer(param) || should_defer = true
|
60
|
+
end
|
61
|
+
|
62
|
+
unless should_defer
|
63
|
+
@inferred_type = typer.method_type(receiver_type, name,
|
64
|
+
parameter_types)
|
65
|
+
end
|
66
|
+
|
67
|
+
@inferred_type ? resolved! : typer.defer(self)
|
68
|
+
end
|
69
|
+
|
70
|
+
@inferred_type
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module Duby::AST
|
2
|
+
class ClassDefinition < Node
|
3
|
+
include Named
|
4
|
+
include Scope
|
5
|
+
attr_accessor :superclass, :body, :interfaces
|
6
|
+
|
7
|
+
def initialize(parent, line_number, name, &block)
|
8
|
+
@interfaces = []
|
9
|
+
@name = name
|
10
|
+
if Duby::AST.type_factory.respond_to? :declare_type
|
11
|
+
Duby::AST.type_factory.declare_type(self)
|
12
|
+
end
|
13
|
+
super(parent, line_number, &block)
|
14
|
+
@superclass, @body = children
|
15
|
+
end
|
16
|
+
|
17
|
+
def infer(typer)
|
18
|
+
unless resolved?
|
19
|
+
@inferred_type ||= typer.define_type(name, superclass, @interfaces) do
|
20
|
+
if body
|
21
|
+
typer.infer(body)
|
22
|
+
else
|
23
|
+
typer.no_type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
@inferred_type ? resolved! : typer.defer(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
@inferred_type
|
30
|
+
end
|
31
|
+
|
32
|
+
def implements(*types)
|
33
|
+
raise ArgumentError if types.any? {|x| x.nil?}
|
34
|
+
@interfaces.concat types
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
defmacro('implements') do |transformer, fcall, parent|
|
39
|
+
interfaces = fcall.args_node.child_nodes.map do |interface|
|
40
|
+
interface.type_reference(parent)
|
41
|
+
end
|
42
|
+
parent.parent.implements(*interfaces)
|
43
|
+
Noop.new(parent, fcall.position)
|
44
|
+
end
|
45
|
+
|
46
|
+
class InterfaceDeclaration < ClassDefinition
|
47
|
+
attr_accessor :superclass, :body, :interfaces
|
48
|
+
|
49
|
+
def initialize(parent, line_number, name)
|
50
|
+
super(parent, line_number, name) {|p| }
|
51
|
+
@interfaces = []
|
52
|
+
@name = name
|
53
|
+
@children = yield(self)
|
54
|
+
@interfaces, @body = children
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
defmacro('interface') do |transformer, fcall, parent|
|
59
|
+
raise "Interface name required" unless fcall.args_node
|
60
|
+
interfaces = fcall.args_node.child_nodes.to_a
|
61
|
+
interface_name = interfaces.shift
|
62
|
+
if (JRubyAst::CallNode === interface_name &&
|
63
|
+
interface_name.args_node.size == 1)
|
64
|
+
interfaces.unshift(interface_name.args_node.get(0))
|
65
|
+
interface_name = interface_name.receiver_node
|
66
|
+
end
|
67
|
+
raise 'Interface body required' unless fcall.iter_node
|
68
|
+
InterfaceDeclaration.new(parent, fcall.position,
|
69
|
+
interface_name.name) do |interface|
|
70
|
+
[interfaces.map {|p| p.type_reference(interface)},
|
71
|
+
if fcall.iter_node.body_node
|
72
|
+
transformer.transform(fcall.iter_node.body_node, interface)
|
73
|
+
end
|
74
|
+
]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class FieldDeclaration < Node
|
79
|
+
include Named
|
80
|
+
include ClassScoped
|
81
|
+
include Typed
|
82
|
+
|
83
|
+
def initialize(parent, line_number, name, &block)
|
84
|
+
super(parent, line_number, &block)
|
85
|
+
@name = name
|
86
|
+
@type = children[0]
|
87
|
+
end
|
88
|
+
|
89
|
+
def infer(typer)
|
90
|
+
unless resolved?
|
91
|
+
resolved!
|
92
|
+
@inferred_type = typer.known_types[type]
|
93
|
+
if @inferred_type
|
94
|
+
resolved!
|
95
|
+
typer.learn_field_type(scope, name, @inferred_type)
|
96
|
+
else
|
97
|
+
typer.defer(self)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
@inferred_type
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class FieldAssignment < Node
|
105
|
+
include Named
|
106
|
+
include Valued
|
107
|
+
include ClassScoped
|
108
|
+
|
109
|
+
def initialize(parent, line_number, name, &block)
|
110
|
+
super(parent, line_number, &block)
|
111
|
+
@value = children[0]
|
112
|
+
@name = name
|
113
|
+
end
|
114
|
+
|
115
|
+
def infer(typer)
|
116
|
+
unless resolved?
|
117
|
+
@inferred_type = typer.learn_field_type(scope, name, typer.infer(value))
|
118
|
+
|
119
|
+
@inferred_type ? resolved! : typer.defer(self)
|
120
|
+
end
|
121
|
+
|
122
|
+
@inferred_type
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Field < Node
|
127
|
+
include Named
|
128
|
+
include ClassScoped
|
129
|
+
|
130
|
+
def initialize(parent, line_number, name, &block)
|
131
|
+
super(parent, line_number, &block)
|
132
|
+
@name = name
|
133
|
+
end
|
134
|
+
|
135
|
+
def infer(typer)
|
136
|
+
unless resolved?
|
137
|
+
@inferred_type = typer.field_type(scope, name)
|
138
|
+
|
139
|
+
@inferred_type ? resolved! : typer.defer(self)
|
140
|
+
end
|
141
|
+
|
142
|
+
@inferred_type
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,328 @@
|
|
1
|
+
module Duby
|
2
|
+
module AST
|
3
|
+
class Condition < Node
|
4
|
+
attr_accessor :predicate
|
5
|
+
|
6
|
+
def initialize(parent, line_number, &block)
|
7
|
+
super(parent, line_number, &block)
|
8
|
+
@predicate = children[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
def infer(typer)
|
12
|
+
unless resolved?
|
13
|
+
@inferred_type = typer.infer(predicate)
|
14
|
+
if @inferred_type && !@inferred_type.primitive?
|
15
|
+
call = Call.new(parent, position, '!=') do |call|
|
16
|
+
@predicate.parent = call
|
17
|
+
[@predicate, [Null.new(call, position)]]
|
18
|
+
end
|
19
|
+
@predicate = children[0] = call
|
20
|
+
@inferred_type = typer.infer(predicate)
|
21
|
+
end
|
22
|
+
|
23
|
+
@inferred_type ? resolved! : typer.defer(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
@inferred_type
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class If < Node
|
31
|
+
attr_accessor :condition, :body, :else
|
32
|
+
|
33
|
+
def initialize(parent, line_number, &block)
|
34
|
+
super(parent, line_number, &block)
|
35
|
+
@condition, @body, @else = children
|
36
|
+
end
|
37
|
+
|
38
|
+
def infer(typer)
|
39
|
+
unless resolved?
|
40
|
+
condition_type = typer.infer(condition)
|
41
|
+
unless condition_type
|
42
|
+
typer.defer(condition)
|
43
|
+
end
|
44
|
+
|
45
|
+
# condition type is unrelated to body types, so we proceed with bodies
|
46
|
+
then_type = typer.infer(body) if body
|
47
|
+
|
48
|
+
if !then_type
|
49
|
+
# attempt to determine else branch
|
50
|
+
if self.else
|
51
|
+
else_type = typer.infer(self.else)
|
52
|
+
|
53
|
+
if !else_type
|
54
|
+
# we have neither type, defer until later
|
55
|
+
typer.defer(self)
|
56
|
+
else
|
57
|
+
# we have else but not then, defer only then and use else type for now
|
58
|
+
@inferred_type = else_type
|
59
|
+
typer.defer(self)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
# no then type could be inferred and no else body, defer for now
|
63
|
+
typer.defer(self)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
if self.else
|
67
|
+
else_type = typer.infer(self.else)
|
68
|
+
|
69
|
+
if !else_type
|
70
|
+
# we determined a then type, so we use that and defer the else body
|
71
|
+
@inferred_type = then_type
|
72
|
+
typer.defer(self)
|
73
|
+
else
|
74
|
+
# both then and else inferred, ensure they're compatible
|
75
|
+
if then_type.compatible?(else_type)
|
76
|
+
# types are compatible...if condition is resolved, we're done
|
77
|
+
@inferred_type = then_type.narrow(else_type)
|
78
|
+
resolved! if condition_type
|
79
|
+
else
|
80
|
+
raise Typer::InferenceError.new("if statement with incompatible result types")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
else
|
84
|
+
# only then and type inferred, we're 100% resolved
|
85
|
+
@inferred_type = then_type
|
86
|
+
resolved! if condition_type
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
@inferred_type
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Loop < Node
|
96
|
+
attr_accessor :redo
|
97
|
+
|
98
|
+
def infer(typer)
|
99
|
+
unless resolved?
|
100
|
+
child_types = children.map {|c| typer.infer(c)}
|
101
|
+
if child_types.any? {|t| t.nil?}
|
102
|
+
typer.defer(self)
|
103
|
+
else
|
104
|
+
resolved!
|
105
|
+
@inferred_type = typer.null_type
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
@inferred_type
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class WhileLoop < Loop
|
114
|
+
attr_accessor :condition, :body, :check_first, :negative
|
115
|
+
|
116
|
+
def initialize(parent, line_number, check_first, negative, &block)
|
117
|
+
super(parent, line_number, &block)
|
118
|
+
@condition, @body = children
|
119
|
+
@check_first = check_first
|
120
|
+
@negative = negative
|
121
|
+
end
|
122
|
+
|
123
|
+
def check_first?; @check_first; end
|
124
|
+
def negative?; @negative; end
|
125
|
+
def has_redo?; @redo; end
|
126
|
+
|
127
|
+
def to_s
|
128
|
+
"WhileLoop(check_first = #{check_first?}, negative = #{negative?})"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class ForLoop < Loop
|
133
|
+
attr_reader :name, :body, :iter
|
134
|
+
|
135
|
+
def initialize(parent, position, &block)
|
136
|
+
super(parent, position, &block)
|
137
|
+
var = children.shift
|
138
|
+
@body, @iter = children
|
139
|
+
@scope = var.scope
|
140
|
+
@name = var.name
|
141
|
+
end
|
142
|
+
|
143
|
+
def infer(typer)
|
144
|
+
super
|
145
|
+
iter_type = @iter.inferred_type
|
146
|
+
if iter_type
|
147
|
+
if !iter_type.iterable?
|
148
|
+
raise "#{iter_type} is not iterable."
|
149
|
+
end
|
150
|
+
typer.learn_local_type(@scope, name, iter_type.component_type)
|
151
|
+
end
|
152
|
+
@inferred_type
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class Not < Node
|
157
|
+
def initialize(parent, line_number, &block)
|
158
|
+
super(parent, line_number, &block)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class JumpNode < Node
|
163
|
+
attr_accessor :ensures
|
164
|
+
|
165
|
+
def initialize(parent, line_number, ensures, &block)
|
166
|
+
super(parent, line_number, &block)
|
167
|
+
@ensures = ensures
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class Return < JumpNode
|
172
|
+
include Valued
|
173
|
+
|
174
|
+
def initialize(parent, line_number, ensures, &block)
|
175
|
+
super(parent, line_number, ensures, &block)
|
176
|
+
@value = children[0]
|
177
|
+
end
|
178
|
+
|
179
|
+
def infer(typer)
|
180
|
+
unless resolved?
|
181
|
+
@inferred_type = typer.infer(value)
|
182
|
+
|
183
|
+
(@inferred_type && value.resolved?) ? resolved! : typer.defer(self)
|
184
|
+
end
|
185
|
+
|
186
|
+
@inferred_type
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class Break < JumpNode;
|
191
|
+
def infer(typer)
|
192
|
+
unless resolved?
|
193
|
+
resolved!
|
194
|
+
@inferred_type = typer.null_type
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class Next < Break; end
|
200
|
+
|
201
|
+
class Redo < Break; end
|
202
|
+
|
203
|
+
class Raise < Node
|
204
|
+
include Valued
|
205
|
+
|
206
|
+
def initialize(parent, line_number, &block)
|
207
|
+
super(parent, line_number, &block)
|
208
|
+
end
|
209
|
+
|
210
|
+
def infer(typer)
|
211
|
+
unless resolved?
|
212
|
+
@inferred_type = AST.unreachable_type
|
213
|
+
throwable = AST.type('java.lang.Throwable')
|
214
|
+
if children.size == 1
|
215
|
+
arg_type = typer.infer(children[0])
|
216
|
+
unless arg_type
|
217
|
+
typer.defer(self)
|
218
|
+
return
|
219
|
+
end
|
220
|
+
if throwable.assignable_from?(arg_type) && !arg_type.meta?
|
221
|
+
@exception = children[0]
|
222
|
+
resolved!
|
223
|
+
return @inferred_type
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
arg_types = children.map {|c| typer.infer(c)}
|
228
|
+
if arg_types.any? {|c| c.nil?}
|
229
|
+
typer.defer(self)
|
230
|
+
else
|
231
|
+
if arg_types[0] && throwable.assignable_from?(arg_types[0])
|
232
|
+
klass = children.shift
|
233
|
+
else
|
234
|
+
klass = Constant.new(self, position, 'RuntimeException')
|
235
|
+
end
|
236
|
+
@exception = Call.new(self, position, 'new') do
|
237
|
+
[klass, children, nil]
|
238
|
+
end
|
239
|
+
resolved!
|
240
|
+
@children = [@exception]
|
241
|
+
typer.infer(@exception)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
@inferred_type
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
defmacro('raise') do |transformer, fcall, parent|
|
249
|
+
Raise.new(parent, fcall.position) do |raise_node|
|
250
|
+
if fcall.args_node
|
251
|
+
fcall.args_node.child_nodes.map do |arg|
|
252
|
+
transformer.transform(arg, raise_node)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
class RescueClause < Node
|
259
|
+
include Scoped
|
260
|
+
attr_accessor :types, :body, :name, :type
|
261
|
+
|
262
|
+
def initialize(parent, position, &block)
|
263
|
+
super(parent, position, &block)
|
264
|
+
@types, @body = children
|
265
|
+
end
|
266
|
+
|
267
|
+
def infer(typer)
|
268
|
+
unless resolved?
|
269
|
+
if name
|
270
|
+
orig_type = typer.local_type(scope, name)
|
271
|
+
# TODO find the common parent Throwable
|
272
|
+
@type = types.size == 1 ? types[0] : AST.type('java.lang.Throwable')
|
273
|
+
typer.learn_local_type(scope, name, @type)
|
274
|
+
end
|
275
|
+
@inferred_type = typer.infer(body)
|
276
|
+
|
277
|
+
(@inferred_type && body.resolved?) ? resolved! : typer.defer(self)
|
278
|
+
typer.local_type_hash(scope)[name] = orig_type if name
|
279
|
+
end
|
280
|
+
|
281
|
+
@inferred_type
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
class Rescue < Node
|
286
|
+
attr_accessor :body, :clauses
|
287
|
+
def initialize(parent, position, &block)
|
288
|
+
super(parent, position, &block)
|
289
|
+
@body, @clauses = children
|
290
|
+
end
|
291
|
+
|
292
|
+
def infer(typer)
|
293
|
+
unless resolved?
|
294
|
+
types = [typer.infer(body)] + clauses.map {|c| typer.infer(c)}
|
295
|
+
if types.any? {|t| t.nil?}
|
296
|
+
typer.defer(self)
|
297
|
+
else
|
298
|
+
# TODO check types for compatibility (maybe only if an expression)
|
299
|
+
resolved!
|
300
|
+
@inferred_type = types[0]
|
301
|
+
end
|
302
|
+
end
|
303
|
+
@inferred_type
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class Ensure < Node
|
308
|
+
attr_reader :body, :clause
|
309
|
+
attr_accessor :state # Used by the some compilers.
|
310
|
+
|
311
|
+
def initialize(parent, position, &block)
|
312
|
+
super(parent, position, &block)
|
313
|
+
@body, @clause = children
|
314
|
+
end
|
315
|
+
|
316
|
+
def infer(typer)
|
317
|
+
resolve_if(typer) do
|
318
|
+
typer.infer(clause)
|
319
|
+
typer.infer(body)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def ensures
|
324
|
+
[self]
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|