typeprof 0.1.4 → 0.2.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.
@@ -3,208 +3,125 @@ require "rbs"
3
3
  module TypeProf
4
4
  class RBSReader
5
5
  def initialize
6
- @env, @builtin_env_dump = RBSReader.builtin_env
6
+ @env, @builtin_env_json = RBSReader.get_builtin_env
7
7
  end
8
8
 
9
- @builtin_env = nil
10
- def self.builtin_env
11
- return @builtin_env.dup, @builtin_env_dump if @builtin_env
9
+ @builtin_env = @builtin_env_json = nil
10
+ def self.get_builtin_env
11
+ unless @builtin_env
12
+ @builtin_env = RBS::Environment.new
13
+ @builtin_env_json = load_rbs(@builtin_env, builtin: true)
14
+ end
12
15
 
13
- loader = RBS::EnvironmentLoader.new
14
- env = RBS::Environment.new
15
- decls = loader.load(env: env)
16
- @builtin_env = env
17
- @builtin_env_dump = RBS2JSON.new(env, decls).dump
18
- return env.dup, @builtin_env_dump
16
+ return @builtin_env.dup, @builtin_env_json
19
17
  end
20
18
 
21
19
  def load_builtin
22
- @builtin_env_dump
20
+ @builtin_env_json
23
21
  end
24
22
 
25
23
  def load_library(lib)
26
- loader = RBS::EnvironmentLoader.new
27
- loader.no_builtin!
28
- loader.add(library: lib)
29
- new_decls = loader.load(env: @env)
30
- RBS2JSON.new(@env, new_decls).dump
24
+ RBSReader.load_rbs(@env, library: lib)
31
25
  end
32
26
 
33
27
  def load_path(path)
34
- loader = RBS::EnvironmentLoader.new
35
- loader.no_builtin!
36
- loader.add(path: path)
37
- new_decls = loader.load(env: @env)
38
- RBS2JSON.new(@env, new_decls).dump
28
+ RBSReader.load_rbs(@env, path: path)
39
29
  end
40
- end
41
30
 
42
- class RBS2JSON
43
- def initialize(env, new_decls)
44
- @all_env = env.resolve_type_names
31
+ def self.load_rbs(env, builtin: false, **opt)
32
+ loader = RBS::EnvironmentLoader.new
33
+ unless builtin
34
+ loader.no_builtin!
35
+ loader.add(**opt)
36
+ end
37
+ new_decls = loader.load(env: env)
45
38
 
46
- resolver = RBS::TypeNameResolver.from_env(env)
47
- @current_env = RBS::Environment.new()
39
+ all_env = env.resolve_type_names
48
40
 
41
+ resolver = RBS::TypeNameResolver.from_env(all_env)
42
+ cur_env = RBS::Environment.new
49
43
  new_decls.each do |decl,|
50
- @current_env << env.resolve_declaration(resolver, decl, outer: [], prefix: RBS::Namespace.root)
44
+ cur_env << env.resolve_declaration(resolver, decl, outer: [], prefix: RBS::Namespace.root)
51
45
  end
46
+
47
+ RBS2JSON.new(all_env, cur_env).dump_json
52
48
  end
49
+ end
53
50
 
54
- def dump
55
- [import_rbs_classes, import_rbs_constants]
51
+ class RBS2JSON
52
+ def initialize(all_env, cur_env)
53
+ @all_env, @cur_env = all_env, cur_env
54
+ end
55
+
56
+ def dump_json
57
+ {
58
+ classes: conv_classes,
59
+ constants: conv_constants,
60
+ globals: conv_globals,
61
+ }
56
62
  end
57
63
 
58
64
  # constant_name = [Symbol]
59
65
  #
60
66
  # { constant_name => type }
61
- def import_rbs_constants
67
+ def conv_constants
62
68
  constants = {}
63
- @current_env.constant_decls.each do |name, decl|
64
- #constants[name] = decl
65
- klass = name.namespace.path + [name.name]
66
- constants[klass] = convert_type(decl.decl.type)
69
+ @cur_env.constant_decls.each do |name, decl|
70
+ klass = conv_type_name(name)
71
+ constants[klass] = conv_type(decl.decl.type)
67
72
  end
68
73
  constants
69
74
  end
70
75
 
71
- # class_name = [Symbol]
72
- # method_name = [singleton: true|false, Symbol}
73
- # method_def = [...]
76
+ # gvar_name = Symbol (:$gvar)
74
77
  #
