package cimport import "../target" import "core:mem" Type_Id :: distinct u32 INVALID_TYPE :: Type_Id(0xffff_ffff) Type_Kind :: enum u8 { Invalid, Void, C_Char, C_Schar, C_Uchar, C_Short, C_Ushort, C_Int, C_Uint, C_Long, C_Ulong, C_Longlong, C_Ulonglong, C_Float, 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 { name: string, type: Type_Id, reason: string, } Function :: struct { name: string, params: []Type_Id, result: Type_Id, variadic: bool, link_name: string, reason: string, } // Trampoline is a generated C wrapper that gives an external symbol to a // `static inline` (or otherwise internal-linkage) C function so brolang can // call it. The wrapper is compiled and linked alongside the program. `source` // is the wrapper function only; `header` is the absolute path the wrapper must // `#include`, emitted once per unique header by the driver. Trampoline :: struct { symbol: string, source: string, header: string, } Variable :: struct { name: string, type: Type_Id, mutable: bool, reason: string, } Macro_Value_Kind :: enum u8 { Invalid, Integer, Float, } Macro_Value :: struct { kind: Macro_Value_Kind, type: Type_Id, integer: u64, negative: bool, } Macro_Constant :: struct { name: string, type: Type_Id, type_name: string, value: Macro_Value, values: []Macro_Value, aggregate: bool, reason: string, } Unsupported :: struct { name: string, reason: string, final_macro: bool, } Result :: struct { types: [dynamic]Type, records: [dynamic]Record, aliases: [dynamic]Alias, functions: [dynamic]Function, variables: [dynamic]Variable, macros: [dynamic]Macro_Constant, unsupported: [dynamic]Unsupported, trampolines: [dynamic]Trampoline, error_message: string, infrastructure: bool, available: bool, allocator: mem.Allocator, } init_result :: proc(allocator := context.allocator) -> Result { result: Result result.allocator = allocator result.types.allocator = allocator result.records.allocator = allocator result.aliases.allocator = allocator result.functions.allocator = allocator result.variables.allocator = allocator result.macros.allocator = allocator result.unsupported.allocator = allocator result.trampolines.allocator = allocator return 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) delete(alias.reason, result.allocator) } for function in result.functions { delete(function.name, result.allocator) delete(function.params, result.allocator) delete(function.link_name, result.allocator) delete(function.reason, result.allocator) } for variable in result.variables { delete(variable.name, result.allocator) delete(variable.reason, result.allocator) } for macro in result.macros { delete(macro.name, result.allocator) delete(macro.type_name, result.allocator) delete(macro.values, result.allocator) delete(macro.reason, result.allocator) } for item in result.unsupported { delete(item.name, result.allocator) delete(item.reason, result.allocator) } for trampoline in result.trampolines { delete(trampoline.symbol, result.allocator) delete(trampoline.source, result.allocator) delete(trampoline.header, result.allocator) } delete(result.error_message, result.allocator) delete(result.types) delete(result.records) delete(result.aliases) delete(result.functions) delete(result.variables) delete(result.macros) delete(result.unsupported) delete(result.trampolines) } Request :: struct { path: string, include_paths: []string, defines: []string, target: target.Target, } Backend_Proc :: proc(user_data: rawptr, request: Request, allocator: mem.Allocator) -> Result Backend :: struct { import_header: Backend_Proc, user_data: rawptr, } Options :: struct { include_paths: []string, defines: []string, backend: Backend, } import_header :: proc(options: Options, path: string, selected := target.DEFAULT, allocator := context.allocator) -> Result { request := Request{ path=path, include_paths=options.include_paths, defines=options.defines, target=selected, } if options.backend.import_header != nil { return options.backend.import_header(options.backend.user_data, request, allocator) } return import_with_libclang(nil, request, allocator) }