You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
5.5 KiB
Ruby

# frozen_string_literal: true
require 'digest/sha2'
require_relative 'aliaser'
require_relative 'util'
class Parser
def init_cpp_info
return if @cpp_info_inited
tu.cursor.visit_children do |c, parent|
next :continue unless filter[c, parent]
case c.kind
when :namespace; next :recurse
when :type_alias_decl
if Util.has_annotation?(c) {|ann| ann == 'libshit_binding_alias' }
aliaser.add_alias c.typedef_type.canonical, c.spelling
end
end
:continue
end
@cpp_info_inited = true
end
end
class CppClass
attr_reader :parser, :type
def initialize parser, t
@parser = parser
@type = t
end
def name
@name ||= @parser.aliaser.type_name @type, @type.declaration
end
def short_name
@type.declaration.spelling
end
def id
# not the most human readable, but at least handles every character without
# collisions
Digest::SHA256.hexdigest name
end
def bases
@bases ||=
begin
tmp = []
@type.declaration.visit_children do |c, par|
tmp << c.type if c.kind == :cxx_base_specifier
:continue
end
tmp
end
end
def enum? = @type.kind == :enum
end
module CppMember
attr_reader :cursor, :klass
def initialize cursor:, klass:
@cursor = cursor
@klass = klass
end
def member? = !!@klass
attr_writer :klass_name
def klass_name
@klass_name ||= @klass.name
end
def name = @cursor.spelling
def qualified_name
@qualified_name ||= Util.fun_qualified_name(@cursor).freeze
end
end
class CppFunction
include CppMember
ANNOTATIONS = %i(result_type).freeze
Annotation = Struct.new *ANNOTATIONS, keyword_init: true
KNOWN_TYPES = %i(
function_decl cxx_method constructor destructor conversion_function
).freeze
attr_reader :aliaser, :annotation
def initialize aliaser:, annotation:, **kw
super **kw
@aliaser = aliaser
@annotation = annotation
@is_template = cursor.kind == :function_template
@real_kind = @is_template ? cursor.template_kind : cursor.kind
unless KNOWN_TYPES.include? @real_kind
raise ArgumentError, "Invalid cursor kind #{@real_kind}"
end
end
def method? = @real_kind != :function_decl
def noexcept? = @cursor.type.noexcept?
def noexcept_suffix_str
noexcept? ? ' noexcept' : ''
end
def const? = @cursor.const?
def const_suffix_str
@cursor.const? ? ' const' : ''
end
def ptr_type_prefix_str
@ptr_type_prefix_str ||=
((!method? || @cursor.static?) ? '' : "#{klass_name}::").freeze
end
def ptr_type_suffix_str
@ptr_type_suffix_str ||=
((@cursor.const? ? ' const' : '') + (noexcept? ? ' noexcept' : '')).freeze
end
def ptr_type_str
@ptr_type_str ||=
"#{result_type_str} (#{ptr_type_prefix_str}*)(#{arguments_str})" \
"#{ptr_type_suffix_str}".freeze
end
def ptr_value_prefix_str
# retarded compiler error with gcc in some cases if a non overloaded
# static member function is casted, if we manually take the address.
# not writing & for non static member functions is a compile error...
@ptr_value_prefix_str ||=
((@cursor.static? ? '' : '&') + (method? ? "#{klass_name}::" : '')).freeze
end
def ptr_value_uncasted_str
@ptr_value_uncasted_str ||=
"#{ptr_value_prefix_str}#{qualified_name}#{template_suffix_str}".freeze
end
def ptr_value_str
@ptr_value_str ||=
"static_cast<#{ptr_type_str}>(#{ptr_value_uncasted_str})".freeze
end
def arguments
@args ||= Util.collect_args(@cursor).freeze
end
def arguments_str wrap = nil, &;
@aliaser.type_list arguments, wrap, &
end
def result_type = @cursor.result_type
def result_type_str
@result_type_str ||= calc_result_type_str.freeze
end
private def calc_result_type_str
return @annotation.result_type if @annotation.result_type
rt = result_type
if rt.spelling == 'auto'
# fake return type with decltype if it's auto, because you can't cast to
# function pointer returning auto...
this = method? ? "std::declval<#{klass_name}>()." : ''
args = arguments_str {|x| "std::declval<#{x}>()" }
"decltype(#{this}#{qualified_name}#{template_suffix_str}(#{args}))"
else
@aliaser.type_name result_type, @cursor
end
end
def template_arguments
@template_args ||= Util.collect_template_args(@cursor).freeze
end
attr_reader :template_arguments_map
def template_arguments_map= map
targs = template_arguments
if map.size != targs.size
raise ArgumentError, "Invalid map size #{map.size} != #{targs.size}"
end
@aliaser = @aliaser.dup # TODO
targs.zip(map).each do |targ, s|
@aliaser.add_alias targ, s.freeze
end
@template_arguments_map = map.freeze
end
def template_arguments_map_str
@template_arguments_map_str ||= @template_arguments_map.join(', ').freeze
end
def template_suffix_str
@template_suffix_str ||=
(@is_template ? "<#{template_arguments_map_str}>" : '').freeze
end
end
class CppVariable
include CppMember
attr_reader :parser
def initialize parser:, **kw
super **kw
@parser = parser
end
def type = @cursor.type
def type_str
@type_str ||= @parser.aliaser.type_name @cursor
end
def ptr_type_str
@ptr_type_str ||= (member? ? "#{type_str} #{klass_name}::*" : type_str).freeze
end
def ptr_value_str
@ptr_value_str ||= "&#{klass_name}::#{qualified_name}".freeze
end
end
class CppEnumConstant
include CppMember
def value_str
@value_str ||= "#{klass_name}::#{qualified_name}".freeze
end
end