75
- # { class_name =>
76
- # [ super_class: class_name,
77
- # included_modules: [class_name],
78
- # methods: { method_name => [method_def] },
79
- # ]
80
- # }
81
- def import_rbs_classes
82
- class2super = {}
83
- # XXX: @env.each_global {|a| p a }
84
- @current_env.class_decls.each do |name, decl|
85
- decl.decls.each do |decl|
86
- decl = decl.decl
87
- if decl.is_a?(RBS::AST::Declarations::Class) && name != RBS::Factory.new.type_name("::Object")
88
- #next unless decl.super_class
89
- class2super[name] ||= decl.super_class&.name || RBS::BuiltinNames::Object.name
90
- else
91
- class2super[name] ||= nil
92
- end
93
- end
78
+ # { gvar_name => type }
79
+ def conv_globals
80
+ gvars = {}
81
+ @cur_env.global_decls.each do |name, decl|
82
+ decl = decl.decl
83
+ gvars[name] = conv_type(decl.type)
94
84
  end
85
+ gvars
86
+ end
95
87
 
96
- classes = []
88
+ def conv_classes
89
+ json = {}
97
90
 
98
- # topological sort
99
- queue = class2super.keys.map {|name| [:visit, name] }
100
- visited = {}
101
- until queue.empty?
102
- #p queue.map {|ev, name| [ev, name.to_s] }
103
- event, name = queue.pop
104
- case event
105
- when :visit
106
- if !visited[name]
107
- visited[name] = true
108
- queue << [:new, name]
109
- decl = @all_env.class_decls[name]
110
- decl.decls.each do |decl|
111
- decl = decl.decl
112
- next if decl.is_a?(RBS::AST::Declarations::Module)
113
- until RBS::BuiltinNames::Object.name == decl.name
114
- super_class = decl.super_class
115
- break unless super_class
116
- decls = @all_env.class_decls[super_class.name].decls
117
- raise if decls.size >= 2 # no need to check
118
- decl = decls.first.decl
119
- queue << [:visit, decl.name]
120
- end
121
- end
122
- if !name.namespace.empty?
123
- queue << [:visit, name.namespace.to_type_name]
124
- end
125
- end
126
- when :new
127
- super_class_name = class2super[name]
128
- klass = name.namespace.path + [name.name]
129
- if super_class_name
130
- superclass = super_class_name.namespace.path + [super_class_name.name]
131
- else
132
- superclass = nil
133
- end
134
- classes << [name, klass, superclass]
135
- end
136
- end
137
-
138
- result = {}
139
- classes.each do |type_name, klass, superclass|
140
- next unless @current_env.class_decls[type_name]
91
+ each_class_decl do |name, decls|
92
+ super_class_name = get_super_class_name(name)
93
+ klass = conv_type_name(name)
94
+ superclass = super_class_name ? conv_type_name(super_class_name) : nil
141
95
 
96
+ type_params = nil
142
97
  included_modules = []
143
98
  methods = {}
99
+ ivars = {}
100
+ cvars = {}
144
101
  rbs_sources = {}
145
- type_params = nil
146
102
 
147
- @current_env.class_decls[type_name].decls.each do |decl|
103
+ decls.each do |decl|
148
104
  decl = decl.decl
149
- raise NotImplementedError if decl.is_a?(RBS::AST::Declarations::Interface)
105
+
106
+ raise NotImplementedError if decl.is_a?(RBS::AST::Declarations::Interface) # XXX
107
+
150
108
  type_params2 = decl.type_params.params.map {|param| [param.name, param.variance] }
151
- if type_params
152
- raise if type_params != type_params2
153
- else
154
- type_params = type_params2
155
- end
109
+ raise "inconsistent type parameter declaration" if type_params && type_params != type_params2
110
+ type_params = type_params2
156
111
 
157
112
  decl.members.each do |member|
158
113
  case member
159
114
  when RBS::AST::Members::MethodDefinition
160
115
  name = member.name
161
116
 
162
- # ad-hoc filter
163
- if member.instance?
164
- case type_name.name
165
- when :Object
166
- next if name == :class
167
- next if name == :send
168
- next if name == :is_a?
169
- next if name == :respond_to?
170
- when :Array
171
- next if name == :[]
172
- next if name == :[]=
173
- next if name == :pop
174
- when :Enumerable
175
- when :Enumerator
176
- when :Hash
177
- next if name == :[]
178
- next if name == :[]=
179
- next if name == :to_proc
180
- #next unless [:empty?, :size].include?(name)
181
- when :Struct
182
- next if name == :initialize
183
- when :Module
184
- next if name == :include
185
- next if name == :module_function
186
- when :Proc
187
- next if name == :call || name == :[]
188
- when :Kernel
189
- next if name == :Array
190
- end
191
- end
192
- if member.singleton?
193
- case type_name.name
194
- when :Array
195
- end
196
- end
197
-
198
117
  method_types = member.types.map do |method_type|
199
118
  case method_type
200
- when RBS::MethodType
201
- method_type
202
- when :super
203
- raise NotImplementedError
119
+ when RBS::MethodType then method_type
120
+ when :super then raise NotImplementedError
204
121
  end
205
122
  end
206
123
 
207
- method_def = translate_typed_method_def(method_types)
124
+ method_def = conv_method_def(method_types)
208
125
  rbs_source = [(member.kind == :singleton ? "self." : "") + member.name.to_s, member.types.map {|type| type.location.source }]
