yadriggy 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,51 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
module Yadriggy
|
4
|
+
module C
|
5
|
+
|
6
|
+
# Compiler options etc.
|
7
|
+
#
|
8
|
+
module Config
|
9
|
+
# Host OS
|
10
|
+
# @return [Symbol] `:linux`, `:macos`, `:unknown`.
|
11
|
+
HostOS = case RbConfig::CONFIG['host_os']
|
12
|
+
when /linux/
|
13
|
+
:linux
|
14
|
+
when /darwin/
|
15
|
+
:macos
|
16
|
+
else
|
17
|
+
:unknown
|
18
|
+
end
|
19
|
+
|
20
|
+
# Working directory.
|
21
|
+
WorkDir = './yadriggy_tmp'
|
22
|
+
|
23
|
+
# Compiler command.
|
24
|
+
# @return [String]
|
25
|
+
Compiler = 'gcc -shared -fPIC -Ofast '
|
26
|
+
|
27
|
+
# Compiler option specifying the output file.
|
28
|
+
# @return [String]
|
29
|
+
CoptOutput = '-o '
|
30
|
+
|
31
|
+
# The suffix to the name of a shared library such as `.so`.
|
32
|
+
# It has to start with a dot.
|
33
|
+
LibExtension = HostOS == :macos ? '.dylib' : '.so'
|
34
|
+
|
35
|
+
# Lines inserted in the generated C source file.
|
36
|
+
Headers = [
|
37
|
+
'#include <stdint.h>',
|
38
|
+
'#include <time.h>',
|
39
|
+
'#include <math.h>',
|
40
|
+
'#include <stdio.h>'
|
41
|
+
]
|
42
|
+
|
43
|
+
# Compiler option for OpenCL
|
44
|
+
# @return [String]
|
45
|
+
OpenCLoptions = '-framework opencl '
|
46
|
+
|
47
|
+
# Lines inserted in the generated OpenCL source file.
|
48
|
+
OpenCLHeaders = [ '#include <OpenCL/opencl.h>' ]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy'
|
4
|
+
require 'yadriggy/c/ffi'
|
5
|
+
|
6
|
+
module Yadriggy
|
7
|
+
module C
|
8
|
+
# Types availalbe in C code.
|
9
|
+
module CType
|
10
|
+
def typedecl(arg) end
|
11
|
+
def arrayof(t) t end
|
12
|
+
|
13
|
+
# Single-precision floating point numbers.
|
14
|
+
# This is used only as a type name.
|
15
|
+
# Note that `Float` represents double-precision floating point numbers.
|
16
|
+
# Do not make an instance.
|
17
|
+
class Float32
|
18
|
+
end
|
19
|
+
|
20
|
+
# @private
|
21
|
+
# An alias `RubyClass[Float32]`.
|
22
|
+
Float32Type = RubyClass[Float32]
|
23
|
+
|
24
|
+
Void = Yadriggy::Void # void
|
25
|
+
Int = Integer # int32_t
|
26
|
+
|
27
|
+
IntArray = Yadriggy::C::IntArray
|
28
|
+
FloatArray = Yadriggy::C::FloatArray
|
29
|
+
Float32Array = Yadriggy::C::Float32Array
|
30
|
+
|
31
|
+
# Types available only as a value of instance variable.
|
32
|
+
class IvarObj
|
33
|
+
include Yadriggy::C::CType
|
34
|
+
end
|
35
|
+
|
36
|
+
# @private
|
37
|
+
# Array type available only in C code.
|
38
|
+
# See also {IntArray} and {FloatArray} in `ffi.rb`.
|
39
|
+
class CArray < IvarObj
|
40
|
+
# @private
|
41
|
+
def typedecl(arg) end
|
42
|
+
|
43
|
+
# debug mode.
|
44
|
+
attr_accessor :debug
|
45
|
+
|
46
|
+
# @return [Array<Integer>] sizes array size.
|
47
|
+
attr_reader :sizes
|
48
|
+
|
49
|
+
# @param [Array<Integer>] sizes size of each dimension.
|
50
|
+
def initialize(*sizes)
|
51
|
+
raise 'unknown array size' unless sizes.size > 0
|
52
|
+
@sizes = sizes
|
53
|
+
@debug = false
|
54
|
+
end
|
55
|
+
|
56
|
+
# @private
|
57
|
+
# @abstract
|
58
|
+
# @return [Type] the element type.
|
59
|
+
def type()
|
60
|
+
Undef
|
61
|
+
end
|
62
|
+
|
63
|
+
# @private
|
64
|
+
def check_range(indexes)
|
65
|
+
raise 'wrong number of indexes' unless indexes.size == @sizes.size
|
66
|
+
indexes.each_index do |i|
|
67
|
+
if indexes[i] >= @sizes[i]
|
68
|
+
raise "out of range: #{self.to_s}[#{indexes[i]}]"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Array of 32bit integers available only in C.
|
75
|
+
#
|
76
|
+
# @see IntArray
|
77
|
+
class IntCArray < CArray
|
78
|
+
def type()
|
79
|
+
RubyClass::Integer
|
80
|
+
end
|
81
|
+
|
82
|
+
def [](*indexes)
|
83
|
+
typedecl foreign: Int
|
84
|
+
check_range(indexes)
|
85
|
+
raise 'IntCArray is not available in Ruby' unless @debug
|
86
|
+
end
|
87
|
+
|
88
|
+
def []=(*indexes)
|
89
|
+
typedecl foreign: Void
|
90
|
+
check_range(indexes[0, indexes.size - 1])
|
91
|
+
raise 'IntCArray is not available in Ruby' unless @debug
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Array of floating point numbers available only in C.
|
96
|
+
#
|
97
|
+
# @see FloatArray
|
98
|
+
class FloatCArray < CArray
|
99
|
+
def type()
|
100
|
+
RubyClass::Float
|
101
|
+
end
|
102
|
+
|
103
|
+
def [](*indexes)
|
104
|
+
typedecl foreign: Float
|
105
|
+
check_range(indexes)
|
106
|
+
raise 'FloatCArray is not available in Ruby' unless @debug
|
107
|
+
end
|
108
|
+
|
109
|
+
def []=(*indexes)
|
110
|
+
typedecl foreign: Void
|
111
|
+
check_range(indexes[0, indexes.size - 1])
|
112
|
+
raise 'FloatCArray is not available in Ruby' unless @debug
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,449 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy/c/ctype'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
module Yadriggy
|
7
|
+
module C
|
8
|
+
|
9
|
+
class ArrayType < CompositeType
|
10
|
+
attr_reader :element_type
|
11
|
+
|
12
|
+
def initialize(element_type)
|
13
|
+
super(Array, element_type)
|
14
|
+
end
|
15
|
+
|
16
|
+
def element_type()
|
17
|
+
first_arg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Type for expressions ending with a return statement.
|
22
|
+
#
|
23
|
+
class WithReturnType < OptionalRole
|
24
|
+
end
|
25
|
+
|
26
|
+
# Type for native methods.
|
27
|
+
#
|
28
|
+
class NativeMethodType < OptionalRole
|
29
|
+
# @return [String] the method body.
|
30
|
+
attr_reader :body
|
31
|
+
|
32
|
+
# @param [MethodType] method_type a method type.
|
33
|
+
# @param [String] body_code the body of a native method.
|
34
|
+
def initialize(method_type, body_code)
|
35
|
+
super(method_type)
|
36
|
+
@body = body_code
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Type for foreign methods.
|
41
|
+
#
|
42
|
+
class ForeignMethodType < OptionalRole
|
43
|
+
# @param [MethodType] method_type a method type.
|
44
|
+
def initialize(method_type)
|
45
|
+
super(method_type)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class ClangTypeChecker < RubyTypeInferer
|
50
|
+
include Yadriggy::C::CType
|
51
|
+
|
52
|
+
# @return [Hash<Def,Hash<Symbol,Type>>] a map from functions to their
|
53
|
+
# local variables.
|
54
|
+
attr_reader :local_vars_table
|
55
|
+
|
56
|
+
# @return [Set<IvarObj>] accessed instance variables.
|
57
|
+
attr_reader :instance_variables
|
58
|
+
|
59
|
+
def initialize(syntax=nil)
|
60
|
+
super(syntax || C::syntax)
|
61
|
+
@local_vars_table = {}
|
62
|
+
@instance_variables = Set.new
|
63
|
+
end
|
64
|
+
|
65
|
+
def valid_var_type?(t)
|
66
|
+
if t.is_a?(Type)
|
67
|
+
et = t.exact_type
|
68
|
+
et == Integer || et == Float || et == String || et == Float32
|
69
|
+
else
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def valid_type?(t)
|
75
|
+
valid_var_type?(t) || ArrayType.role(t)
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_subsumed_by?(sub_type, super_type)
|
79
|
+
(valid_var_type?(sub_type) && valid_var_type?(super_type)) ||
|
80
|
+
sub_type <= super_type
|
81
|
+
end
|
82
|
+
|
83
|
+
rule(:typedecl) do
|
84
|
+
unless ast.args.nil?
|
85
|
+
type_assert(ast.args.size == 1, 'bad typedecl')
|
86
|
+
type(ast.args[0])
|
87
|
+
end
|
88
|
+
Void
|
89
|
+
end
|
90
|
+
|
91
|
+
rule(:typedecl_hash) do
|
92
|
+
ast.pairs.each do |e|
|
93
|
+
t = typedecl_type(e[1])
|
94
|
+
declare_type(e[0].name, e[0], t)
|
95
|
+
end
|
96
|
+
Void
|
97
|
+
end
|
98
|
+
|
99
|
+
# @private
|
100
|
+
# @param [ASTnode] type_expr
|
101
|
+
def typedecl_type(type_expr)
|
102
|
+
if type_expr.is_a?(Call)
|
103
|
+
type_assert(type_expr.args.size == 1, 'bad array type')
|
104
|
+
etype = RubyClass[type_expr.args[0].value]
|
105
|
+
type_assert(etype != Undef, 'cannot resolve a type name')
|
106
|
+
type_assert(valid_var_type?(etype), "bad array type: #{etype}")
|
107
|
+
ArrayType.new(etype)
|
108
|
+
else
|
109
|
+
rt = type_expr.value
|
110
|
+
type_assert(rt != Undef, 'cannot resolve a type name')
|
111
|
+
if rt.is_a?(Module) && rt <= FFIArray
|
112
|
+
ArrayType.new(RubyClass[rt.element_type])
|
113
|
+
else
|
114
|
+
RubyClass[rt]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# @private
|
120
|
+
def declare_type(name, name_ast, t)
|
121
|
+
if name == 'return' || name == 'foreign'
|
122
|
+
type_assert(valid_type?(t) || t == Void,
|
123
|
+
"bad return type: #{t.name}")
|
124
|
+
check_duplicate(name, t)
|
125
|
+
type_env.bind_name(name.to_sym, t)
|
126
|
+
elsif name == 'native'
|
127
|
+
type_assert(t.is_a?(String), 'bad native argument. not String.')
|
128
|
+
type_assert(type_env.bound_name?(:native).nil?,
|
129
|
+
'duplicate declaration: native')
|
130
|
+
type_env.bind_name(:native, InstanceType.new(t))
|
131
|
+
else
|
132
|
+
type_assert(valid_type?(t), "bad parameter type: #{name}")
|
133
|
+
check_duplicate(name, t)
|
134
|
+
bind_local_var(type_env, name_ast, t, false)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# @private
|
139
|
+
def check_duplicate(name, t)
|
140
|
+
old_type = type_env.bound_name?(name)
|
141
|
+
type_assert(old_type.nil? || old_type == t,
|
142
|
+
"incompatible or duplicate declaration: #{name}")
|
143
|
+
end
|
144
|
+
|
145
|
+
rule(:return_type) do
|
146
|
+
typedecl_type(ast.expr)
|
147
|
+
end
|
148
|
+
|
149
|
+
rule(Number) do
|
150
|
+
if ast.value.is_a?(Float)
|
151
|
+
RubyClass::Float
|
152
|
+
else
|
153
|
+
RubyClass::Integer
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
rule(Const) do
|
158
|
+
t = proceed(ast)
|
159
|
+
type_assert(t != Undef, 'unknown constant')
|
160
|
+
type_assert(valid_var_type?(t), 'bad constant type')
|
161
|
+
t
|
162
|
+
end
|
163
|
+
|
164
|
+
rule(ConstPathRef) do
|
165
|
+
v = ast.value
|
166
|
+
type_assert(v != Undef, 'unknown constant')
|
167
|
+
t = InstanceType.new(v)
|
168
|
+
type_assert(valid_var_type?(t), 'bad constant type')
|
169
|
+
t
|
170
|
+
end
|
171
|
+
|
172
|
+
rule(InstanceVariable) do
|
173
|
+
v = ast.value
|
174
|
+
key = type_env.context
|
175
|
+
if v == Undef
|
176
|
+
get_instance_variable_type(key, ast, false, DynType)
|
177
|
+
else
|
178
|
+
type_assert(v.is_a?(IvarObj), 'badly typed instance variable')
|
179
|
+
@instance_variables << v
|
180
|
+
get_instance_variable_type(key, ast, true, InstanceType.new(v))
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
rule(Assign) do
|
185
|
+
rtype = type(ast.right)
|
186
|
+
type_assert(valid_var_type?(rtype), 'bad assigned value')
|
187
|
+
if ast.left.is_a?(ArrayRef)
|
188
|
+
type(ast.left)
|
189
|
+
else
|
190
|
+
type_assert(ast.left.is_a?(IdentifierOrCall), 'bad assignment')
|
191
|
+
ltype = type_env.bound_name?(ast.left)
|
192
|
+
if ltype.nil? # if a new name is found,
|
193
|
+
bind_local_var(type_env, ast.left, rtype)
|
194
|
+
else
|
195
|
+
LocalVarType.role(ltype)&.definition = ast.left
|
196
|
+
ltype
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
rule(Binary) do
|
202
|
+
t1 = type(ast.left)
|
203
|
+
t2 = type(ast.right)
|
204
|
+
binary_cexpr_type(ast.op, t1, t2)
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
def binary_cexpr_type(op, t1, t2)
|
209
|
+
case op
|
210
|
+
when :+, :-, :*, :/
|
211
|
+
if t1 <= RubyClass::Float || t2 <= RubyClass::Float
|
212
|
+
return RubyClass::Float
|
213
|
+
elsif t1 <= Float32Type || t2 <= Float32Type
|
214
|
+
return Float32Type
|
215
|
+
else
|
216
|
+
return RubyClass::Integer
|
217
|
+
end
|
218
|
+
when :%
|
219
|
+
type_assert(t1 <= RubyClass::Integer &&
|
220
|
+
t2 <= RubyClass::Integer, 'bad operand type')
|
221
|
+
return RubyClass::Integer
|
222
|
+
when :<, :>, :<=, :>=, :==, :'&&', :'||'
|
223
|
+
return RubyClass::Boolean
|
224
|
+
else
|
225
|
+
type_assert(false, "bad operator: #{ast.op}")
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
rule(ArrayRef) do
|
230
|
+
array_type = type(ast.array)
|
231
|
+
indexes = ast.indexes
|
232
|
+
if InstanceType.role(array_type)&.object.is_a?(IvarObj)
|
233
|
+
sizes = array_type.object.sizes
|
234
|
+
type_assert(indexes.size == sizes.size, 'bad array index')
|
235
|
+
indexes.each do |idx|
|
236
|
+
type_assert(type(idx) <= RubyClass::Integer, 'bad array index')
|
237
|
+
end
|
238
|
+
array_type.object.type
|
239
|
+
else
|
240
|
+
type_assert(indexes.size == 1, 'bad array index')
|
241
|
+
itype = type(indexes[0])
|
242
|
+
type_assert(itype <= RubyClass::Integer, 'bad array index')
|
243
|
+
|
244
|
+
atype = ArrayType.role(array_type)
|
245
|
+
type_assert_false(atype.nil?, 'bad array access')
|
246
|
+
atype.element_type
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
rule(Unary) do
|
251
|
+
t = type(ast.expr)
|
252
|
+
type_assert(ast.op == :-@, "bad operator: #{ast.op}")
|
253
|
+
t
|
254
|
+
end
|
255
|
+
|
256
|
+
rule(Conditional) do
|
257
|
+
type(ast.cond)
|
258
|
+
t1 = type(ast.then)
|
259
|
+
ast.all_elsif.each do |cond_then|
|
260
|
+
type(cond_then[0])
|
261
|
+
type(cond_then[1])
|
262
|
+
end
|
263
|
+
t2 = type(ast.else)
|
264
|
+
if WithReturnType.role(t1) && WithReturnType.role(t2)
|
265
|
+
WithReturnType.new(UnionType.make(t1, t2))
|
266
|
+
elsif ast.op == :ifop
|
267
|
+
UnionType.make(t1, t2)
|
268
|
+
else
|
269
|
+
Void
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
rule(Loop) do
|
274
|
+
type(ast.cond)
|
275
|
+
type(ast.body, type_env)
|
276
|
+
Void
|
277
|
+
end
|
278
|
+
|
279
|
+
rule(ForLoop) do
|
280
|
+
ast.vars.each {|v| bind_local_var(type_env, v.name,
|
281
|
+
RubyClass::Integer) }
|
282
|
+
type_assert(type(ast.set.left) <= RubyClass::Integer, 'bad for-range')
|
283
|
+
type_assert(type(ast.set.right) <= RubyClass::Integer, 'bad for-range')
|
284
|
+
type(ast.body, type_env)
|
285
|
+
Void
|
286
|
+
end
|
287
|
+
|
288
|
+
rule(Return) do
|
289
|
+
t = proceed(ast)
|
290
|
+
ret_type = type_env.bound_name?(:return)
|
291
|
+
if ret_type == Void
|
292
|
+
type_assert(ast.values.size == 0, 'bad return')
|
293
|
+
else
|
294
|
+
type_assert(is_subsumed_by?(t, ret_type), 'bad return type')
|
295
|
+
end
|
296
|
+
WithReturnType.new(t)
|
297
|
+
end
|
298
|
+
|
299
|
+
rule(Call) do
|
300
|
+
method_name = ast.name.name
|
301
|
+
if method_with_block?(method_name)
|
302
|
+
type_assert(ast.block,
|
303
|
+
"no block given: #{method_name}")
|
304
|
+
type_assert(ast.receiver,
|
305
|
+
"no receiver given: #{method_name}")
|
306
|
+
typecheck_call_with_block(ast)
|
307
|
+
else
|
308
|
+
type_assert_false(ast.block,
|
309
|
+
"a block is not taken: #{method_name}")
|
310
|
+
t = proceed(ast)
|
311
|
+
type_assert(ResultType.role(t), "bad call to: #{method_name}")
|
312
|
+
t
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# Specifies the names of methods with a block.
|
317
|
+
#
|
318
|
+
# @param [String] name a method name.
|
319
|
+
# @see {CodeGen#call_with_block}
|
320
|
+
# @see {#typecheck_call_with_block}
|
321
|
+
def method_with_block?(name)
|
322
|
+
name == 'times'
|
323
|
+
end
|
324
|
+
|
325
|
+
def typecheck_call_with_block(call_ast)
|
326
|
+
type_assert(ast.name.name == 'times',
|
327
|
+
"no such method: #{ast.name.name}")
|
328
|
+
type_assert(type(ast.receiver) == RubyClass::Integer,
|
329
|
+
'the receiver must be an integer')
|
330
|
+
type_assert(ast.block.params.size == 1,
|
331
|
+
"wrong number of block parameters")
|
332
|
+
type_as(ast.block.params[0], RubyClass::Integer)
|
333
|
+
tenv = type_env.new_tenv
|
334
|
+
tenv.bind_name(ast.block.params[0], RubyClass::Integer)
|
335
|
+
tenv.bind_name(:return, Void)
|
336
|
+
type(ast.block, tenv)
|
337
|
+
Void
|
338
|
+
end
|
339
|
+
|
340
|
+
rule(Block) do
|
341
|
+
if ast.params.size == 0 && type_env.bound_name?(:return).nil? &&
|
342
|
+
ast.body.is_a?(Return)
|
343
|
+
case ast.body.values[0].usertype
|
344
|
+
when :expr, :method_call
|
345
|
+
type_env.bind_name(:return, type(ast.body.values[0]))
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
# a new type environment is created by a caller
|
350
|
+
# (i.e. typecheck_call_with_block).
|
351
|
+
def_block_rule(true, type_env)
|
352
|
+
end
|
353
|
+
|
354
|
+
rule(Def) do
|
355
|
+
def_block_rule(false, type_env.new_tenv)
|
356
|
+
end
|
357
|
+
|
358
|
+
private
|
359
|
+
|
360
|
+
def def_block_rule(is_block, new_tenv)
|
361
|
+
type_block(ast, new_tenv)
|
362
|
+
|
363
|
+
ptypes = ast.params.map { |v| new_tenv.bound_name?(v.name) }
|
364
|
+
ptypes.each_with_index do |t, i|
|
365
|
+
type_assert(t, "missing parameter type: #{ast.params[i].name}")
|
366
|
+
end
|
367
|
+
result_t = new_tenv.bound_name?(:return)
|
368
|
+
result_t = new_tenv.bound_name?(:foreign) if result_t.nil?
|
369
|
+
type_assert(result_t, 'no return type specified')
|
370
|
+
|
371
|
+
mtype = MethodType.new(ast, ptypes, result_t)
|
372
|
+
type_env.bind_name(ast.name.name, mtype.result) unless is_block
|
373
|
+
|
374
|
+
code = new_tenv.bound_name?(:native)
|
375
|
+
if code
|
376
|
+
ins_t = InstanceType.role(code)
|
377
|
+
type_assert(ins_t, 'bad native declaration')
|
378
|
+
return NativeMethodType.new(mtype, ins_t.object)
|
379
|
+
end
|
380
|
+
|
381
|
+
foreign_value = new_tenv.bound_name?(:foreign)
|
382
|
+
if foreign_value && !is_block
|
383
|
+
mtype2 = MethodType.new(nil, DynType, result_t)
|
384
|
+
return ForeignMethodType.new(mtype2)
|
385
|
+
end
|
386
|
+
|
387
|
+
type_assert_later_unless(is_block) do
|
388
|
+
body_t = type(ast.body, new_tenv)
|
389
|
+
wt = WithReturnType.role(body_t)
|
390
|
+
if result_t == Void
|
391
|
+
type_assert(wt.nil? || body_t == Void, 'non-void return statement')
|
392
|
+
else
|
393
|
+
type_assert(wt, 'no return statement')
|
394
|
+
type_assert(is_subsumed_by?(result_t, body_t), 'bad result type')
|
395
|
+
end
|
396
|
+
|
397
|
+
local_vars = {}
|
398
|
+
new_tenv.each do |name, type|
|
399
|
+
lvt = LocalVarType.role(type)
|
400
|
+
local_vars[name] = type unless lvt.nil?
|
401
|
+
end
|
402
|
+
ast.params.each do |p|
|
403
|
+
local_vars.delete(p.name.to_sym)
|
404
|
+
end
|
405
|
+
|
406
|
+
@local_vars_table[ast] = local_vars
|
407
|
+
end
|
408
|
+
mtype
|
409
|
+
end
|
410
|
+
|
411
|
+
def type_assert_later_unless(value, &proc)
|
412
|
+
unless value
|
413
|
+
check_later(&proc)
|
414
|
+
else
|
415
|
+
yield
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# Do typing the given block according to typedecl.
|
420
|
+
#
|
421
|
+
def type_block(block_ast, new_env)
|
422
|
+
expr0 = nil
|
423
|
+
expr1 = nil
|
424
|
+
if block_ast.body.is_a?(Exprs)
|
425
|
+
size = block_ast.body.expressions.size
|
426
|
+
expr0 = block_ast.body.expressions[0] if size > 0
|
427
|
+
expr1 = block_ast.body.expressions[1] if size > 1
|
428
|
+
else
|
429
|
+
expr0 = block_ast.body
|
430
|
+
end
|
431
|
+
|
432
|
+
if expr0&.usertype == :return_type
|
433
|
+
new_env.bind_name(:return, type(expr0))
|
434
|
+
end
|
435
|
+
|
436
|
+
if expr0&.usertype == :typedecl
|
437
|
+
type(expr0, new_env)
|
438
|
+
elsif expr1&.usertype == :typedecl
|
439
|
+
type(expr1, new_env)
|
440
|
+
end
|
441
|
+
|
442
|
+
unless new_env.bound_name?(:return) || new_env.bound_name?(:foreign)
|
443
|
+
new_env.bind_name(:return, Void)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|