Files
brolang/compiler/cimport/cimport.odin
T

246 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_Bool,
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)
}