209
126
  if member.instance?
210
127
  methods[[false, name]] = method_def
@@ -214,8 +131,16 @@ module TypeProf
214
131
  methods[[true, name]] = method_def
215
132
  rbs_sources[[true, name]] = rbs_source
216
133
  end
217
- #when RBS::AST::Members::AttrReader, RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrWriter
218
- #raise NotImplementedError
134
+ when RBS::AST::Members::AttrReader
135
+ ty = conv_type(member.type)
136
+ methods[[false, member.name]] = attr_reader_def(ty)
137
+ when RBS::AST::Members::AttrWriter
138
+ ty = conv_type(member.type)
139
+ methods[[false, :"#{ member.name }="]] = attr_writer_def(ty)
140
+ when RBS::AST::Members::AttrAccessor
141
+ ty = conv_type(member.type)
142
+ methods[[false, member.name]] = attr_reader_def(ty)
143
+ methods[[false, :"#{ member.name }="]] = attr_writer_def(ty)
219
144
  when RBS::AST::Members::Alias
220
145
  if member.instance?
221
146
  method_def = methods[[false, member.old_name]]
@@ -225,322 +150,438 @@ module TypeProf
225
150
  method_def = methods[[true, member.old_name]]
226
151
  methods[[true, member.new_name]] = method_def if method_def
227
152
  end
153
+
228
154
  when RBS::AST::Members::Include
229
155
  name = member.name
230
- mod = name.namespace.path + [name.name]
231
- included_modules << mod
156
+ if name.kind == :class
157
+ mod = conv_type_name(name)
158
+ included_modules << mod
159
+ else
160
+ # including an interface is not supported yet
161
+ end
162
+
232
163
  when RBS::AST::Members::InstanceVariable
164
+ ivars[member.name] = conv_type(member.type)
233
165
  when RBS::AST::Members::ClassVariable
234
- when RBS::AST::Members::Public, RBS::AST::Members::Private
166
+ cvars[member.name] = conv_type(member.type)
167
+
168
+ when RBS::AST::Members::Public, RBS::AST::Members::Private # XXX
169
+
170
+ # The following declarations are ignoreable because they are handled in other level
235
171
  when RBS::AST::Declarations::Constant
236
- when RBS::AST::Declarations::Alias
172
+ when RBS::AST::Declarations::Alias # type alias
173
+ when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
174
+ when RBS::AST::Declarations::Interface
175
+
237
176
  else
238
177
  warn "Importing #{ member.class.name } is not supported yet"
239
- #p member
240
178
  end
241
179
  end
242
180
  end
243
181
 
244
- result[klass] = [type_params, superclass, included_modules, methods, rbs_sources]
245
- end.compact
182
+ json[klass] = {
183
+ type_params: type_params,
184
+ superclass: superclass,
185
+ members: {
186
+ included_modules: included_modules,
187
+ methods: methods,
188
+ ivars: ivars,
189
+ cvars: cvars,
190
+ rbs_sources: rbs_sources,
191
+ },
192
+ }
193
+ end
194
+
195
+ json
196
+ end
197
+
198
+ def each_class_decl
199
+ classes = []
200
+
201
+ # topological sort
202
+ # * superclasses and modules appear earlier than their subclasses (Object is earlier than String)
203
+ # * namespace module appers earlier than its children (Process is earlier than Process::Status)
204
+ visited = {}
205
+ queue = @cur_env.class_decls.keys.map {|name| [:visit, name] }
206
+ until queue.empty?
207
+ event, name = queue.pop
208
+ case event
209
+ when :visit
210
+ if !visited[name]
211
+ visited[name] = true
212
+ queue << [:new, name]
213
+ @all_env.class_decls[name].decls.each do |decl|
214
+ decl = decl.decl
215
+ next if decl.is_a?(RBS::AST::Declarations::Module)
216
+ each_ancestor(decl) {|name| queue << [:visit, name] }
217
+ end
218
+ queue << [:visit, name.namespace.to_type_name] if !name.namespace.empty?
219
+ end
220
+ when :new
221
+ decls = @cur_env.class_decls[name]
222
+ yield name, decls.decls if decls
223
+ end
224
+ end
246
225
 
247
- result
226
+ classes
248
227
  end
249
228
 
250
- def translate_typed_method_def(rs_method_types)
251
- rs_method_types.map do |type|
252
- if type.block
253
- blk = translate_typed_block(type.block)
229
+ def each_ancestor(decl, &blk)
230
+ yield decl.name
231
+ super_class = decl.super_class || RBS::BuiltinNames::Object
232
+ return if decl.name == RBS::BuiltinNames::BasicObject.name
233
+ return if decl.name == super_class.name
234
+ @all_env.class_decls[super_class.name].decls.each do |decl|
235
+ each_ancestor(decl.decl, &blk)
236
+ end
237
+ end
238
+
239
+ def get_super_class_name(name)
240
+ return nil if name == RBS::BuiltinNames::BasicObject.name
241
+
242
+ @all_env.class_decls[name].decls.each do |decl|
243
+ decl = decl.decl
244
+ case decl
245
+ when RBS::AST::Declarations::Class
246
+ return decl.super_class.name if decl.super_class
247
+ when RBS::AST::Declarations::Module
248
+ return nil
254
249
  else
