function pointers and callbacks
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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(¶ms, 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:
|
||||
|
||||
Reference in New Issue
Block a user