imgui-odin/generator.js

343 lines
9.4 KiB
JavaScript
Raw Normal View History

2025-01-12 18:33:36 -05:00
// a crappy dear_binding -> odin generator
const file = await Bun.file('glfw/impl_glfw.json').json()
const keywords =['asm','auto_cast','bit_set','break','case','cast','context','continue',
'defer','distinct','do','dynamic','else','enum','fallthrough','for','foreign','if',
'import','in','map','not_in','or_else','or_return','package','proc','return','struct',
'switch','transmute','typeid','union','using','when','where'];
const namespace = {} // [c-name]: odin-name
console.log(`package imgui\n
foreign import imgui "!!!!!!!!!!!!!"
`)
for (const en of file.enums) {
let name = en.name;
if (name.startsWith('ImGui'))
name = name.substring(5)
if (name.endsWith('_'))
name = name.substring(0, name.length - 1)
let out = `${name} :: enum {`
for (const el of en.elements) {
let el_name = el.name
if (el_name.startsWith(en.name)) el_name = el_name.substring(en.name.length)
if (el_name.startsWith('_')) el_name = el_name.substring(1)
if (el_name.match(/^\d/)) el_name = 'Num' + el_name
out += `\n\t${el_name}`;
if (el.value !== undefined) {
let v = el.value
// if (el.value_expression.startsWith(en.name)) ve = el_name.substring(en.name.length)
out += ` = ${v}`
}
out += ','
}
out += '\n}'
console.log(out)
if (en.name.endsWith('_')) namespace[en.name.substring(0, en.name.length - 1)] = name
else namespace[en.name] = name
}
// see odin core:c
const cToOdinTypes = {
'int': 'i32',
'signed char': 'i8',
'unsigned char': 'u8',
'short': 'i16',
'signed short': 'i16',
'unsigned short': 'u16',
'signed int': 'i32',
'unsigned int': 'u32',
'long long': 'i64',
'signed long long': 'i64',
'unsigned long long': 'u64',
'void*': 'rawptr',
'const void*': 'rawptr',
'size_t': 'u32',
'ssize_t': 'i32',
'const char*': 'cstring',
'char*': 'cstring',
'unsigned char*': 'cstring',
'bool': 'b8',
'float': 'f32',
'double': 'f64',
}
const fp_typedef = []
for (const td of file.typedefs) {
if (namespace[td.name]) continue
let name = td.name;
if (name.startsWith('ImGui'))
name = name.substring(5)
let decl = td.type.declaration;
if (decl in cToOdinTypes)
decl = cToOdinTypes[decl];
if (td.type.type_details?.flavour === 'function_pointer') {
const fp_return_type = td.type.type_details.return_type.declaration
const args = []
for (const arg of td.type.type_details.arguments) {
let type = '';
if (arg.type.declaration in cToOdinTypes)
type = cToOdinTypes[arg.type.declaration]
else {
let innerType = arg.type.description
while (innerType.kind === 'Pointer') {
type += '^'
innerType = innerType.inner_type
}
if (innerType.name in namespace)
type += namespace[innerType.name]
else
{
type += innerType.name
}
}
// args.push(`${arg.name}: ${type}`)
args.push({
name: arg.name,
type: type,
})
}
let return_type = null
if (fp_return_type !== 'void'){
if (fp_return_type in cToOdinTypes)
return_type = cToOdinTypes[fp_return_type]
else {
let innerType = td.type.type_details.return_type
while (innerType.kind === 'Pointer') {
return_type += '^'
innerType = innerType.inner_type
}
// return_type += innerType.name
}
}
fp_typedef.push({
name: name,
args: args,
return_type: return_type,
})
} else {
console.log(`${name} :: ${decl}`)
}
namespace[td.name] = name
}
for (const fptd of fp_typedef) {
let sep = ''
let out = fptd.name
out += ` :: proc(`
for (const arg of fptd.args) {
let type = arg.type
if (arg.type in namespace) type = namespace[arg.type]
out += `${sep}${arg.name}: ${type}`
sep = ', '
}
out += `)`
if (fptd.return_type !== null) out += ` -> ${fptd.return_type}`
console.log(out)
}
console.log(`@(default_calling_convention = "cdecl", link_prefix = "ImGui_")
foreign imgui {`)
for (const fn of file.functions) {
let name = fn.name;
if (name.startsWith('ImGui_')) name = name.substring(6)
const args = []
for (const arg of fn.arguments) {
let type = '';
let name = (keywords.includes(arg.name))? '_' + arg.name: arg.name
if (arg.is_varargs){
name = '#c_vararg ' + name
type = '..any'
}
else {
if (arg.type.declaration in cToOdinTypes)
type = cToOdinTypes[arg.type.declaration]
else if (arg.type.declaration in namespace) {
if (namespace[arg.type.declaration].startsWith('ImGui'))
type = namespace[arg.type.declaration].substring('ImGui'.length)
else
type = namespace[arg.type.declaration]
}
else {
let innerType = arg.type.description
if (arg.is_array) {
type += `[${innerType.bounds ?? ''}]`
innerType = innerType.inner_type
}
let ptr = 0
let ptr_chr = '^'
while (innerType.kind === 'Pointer') {
ptr++
innerType = innerType.inner_type
}
if (ptr && innerType.builtin_type == 'void' || innerType.builtin_type?.endsWith('char')) {
ptr--
ptr_chr = '[^]'
}
for (let i = 0; i < ptr; i++) {
type += ptr_chr
}
if (ptr_chr === '[^]') {
if (innerType.builtin_type == 'void') type += 'rawptr'
else if (innerType.builtin_type.endsWith('char')) type += 'cstring'
}
else if (innerType.name in namespace) type += namespace[innerType.name]
else if (innerType.name in cToOdinTypes) type += cToOdinTypes[innerType.name]
else if (innerType.builtin_type in cToOdinTypes) type += cToOdinTypes[innerType.builtin_type]
else if (innerType.builtin_type?.replace('_',' ') in cToOdinTypes) type += cToOdinTypes[innerType.builtin_type.replace('_',' ')]
else if (innerType.name) {
if (innerType.name.startsWith('ImGui'))
type += innerType.name.substring('ImGui'.length)
else
type += innerType.name
}
else type = '[!!!]'
}
}
// args.push(`${arg.name}: ${type}`)
args.push({
name: name, // do a keyword check instead
type: type,
})
}
let sep = ''
let out = name
out += ` :: proc(`
for (const arg of args) {
let type = arg.type
if (arg.type in namespace) type = namespace[arg.type]
out += `${sep}${arg.name}: ${type}`
sep = ', '
}
out += `)`
if (fn.return_type.declaration !== 'void'){
let return_type = ''
if (fn.return_type in cToOdinTypes)
return_type = cToOdinTypes[fp_return_type]
else if (fn.return_type in namespace) {
if (namespace[fn.return_type].startsWith('ImGui'))
return_type = namespace[fn.return_type].substring('ImGui'.length)
}
else {
let innerType = fn.return_type.description
let ptr = 0
let ptr_chr = '^'
while (innerType.kind === 'Pointer') {
ptr++
innerType = innerType.inner_type
}
if (ptr && innerType.builtin_type == 'void' || innerType.builtin_type == 'char') {
ptr--
ptr_chr = '[^]'
}
for (let i = 0; i < ptr; i++) {
return_type += ptr_chr
}
if (ptr_chr === '[^]') {
if (innerType.builtin_type == 'void') return_type += 'rawptr'
else if (innerType.builtin_type == 'char') return_type += 'cstring'
}
else if (innerType.name in namespace) {
if (namespace[innerType.name].startsWith('ImGui'))
return_type += namespace[innerType.name].substring('ImGui'.length)
else
return_type += namespace[innerType.name]
}
else if (innerType.name in cToOdinTypes) return_type += cToOdinTypes[innerType.name]
else if (innerType.builtin_type in cToOdinTypes) return_type += cToOdinTypes[innerType.builtin_type]
else if (innerType.builtin_type?.replace('_',' ') in cToOdinTypes) return_type += cToOdinTypes[innerType.builtin_type.replace('_',' ')]
else if (innerType.name) {
if (innerType.name.startsWith('ImGui'))
return_type += innerType.name.substring('ImGui'.length)
else
return_type += innerType.name
}
else return_type = '[!!!]'
}
out += ` -> ${return_type}`
}
out += ` ---`
console.log('\t'+out)
namespace[fn.name] = name
}
console.log('}')
for (const struct of file.structs) {
let name = struct.name;
if (name.startsWith('ImGui'))
name = name.substring(5)
namespace[struct.name] = name
let out = `${name} :: struct {\n`;
for (const field of struct.fields) {
out += '\t'
out += field.name
out += ': '
let innerType = field.type.description
if (field.is_array) {
let bound = innerType.bounds
// bleh
if (innerType.bounds.startsWith('ImGui')) {
bound = bound.substring('ImGui'.length)
if (bound.split('_')[0] in namespace)
bound = bound.split('_')[1]
else
bound = innerType.bounds
}
out += `[${bound ?? ''}]`
innerType = innerType.inner_type
}
let ptr = 0
let ptr_chr = '^'
while (innerType.kind === 'Pointer') {
ptr++
innerType = innerType.inner_type
}
if (ptr && innerType.builtin_type == 'void' || innerType.builtin_type?.endsWith('char')) {
ptr--
ptr_chr = '[^]'
}
for (let i = 0; i < ptr; i++) {
out += ptr_chr
}
if (ptr_chr === '[^]') {
if (innerType.builtin_type == 'void') out += 'rawptr'
else if (innerType.builtin_type.endsWith('char')) out += 'cstring'
}
else if (innerType.name in namespace) out += namespace[innerType.name]
else if (innerType.name in cToOdinTypes) out += cToOdinTypes[innerType.name]
else if (innerType.builtin_type in cToOdinTypes) out += cToOdinTypes[innerType.builtin_type]
else if (innerType.builtin_type?.replace('_',' ') in cToOdinTypes) out += cToOdinTypes[innerType.builtin_type.replace('_',' ')]
else if (innerType.name) {
if (innerType.name.startsWith('ImGui'))
out += innerType.name.substring('ImGui'.length)
else
out += innerType.name
}
out += ',\n'
}
out += '}'
console.log(out)
}