function pointers and callbacks

This commit is contained in:
2026-06-15 21:09:46 +02:00
parent 3b7c3fcbd0
commit f5605fd3ec
21 changed files with 1927 additions and 122 deletions
+30
View File
@@ -24,19 +24,41 @@ Type_Kind :: enum u8 {
C_Double,
C_Longdouble,
Pointer,
Array,
Function,
Record,
}
Type :: struct {
kind: Type_Kind,
child: Type_Id,
params: []Type_Id,
record: u32,
count: u64,
mutable: bool,
variadic: bool,
}
Record_Kind :: enum u8 {
Struct,
Union,
}
Field :: struct {
name: string,
type: Type_Id,
offset: u64,
}
Record :: struct {
name: string,
identity: string,
fields: [dynamic]Field,
size: u64,
alignment: u32,
kind: Record_Kind,
complete: bool,
reason: string,
}
Alias :: struct {
@@ -82,9 +104,17 @@ init_result :: proc(allocator := context.allocator) -> Result {
}
destroy_result :: proc(result: ^Result) {
for type_item in result.types {
delete(type_item.params, result.allocator)
}
for record in result.records {
delete(record.name, result.allocator)
delete(record.identity, result.allocator)
for field in record.fields {
delete(field.name, result.allocator)
}
delete(record.fields)
delete(record.reason, result.allocator)
}
for alias in result.aliases {
delete(alias.name, result.allocator)
+155 -9
View File
@@ -43,16 +43,25 @@ Api :: struct {
get_cursor_spelling: proc "c"(CXCursor) -> CXString,
get_cursor_usr: proc "c"(CXCursor) -> CXString,
get_cursor_linkage: proc "c"(CXCursor) -> i32,
get_cursor_definition: proc "c"(CXCursor) -> CXCursor,
is_cursor_definition: proc "c"(CXCursor) -> u32,
get_cursor_type: proc "c"(CXCursor) -> CXType,
get_typedef_underlying_type: proc "c"(CXCursor) -> CXType,
get_type_declaration: proc "c"(CXType) -> CXCursor,
get_canonical_type: proc "c"(CXType) -> CXType,
get_pointee_type: proc "c"(CXType) -> CXType,
get_array_element_type: proc "c"(CXType) -> CXType,
get_array_size: proc "c"(CXType) -> i64,
get_result_type: proc "c"(CXType) -> CXType,
get_num_arg_types: proc "c"(CXType) -> i32,
get_arg_type: proc "c"(CXType, u32) -> CXType,
is_function_type_variadic: proc "c"(CXType) -> u32,
is_const_qualified_type: proc "c"(CXType) -> u32,
is_volatile_qualified_type: proc "c"(CXType) -> u32,
cursor_is_bitfield: proc "c"(CXCursor) -> u32,
cursor_get_offset_of_field: proc "c"(CXCursor) -> i64,
type_get_size_of: proc "c"(CXType) -> i64,
type_get_align_of: proc "c"(CXType) -> i64,
cursor_is_variadic: proc "c"(CXCursor) -> u32,
get_num_diagnostics: proc "c"(CXTranslationUnit) -> u32,
get_diagnostic: proc "c"(CXTranslationUnit, u32) -> CXDiagnostic,
@@ -70,6 +79,7 @@ CXCursor_FunctionDecl :: i32(8)
CXCursor_VarDecl :: i32(9)
CXCursor_TypedefDecl :: i32(20)
CXCursor_MacroDefinition :: i32(501)
CXCursor_FieldDecl :: i32(6)
CXLinkage_External :: i32(4)
@@ -97,6 +107,10 @@ CXType_Enum :: i32(106)
CXType_Typedef :: i32(107)
CXType_FunctionNoProto :: i32(110)
CXType_FunctionProto :: i32(111)
CXType_ConstantArray :: i32(112)
CXType_IncompleteArray :: i32(114)
CXType_VariableArray :: i32(115)
CXType_DependentSizedArray :: i32(116)
CXType_Elaborated :: i32(119)
CXType_Attributed :: i32(163)
@@ -135,16 +149,25 @@ load_api_from :: proc(path: string) -> (Api, bool) {
load_proc(&api, "clang_getCursorSpelling", &api.get_cursor_spelling) &&
load_proc(&api, "clang_getCursorUSR", &api.get_cursor_usr) &&
load_proc(&api, "clang_getCursorLinkage", &api.get_cursor_linkage) &&
load_proc(&api, "clang_getCursorDefinition", &api.get_cursor_definition) &&
load_proc(&api, "clang_isCursorDefinition", &api.is_cursor_definition) &&
load_proc(&api, "clang_getCursorType", &api.get_cursor_type) &&
load_proc(&api, "clang_getTypedefDeclUnderlyingType", &api.get_typedef_underlying_type) &&
load_proc(&api, "clang_getTypeDeclaration", &api.get_type_declaration) &&
load_proc(&api, "clang_getCanonicalType", &api.get_canonical_type) &&
load_proc(&api, "clang_getPointeeType", &api.get_pointee_type) &&
load_proc(&api, "clang_getArrayElementType", &api.get_array_element_type) &&
load_proc(&api, "clang_getArraySize", &api.get_array_size) &&
load_proc(&api, "clang_getResultType", &api.get_result_type) &&
load_proc(&api, "clang_getNumArgTypes", &api.get_num_arg_types) &&
load_proc(&api, "clang_getArgType", &api.get_arg_type) &&
load_proc(&api, "clang_isFunctionTypeVariadic", &api.is_function_type_variadic) &&
load_proc(&api, "clang_isConstQualifiedType", &api.is_const_qualified_type) &&
load_proc(&api, "clang_isVolatileQualifiedType", &api.is_volatile_qualified_type) &&
load_proc(&api, "clang_Cursor_isBitField", &api.cursor_is_bitfield) &&
load_proc(&api, "clang_Cursor_getOffsetOfField", &api.cursor_get_offset_of_field) &&
load_proc(&api, "clang_Type_getSizeOf", &api.type_get_size_of) &&
load_proc(&api, "clang_Type_getAlignOf", &api.type_get_align_of) &&
load_proc(&api, "clang_Cursor_isVariadic", &api.cursor_is_variadic) &&
load_proc(&api, "clang_getNumDiagnostics", &api.get_num_diagnostics) &&
load_proc(&api, "clang_getDiagnostic", &api.get_diagnostic) &&
@@ -228,10 +251,99 @@ add_record :: proc(ctx: ^Context, declaration: CXCursor, preferred_name: string)
name = clone_cx_string(ctx.api, ctx.api.get_cursor_spelling(declaration), ctx.allocator)
}
index := u32(len(ctx.result.records))
append(&ctx.result.records, Record{name=name, identity=identity})
append(&ctx.result.records, Record{
name=name,
identity=identity,
kind=.Union if ctx.api.get_cursor_kind(declaration) == CXCursor_UnionDecl else .Struct,
reason=fmt.aprintf("", allocator=ctx.allocator),
})
ctx.result.records[index].fields.allocator = ctx.allocator
return index
}
Record_Field_Context :: struct {
ctx: ^Context,
record: u32,
}
visit_record_field :: proc "c"(cursor, parent: CXCursor, client_data: rawptr) -> i32 {
context = runtime.default_context()
field_ctx := (^Record_Field_Context)(client_data)
ctx := field_ctx.ctx
if ctx.api.get_cursor_kind(cursor) != CXCursor_FieldDecl {
return CXChildVisit_Continue
}
if len(ctx.result.records[field_ctx.record].reason) > 0 {
return CXChildVisit_Continue
}
name := clone_cx_string(ctx.api, ctx.api.get_cursor_spelling(cursor), ctx.allocator)
if len(name) == 0 {
delete(name, ctx.allocator)
delete(ctx.result.records[field_ctx.record].reason, ctx.allocator)
ctx.result.records[field_ctx.record].reason = fmt.aprintf("anonymous C record fields are not supported", allocator=ctx.allocator)
return CXChildVisit_Continue
}
field_type := ctx.api.get_cursor_type(cursor)
if ctx.api.cursor_is_bitfield(cursor) != 0 {
delete(name, ctx.allocator)
delete(ctx.result.records[field_ctx.record].reason, ctx.allocator)
ctx.result.records[field_ctx.record].reason = fmt.aprintf("C bitfields are not supported", allocator=ctx.allocator)
return CXChildVisit_Continue
}
if ctx.api.is_const_qualified_type(field_type) != 0 ||
ctx.api.is_volatile_qualified_type(field_type) != 0 {
delete(name, ctx.allocator)
delete(ctx.result.records[field_ctx.record].reason, ctx.allocator)
ctx.result.records[field_ctx.record].reason = fmt.aprintf("qualified C record fields are not supported", allocator=ctx.allocator)
return CXChildVisit_Continue
}
if field_type.kind == CXType_IncompleteArray ||
field_type.kind == CXType_VariableArray ||
field_type.kind == CXType_DependentSizedArray {
delete(name, ctx.allocator)
delete(ctx.result.records[field_ctx.record].reason, ctx.allocator)
ctx.result.records[field_ctx.record].reason = fmt.aprintf("flexible or variable C array fields are not supported", allocator=ctx.allocator)
return CXChildVisit_Continue
}
translated := translate_type(ctx, field_type)
offset_bits := ctx.api.cursor_get_offset_of_field(cursor)
if translated == INVALID_TYPE || offset_bits < 0 || offset_bits%8 != 0 {
delete(name, ctx.allocator)
delete(ctx.result.records[field_ctx.record].reason, ctx.allocator)
ctx.result.records[field_ctx.record].reason = fmt.aprintf("C record field type or layout is not supported", allocator=ctx.allocator)
return CXChildVisit_Continue
}
append(&ctx.result.records[field_ctx.record].fields, Field{name=name, type=translated, offset=u64(offset_bits/8)})
return CXChildVisit_Continue
}
populate_record :: proc(ctx: ^Context, index: u32, declaration: CXCursor) {
if ctx.result.records[index].complete || len(ctx.result.records[index].reason) > 0 {
return
}
definition := declaration
if ctx.api.is_cursor_definition(definition) == 0 {
definition = ctx.api.get_cursor_definition(declaration)
}
if ctx.api.is_cursor_definition(definition) == 0 {
return
}
record_type := ctx.api.get_cursor_type(definition)
size := ctx.api.type_get_size_of(record_type)
alignment := ctx.api.type_get_align_of(record_type)
if size < 0 || alignment <= 0 {
delete(ctx.result.records[index].reason, ctx.allocator)
ctx.result.records[index].reason = fmt.aprintf("C record size or alignment is not supported", allocator=ctx.allocator)
return
}
ctx.result.records[index].kind = .Union if ctx.api.get_cursor_kind(definition) == CXCursor_UnionDecl else .Struct
ctx.result.records[index].size = u64(size)
ctx.result.records[index].alignment = u32(alignment)
field_ctx := Record_Field_Context{ctx=ctx, record=index}
_ = ctx.api.visit_children(definition, visit_record_field, &field_ctx)
ctx.result.records[index].complete = len(ctx.result.records[index].reason) == 0
}
translate_type :: proc(ctx: ^Context, value: CXType, preferred_record_name := "", depth := 0) -> Type_Id {
if depth > 64 || value.kind == CXType_Invalid || ctx.api.is_volatile_qualified_type(value) != 0 {
return INVALID_TYPE
@@ -259,18 +371,52 @@ translate_type :: proc(ctx: ^Context, value: CXType, preferred_record_name := ""
if child == INVALID_TYPE {
return INVALID_TYPE
}
mutable := ctx.api.is_const_qualified_type(pointee) == 0
if pointee.kind == CXType_FunctionProto {
mutable = false
}
return add_type(ctx, Type{
kind=.Pointer,
child=child,
mutable=ctx.api.is_const_qualified_type(pointee) == 0,
mutable=mutable,
})
case CXType_Record:
declaration := ctx.api.get_type_declaration(value)
if ctx.api.get_cursor_kind(declaration) == CXCursor_UnionDecl {
case CXType_ConstantArray:
count := ctx.api.get_array_size(value)
child := translate_type(ctx, ctx.api.get_array_element_type(value), "", depth+1)
if count <= 0 || child == INVALID_TYPE {
return INVALID_TYPE
}
return add_type(ctx, Type{kind=.Array, child=child, count=u64(count), mutable=true})
case CXType_Record:
declaration := ctx.api.get_type_declaration(value)
record := add_record(ctx, declaration, preferred_record_name)
populate_record(ctx, record, declaration)
return add_type(ctx, Type{kind=.Record, child=INVALID_TYPE, record=record})
case CXType_FunctionProto:
result := translate_type(ctx, ctx.api.get_result_type(value), "", depth+1)
if result == INVALID_TYPE {
return INVALID_TYPE
}
count := ctx.api.get_num_arg_types(value)
if count < 0 {
return INVALID_TYPE
}
params: [dynamic]Type_Id
params.allocator = ctx.allocator
for index in 0..<count {
param := translate_type(ctx, ctx.api.get_arg_type(value, u32(index)), "", depth+1)
append(&params, param)
if param == INVALID_TYPE {
delete(params)
return INVALID_TYPE
}
}
return add_type(ctx, Type{
kind=.Function,
child=result,
params=params[:],
variadic=ctx.api.is_function_type_variadic(value) != 0,
})
case CXType_Typedef:
declaration := ctx.api.get_type_declaration(value)
name := clone_cx_string(ctx.api, ctx.api.get_cursor_spelling(declaration), ctx.allocator)
@@ -282,7 +428,8 @@ translate_type :: proc(ctx: ^Context, value: CXType, preferred_record_name := ""
return INVALID_TYPE
}
return translate_type(ctx, canonical, preferred_record_name, depth+1)
case CXType_Enum, CXType_FunctionNoProto, CXType_FunctionProto:
case CXType_Enum, CXType_FunctionNoProto,
CXType_IncompleteArray, CXType_VariableArray, CXType_DependentSizedArray:
return INVALID_TYPE
}
return INVALID_TYPE
@@ -373,14 +520,13 @@ visit_cursor :: proc "c"(cursor, parent: CXCursor, client_data: rawptr) -> i32 {
reason = "typedef underlying type is not supported"
}
add_alias(ctx, name, value, reason)
case CXCursor_StructDecl:
case CXCursor_StructDecl, CXCursor_UnionDecl:
if len(name) > 0 {
record := add_record(ctx, cursor, name)
populate_record(ctx, record, cursor)
value := add_type(ctx, Type{kind=.Record, child=INVALID_TYPE, record=record})
add_alias(ctx, name, value)
}
case CXCursor_UnionDecl:
add_unsupported(ctx, name, "C unions are not supported")
case CXCursor_EnumDecl:
add_unsupported(ctx, name, "C enums are not supported")
case CXCursor_VarDecl: