typeprof 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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