Compare commits

..

8 Commits

Author SHA1 Message Date
sonoro1234
9bffa7632f cpp2ffi: post skipped functions 2026-06-11 12:42:33 +02:00
sonoro1234
e2c1d90128 cpp2ffi: better printing and add const return when :: appears 2026-06-11 12:24:01 +02:00
sonoro1234
64fcbf194b cpp2ffi: explicit str_subst 2026-06-10 19:21:37 +02:00
sonoro1234
fced8c3451 README.md: more update bindings list 2026-06-10 11:52:57 +02:00
sonoro1234
7388e030e8 README.md: update bindings list 2026-06-10 11:23:33 +02:00
sonoro1234
bbddc623b5 cpp2ffi: add prevcomments in functions 2026-05-29 17:20:22 +02:00
sonoro1234
07fde25e7a cpp2ffi: functions to check int32_t 2026-05-18 16:51:22 +02:00
sonoro1234
1261b23193 generator.lua: impl defines table.do_sorted 2026-05-14 09:20:18 +02:00
3 changed files with 186 additions and 26 deletions

View File

@@ -106,10 +106,14 @@ Notes:
# example bindings based on cimgui # example bindings based on cimgui
* [LuaJIT-ImGui](https://github.com/sonoro1234/LuaJIT-ImGui) * [LuaJIT-ImGui](https://github.com/sonoro1234/LuaJIT-ImGui)
* [cimgui-go](https://github.com/AllenDang/cimgui-go)
* [Hexa.NET.ImGui](https://github.com/HexaEngine/Hexa.NET.ImGui)
* [dear-imgui-rs](https://github.com/Latias94/dear-imgui-rs)
* [CImGui.jl](https://github.com/Gnimuc/CImGui.jl)
* [ImGui.NET](https://github.com/mellinoe/ImGui.NET) * [ImGui.NET](https://github.com/mellinoe/ImGui.NET)
* [Zig-ImGui](https://github.com/SpexGuy/Zig-ImGui)
* [nimgl/imgui](https://github.com/nimgl/imgui) * [nimgl/imgui](https://github.com/nimgl/imgui)
* [kotlin-imgui](https://github.com/Dominaezzz/kotlin-imgui) * [kotlin-imgui](https://github.com/Dominaezzz/kotlin-imgui)
* [CImGui.jl](https://github.com/Gnimuc/CImGui.jl)
* [odin-imgui](https://github.com/ThisDrunkDane/odin-imgui) * [odin-imgui](https://github.com/ThisDrunkDane/odin-imgui)
* [DerelictImgui](https://github.com/Extrawurst/DerelictImgui) * [DerelictImgui](https://github.com/Extrawurst/DerelictImgui)
* [BindBC-CimGui](https://github.com/MrcSnm/bindbc-cimgui) * [BindBC-CimGui](https://github.com/MrcSnm/bindbc-cimgui)

View File

@@ -207,6 +207,26 @@ local function check_template(code)
return ttype,template,te,code2 return ttype,template,te,code2
end end
---------------------------------------- ----------------------------------------
local CCCnum = 0
local function getffiint32val(val)
local str = [[
local ffi = require"ffi"
ffi.cdef("static const int32_t CCC]]..CCCnum..[[ = ]]..val..[[;") return ffi.C.CCC]]..CCCnum
local f,err = loadstring(str)
assert(f,err)
CCCnum = CCCnum + 1
return f()
end
local function getffival(name,val)
local str = [[
local ffi = require"ffi"
ffi.cdef("static const int32_t ]]..name..[[ = ]]..val..[[;") return ffi.C.]]..name
print(str)
local f,err = loadstring(str)
assert(f,err)
return f()
end
local function parse_enum_value(value, allenums,dontpost) local function parse_enum_value(value, allenums,dontpost)
local function clean(val) local function clean(val)
if type(val)=="string" then if type(val)=="string" then
@@ -235,6 +255,13 @@ local function parse_enum_value(value, allenums,dontpost)
assert(not value:match("[%(%)]"),value) assert(not value:match("[%(%)]"),value)
local numval = tonumber(value) local numval = tonumber(value)
--check int32_t
-- if numval then
-- local ok,numval2 = pcall(getffiint32val,value)
-- if ok and numval~=numval2 then
-- print("===========",value,numval,numval2)
-- end
-- end
if numval then return numval end if numval then return numval end
local several,seps = strsplit(value,"([<>&|~%+%-]+)") local several,seps = strsplit(value,"([<>&|~%+%-]+)")
@@ -749,8 +776,16 @@ local function parseFunction(self,stname,itt,namespace,locat)
return return
end end
local ret = line:match("([^%(%):,]+[%*%s])%s?~?[_%w]+%b()") local ret = line:match("([^%(%):,]+[%*%s])%s?~?[_%w]+%b()")
local rettt = line:match("(.+[%*%s])%s?~?[_%w]+%b()")
--if rettt and rettt:match"::" then print("rettt",rettt,ret);error"debug" end
--if ret~=rettt then print("++++++++ret~=rettt",ret,rettt) end
if rettt and rettt:match"^const" and not ret:match"^const" then
ret = "const "..ret
print("++++++++++++add const",ret)
end
--local ret = line:match("(.+[%*%s])%s?~?[_%w]+%b()") --local ret = line:match("(.+[%*%s])%s?~?[_%w]+%b()")
--local funcname, args = line:match("(~?[_%w]+)%s*(%b())") --local funcname, args = line:match("(~?[_%w]+)%s*(%b())")
local funcname, args, extraconst = line:match("(~?[_%w]+)%s*(%b())(.*)") local funcname, args, extraconst = line:match("(~?[_%w]+)%s*(%b())(.*)")
@@ -968,7 +1003,7 @@ local function parseFunction(self,stname,itt,namespace,locat)
defT.call_args = caar --call_args defT.call_args = caar --call_args
defT.isvararg = signat:match("%.%.%.%)$") defT.isvararg = signat:match("%.%.%.%)$")
defT.location = locat defT.location = locat
local comentario = (itt.comments or "")..(comment or "") local comentario = (itt.prevcomments or "")..(itt.comments or "")..(comment or "")
if comentario=="" then comentario=nil end if comentario=="" then comentario=nil end
defT.comment = comentario defT.comment = comentario
defT.argsT = argsArr defT.argsT = argsArr
@@ -1169,7 +1204,9 @@ local function get_nonPOD(FP)
end end
end end
FP.structs_and_enums_table.nonPOD = nonPOD FP.structs_and_enums_table.nonPOD = nonPOD
if next(nonPOD) then
M.prtable("nonPOD",nonPOD) M.prtable("nonPOD",nonPOD)
end
return nonPOD return nonPOD
end end
local function recur_calc_depth(FP, structs, k,n) local function recur_calc_depth(FP, structs, k,n)
@@ -1336,7 +1373,9 @@ local function get_nonPODused(FP)
FP.structs_and_enums_table.nonPOD_used = FP.nP_used FP.structs_and_enums_table.nonPOD_used = FP.nP_used
FP.nP_args = typeargs FP.nP_args = typeargs
FP.nP_ret = typeargs_ret FP.nP_ret = typeargs_ret
if next(FP.nP_ret) then
M.prtable("np_ret",FP.nP_ret) M.prtable("np_ret",FP.nP_ret)
end
end end
local function header_subs_nonPOD(FP,txt) local function header_subs_nonPOD(FP,txt)
@@ -1353,7 +1392,9 @@ local function header_subs_nonPOD(FP,txt)
return txt return txt
end end
M.header_subs_nonPOD = header_subs_nonPOD M.header_subs_nonPOD = header_subs_nonPOD
local function get_std_function(ar) local function get_std_function(ar,def)
print("get_std_function",ar.template_orig)
print(" from",def.ov_cimguiname)
local skip = false local skip = false
local ty=ar.template_orig:gsub(ar.name,"") local ty=ar.template_orig:gsub(ar.name,"")
ty = ty:match("std::function(%b<>)") ty = ty:match("std::function(%b<>)")
@@ -1371,12 +1412,14 @@ local function get_std_function(ar)
local argsT2 = {} local argsT2 = {}
local noname_counter = 0 local noname_counter = 0
for i,v in ipairs(argsT) do for i,v in ipairs(argsT) do
local typ, name = v:match("(.+)%s+(%w+)") print(" arg",i,v)
local typ, name = v:match("^(.+)%s+(%w*)$")
if not name then if not name then
typ = v typ = v
noname_counter = noname_counter + 1 noname_counter = noname_counter + 1
name = "noname" .. noname_counter name = "noname" .. noname_counter
end end
print(" ",typ,name)
argsT2[i] = {type=typ,name=name} argsT2[i] = {type=typ,name=name}
end end
--get conversions --get conversions
@@ -1392,6 +1435,9 @@ local function get_std_function(ar)
elseif v.type:match("std::") then elseif v.type:match("std::") then
skip = true skip = true
else else
print(" get_std_function found type",v.type)
-- require"anima.utils"
-- prtable(ar)
end end
argsT3[i] = {type=typ or v.type,conv=conv,name=v.name} argsT3[i] = {type=typ or v.type,conv=conv,name=v.name}
end end
@@ -1430,10 +1476,12 @@ local function get_std_function(ar)
return caar,asp,skip return caar,asp,skip
end end
local function ADDnonUDT(FP) local function ADDnonUDT(FP)
print"===================ADDnonUDT==================================="
local nonPOD = get_nonPOD(FP) local nonPOD = get_nonPOD(FP)
get_nonPODused(FP) get_nonPODused(FP)
for k,defs in pairs(FP.defsT) do for k,defs in pairs(FP.defsT) do
for i, def in ipairs(defs) do for i, def in ipairs(defs) do
--print(" ADDnonUDT",def.ov_cimguiname,def.ret)
local skip = nil local skip = nil
--ret --ret
local rets = (def.ret or ""):gsub("const ","") local rets = (def.ret or ""):gsub("const ","")
@@ -1464,6 +1512,7 @@ local function ADDnonUDT(FP)
end end
--return std:: -> skip function --return std:: -> skip function
elseif def.stdret then -- not std::string elseif def.stdret then -- not std::string
print("skip",def.stdret,"on return")
skip = true skip = true
end end
--args --args
@@ -1496,7 +1545,7 @@ local function ADDnonUDT(FP)
caar = caar .. "std::string("..name..")," caar = caar .. "std::string("..name.."),"
asp = asp .. "const char* "..v.name.."," asp = asp .. "const char* "..v.name..","
elseif v.type:match"std::function" then elseif v.type:match"std::function" then
local ca2,asp2,skip2 = get_std_function(v) local ca2,asp2,skip2 = get_std_function(v,def)
caar = caar .. ca2.."," caar = caar .. ca2..","
asp = asp .. asp2.."," asp = asp .. asp2..","
if skip2 then skip = true end if skip2 then skip = true end
@@ -1534,6 +1583,7 @@ local function ADDnonUDT(FP)
asp = "()" asp = "()"
end end
if skip then if skip then
print("-------ADDnonUDT skips",def.ov_cimguiname)
def.skipped = skip def.skipped = skip
FP.skipped[def.ov_cimguiname] = true FP.skipped[def.ov_cimguiname] = true
else else
@@ -1543,6 +1593,10 @@ local function ADDnonUDT(FP)
end end
end end
end end
if next(FP.skipped) then
print(" =======skipped functions=====")
M.prtable(FP.skipped)
end
end end
local function ADDnonUDT_OLD(FP) local function ADDnonUDT_OLD(FP)
local nonPOD = get_nonPOD(FP) local nonPOD = get_nonPOD(FP)
@@ -1611,6 +1665,9 @@ local function ADDnonUDT_OLD(FP)
end end
local function ADDdestructors(FP) local function ADDdestructors(FP)
print"======================================================="
print"==============ADDdestructors========================="
print"======================================================="
local defsT = FP.defsT local defsT = FP.defsT
local newcdefs = {} local newcdefs = {}
@@ -1801,6 +1858,8 @@ function M.Parser()
return par.skipped[def.ov_cimguiname] or par.skipped[def.cimguiname] return par.skipped[def.ov_cimguiname] or par.skipped[def.cimguiname]
end end
function par:take_lines(cmd_line,names,compiler) function par:take_lines(cmd_line,names,compiler)
assert(compiler)
self.COMPILER = compiler
if self.COMMENTS_GENERATION then if self.COMMENTS_GENERATION then
cmd_line = cmd_line .. (compiler=="cl" and " /C " or " -C ") cmd_line = cmd_line .. (compiler=="cl" and " /C " or " -C ")
end end
@@ -1831,13 +1890,90 @@ function M.Parser()
self.constants = defines self.constants = defines
return defines return defines
end end
--------------------------------------------------------------------
local function get_cdefs(gccline,locat,cdef)
--print("get_cdefs",gccline,locat,cdef)
cdef = cdef or {}
numerr = numerr + 1
local errfile = "err_cdefs"..numerr..".txt"
local pipe,err = io.popen(gccline.." 2>"..errfile,"r")
--local pipe,err = io.popen(gccline,"r")
if not pipe then error("could not execute gcc "..err) end
local skip
for line in M.location(pipe,{locat}) do
--print(line)
line = line:gsub("extern __attribute__%(%(dllexport%)%)%s*","")
line = line:gsub("extern __declspec%(dllexport%)%s*","")
skip = false
if line~="" then
if line:match("^%s*static const") and not line:match("static const int") then skip=true end
if not skip then
table.insert(cdef,line)
end
end
end
pipe:close()
local f = assert(io.open(errfile,"r"))
local errstr = f:read"*a"
f:close()
print(#errstr,"errstr")
print(errstr)
--try to guess a compiler error
assert(not errstr:match" error")
os.remove(errfile)
return cdef
end
local ffi = require"ffi"
--utility functions
local ffi_cdef = function(code)
local ret,err = pcall(ffi.cdef,code)
if not ret then
local lineN = 1
for line in code:gmatch("([^\n\r]*)\r?\n") do
print(lineN, line)
lineN = lineN + 1
end
print(err)
error"bad cdef"
end
end
function par:get_cal_value_ffi()
local COMPILER, CPRE = self.COMPILER
if COMPILER == "cl" then
CPRE = COMPILER..[[ /E /DCIMGUI_DEFINE_ENUMS_AND_STRUCTS -DIMGUI_ENABLE_FREETYPE ./ccode.h]]
else
CPRE = COMPILER..[[ -E -DCIMGUI_DEFINE_ENUMS_AND_STRUCTS -DIMGUI_ENABLE_FREETYPE ./ccode.h]]
end
local cdefs = "typedef void FILE;"
cdefs = cdefs..self.structs_and_enums[1]..self.structs_and_enums[2]
save_data("ccode.h", cdefs)
local cdefs = get_cdefs(CPRE,"ccode")
--M.prtable(cdefs)
cdefs = table.concat(cdefs,"\n")
--print("===================================",cdefs)
save_data("ccode.h.lua", cdefs)
local ffi = require"ffi"
ffi_cdef(cdefs)
for k,enum in pairs(self.structs_and_enums_table.enums) do
for i,field in ipairs(enum) do
--print(field.calc_value)
if field.calc_value ~= ffi.C[field.name] then
print(field.name,field.calc_value , ffi.C[field.name])
end
end
end
end
function par:do_parse() function par:do_parse()
self:parseItems() self:parseItems()
self:gen_structs_and_enums_table() self:gen_structs_and_enums_table()
self:compute_overloads() self:compute_overloads()
self:gen_structs_and_enums() self:gen_structs_and_enums()
--self:compute_overloads()
--self:compute_templated() --self:compute_templated()
--check int32_t and others
--self:get_cal_value_ffi()
ADDdestructors(self) ADDdestructors(self)
end end
function par:initTypedefsDict() function par:initTypedefsDict()
@@ -1946,7 +2082,7 @@ function M.Parser()
--clean class and get name --clean class and get name
if it.re_name == "class_re" then if it.re_name == "class_re" then
it.name = it.item:match("class%s+(%S+)") it.name = it.item:match("class%s+(%S+)")
print("cleaning class",it.name) print("cleaning class",it.name,"-------------------------------------")
--it.item = it.item:gsub("private:.+};$","};") --it.item = it.item:gsub("private:.+};$","};")
--it.item = it.item:gsub("private:","") --it.item = it.item:gsub("private:","")
it.item = it.item:gsub("public:","") it.item = it.item:gsub("public:","")
@@ -2010,7 +2146,7 @@ function M.Parser()
local derived2 = derived:gsub("%b<>","") local derived2 = derived:gsub("%b<>","")
derived2 = derived2:gsub("%w+::","") derived2 = derived2:gsub("%w+::","")
print(" --derived check",stname, derived, derived2) print(" --derived check",stname, derived, derived2)
M.prtable(self.opaque_structs) --M.prtable(self.opaque_structs)
if self.opaque_structs[derived2] then if self.opaque_structs[derived2] then
print(" --make opaque opaque derived",it.name,derived,derived2) print(" --make opaque opaque derived",it.name,derived,derived2)
it.opaque_struct = get_parents_name(it)..it.name it.opaque_struct = get_parents_name(it)..it.name
@@ -2033,7 +2169,7 @@ function M.Parser()
-- print("=====using",child.item) -- print("=====using",child.item)
-- end -- end
if (child.re_name == "vardef_re") and child.item:match"std::" then if (child.re_name == "vardef_re") and child.item:match"std::" then
print("--make opaque",it.name,child.item) print(" --make opaque with child std::",it.name,child.item)
--M.prtable(itparent) --M.prtable(itparent)
--it.opaque_struct = (itparent and itparent.name .."::" or "")..it.name --it.opaque_struct = (itparent and itparent.name .."::" or "")..it.name
it.opaque_struct = get_parents_name(it)..it.name it.opaque_struct = get_parents_name(it)..it.name
@@ -2066,6 +2202,9 @@ function M.Parser()
return table.concat(txtclean) return table.concat(txtclean)
end end
function par:parseItems() function par:parseItems()
print"================================================================"
print"===================parseItems==================================="
print"================================================================"
--self:initTypedefsDict() --self:initTypedefsDict()
self.linenumdict = {} self.linenumdict = {}
@@ -2088,9 +2227,13 @@ function M.Parser()
local txt = table.concat(cdefs2,"\n") local txt = table.concat(cdefs2,"\n")
--string substitution --string substitution
if self.str_subst then if self.str_subst then
print("========== str_subst")
local nn
for k,v in pairs(self.str_subst) do for k,v in pairs(self.str_subst) do
txt = txt:gsub(k,v) txt,nn = txt:gsub(k,v)
print(k,"done times:",nn)
end end
print("========== str_subst end")
end end
--clean = default in constructor (implot3d) --clean = default in constructor (implot3d)
txt = txt:gsub("=%s*default","") txt = txt:gsub("=%s*default","")
@@ -2123,9 +2266,9 @@ function M.Parser()
table.insert(txtclean,txt:sub(ini)) table.insert(txtclean,txt:sub(ini))
print("end cleaning ------------------------------",nn) print("end cleaning ------------------------------",nn)
txt = table.concat(txtclean) txt = table.concat(txtclean)
--]]
end end
--save_data("./preparse"..tostring(self):gsub("table: ","")..".c",txt) --save_data("./preparse"..tostring(self):gsub("table: ","")..".c",txt)
--]]
self.itemsarr = par:parseItemsR2(txt) self.itemsarr = par:parseItemsR2(txt)
save_data("./itemsarr.lua",M.serializeTableF(self.itemsarr))--ToStr(self.itemsarr)) save_data("./itemsarr.lua",M.serializeTableF(self.itemsarr))--ToStr(self.itemsarr))
itemsarr = self.itemsarr itemsarr = self.itemsarr
@@ -2435,7 +2578,9 @@ function M.Parser()
end end
end end
function par:gen_structs_and_enums() function par:gen_structs_and_enums()
print"======================================================="
print"--------------gen_structs_and_enums" print"--------------gen_structs_and_enums"
print"======================================================="
--M.prtable(self.typenames) --M.prtable(self.typenames)
local outtab = {} local outtab = {}
local outtabpre = {} local outtabpre = {}
@@ -2724,7 +2869,9 @@ function M.Parser()
end end
par.enums_for_table = enums_for_table par.enums_for_table = enums_for_table
function par:gen_structs_and_enums_table() function par:gen_structs_and_enums_table()
print"--------------gen_structs_and_enums_table" print"================================================================"
print"===================gen_structs_and_enums_table==================================="
print"================================================================"
local outtab = {enums={},structs={},locations={},enumtypes={},struct_comments={},enum_comments={},opaque_structs={}} local outtab = {enums={},structs={},locations={},enumtypes={},struct_comments={},enum_comments={},opaque_structs={}}
--self.typedefs_table = {} --self.typedefs_table = {}
local enumsordered = {} local enumsordered = {}
@@ -2806,8 +2953,8 @@ function M.Parser()
-- M.prtable(outtab.structs[structname]) -- M.prtable(outtab.structs[structname])
-- end -- end
else --self.typenames[structname] else --self.typenames[structname]
M.prtable("--self.typenames",structname,self.typenames[structname]) --M.prtable("--self.typenames",structname,self.typenames[structname])
M.prtable("strtab 3, -1",strtab) --M.prtable("strtab 3, -1",strtab)
--templated struct --templated struct
if structname then if structname then
print("saving templated struct",structname) print("saving templated struct",structname)
@@ -2817,7 +2964,7 @@ function M.Parser()
self:parse_struct_line(strtab[j],self.templated_structs[structname],comstab[j]) self:parse_struct_line(strtab[j],self.templated_structs[structname],comstab[j])
end end
end end
M.prtable("--template_structs",structname,self.templated_structs[structname]) --M.prtable("--template_structs",structname,self.templated_structs[structname])
else else
print("skipped unnamed struct",structname) print("skipped unnamed struct",structname)
end end
@@ -2900,6 +3047,9 @@ function M.Parser()
end end
function par:compute_overloads() function par:compute_overloads()
print"================================================================"
print"===================compute_overloads==================================="
print"================================================================"
-- if self.IMGUI_HAS_TEXTURES then -- if self.IMGUI_HAS_TEXTURES then
-- print"----------replacing ImTextureID with ImTextureUserID" -- print"----------replacing ImTextureID with ImTextureUserID"
-- REPLACE_TEXTUREID(self) -- REPLACE_TEXTUREID(self)
@@ -3126,6 +3276,9 @@ function M.Parser()
end end
--generate cimgui.cpp cimgui.h --generate cimgui.cpp cimgui.h
function par:cimgui_generation( cimgui_header) function par:cimgui_generation( cimgui_header)
print"=========================================================="
print"===============cimgui_generation==========================="
print"=========================================================="
local name = self.modulename local name = self.modulename
local hstrfile = read_data("./"..name.."_template.h") local hstrfile = read_data("./"..name.."_template.h")
M.prtable("templates",self.templates) M.prtable("templates",self.templates)
@@ -3363,10 +3516,12 @@ local function location(file,locpathT,defines,COMPILER,keepemptylines)
-- Is this a location pragma? -- Is this a location pragma?
local loc_num_t,location_match = line:match(location_re) local loc_num_t,location_match = line:match(location_re)
if location_match then if location_match then
--print(location_match)
in_location = false in_location = false
for i,path_re in ipairs(path_reT) do for i,path_re in ipairs(path_reT) do
local locpath = location_match:match(path_re) local locpath = location_match:match(path_re)
if locpath then if locpath then
--print("locpath",locpath)
in_location = true; in_location = true;
loc_num = loc_num_t loc_num = loc_num_t
loc_num_incr = 0 loc_num_incr = 0

View File

@@ -123,9 +123,10 @@ local serializeTableF = cpp2ffi.serializeTableF
local function func_header_impl_generate(FP, defines) local function func_header_impl_generate(FP, defines)
local outtab = {} local outtab = {}
for k,v in pairs(defines) do --may be key sorting is not enough and declaration order needed
cpp2ffi.table_do_sorted(defines, function(k,v)
table.insert(outtab,"#define "..k.." "..v.."\n") table.insert(outtab,"#define "..k.." "..v.."\n")
end end)
-- for _,t in ipairs(FP.funcdefs) do -- for _,t in ipairs(FP.funcdefs) do
-- if t.cimguiname then -- if t.cimguiname then
-- local cimf = FP.defsT[t.cimguiname] -- local cimf = FP.defsT[t.cimguiname]