255
- blk = nil
250
+ raise "unknown declaration: %p" % decl.class
256
251
  end
252
+ end
253
+
254
+ return RBS::BuiltinNames::Object.name
255
+ end
256
+
257
+ def conv_method_def(rbs_method_types)
258
+ rbs_method_types.map do |type|
259
+ blk = type.block ? conv_block(type.block) : nil
257
260
  type_params = type.type_params
258
261
 
259
- begin
260
- lead_tys = type.type.required_positionals.map do |type|
261
- convert_type(type.type)
262
- end
263
- opt_tys = type.type.optional_positionals.map do |type|
264
- convert_type(type.type)
265
- end
266
- rest_ty = type.type.rest_positionals
267
- rest_ty = convert_type(rest_ty.type) if rest_ty
268
- opt_kw_tys = type.type.optional_keywords.to_h do |key, type|
269
- [key, convert_type(type.type)]
270
- end
271
- req_kw_tys = type.type.required_keywords.to_h do |key, type|
272
- [key, convert_type(type.type)]
273
- end
274
- rest_kw_ty = type.type.rest_keywords
275
- raise NotImplementedError if rest_kw_ty
262
+ lead_tys = type.type.required_positionals.map {|type| conv_type(type.type) }
263
+ opt_tys = type.type.optional_positionals.map {|type| conv_type(type.type) }
264
+ rest_ty = type.type.rest_positionals
265
+ rest_ty = conv_type(rest_ty.type) if rest_ty
266
+ opt_kw_tys = type.type.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] }
267
+ req_kw_tys = type.type.required_keywords.to_h {|key, type| [key, conv_type(type.type)] }
268
+ rest_kw_ty = type.type.rest_keywords
269
+ raise NotImplementedError if rest_kw_ty # XXX
270
+
271
+ ret_ty = conv_type(type.type.return_type)
272
+
273
+ {
274
+ type_params: type_params,
275
+ lead_tys: lead_tys,
276
+ opt_tys: opt_tys,
277
+ rest_ty: rest_ty,
278
+ req_kw_tys: req_kw_tys,
279
+ opt_kw_tys: opt_kw_tys,
280
+ rest_kw_ty: rest_kw_ty,
281
+ blk: blk,
282
+ ret_ty: ret_ty,
283
+ }
284
+ end
285
+ end
276
286
 
277
- ret_ty = convert_type(type.type.return_type)
278
- [type_params, lead_tys, opt_tys, rest_ty, req_kw_tys, opt_kw_tys, rest_kw_ty, blk, ret_ty]
279
- rescue UnsupportedType
280
- nil
281
- end
282
- end.compact
287
+ def attr_reader_def(ty)
288
+ [{
289
+ type_params: [],
290
+ lead_tys: [],
291
+ opt_tys: [],
292
+ rest_ty: nil,
293
+ req_kw_tys: {},
294
+ opt_kw_tys: {},
295
+ rest_kw_ty: nil,
296
+ blk: nil,
297
+ ret_ty: ty,
298
+ }]
299
+ end
300
+
301
+ def attr_writer_def(ty)
302
+ [{
303
+ type_params: [],
304
+ lead_tys: [ty],
305
+ opt_tys: [],
306
+ rest_ty: nil,
307
+ req_kw_tys: {},
308
+ opt_kw_tys: {},
309
+ rest_kw_ty: nil,
310
+ blk: nil,
311
+ ret_ty: ty,
312
+ }]
283
313
  end
284
314
 
285
- def translate_typed_block(rs_block)
286
- type = rs_block.type
315
+ def conv_block(rbs_block)
316
+ type = rbs_block.type
317
+
318
+ # XXX
287
319
  raise NotImplementedError unless type.optional_keywords.empty?
288
320
  raise NotImplementedError unless type.required_keywords.empty?
289
- raise NotImplementedError unless type.optional_positionals.empty?
290
321
  raise NotImplementedError if type.rest_keywords
322
+
291
323
  lead_tys = type.required_positionals.map do |type|
292
- convert_type(type.type)
324
+ conv_type(type.type)
325
+ end
326
+ opt_tys = type.optional_positionals.map do |type|
327
+ conv_type(type.type)
293
328
  end
294
- ret_ty = convert_type(type.return_type)
295
- [lead_tys, ret_ty]
296
- end
297
329
 
298
- class UnsupportedType < StandardError
330
+ ret_ty = conv_type(type.return_type)
331
+
332
+ [lead_tys, opt_tys, ret_ty]
299
333
  end
300
334
 
