add bindings generator

This commit is contained in:
nub31
2025-10-16 22:09:33 +02:00
parent 915689fa63
commit 1edeb7253e

116
bindings/generate.py Normal file
View File

@@ -0,0 +1,116 @@
import json
import sys
import clang.cindex
from clang.cindex import CursorKind, TypeKind, Type
def map_type(clang_type: Type):
canonical = clang_type.get_canonical()
kind = canonical.kind
spelling = (
canonical.spelling.replace("const ", "")
.replace("volatile ", "")
.replace("restrict ", "")
)
if kind == TypeKind.POINTER:
pointee = canonical.get_pointee()
if pointee.kind == TypeKind.CHAR_S or pointee.kind == TypeKind.CHAR_U:
return "cstring"
return f"^{map_type(pointee)}"
if kind == TypeKind.CONSTANTARRAY:
element_type = canonical.get_array_element_type()
size = canonical.get_array_size()
return f"[{size}]{map_type(element_type)}"
if kind == TypeKind.FUNCTIONPROTO or kind == TypeKind.FUNCTIONNOPROTO:
arg_types = []
for arg in canonical.argument_types():
arg_types.append(map_type(arg))
mapped_return = map_type(canonical.get_result())
args_str = ", ".join(arg_types)
return f"func({args_str}): {mapped_return}"
if kind == TypeKind.VOID:
return "void"
if kind == TypeKind.BOOL:
return "bool"
if kind in [TypeKind.CHAR_S, TypeKind.SCHAR]:
return "i8"
if kind == TypeKind.CHAR_U or kind == TypeKind.UCHAR:
return "u8"
if kind == TypeKind.SHORT:
return "i16"
if kind == TypeKind.USHORT:
return "u16"
if kind == TypeKind.INT:
return "i32"
if kind == TypeKind.UINT:
return "u32"
if kind in [TypeKind.LONG, TypeKind.LONGLONG]:
return "i64"
if kind in [TypeKind.ULONG, TypeKind.ULONGLONG]:
return "u64"
if kind == TypeKind.FLOAT:
return "f32"
if kind == TypeKind.DOUBLE or kind == TypeKind.LONGDOUBLE:
return "f64"
if kind == TypeKind.RECORD:
if not spelling.startswith("struct "):
name = clang_type.get_canonical().spelling
raise Exception(f"Unknown custom type: {name}")
return spelling.replace("struct ", "")
name = clang_type.get_canonical().spelling
raise Exception(f"Unresolved type: {name}")
filename = "../examples/raylib/raylib-5.5_linux_amd64/include/raylib.h"
index = clang.cindex.Index.create()
args = ["-x", "c"]
tu = index.parse(filename, args=args)
if tu.diagnostics:
for diag in tu.diagnostics:
if diag.severity >= clang.cindex.Diagnostic.Error:
print(f"Error: {diag.spelling}", file=sys.stderr)
for cursor in tu.cursor.walk_preorder():
if cursor.kind == CursorKind.FUNCTION_DECL:
name = cursor.spelling
return_type = map_type(cursor.result_type)
params = []
for arg in cursor.get_arguments():
param_name = arg.spelling
param_type = map_type(arg.type)
params.append(f"{param_name}: {param_type}")
params_str = ", ".join(params)
print(f'export extern "{name}" func {name}({params_str}): {return_type}')
elif cursor.kind == CursorKind.STRUCT_DECL:
name = cursor.spelling
print(f"export struct {name}")
print("{")
for field in cursor.get_children():
if field.kind == CursorKind.FIELD_DECL:
field_name = field.spelling
field_type = map_type(field.type)
print(f" {field_name}: {field_type}")
else:
raise Exception(f"Unsupported child of struct: {field.spelling}")
print("}")