245 lines
5.3 KiB
Odin
245 lines
5.3 KiB
Odin
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,
|
|
param_names: []string,
|
|
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)
|
|
for param_name in function.param_names {
|
|
delete(param_name, result.allocator)
|
|
}
|
|
delete(function.param_names, 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)
|
|
}
|