301
- def convert_type(ty)
335
+ def conv_type(ty)
302
336
  case ty
303
337
  when RBS::Types::ClassSingleton
304
- klass = ty.name.namespace.path + [ty.name.name]
305
- [:class, klass]
338
+ [:class, conv_type_name(ty.name)]
306
339
  when RBS::Types::ClassInstance
307
- klass = ty.name.namespace.path + [ty.name.name]
340
+ klass = conv_type_name(ty.name)
308
341
  case klass
309
342
  when [:Array]
310
343
  raise if ty.args.size != 1
311
- [:array, :Array, [], convert_type(ty.args.first)]
344
+ [:array, [:Array], [], conv_type(ty.args.first)]
312
345
  when [:Hash]
313
346
  raise if ty.args.size != 2
314
347
  key, val = ty.args
315
- [:hash, :Hash, [convert_type(key), convert_type(val)]]
348
+ [:hash, [:Hash], [conv_type(key), conv_type(val)]]
316
349
  when [:Enumerator]
317
350
  raise if ty.args.size != 2
318
- [:array, :Enumerator, [], convert_type(ty.args.first)]
351
+ [:array, [:Enumerator], [], conv_type(ty.args.first)]
319
352
  else
320
353
  [:instance, klass]
321
354
  end
322
- when RBS::Types::Bases::Bool
323
- [:bool]
324
- when RBS::Types::Bases::Any
325
- [:any]
326
- when RBS::Types::Bases::Void
327
- [:any]
328
- when RBS::Types::Bases::Self
329
- [:self]
330
- when RBS::Types::Bases::Nil
331
- [:nil]
332
- when RBS::Types::Bases::Bottom
333
- [:union, []]
334
- when RBS::Types::Variable
335
- [:var, ty.name]
355
+ when RBS::Types::Bases::Bool then [:bool]
356
+ when RBS::Types::Bases::Any then [:any]
357
+ when RBS::Types::Bases::Void then [:any]
358
+ when RBS::Types::Bases::Self then [:self]
359
+ when RBS::Types::Bases::Nil then [:nil]
360
+ when RBS::Types::Bases::Bottom then [:union, []]
361
+ when RBS::Types::Variable then [:var, ty.name]
336
362
  when RBS::Types::Tuple
337
- tys = ty.types.map {|ty2| convert_type(ty2) }
338
- [:array, :Array, tys, [:union, []]]
363
+ tys = ty.types.map {|ty2| conv_type(ty2) }
364
+ [:array, [:Array], tys, [:union, []]]
339
365
  when RBS::Types::Literal
340
366
  case ty.literal
341
- when Integer
342
- [:int]
343
- when String
344
- [:str]
345
- when true
346
- [:true]
347
- when false
348
- [:false]
349
- when Symbol
350
- [:sym, ty.literal]
367
+ when Integer then [:int]
368
+ when String then [:str]
369
+ when true then [:true]
370
+ when false then [:false]
371
+ when Symbol then [:sym, ty.literal]
351
372
  else
352
373
  p ty.literal
353
374
  raise NotImplementedError
354
375
  end
355
376
  when RBS::Types::Alias
356
377
  alias_decl = @all_env.alias_decls[ty.name]
357
- alias_decl ? convert_type(alias_decl.decl.type) : [:any]
378
+ alias_decl ? conv_type(alias_decl.decl.type) : [:any]
358
379
  when RBS::Types::Union
359
- [:union, ty.types.map {|ty2| begin convert_type(ty2); rescue UnsupportedType; end }.compact]
380
+ [:union, ty.types.map {|ty2| conv_type(ty2) }.compact]
360
381
  when RBS::Types::Optional
361
- [:optional, convert_type(ty.type)]
362
- when RBS::Types::Record
363
- [:any]
382
+ [:optional, conv_type(ty.type)]
364
383
  when RBS::Types::Interface
365
- raise UnsupportedType if ty.to_s == "::_ToStr" # XXX
366
- raise UnsupportedType if ty.to_s == "::_ToInt" # XXX
367
- if ty.to_s == "::_ToAry[U]" # XXX
368
- return [:array, :Array, [], [:var, :U]]
384
+ # XXX: Currently, only a few builtin interfaces are supported
385
+ case ty.to_s
386
+ when "::_ToStr" then [:str]
387
+ when "::_ToInt" then [:int]
388
+ when "::_ToAry[U]" then [:array, [:Array], [], [:var, :U]]
389
+ else
390
+ [:any]
369
391
  end
370
- [:any]
392
+ when RBS::Types::Bases::Instance then [:any] # XXX: not implemented yet
393
+ when RBS::Types::Record then [:any] # XXX: not implemented yet
394
+ when RBS::Types::Proc then [:any] # XXX: not implemented yet
371
395
  else
372
- pp ty
373
- raise NotImplementedError
396
+ warn "unknown RBS type: %p" % ty.class
397
+ [:any]
374
398
  end
