Class: TypeProf::RBS2JSON
Relationships & Source Files | |
Inherits: | Object |
Defined in: | lib/typeprof/import.rb |
Constant Summary
-
AliasDecl =
# File 'lib/typeprof/import.rb', line 165defined?(RBS::AST::Declarations::Alias) ? RBS::AST::Declarations::Alias : RBS::AST::Declarations::AliasDecl
-
TypeAlias =
# File 'lib/typeprof/import.rb', line 166defined?(RBS::AST::Declarations::TypeAlias) ? RBS::AST::Declarations::TypeAlias : nil
Class Method Summary
- .new(all_env, cur_env) ⇒ RBS2JSON constructor
Instance Method Summary
- #attr_method_def(kind, name, ty, visibility)
- #attr_rbs_source(member)
- #conv_block(rbs_block)
- #conv_classes
-
#conv_constants
constant_name = [Symbol].
- #conv_func(type_params, func, block)
-
#conv_globals
gvar_name = Symbol (:$gvar).
- #conv_method_def(rbs_method_types, visibility)
- #conv_type(ty)
- #conv_type_name(name)
- #dump_json
- #each_class_decl
- #each_reference(decl) {|decl.name| ... }
- #get_super_class(name, decls)
Constructor Details
.new(all_env, cur_env) ⇒ RBS2JSON
# File 'lib/typeprof/import.rb', line 128
def initialize(all_env, cur_env) @all_env, @cur_env = all_env, cur_env @alias_resolution_stack = {} end
Instance Method Details
#attr_method_def(kind, name, ty, visibility)
[ GitHub ]# File 'lib/typeprof/import.rb', line 431
def attr_method_def(kind, name, ty, visibility) { kind: kind, ivar: name, ty: ty, visibility: visibility, } end
#attr_rbs_source(member)
[ GitHub ]#conv_block(rbs_block)
[ GitHub ]# File 'lib/typeprof/import.rb', line 448
def conv_block(rbs_block) blk = rbs_block.type lead_tys = blk.required_positionals.map {|type| conv_type(type.type) } opt_tys = blk.optional_positionals.map {|type| conv_type(type.type) } rest_ty = blk.rest_positionals rest_ty = conv_type(rest_ty.type) if rest_ty opt_kw_tys = blk.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] } req_kw_tys = blk.required_keywords.to_h {|key, type| [key, conv_type(type.type)] } rest_kw_ty = blk.rest_keywords rest_kw_ty = conv_type(rest_kw_ty.type) if rest_kw_ty ret_ty = conv_type(blk.return_type) { required_block: rbs_block.required, lead_tys: lead_tys, opt_tys: opt_tys, rest_ty: rest_ty, req_kw_tys: req_kw_tys, opt_kw_tys: opt_kw_tys, rest_kw_ty: rest_kw_ty, blk: blk, ret_ty: ret_ty, } end
#conv_classes
[ GitHub ]# File 'lib/typeprof/import.rb', line 168
def conv_classes json = {} each_class_decl do |name, decls| klass = conv_type_name(name) super_class_name, super_class_args = get_super_class(name, decls) if super_class_name name = conv_type_name(super_class_name) type_args = super_class_args.map {|type| conv_type(type) } superclass = [name, type_args] end type_params = nil modules = { include: [], extend: [], prepend: [] } methods = {} attr_methods = {} ivars = {} cvars = {} rbs_sources = {} visibility = true decls.each do |decl| decl = decl.decl type_params2 = decl.type_params # A hack to deal with the imcompatibility between rbs 1.8 and 2.0 type_params2 = type_params2.params if type_params2.respond_to?(:params) type_params2 = type_params2.map {|param| [param.name, param.variance] } raise "inconsistent type parameter declaration" if type_params && type_params != type_params2 type_params = type_params2 decl.members.each do |member| case member when RBS::AST::Members::MethodDefinition name = member.name if member.respond_to?(:overloads) types = member.overloads.map {|overload| overload.method_type } else types = member.types end method_types = types.map do |method_type| case method_type when RBS::MethodType then method_type when :super then raise NotImplementedError end end method_def = conv_method_def(method_types, visibility) rbs_source = [ (member.kind == :singleton ? "self." : "") + member.name.to_s, types.map {|type| type.location.source }, [member.location.name, CodeRange.from_rbs(member.location)], ] if member.instance? methods[[false, name]] = method_def rbs_sources[[false, name]] = rbs_source end if member.singleton? methods[[true, name]] = method_def rbs_sources[[true, name]] = rbs_source end when RBS::AST::Members::AttrReader ty = conv_type(member.type) attr_methods[[false, member.name]] = attr_method_def(:reader, member.name, ty, visibility) rbs_sources[[false, member.name]] = attr_rbs_source(member) when RBS::AST::Members::AttrWriter ty = conv_type(member.type) attr_methods[[false, member.name]] = attr_method_def(:writer, member.name, ty, visibility) rbs_sources[[false, member.name]] = attr_rbs_source(member) when RBS::AST::Members::AttrAccessor ty = conv_type(member.type) attr_methods[[false, member.name]] = attr_method_def(:accessor, member.name, ty, visibility) rbs_sources[[false, member.name]] = attr_rbs_source(member) when RBS::AST::Members::Alias # XXX: an alias to attr methods? if member.instance? method_def = methods[[false, member.old_name]] methods[[false, member.new_name]] = method_def if method_def end if member.singleton? method_def = methods[[true, member.old_name]] methods[[true, member.new_name]] = method_def if method_def end when RBS::AST::Members::Include name = member.name if name.kind == :class # including a module mod = conv_type_name(name) type_args = member.args.map {|type| conv_type(type) } modules[:include] << [mod, type_args] else # including an interface mod = conv_type_name(name) type_args = member.args.map {|type| conv_type(type) } modules[:include] << [mod, type_args] end when RBS::AST::Members::Extend name = member.name if name.kind == :class mod = conv_type_name(name) type_args = member.args.map {|type| conv_type(type) } modules[:extend] << [mod, type_args] else # extending a module with an interface is not supported yet end when RBS::AST::Members::Prepend name = member.name if name.kind == :class mod = conv_type_name(name) type_args = member.args.map {|type| conv_type(type) } modules[:prepend] << [mod, type_args] else # extending a module with an interface is not supported yet end when RBS::AST::Members::InstanceVariable ivars[member.name] = conv_type(member.type) when RBS::AST::Members::ClassVariable cvars[member.name] = conv_type(member.type) when RBS::AST::Members::Public visibility = true when RBS::AST::Members::Private visibility = false # The following declarations are ignoreable because they are handled in other level when RBS::AST::Declarations::Constant when AliasDecl # type alias when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module when RBS::AST::Declarations::Interface when TypeAlias else warn "Importing #{ member.class.name } is not supported yet" end end end json[klass] = { type_params: type_params, superclass: superclass, members: { modules: modules, methods: methods, attr_methods: attr_methods, ivars: ivars, cvars: cvars, rbs_sources: rbs_sources, }, } end json end
#conv_constants
constant_name = [Symbol]
{ constant_name => type }
# File 'lib/typeprof/import.rb', line 144
def conv_constants constants = {} @cur_env.constant_decls.each do |name, decl| klass = conv_type_name(name) constants[klass] = conv_type(decl.decl.type) end constants end
#conv_func(type_params, func, block)
[ GitHub ]# File 'lib/typeprof/import.rb', line 404
def conv_func(type_params, func, block) blk = block ? conv_block(block) : nil lead_tys = func.required_positionals.map {|type| conv_type(type.type) } opt_tys = func.optional_positionals.map {|type| conv_type(type.type) } rest_ty = func.rest_positionals rest_ty = conv_type(rest_ty.type) if rest_ty opt_kw_tys = func.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] } req_kw_tys = func.required_keywords.to_h {|key, type| [key, conv_type(type.type)] } rest_kw_ty = func.rest_keywords rest_kw_ty = conv_type(rest_kw_ty.type) if rest_kw_ty ret_ty = conv_type(func.return_type) { type_params: type_params, lead_tys: lead_tys, opt_tys: opt_tys, rest_ty: rest_ty, req_kw_tys: req_kw_tys, opt_kw_tys: opt_kw_tys, rest_kw_ty: rest_kw_ty, blk: blk, ret_ty: ret_ty, } end
#conv_globals
gvar_name = Symbol (:$gvar)
{ gvar_name => type }
# File 'lib/typeprof/import.rb', line 156
def conv_globals gvars = {} @cur_env.global_decls.each do |name, decl| decl = decl.decl gvars[name] = conv_type(decl.type) end gvars end
#conv_method_def(rbs_method_types, visibility)
[ GitHub ]# File 'lib/typeprof/import.rb', line 394
def conv_method_def(rbs_method_types, visibility) sig_rets = rbs_method_types.map do |method_type| conv_func(method_type.type_params, method_type.type, method_type.block) end { sig_rets: sig_rets, visibility: visibility, } end
#conv_type(ty)
[ GitHub ]# File 'lib/typeprof/import.rb', line 475
def conv_type(ty) case ty when RBS::Types::ClassSingleton [:class, conv_type_name(ty.name)] when RBS::Types::ClassInstance klass = conv_type_name(ty.name) case klass when [:Array] raise if ty.args.size != 1 [:array, [:Array], [], conv_type(ty.args.first)] when [:Hash] raise if ty.args.size != 2 key, val = ty.args [:hash, [:Hash], [conv_type(key), conv_type(val)]] when [:Enumerator] raise if ty.args.size != 2 [:array, [:Enumerator], [], conv_type(ty.args.first)] else if ty.args.empty? [:instance, klass] else [:cell, [:instance, klass], ty.args.map {|ty| conv_type(ty) }] end end when RBS::Types::Bases::Bool then [:bool] when RBS::Types::Bases::Any then [:any] when RBS::Types::Bases::Top then [:any] when RBS::Types::Bases::Void then [:void] when RBS::Types::Bases::Self then [:self] when RBS::Types::Bases::Nil then [:nil] when RBS::Types::Bases::Bottom then [:union, []] when RBS::Types::Variable then [:var, ty.name] when RBS::Types::Tuple tys = ty.types.map {|ty2| conv_type(ty2) } [:array, [:Array], tys, [:union, []]] when RBS::Types::Literal case ty.literal when Integer then [:int] when String then [:str] when true then [:true] when false then [:false] when Symbol then [:sym, ty.literal] else p ty.literal raise NotImplementedError end when RBS::Types::Alias if @alias_resolution_stack[ty.name] [:any] else begin @alias_resolution_stack[ty.name] = true alias_decl = (@all_env.respond_to?(:alias_decls) ? @all_env.alias_decls : @all_env.type_alias_decls)[ty.name] alias_decl ? conv_type(alias_decl.decl.type) : [:any] ensure @alias_resolution_stack.delete(ty.name) end end when RBS::Types::Union [:union, ty.types.map {|ty2| conv_type(ty2) }.compact] when RBS::Types::Intersection [:intersection, ty.types.map {|ty2| conv_type(ty2) }.compact] when RBS::Types::Optional [:optional, conv_type(ty.type)] when RBS::Types::Interface # XXX: Currently, only a few builtin interfaces are supported case ty.to_s when "::_ToS" then [:str] when "::_ToStr" then [:str] when "::_ToInt" then [:int] when "::_ToAry[U]" then [:array, [:Array], [], [:var, :U]] else [:instance, conv_type_name(ty.name)] end when RBS::Types::Bases::Instance then [:any] # XXX: not implemented yet when RBS::Types::Bases::Class then [:any] # XXX: not implemented yet when RBS::Types::Record [:hash_record, [:Hash], ty.fields.map {|key, ty| [key, conv_type(ty)] }] when RBS::Types::Proc [:proc, conv_func(nil, ty.type, nil)] else warn "unknown RBS type: %p" % ty.class [:any] end end
#conv_type_name(name)
[ GitHub ]# File 'lib/typeprof/import.rb', line 561
def conv_type_name(name) name.namespace.path + [name.name] end
#dump_json
[ GitHub ]# File 'lib/typeprof/import.rb', line 133
def dump_json { classes: conv_classes, constants: conv_constants, globals: conv_globals, } end
#each_class_decl
[ GitHub ]# File 'lib/typeprof/import.rb', line 327
def each_class_decl # topological sort # * superclasses and modules appear earlier than their subclasses (Object is earlier than String) # * namespace module appers earlier than its children (Process is earlier than Process::Status) visited = {} queue = @cur_env.class_decls.keys.map {|name| [:visit, name] }.reverse until queue.empty? event, name = queue.pop case event when :visit if !visited[name] visited[name] = true queue << [:new, name] @all_env.class_decls[name].decls.each do |decl| decl = decl.decl next if decl.is_a?(RBS::AST::Declarations::Module) each_reference(decl) {|name| queue << [:visit, name] } end queue << [:visit, name.namespace.to_type_name] if !name.namespace.empty? end when :new decls = @cur_env.class_decls[name] yield name, decls.decls if decls end end @cur_env.interface_decls.each do |name, decl| yield name, [decl] end end
#each_reference(decl) {|decl.name| ... }
# File 'lib/typeprof/import.rb', line 358
def each_reference(decl, &blk) yield decl.name if decl.super_class name = decl.super_class.name else name = RBS::BuiltinNames::Object.name end return if decl.name == RBS::BuiltinNames::BasicObject.name return if decl.name == name decls = @all_env.class_decls[name] if decls decls.decls.each do |decl| each_reference(decl.decl, &blk) end end end
#get_super_class(name, decls)
[ GitHub ]# File 'lib/typeprof/import.rb', line 375
def get_super_class(name, decls) return nil if name == RBS::BuiltinNames::BasicObject.name decls.each do |decl| decl = decl.decl case decl when RBS::AST::Declarations::Class super_class = decl.super_class return super_class.name, super_class.args if super_class when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface return nil else raise "unknown declaration: %p" % decl.class end end return RBS::BuiltinNames::Object.name, [] end