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
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
|