375
399
  end
376
- end
377
-
378
- module RubySignatureImporter
379
- module_function
380
400
 
381
- def path_to_klass(scratch, path)
382
- klass = Type::Builtin[:obj]
383
- path.each do |name|
384
- klass = scratch.get_constant(klass, name)
385
- raise if klass == Type.any
386
- end
387
- klass
401
+ def conv_type_name(name)
402
+ name.namespace.path + [name.name]
388
403
  end
404
+ end
389
405
 
390
- CACHE = {}
391
-
392
- def import_builtin(scratch)
393
- import_ruby_signature(scratch, scratch.rbs_reader.load_builtin)
406
+ class Import
407
+ def self.import_builtin(scratch)
408
+ Import.new(scratch, scratch.rbs_reader.load_builtin).import
394
409
  end
395
410
 
396
- def import_library(scratch, feature)
411
+ def self.import_library(scratch, feature)
412
+ begin
413
+ json = scratch.rbs_reader.load_library(feature)
414
+ rescue RBS::EnvironmentLoader::UnknownLibraryNameError
415
+ return nil
416
+ end
397
417
  # need cache?
398
- import_ruby_signature(scratch, scratch.rbs_reader.load_library(feature))
399
- rescue RBS::EnvironmentLoader::UnknownLibraryNameError
400
- false
418
+ Import.new(scratch, json).import
401
419
  end
402
420
 
403
- def import_rbs_file(scratch, rbs_path)
404
- import_ruby_signature(scratch, scratch.rbs_reader.load_path(Pathname(rbs_path)), true)
421
+ def self.import_rbs_file(scratch, rbs_path)
422
+ Import.new(scratch, scratch.rbs_reader.load_path(Pathname(rbs_path))).import(true)
405
423
  end
406
424
 
407
- def import_ruby_signature(scratch, dump, explicit = false)
408
- rbs_classes, rbs_constants = dump
409
- classes = []
410
- rbs_classes.each do |classpath, (type_params, superclass, included_modules, methods, rbs_sources)|
411
- if classpath == [:Object]
412
- klass = Type::Builtin[:obj]
413
- else
414
- name = classpath.last
415
- base_klass = path_to_klass(scratch, classpath[0..-2])
416
- superclass = path_to_klass(scratch, superclass) if superclass
417
- klass = scratch.get_constant(base_klass, name)
418
- if klass.is_a?(Type::Any)
419
- klass = scratch.new_class(base_klass, name, type_params, superclass)
420
- case classpath
421
- when [:NilClass] then Type::Builtin[:nil] = klass
422
- when [:Integer] then Type::Builtin[:int] = klass
423
- when [:String] then Type::Builtin[:str] = klass
424
- when [:Symbol] then Type::Builtin[:sym] = klass
425
- when [:Array] then Type::Builtin[:ary] = klass
426
- when [:Hash] then Type::Builtin[:hash] = klass
427
- end
425
+ def initialize(scratch, json)
426
+ @scratch = scratch
427
+ @json = json
428
+ end
429
+
430
+ def import(explicit = false)
431
+ classes = @json[:classes].map do |classpath, cdef|
432
+ type_params = cdef[:type_params]
433
+ superclass = cdef[:superclass]
434
+ members = cdef[:members]
435
+
436
+ name = classpath.last
437
+ superclass = path_to_klass(superclass) if superclass
438
+ base_klass = path_to_klass(classpath[0..-2])
439
+
440
+ klass = @scratch.get_constant(base_klass, name)
441
+ if klass.is_a?(Type::Any)
442
+ klass = @scratch.new_class(base_klass, name, type_params, superclass, nil)
443
+
444
+ # There builtin classes are needed to interpret RBS declarations
445
+ case classpath
446
+ when [:NilClass] then Type::Builtin[:nil] = klass
447
+ when [:TrueClass] then Type::Builtin[:true] = klass
448
+ when [:FalseClass] then Type::Builtin[:false] = klass
449
+ when [:Integer] then Type::Builtin[:int] = klass
450
+ when [:String] then Type::Builtin[:str] = klass
451
+ when [:Symbol] then Type::Builtin[:sym] = klass
452
+ when [:Array] then Type::Builtin[:ary] = klass
453
+ when [:Hash] then Type::Builtin[:hash] = klass
428
454
  end
429
455
  end
430
- classes << [klass, included_modules, methods, rbs_sources]
456
+
457
+ [klass, members]
431
458
  end
432
459
 
433
- classes.each do |klass, included_modules, methods, rbs_sources|
460
+ classes.each do |klass, members|
461
+ included_modules = members[:included_modules]
462
+ methods = members[:methods]
463
+ ivars = members[:ivars]
464
+ cvars = members[:cvars]
465
+ rbs_sources = members[:rbs_sources]
466
+
434
467
  included_modules.each do |mod|
