libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

cpp_info.rb (5656B)


      1 # frozen_string_literal: true
      2 
      3 require 'digest/sha2'
      4 
      5 require_relative 'aliaser'
      6 require_relative 'util'
      7 
      8 class Parser
      9   def init_cpp_info
     10     return if @cpp_info_inited
     11 
     12     tu.cursor.visit_children do |c, parent|
     13       next :continue unless filter[c, parent]
     14       case c.kind
     15       when :namespace; next :recurse
     16       when :type_alias_decl
     17         if Util.has_annotation?(c) {|ann| ann == 'libshit_binding_alias' }
     18           aliaser.add_alias c.typedef_type.canonical, c.spelling
     19         end
     20       end
     21       :continue
     22     end
     23 
     24     @cpp_info_inited = true
     25   end
     26 end
     27 
     28 class CppClass
     29   attr_reader :parser, :type
     30 
     31   def initialize parser, t
     32     @parser = parser
     33     @type = t
     34   end
     35 
     36   def name
     37     @name ||= @parser.aliaser.type_name @type, @type.declaration
     38   end
     39 
     40   def short_name
     41     @type.declaration.spelling
     42   end
     43 
     44   def id
     45     # not the most human readable, but at least handles every character without
     46     # collisions
     47     Digest::SHA256.hexdigest name
     48   end
     49 
     50   def bases
     51     @bases ||=
     52       begin
     53         tmp = []
     54         @type.declaration.visit_children do |c, par|
     55           tmp << c.type if c.kind == :cxx_base_specifier
     56           :continue
     57         end
     58         tmp
     59       end
     60   end
     61 
     62   def enum? = @type.kind == :enum
     63 end
     64 
     65 module CppMember
     66   attr_reader :cursor, :klass
     67 
     68   def initialize cursor:, klass:
     69     @cursor = cursor
     70     @klass = klass
     71   end
     72 
     73   def member? = !!@klass
     74 
     75   attr_writer :klass_name
     76   def klass_name
     77     @klass_name ||= @klass.name
     78   end
     79 
     80   def name = @cursor.spelling
     81   def qualified_name
     82     @qualified_name ||= Util.fun_qualified_name(@cursor).freeze
     83   end
     84 end
     85 
     86 class CppFunction
     87   include CppMember
     88   ANNOTATIONS = %i(result_type).freeze
     89   Annotation = Struct.new *ANNOTATIONS, keyword_init: true
     90 
     91   KNOWN_TYPES = %i(
     92     function_decl cxx_method constructor destructor conversion_function
     93   ).freeze
     94 
     95   attr_reader :aliaser, :annotation
     96 
     97   def initialize aliaser:, annotation:, **kw
     98     super **kw
     99     @aliaser = aliaser
    100     @annotation = annotation
    101     @is_template = cursor.kind == :function_template
    102     @real_kind = @is_template ? cursor.template_kind : cursor.kind
    103 
    104     unless KNOWN_TYPES.include? @real_kind
    105       raise ArgumentError, "Invalid cursor kind #{@real_kind}"
    106     end
    107   end
    108 
    109   def method? = @real_kind != :function_decl
    110   def noexcept? = @cursor.type.noexcept?
    111   def noexcept_suffix_str
    112     noexcept? ? ' noexcept' : ''
    113   end
    114 
    115   def const? = @cursor.const?
    116   def const_suffix_str
    117     @cursor.const? ? ' const' : ''
    118   end
    119 
    120   def ptr_type_prefix_str
    121     @ptr_type_prefix_str ||=
    122       ((!method? || @cursor.static?) ? '' : "#{klass_name}::").freeze
    123   end
    124   def ptr_type_suffix_str
    125     @ptr_type_suffix_str ||=
    126       ((@cursor.const? ? ' const' : '') + (noexcept? ? ' noexcept' : '')).freeze
    127   end
    128 
    129   def ptr_type_str
    130     @ptr_type_str ||=
    131       "#{result_type_str} (#{ptr_type_prefix_str}*)(#{arguments_str})" \
    132       "#{ptr_type_suffix_str}".freeze
    133   end
    134 
    135   def ptr_value_prefix_str
    136     # retarded compiler error with gcc in some cases if a non overloaded
    137     # static member function is casted, if we manually take the address.
    138     # not writing & for non static member functions is a compile error...
    139     @ptr_value_prefix_str ||=
    140       ((@cursor.static? ? '' : '&') + (method? ? "#{klass_name}::" : '')).freeze
    141   end
    142 
    143   def ptr_value_uncasted_str
    144     @ptr_value_uncasted_str ||=
    145       "#{ptr_value_prefix_str}#{qualified_name}#{template_suffix_str}".freeze
    146   end
    147 
    148   def ptr_value_str
    149     @ptr_value_str ||=
    150       "static_cast<#{ptr_type_str}>(#{ptr_value_uncasted_str})".freeze
    151   end
    152 
    153   def arguments
    154     @args ||= Util.collect_args(@cursor).freeze
    155   end
    156 
    157   def arguments_str wrap = nil, &;
    158     @aliaser.type_list arguments, wrap, &
    159   end
    160 
    161   def result_type = @cursor.result_type
    162   def result_type_str
    163     @result_type_str ||= calc_result_type_str.freeze
    164   end
    165 
    166   private def calc_result_type_str
    167     return @annotation.result_type if @annotation.result_type
    168     rt = result_type
    169     if rt.spelling == 'auto'
    170       # fake return type with decltype if it's auto, because you can't cast to
    171       # function pointer returning auto...
    172       this = method? ? "std::declval<#{klass_name}>()." : ''
    173       args = arguments_str {|x| "std::declval<#{x}>()" }
    174       "decltype(#{this}#{qualified_name}#{template_suffix_str}(#{args}))"
    175     else
    176       @aliaser.type_name result_type, @cursor
    177     end
    178   end
    179 
    180   def template_arguments
    181     @template_args ||= Util.collect_template_args(@cursor).freeze
    182   end
    183 
    184   attr_reader :template_arguments_map
    185   def template_arguments_map= map
    186     targs = template_arguments
    187     if map.size != targs.size
    188       raise ArgumentError, "Invalid map size #{map.size} != #{targs.size}"
    189     end
    190 
    191     @aliaser = @aliaser.dup # TODO
    192     targs.zip(map).each do |targ, s|
    193       @aliaser.add_alias targ, s.freeze
    194     end
    195     @template_arguments_map = map.freeze
    196   end
    197 
    198   def template_arguments_map_str
    199     @template_arguments_map_str ||= @template_arguments_map.join(', ').freeze
    200   end
    201 
    202   def template_suffix_str
    203     @template_suffix_str ||=
    204       (@is_template ? "<#{template_arguments_map_str}>" : '').freeze
    205   end
    206 end
    207 
    208 class CppVariable
    209   include CppMember
    210   attr_reader :parser
    211 
    212   def initialize parser:, **kw
    213     super **kw
    214     @parser = parser
    215   end
    216 
    217   def type = @cursor.type
    218   def type_str
    219     @type_str ||= @parser.aliaser.type_name @cursor
    220   end
    221 
    222   def ptr_type_str
    223     @ptr_type_str ||= (member? ? "#{type_str} #{klass_name}::*" : type_str).freeze
    224   end
    225 
    226   def ptr_value_str
    227     @ptr_value_str ||= "&#{klass_name}::#{qualified_name}".freeze
    228   end
    229 end
    230 
    231 class CppEnumConstant
    232   include CppMember
    233 
    234   def value_str
    235     @value_str ||= "#{klass_name}::#{qualified_name}".freeze
    236   end
    237 end