435
- mod = path_to_klass(scratch, mod)
436
- scratch.include_module(klass, mod, false)
468
+ @scratch.include_module(klass, path_to_klass(mod), nil)
437
469
  end
470
+
438
471
  methods.each do |(singleton, method_name), mdef|
439
- rbs_source = nil
440
- rbs_source = rbs_sources[[singleton, method_name]] if explicit
441
- mdef = translate_typed_method_def(scratch, method_name, mdef, rbs_source)
442
- scratch.add_method(klass, method_name, singleton, mdef)
472
+ rbs_source = explicit ? rbs_sources[[singleton, method_name]] : nil
473
+ mdef = conv_method_def(method_name, mdef, rbs_source)
474
+ @scratch.add_method(klass, method_name, singleton, mdef)
475
+ end
476
+
477
+ ivars.each do |ivar_name, ty|
478
+ ty = conv_type(ty)
479
+ @scratch.add_ivar_write!(Type::Instance.new(klass), ivar_name, ty, nil)
480
+ end
481
+
482
+ cvars.each do |ivar_name, ty|
483
+ ty = conv_type(ty)
484
+ @scratch.add_cvar_write!(klass, ivar_name, ty, nil)
443
485
  end
444
486
  end
445
487
 
446
- rbs_constants.each do |classpath, value|
447
- base_klass = path_to_klass(scratch, classpath[0..-2])
448
- value = convert_type(scratch, value)
449
- scratch.add_constant(base_klass, classpath[-1], value)
488
+ @json[:constants].each do |classpath, value|
489
+ base_klass = path_to_klass(classpath[0..-2])
490
+ value = conv_type(value)
491
+ @scratch.add_constant(base_klass, classpath[-1], value)
492
+ end
493
+
494
+ @json[:globals].each do |name, value|
495
+ @scratch.add_gvar_write!(name, conv_type(value), nil)
450
496
  end
451
497
 
452
498
  true
453
499
  end
454
500
 
455
- def translate_typed_method_def(scratch, method_name, mdef, rbs_source)
456
- sig_rets = mdef.map do |type_params, lead_tys, opt_tys, rest_ty, req_kw_tys, opt_kw_tys, rest_kw_ty, blk, ret_ty|
457
- if blk
458
- blk = translate_typed_block(scratch, blk)
459
- else
460
- blk = Type::Instance.new(scratch.get_constant(Type::Builtin[:obj], :NilClass))
461
- end
462
-
463
- begin
464
- lead_tys = lead_tys.map {|ty| convert_type(scratch, ty) }
465
- opt_tys = opt_tys.map {|ty| convert_type(scratch, ty) }
466
- rest_ty = convert_type(scratch, rest_ty) if rest_ty
467
- kw_tys = []
468
- req_kw_tys.each {|key, ty| kw_tys << [true, key, convert_type(scratch, ty)] }
469
- opt_kw_tys.each {|key, ty| kw_tys << [false, key, convert_type(scratch, ty)] }
470
- kw_rest_ty = convert_type(scratch, rest_kw_ty) if rest_kw_ty
471
- fargs = FormalArguments.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk)
472
- ret_ty = convert_type(scratch, ret_ty)
473
- [fargs, ret_ty]
474
- rescue UnsupportedType
475
- nil
476
- end
501
+ def conv_method_def(method_name, mdef, rbs_source)
502
+ sig_rets = mdef.map do |sig_ret|
503
+ #type_params = sig_ret[:type_params] # XXX
504
+ lead_tys = sig_ret[:lead_tys]
505
+ opt_tys = sig_ret[:opt_tys]
506
+ rest_ty = sig_ret[:rest_ty]
507
+ req_kw_tys = sig_ret[:req_kw_tys]
508
+ opt_kw_tys = sig_ret[:opt_kw_tys]
509
+ rest_kw_ty = sig_ret[:rest_kw_ty]
510
+ blk = sig_ret[:blk]
511
+ ret_ty = sig_ret[:ret_ty]
512
+
513
+ lead_tys = lead_tys.map {|ty| conv_type(ty) }
514
+ opt_tys = opt_tys.map {|ty| conv_type(ty) }
515
+ rest_ty = conv_type(rest_ty) if rest_ty
516
+ kw_tys = []
517
+ req_kw_tys.each {|key, ty| kw_tys << [true, key, conv_type(ty)] }
518
+ opt_kw_tys.each {|key, ty| kw_tys << [false, key, conv_type(ty)] }
519
+ kw_rest_ty = conv_type(rest_kw_ty) if rest_kw_ty
520
+ blk = blk ? conv_block(blk) : Type.nil
521
+ fargs = FormalArguments.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk)
522
+
523
+ ret_ty = conv_type(ret_ty)
524
+
525
+ [fargs, ret_ty]
477
526
  end.compact
478
527
 
479
528
  TypedMethodDef.new(sig_rets, rbs_source)
480
529
  end
481
530
 
482
- def translate_typed_block(scratch, blk)
483
- lead_tys, ret_ty = blk
484
- lead_tys = lead_tys.map {|ty| convert_type(scratch, ty) }
485
- ret_ty = convert_type(scratch, ret_ty)
486
- Type::TypedProc.new(lead_tys, ret_ty, Type::Builtin[:proc])
531
+ def conv_block(blk)
532
+ lead_tys, opt_tys, ret_ty = blk
533
+ lead_tys = lead_tys.map {|ty| conv_type(ty) }
534
+ opt_tys = opt_tys.map {|ty| conv_type(ty) }
535
+ fargs = FormalArguments.new(lead_tys, opt_tys, nil, nil, nil, nil, nil)
536
+ ret_ty = conv_type(ret_ty)
537
+ Type::TypedProc.new(fargs, ret_ty, Type::Builtin[:proc])
487
538
  end
488
539
 
489
- class UnsupportedType < StandardError
490
- end
491
-
492
- def convert_type(scratch, ty)
540
+ def conv_type(ty)
493
541
  case ty.first
494
- when :class
495
- path_to_klass(scratch, ty[1])
496
- when :instance
497
- begin
498
- Type::Instance.new(path_to_klass(scratch, ty[1]))
499
- rescue
500
- raise UnsupportedType
501
- end
502
- when :bool
503
- Type.bool
504
- when :any
505
- Type.any
506
- when :self
507
- Type::Var.new(:self)
508
- when :int
509
- Type::Instance.new(Type::Builtin[:int])
510
- when :str
511
- Type::Instance.new(Type::Builtin[:str])
512
- when :sym
513
- Type::Symbol.new(ty.last, Type::Instance.new(Type::Builtin[:sym]))
514
- when :nil
515
- Type.nil
516
- when :true
517
- Type::Instance.new(Type::Builtin[:true])
518
- when :false
519
- Type::Instance.new(Type::Builtin[:false])
542
+ when :class then path_to_klass(ty[1])
543
+ when :instance then Type::Instance.new(path_to_klass(ty[1]))
544
+ when :any then Type.any
545
+ when :nil then Type.nil
546
+ when :optional then Type.optional(conv_type(ty[1]))
547
+ when :bool then Type.bool
548
+ when :self then Type::Var.new(:self)
549
+ when :int then Type::Instance.new(Type::Builtin[:int])
550
+ when :str then Type::Instance.new(Type::Builtin[:str])
551
+ when :sym then Type::Symbol.new(ty.last, Type::Instance.new(Type::Builtin[:sym]))
552
+ when :true then Type::Instance.new(Type::Builtin[:true])
553
+ when :false then Type::Instance.new(Type::Builtin[:false])
520
554
  when :array
521
- _, klass, lead_tys, rest_ty = ty
522
- lead_tys = lead_tys.map {|ty| convert_type(scratch, ty) }
523
- rest_ty = convert_type(scratch, rest_ty)
524
- base_type = Type::Instance.new(scratch.get_constant(Type::Builtin[:obj], klass))
555
+ _, path, lead_tys, rest_ty = ty
556
+ lead_tys = lead_tys.map {|ty| conv_type(ty) }
557
+ rest_ty = conv_type(rest_ty)
558
+ base_type = Type::Instance.new(path_to_klass(path))
525
559
  Type::Array.new(Type::Array::Elements.new(lead_tys, rest_ty), base_type)
526
560
  when :hash
527
- _, _klass, (k, v) = ty
528
- Type.gen_hash do |h|
529
- k_ty = convert_type(scratch, k)
530
- v_ty = convert_type(scratch, v)
561
+ _, path, (k, v) = ty
562
+ Type.gen_hash(Type::Instance.new(path_to_klass(path))) do |h|
563
+ k_ty = conv_type(k)
564
+ v_ty = conv_type(v)
531
565
  h[k_ty] = v_ty
532
566
  end
533
567
  when :union
534
- tys = ty[1].reject {|ty2| ty2[1] == [:BigDecimal] } # XXX
535
- Type::Union.new(Utils::Set[*tys.map {|ty2| convert_type(scratch, ty2) }], nil) # Array support
536
- when :optional
537
- Type.optional(convert_type(scratch, ty[1]))
568
+ tys = ty[1]
569
+ Type::Union.new(Utils::Set[*tys.map {|ty2| conv_type(ty2) }], nil) # XXX: Array and Hash support
538
570
  when :var
539
- Type::Var.new(ty[1]) # Currently, only for Array#* : (int | string) -> Array[Elem]
571
+ Type::Var.new(ty[1])
540
572
  else
541
573
  pp ty
542
574
  raise NotImplementedError
543
575
  end
544
576
  end
577
+
578
+ def path_to_klass(path)
579
+ klass = Type::Builtin[:obj]
580
+ path.each do |name|
581
+ klass = @scratch.get_constant(klass, name)
582
+ raise path.inspect if klass == Type.any
583
+ end
584
+ klass
585
+ end
545
586
  end
546
587
  end