From 975a735d382d2739d1ee19a23cd1ea1e4ca09928 Mon Sep 17 00:00:00 2001 From: sonoro1234 Date: Tue, 25 Jun 2019 10:50:04 +0200 Subject: [PATCH] rename generator2 to generator and generator to generator_old --- README.md | 2 +- generator/generator.lua | 1358 ++----------- generator/generator2.lua | 646 ------- .../{generator2.bat => generator_old.bat} | 2 +- generator/generator_old.lua | 1682 +++++++++++++++++ 5 files changed, 1845 insertions(+), 1845 deletions(-) delete mode 100644 generator/generator2.lua rename generator/{generator2.bat => generator_old.bat} (94%) create mode 100644 generator/generator_old.lua diff --git a/README.md b/README.md index 793f0c1..fb0dca8 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Notes: * you will need LuaJIT (https://github.com/LuaJIT/LuaJIT.git better 2.1 branch) or precompiled for linux/macOS/windows in https://luapower.com/luajit/download * you can use also a C++ compiler for doing preprocessing: gcc (In windows MinGW-W64-builds for example), clang or cl (MSVC) or not use a compiler (experimental nocompiler option) at all. (this repo was done with gcc) * update `imgui` folder to the version you desire. -* edit `generator/generator2.bat` (or make a .sh version and please PR) to choose between gcc, clang, cl or nocompiler. Run it with gcc, clang or cl and LuaJIT on your PATH. +* edit `generator/generator.bat` (or make a .sh version and please PR) to choose between gcc, clang, cl or nocompiler. Run it with gcc, clang or cl and LuaJIT on your PATH. * as a result some files are generated: `cimgui.cpp` and `cimgui.h` for compiling and some lua/json files with information about the binding: `definitions.json` with function info, `structs_and_enums.json` with struct and enum info, `impl_definitions.json` with functions from the implementations info. # generate binding diff --git a/generator/generator.lua b/generator/generator.lua index 1e2da1a..93cd1ae 100644 --- a/generator/generator.lua +++ b/generator/generator.lua @@ -99,16 +99,11 @@ local cimgui_header = local gdefines = {} --for FLT_MAX and others -------------------------------------------------------------------------- --helper functions --------------------------------------------------------------------------- -local function split_comment(line) - local comment = line:match("(%s*//.*)") or "" - line = line:gsub("%s*//.*","") - line = line:gsub("%s*$","") - return line,comment -end ---minimal preprocessor + +---------------------------minimal preprocessor without compiler for ImGui.h local function filelines(file,locats) + local split_comment = require"cpp2ffi".split_comment local iflevels = {} --generated known prepros local prepro = { @@ -155,10 +150,12 @@ local prepro = { local function location_it() repeat local line = file:read"*l" + if not line then return nil end + line,_ = split_comment(line) --if line:sub(1,1) == "#" then if line:match("^%s*#") then - line,_ = split_comment(line) + local pre,cond = line:match("^%s*(#%S*)%s+(.*)%s*$") if line:match("#if") then iflevels[#iflevels +1 ] = prepro_boolif(pre,cond) @@ -189,1030 +186,21 @@ local prepro = { end return location_it end ---iterates lines from a gcc/clang -E in a specific location -local function location(file,locpathT) - local location_re - if COMPILER == "cl" then - location_re = '^#line (%d+) "([^"]*)"' - else --gcc, clang - location_re = '^# (%d+) "([^"]*)"' - end - local path_reT = {} - for i,locpath in ipairs(locpathT) do - table.insert(path_reT,'^(.*[\\/])('..locpath..')%.h$') - end - local in_location = false - local which_location = "" - local loc_num - local loc_num_incr - local lineold = "" - local which_locationold,loc_num_realold - local lastdumped = false - local function location_it() - repeat - local line = file:read"*l" - if not line then - if not lastdumped then - lastdumped = true - return lineold, which_locationold,loc_num_realold - else - return nil - end - end - if #line==0 then --nothing on emptyline - elseif not line:match("%S") then --nothing if only spaces - elseif line:sub(1,1) == "#" then - -- Is this a location pragma? - local loc_num_t,location_match = line:match(location_re) - if location_match then - in_location = false - for i,path_re in ipairs(path_reT) do - if location_match:match(path_re) then - in_location = true; - loc_num = loc_num_t - loc_num_incr = 0 - which_location = locpathT[i] - break - end - end - end - elseif in_location then - local loc_num_real = loc_num + loc_num_incr - loc_num_incr = loc_num_incr + 1 - if loc_num_realold and loc_num_realold < loc_num_real then - --old line complete - local lineR,which_locationR,loc_num_realR = lineold, which_locationold,loc_num_realold - lineold, which_locationold,loc_num_realold = line,which_location,loc_num_real - return lineR,which_locationR,loc_num_realR - else - lineold=lineold..line - which_locationold,loc_num_realold = which_location,loc_num_real - --return line,loc_num_real, which_location - end - end - until false --forever - end - return location_it -end -local function copyfile(src,dst,blocksize) - blocksize = blocksize or 1024*4 - print( "copyfile", src, dst) - local srcf, err = io.open(src,"rb") - if not srcf then error(err) end - local dstf, err = io.open(dst,"wb") - if not dstf then error(err) end - while true do - local data = srcf:read(blocksize) - if not data then break end - dstf:write(data) - end - srcf:close() - dstf:close() -end -------serializeTable("anyname",table) gives a string that recreates the table with dofile(generated_string) -local function serializeTable(name, value, saved) - - local function basicSerialize (o) - if type(o) == "number" or type(o)=="boolean" then - return tostring(o) - elseif type(o) == "string" then - return string.format("%q", o) - else - return "nil" - end - end - - local string_table = {} - if not saved then - table.insert(string_table, "local "..name.." = ") - else - table.insert(string_table, name.." = ") - end - - saved = saved or {} -- initial value - - if type(value) == "number" or type(value) == "string" or type(value)=="boolean" then - table.insert(string_table,basicSerialize(value).."\n") - elseif type(value) == "table" then - if saved[value] then -- value already saved? - table.insert(string_table,saved[value].."\n") - else - saved[value] = name -- save name for next time - table.insert(string_table, "{}\n") ----[[ - local ordered_keys = {} - for k,v in pairs(value) do - table.insert(ordered_keys,k) - end - local function sorter(a,b) - if type(a)==type(b) then - return a") - if template then - local te = template:gsub("%s","_") - te = te:gsub("%*","Ptr") - ImVector_templates[template] = true - linea = linea:gsub("(%b<>)","_"..te) --comment template parameters - end - --linea = linea:gsub("(%b<>)","/*%1*/") --comment template parameters - --linea = linea:gsub("<([%w_]+)>","_%1") --ImVector expand templates - table.insert(structcdefs,linea..comment) - end - return - end - return STP -end - -local function typetoStr(typ) - --typ = typ:gsub("[^%(%)]+%(%*?(.+)%).+","%1") -- funcs - typ = typ:gsub("[^%(%)]+%(%*?(.+)%).+","FnPtr") - typ = typ:gsub("[%w_]+%[(%d*)%]","arr%1") - typ = typ:gsub("%*","Ptr") - typ = typ:gsub("void","") - typ = typ:gsub("unsigned%s","u") - typ = typ:gsub("const%s","")--"c") - typ = typ:gsub("%s+","_") - typ = typ:gsub("charPtr","Str") - typ = typ:gsub("int","Int") - typ = typ:gsub("bool","Bool") - typ = typ:gsub("float","Float") - typ = typ:gsub("uInt","Uint") - typ = typ:gsub("ImGui","") - typ = typ:gsub("Im","") - typ = typ:gsub("[<>]","") - return typ -end -local function name_overloadsAlgo(v) - local aa = {} - local bb = {} - local done = {} - local maxnum = 0 - for i,t in ipairs(v) do - bb[i] = "" - local signature = t.signature:sub(2,-2) -- without parenthesis - aa[i] = {} - local num = 1 - --for typec in t.signature:gmatch(".-([^,%(%s]+)[,%)]") do - --for typec in t.signature:gmatch(".-([^,%(]+)[,%)]") do - --for typec in signature:gmatch(".-([^,]+),?") do - for typec in signature:gsub("(%(.-%))", function(x) return x:gsub(",","\0") end):gmatch(".-([^,]+),?") do - --typec = typec:gsub - aa[i][num] = typec:gsub("%z+", ",") - num = num + 1 - end - num = num - 1 - maxnum = (num > maxnum) and num or maxnum - end - - for l=1,maxnum do - local keys = {} - local diferent = true - local equal = true - for i=1,#v do - aa[i][l] = aa[i][l] or "nil" - keys[aa[i][l]] = 1 + (aa[i][l] and keys[aa[i][l]] or 0) - if not done[i] then - for j=i+1,#v do - if not done[j] then - if aa[i][l] == aa[j][l] then - diferent = false - else - equal = false - end - end - end - end - end - if not equal then -- not all the same - for i=1,#v do - if not done[i] then - bb[i] = bb[i]..(aa[i][l]=="nil" and "" or aa[i][l]) - if keys[aa[i][l]] == 1 then - done[i] = true - end - end - end - end - end - return aa,bb -end - -local function func_parser() - local function_closing_re = "}" - --local function_re = "(%a*%w+%b())" --"(%a*%w+%s+%w+%b())" - local function_re = "(%a*[%w%[%]]+%s*%b())" - local function_closed_re = "[;}]$" - local namespace_re = "namespace ([^%s]+)" - local namespace_closing_re = "^}" - local struct_re = "^struct%s+([^%s;]+)$" - local struct_closing_re = "};" - local struct_op_close_re = "%b{}" - local functype_re = "^%s*[%w%s]+(%(%*)[%w_]+(%)%([^%(%)]*%))" - - local in_function = false - local line_in_function - local in_namespace = false - local cdefs = {} - local structnames = {} - local embeded_structs = {} - local stname = "" - local defsT = {} - local ImVector_templates = {} - - - local FP = {} - FP.cdefs = cdefs - FP.embeded_structs = embeded_structs - FP.defsT = defsT - FP.ImVector_templates = ImVector_templates - - function FP.insert(line,comment,locat) - local lineorig = line - if line:match"template" then return end - line = line:gsub("%S+",{class="struct",mutable="",inline=""}) --class -> struct - line = clean_spaces(line) - - if in_function then - if line:match(function_closing_re) then - in_function = false - end - return --discard - end - if line:match(function_re) and not line:match("typedef.*%b().*%b().*") then - if not line:match(function_closed_re) then - in_function = true - line_in_function = lineorig - end - end - if line:match(namespace_re) then - in_namespace = true - stname = line:match(namespace_re) - end - if in_namespace then - if line:match(namespace_closing_re) then - in_namespace = false - stname = "" - end - end - structnames[#structnames + 1] = line:match(struct_re) - if #structnames > 0 then - if line:match(struct_closing_re) and not line:match(struct_op_close_re) then - structnames[#structnames] = nil - end - stname = structnames[#structnames] or "" - if #structnames > 1 then - local embeded_name = table.concat(structnames,"::") - embeded_structs[stname] = embeded_name - end - end - local func = line:match(function_re) - if func and not in_function and not line:match("typedef.*%b().*%b().*") - and not line:match(functype_re) - then - --if line:match(functype_re) then print("ft",line) end - if stname~="ImVectorNO" - --and stname~="GlyphRangesBuilder" and stname~="CustomRect" and stname~="TextRange" and stname~="Pair" - and not line:match("operator") then - - --clean implemetation - line = line:gsub("%s*%b{}","") - --clean attribute - line = line:gsub("%s*__attribute__%b()","") - --clean static - line = line:gsub("static","") - - local ret = line:match("([^%(%)]+[%*%s])%s?~?[_%w]+%b()") - local funcname, args = line:match("(~?[_%w]+)(%b())") - - local argscsinpars = args:gsub("(=[^,%(%)]*)(%b())","%1") - argscsinpars = argscsinpars:gsub("(=[^,%(%)]*)([,%)])","%2") - -- if argscsinpars:match("&") then - -- for arg in argscsinpars:gmatch("[%(,]*([^,%(%)]+)[%),]") do - -- if arg:match("&") and not arg:match("const") then - -- print(funcname,argscsinpars) - -- end - -- end - -- end - --argscsinpars = argscsinpars:gsub("&","") - - local template = argscsinpars:match("ImVector<(.+)>") - if template then - --template = template:gsub("%s","_") - --template = template:gsub("%*","Ptr") - ImVector_templates[template] = true - end - - argscsinpars = argscsinpars:gsub("<([%w_]+)>","_%1") --ImVector - - local argsArr = {} - local functype_re = "^%s*[%w%s%*]+%(%*[%w_]+%)%([^%(%)]*%)" - local functype_reex = "^(%s*[%w%s%*]+)%(%*([%w_]+)%)(%([^%(%)]*%))" - local functype_arg_rest = "^(%s*[%w%s%*]+%(%*[%w_]+%)%([^%(%)]*%)),*(.*)" - local rest = argscsinpars:sub(2,-2) --strip () - - while true do - --local tt = strsplit(rest,",") - --for ii,arg in ipairs(tt) do - --for arg in argscsinpars:gmatch("[%(,]*([^,%(%)]+)[%),]") do - local type,name,retf,sigf - local arg,restt = rest:match(functype_arg_rest) - if arg then - local t1,namef,t2 = arg:match(functype_reex) - type=t1.."(*)"..t2;name=namef - retf = t1 - sigf = t2 - rest = restt - else - arg,restt = rest:match(",*([^,%(%)]+),*(.*)") - if not arg then break end - rest = restt - if arg:match("&") and arg:match("const") then - arg = arg:gsub("&","") - end - if arg:match("%.%.%.") then - type="...";name="..." - else - type,name = arg:match("(.+)%s([^%s]+)") - end - if not type or not name then - print("failure arg detection",funcname,type,name,argscsinpars,arg) - print(lineorig) - print(line_in_function) - else - --float name[2] to float[2] name - local siz = name:match("(%[%d*%])") - if siz then - type = type..siz - name = name:gsub("(%[%d*%])","") - end - end - end - table.insert(argsArr,{type=type,name=name,ret=retf,signature=sigf}) - if arg:match("&") and not arg:match("const") then - --only post error if not manual - local cname = getcimguiname(stname,funcname) - if not cimgui_manuals[cname] then - print("reference to no const arg in",funcname,argscsinpars) - end - end - end - argscsinpars = argscsinpars:gsub("&","") - - local signature = argscsinpars:gsub("([%w%s%*_]+)%s[%w_]+%s*([,%)])","%1%2") - signature = signature:gsub("%s*([,%)])","%1") --space before , and ) - signature = signature:gsub(",%s*",",")--space after , - signature = signature:gsub("([%w_]+)%s[%w_]+(%[%d*%])","%1%2") -- float[2] - signature = signature:gsub("(%(%*)[%w_]+(%)%([^%(%)]*%))","%1%2") --func defs - - local call_args = argscsinpars:gsub("([%w_]+%s[%w_]+)%[%d*%]","%1") --float[2] - call_args = call_args:gsub("%(%*([%w_]+)%)%([^%(%)]*%)"," %1") --func type - call_args = call_args:gsub("[^%(].-([%w_]+)%s*([,%)])","%1%2") - - if not ret then --must be constructors - if not (stname == funcname or "~"..stname==funcname) then --break end - print("false constructor:",line); - print("b2:",ret,stname,funcname,args) - return --are function defs - end - end - - local cimguiname = getcimguiname(stname,funcname) - table.insert(cdefs,{stname=stname,funcname=funcname,args=args,argsc=argscsinpars,signature=signature,cimguiname=cimguiname,call_args=call_args,ret =ret,comment=comment}) - - defsT[cimguiname] = defsT[cimguiname] or {} - table.insert(defsT[cimguiname],{}) - local defT = defsT[cimguiname][#defsT[cimguiname]] - defT.defaults = {} - --for k,def in args:gmatch("([%w%s%*_]+)=([%w_%(%)%s,%*]+)[,%)]") do - --for k,def in args:gmatch("([%w_]+)=([%w_%(%)%s,%*%.%-]+)[,%)]") do - for k,def in args:gmatch('([%w_]+)=([%w_%(%)%s,%*%.%-%+%%"]+)[,%)]') do - defT.defaults[k]=def - end - defT.cimguiname = cimguiname - defT.stname = stname - defT.funcname = funcname - defT.argsoriginal = args - defT.args=argscsinpars - defT.signature = signature - defT.call_args = call_args - defT.isvararg = signature:match("%.%.%.%)$") - defT.location = locat - defT.comment = comment - defT.argsT = argsArr - if get_manuals(defT) then - defT.manual = true - end - if ret then - defT.ret = clean_spaces(ret:gsub("&","*")) - defT.retref = ret:match("&") - -- if defT.ret=="ImVec2" or defT.ret=="ImVec4" or defT.ret=="ImColor" then - -- defT.ret = defT.ret.."_Simple" - -- end - end - defsT[cimguiname][signature] = defT - end - elseif line=="" and stname~="" then -- not funcdef must be comment - table.insert(cdefs,{stname=stname,comment=comment}) - end - end - FP.alltypes = {} - local function get_types(v) - for i,t in ipairs(v) do - local signature = t.signature:sub(2,-2) -- without parenthesis - for typec in signature:gsub("(%(.-%))", function(x) return x:gsub(",","\0") end):gmatch(".-([^,]+),?") do - local key = typec:gsub("%z+", ",") - FP.alltypes[key] = true - end - end - end - function FP:dump_alltypes() - for k,v in pairs(self.alltypes) do print(k, typetoStr(k) ) end - end - function FP:compute_overloads() - local strt = {} - local numoverloaded = 0 - FP.alltypes = {} - table.insert(strt,"----------------overloadings---------------------------") - --require"anima.utils" - for k,v in pairs(FP.defsT) do - get_types(v) - if #v > 1 then - numoverloaded = numoverloaded + #v - --print(k,#v) - table.insert(strt,string.format("%s\t%d",k,#v)) - local typesc,post = name_overloadsAlgo(v) - for i,t in ipairs(v) do - --take overloaded name from manual table or algorythm - t.ov_cimguiname = getcimguiname_overload(t.stname,t.funcname,t.signature) or k..typetoStr(post[i]) - --print(i,t.signature,t.ret,t.ov_cimguiname)--,post[i])--,typetoStr(post[i])) - table.insert(strt,string.format("%d\t%s\t%s %s",i,t.ret,t.ov_cimguiname,t.signature)) - --prtable(typesc[i]) - end - --check not two names are equal (produced by bad cimguiname_overload) - for i=1,#v-1 do - for j=i+1,#v-1 do - if v[i].ov_cimguiname == v[j].ov_cimguiname then - local t,tj = v[i],v[j] - print("Error caused by Bad overloading "..t.ov_cimguiname.." of function ",t.funcname,t.signature,"conflicts with ",tj.funcname,tj.signature) - error("Bad overloading:"..t.ov_cimguiname) - end - end - end - end - end - --print(numoverloaded, "overloaded") - table.insert(strt,string.format("%d overloaded",numoverloaded)) - return table.concat(strt,"\n") - end - return FP -end -local function ADDdestructors(FP) - local defsT = FP.defsT - local newcdefs = {} - --TODO add constructor = true - for numcdef,t in ipairs(FP.cdefs) do - newcdefs[#newcdefs+1] = t - if t.cimguiname then - local defT = defsT[t.cimguiname] - --local defT = cimf[t.signature] - --for fname,defT in pairs(FP.defsT) do - if not defT[1].ret and not defT[1].constructor then --if constructor not processed - if defT[1].funcname:match("~") then - defsT[t.cimguiname] = nil --clear destructor - newcdefs[#newcdefs] = nil - else - for j,cons in ipairs(defT) do - cons.constructor = true - end - assert(defT[1].stname==defT[1].funcname) - local def = {} - def.stname = defT[1].stname - def.ret = "void" - def.ov_cimguiname = def.stname.."_destroy" - def.cimguiname = def.ov_cimguiname - def.destructor = true - def.args = "("..def.stname.."* self)" - def.call_args = "(self)" - def.signature = "("..def.stname.."*)" - def.defaults = {} - def.argsT = {{type=def.stname.."*",name="self"}} - defsT[def.ov_cimguiname] = {def} - defsT[def.ov_cimguiname][def.signature] = def - newcdefs[#newcdefs+1]={stname=def.stname,funcname=def.ov_cimguiname,args=def.args,signature=def.signature,cimguiname=def.cimguiname,call_args=def.call_args,ret =def.ret} - end - end - end - end - FP.cdefs = newcdefs -end -local function ADDnonUDT(FP) - --for cimguiname,defs in pairs(defsT) do - --for i,defT in ipairs(defs) do - local defsT = FP.defsT - local newcdefs = {} - for numcdef,t in ipairs(FP.cdefs) do - if t.cimguiname then - local cimf = defsT[t.cimguiname] - local defT = cimf[t.signature] - --if UDT return generate nonUDT version - if defT.ret=="ImVec2" or defT.ret=="ImVec4" or defT.ret=="ImColor" then - --passing as a pointer arg - local defT2 = {} - --first strings - for k,v in pairs(defT) do - defT2[k] = v - end - --then argsT table - defT2.argsT = {{type=defT.ret.."*",name="pOut"}} - for k,v in ipairs(defT.argsT) do - table.insert(defT2.argsT,{type=v.type,name=v.name}) - end - local comma = (#defT.argsT > 0) and "," or "" - defT2.args = "("..defT.ret.." *pOut"..comma..defT.args:sub(2) - defT2.ret = "void" - defT2.ov_cimguiname = (defT2.ov_cimguiname or defT2.cimguiname).."_nonUDT" - defT2.nonUDT = 1 - defT2.retref = nil - defsT[t.cimguiname][#defsT[t.cimguiname] + 1] = defT2 - defsT[t.cimguiname][t.signature.."nonUDT"] = defT2 - table.insert(newcdefs,{stname=t.stname,funcname=t.funcname,args=args,argsc=argscsinpars,signature=t.signature.."nonUDT",cimguiname=t.cimguiname,call_args=call_args,ret =t.ret,comment=comment}) - --converting to Simple type---------------------------------------------------- - local defT3 = {} - --first strings - for k,v in pairs(defT) do - defT3[k] = v - end - --then argsT table - defT3.argsT = {} - for k,v in ipairs(defT.argsT) do - table.insert(defT3.argsT,{type=v.type,name=v.name}) - end - local comma = (#defT.argsT > 0) and "," or "" - --defT3.args = "("..defT.ret.." *pOut"..comma..defT.args:sub(2) - defT3.ret = defT.ret.."_Simple" - defT3.retorig = defT.ret - defT3.ov_cimguiname = (defT3.ov_cimguiname or defT3.cimguiname).."_nonUDT2" - defT3.nonUDT = 2 - defT3.retref = nil - defsT[t.cimguiname][#defsT[t.cimguiname] + 1] = defT3 - defsT[t.cimguiname][t.signature.."nonUDT2"] = defT3 - table.insert(newcdefs,{stname=t.stname,funcname=t.funcname,args=args,argsc=argscsinpars,signature=t.signature.."nonUDT2",cimguiname=t.cimguiname,call_args=call_args,ret =t.ret,comment=comment}) - end - end - end - for i,v in ipairs(newcdefs) do - table.insert(FP.cdefs,v) - end -end - -local function gen_structs_and_enums_table(cdefs) - local function_closing_re = "}" - local namespace_re = "namespace" - local in_namespace = false - local struct_re = "^%s*struct%s+([^%s;]+)$" - local in_struct = false - local struct_closed_re = "^%s*struct%s+([^%s]+);$" - local struct_closing_re = "};" - local struct_op_close_re = "%b{}" - local structnames = {} - local enumnames = {} - local enums_re = "^%s*enum%s+([^%s;]+)" - local outtab = {structs={},enums={}} - local typedefs_dict = {} - - for i,line in ipairs(cdefs) do - repeat -- simulating continue with break - -- separate comments from code - local linecom = line - local line, comment = split_comment(line) - line = clean_spaces(line) - --typedefs dictionary - if line:match("typedef") then - local value,key = line:match("typedef%s+(.+)%s+([%w_]+);") - if key and value then - typedefs_dict[key] = value - else --try function typedef - local key = line:match("%(%*([%w_]+)%)%([^%(%)]*%)") - if key then - local linet = line - linet = linet:gsub("typedef ","") - linet = linet:gsub("%(%*("..key..")%)","(*)") - typedefs_dict[key] = linet - else - print(key,value,line) - end - end - end - if line:match(namespace_re) then - in_namespace = true - end - - local structbegin = line:match(struct_re) - if structbegin then - structnames[#structnames + 1] = structbegin - outtab.structs[structbegin] = outtab.structs[structbegin] or {} - break - end - - local enumname = line:match(enums_re) - if enumname then - enumnames[#enumnames + 1] = enumname - outtab.enums[enumname] = outtab.enums[enumname] or {} - break - end - - if in_namespace then - if line:match(function_closing_re) then - in_namespace = false - end - break -- dont write anything inside - end - - if (#enumnames > 0) then - assert(#structnames==0,"enum in struct") - -- if #structnames~=0 then - -- print(line,#line) - -- print(linecom,#linecom) - -- error"enuminstruct" - -- end - if line:match(struct_closing_re) and not line:match(struct_op_close_re) then - enumnames[#enumnames] = nil - break - end - if line=="" or line:match("^{") then - break - else - local name,value = line:match("%s*([%w_]+)%s*=%s*([^,]+)") - if value then - table.insert(outtab.enums[enumnames[#enumnames]],{name=name,value=value}) - else --increment by one - local name = line:match("%s*([^,]+)") - local enum_table = outtab.enums[enumnames[#enumnames]] - local value = enum_table[#enum_table] and (enum_table[#enum_table].value + 1) or 0 - table.insert(outtab.enums[enumnames[#enumnames]],{name=name,value=value}) - end - end - end - - if (#structnames > 0) then - if line:match(struct_closing_re) and not line:match(struct_op_close_re) then - structnames[#structnames] = nil - break - end - if line=="" or line:match("^{") then - break - elseif structnames[#structnames] ~="ImVectorNO" then --avoid ImVector - --local functype_re = "^%s*[%w%s%*]+(%(%*)[%w_]+(%)%([^%(%)]*%))" - local functype_re = "^%s*[%w%s%*]+%(%*[%w_]+%)%([^%(%)]*%)" - local functype_reex = "^(%s*[%w%s%*]+%(%*)([%w_]+)(%)%([^%(%)]*%))" - if line:match(functype_re) then - local t1,name,t2 = line:match(functype_reex) - table.insert(outtab.structs[structnames[#structnames]],{type=t1..t2,name=name}) - break - end - --split type name1,name2; in several lines - local typen,rest = line:match("([^,]+)%s(%S+[,;])") - if not typen then -- Lets try Type*name - typen,rest = line:match("([^,]+%*)(%S+[,;])") - end - --local template_type = typen:match("/%*<(.+)>%*/") - --if template_type then typen = typen:match("(.+)/%*") end - local template_type = typen:match("ImVector_(.+)") - if template_type then - --typen = "ImVector" - template_type = template_type:gsub("_"," ") - template_type = template_type:gsub("Ptr","%*") - end - for name in rest:gmatch("([^%s,;]+)%s?[,;]") do - table.insert(outtab.structs[structnames[#structnames]],{type=typen,template_type=template_type,name=name}) - end - end - end - until true - end - --calcule size of name[16+1] [xxx_COUNT] - local allenums = {} - --first calc_value in enums - for enumname,enum in pairs(outtab.enums) do - for i,t in ipairs(enum) do - local val = tonumber(t.value) - if val then - t.calc_value = val - elseif t.value:match"<<" then - local v1,v2 = t.value:match("(%d+)%s*<<%s*(%d+)") - t.calc_value = bit.lshift(v1,v2) - elseif t.value:match"|" then --or several enums - local ens = t.value - ens = strsplit(ens,"|") - for i,v in ipairs(ens) do ens[i] = allenums[clean_spaces(v)] end - t.calc_value = bit.bor(unpack(ens)) - elseif allenums[t.value] then - t.calc_value = allenums[t.value] - else - print("Error unknown value in enums",t.value) - end - assert(t.calc_value) - allenums[t.name] = t.calc_value - end - end - --then calcsize in struct members - for stname,struct in pairs(outtab.structs) do - for i,t in ipairs(struct) do - local val = t.name:match"%[([^%[%]]+)%]" - if val then - if tonumber(val) then - t.size = tonumber(val) - elseif allenums[val] then - t.size = allenums[val] - elseif val:match"%+" then - local s1,s2 = val:match("(%d+)%s*%+%s*(%d+)") - t.size = s1+s2 - else - print("Error size is",val) - end - assert(t.size) - end - end - end - return outtab, typedefs_dict -end - -local function generate_templates(code,templates) - for k,v in pairs(templates) do - local te = k:gsub("%s","_") - te = te:gsub("%*","Ptr") - table.insert(code,"typedef struct ImVector_"..te.." {int Size;int Capacity;"..k.."* Data;} ImVector_"..te..";\n") - end -end - -local function gen_structs_and_enums(cdefs,templates) - local function_closing_re = "}" - local namespace_re = "namespace" - local in_namespace = false - local struct_re = "^%s*struct%s+([^%s;]+)$" - local struct_closed_re = "^%s*struct%s+([^%s]+);$" - local struct_closing_re = "};" - local struct_op_close_re = "%b{}" - local structnames = {} - local innerstructs = {} - local typedefs_table = {} - local typedefs_dict = {} - local outtab = {} - -- Output the file - --table.insert(outtab,"/////////////// BEGIN AUTOGENERATED SEGMENT\n") - - for i,line in ipairs(cdefs) do - repeat -- simulating continue with break - -- separate comments from code and try to add them with same tab - local line, comment = split_comment(line) - local linelen = #line - local desired_linelen = (linelen==0) and 0 or math.max(math.ceil(linelen/10)*10,40) - local spaces_to_add = 0 --desired_linelen - linelen - local linecom = line..string.rep(" ",spaces_to_add)..comment - - -- ImNewDummy drop for MSVC - if line:match"ImNewDummy" then break end - - if line:match(namespace_re) then - in_namespace = true - end - local structbegin = line:match(struct_re) - if structbegin then - structnames[#structnames + 1] = structbegin - if #structnames < 2 and structbegin~= "ImVectorNO" then --not inner and not ImVector - table.insert(outtab,linecom.."\n") - break - end - end - - -- ImVector special treatment - if structnames[#structnames] == "ImVector" then - if line:match(struct_closing_re) then - table.insert(outtab,[[typedef struct ImVector{int Size;int Capacity;void* Data;} ImVector;]].."\n") - generate_templates(outtab,templates) - structnames[#structnames] = nil - end - break -- dont write - end - - if in_namespace then - if line:match(function_closing_re) then - in_namespace = false - end - break -- dont write anything inside - end - - if #structnames < 2 then -- not inner - if line:match("typedef") and line:match("ImDrawIdx") then --save typedefs of ImDrawIdx - table.insert(typedefs_table,line..";\n") - break - end - if (#structnames > 0) then - if line:match("typedef") then --dont allow inner typedefs - break --already saved - elseif not line:match("^{$") and not line:match(struct_closing_re) then --avoid tab { and }; - --line = " "..line - end - end - table.insert(outtab,linecom.."\n") - local struct_closed_name = line:match(struct_closed_re) - if struct_closed_name then - table.insert(typedefs_table,"typedef struct "..struct_closed_name.." "..struct_closed_name..";\n") - typedefs_dict[struct_closed_name] = "struct "..struct_closed_name - end - end - - if #structnames > 0 then - if #structnames > 1 then --inner structs - innerstructs[structnames[#structnames]] = innerstructs[structnames[#structnames]] or {} - local st = innerstructs[structnames[#structnames]] - -- if not line:match("struct") and not line:match("^{$") and not line:match(struct_closing_re) then --avoid tab in struct { and }; - --line = " "..line - -- end - st[#st + 1] = line - if line:match(struct_closing_re) and not line:match(struct_op_close_re) then - local structname = structnames[#structnames] - --st[#st + 1] = string.format("typedef struct %s %s;\n",structname,structname) - table.insert(typedefs_table,string.format("typedef struct %s %s;\n",structname,structname)) - typedefs_dict[structname] = "struct "..structname - structnames[#structnames] = nil - end - elseif line:match(struct_closing_re) and not line:match(struct_op_close_re) then - local structname = structnames[#structnames] - --table.insert(outtab,"typedef struct "..structname.." "..structname..";\n") - table.insert(typedefs_table,"typedef struct "..structname.." "..structname..";\n") - typedefs_dict[structname] = "struct "..structname - structnames[#structnames] = nil - end - end - - - until true - end - for k,v in pairs(innerstructs) do - for i,line in ipairs(v) do - table.insert(outtab,line.."\n") - end - end - - --table.insert(outtab,"//////////////// END AUTOGENERATED SEGMENT \n") - local uniques = {} - for i,l in ipairs(typedefs_table) do - if not uniques[l] then - uniques[l] = true - table.insert(outtab,1,l) - end - end - --if templates then generate_templates(outtab,templates) end - local cstructsstr = table.concat(outtab) - cstructsstr = cstructsstr:gsub("\n+","\n") --several empty lines to one empty line - return cstructsstr, typedefs_dict -end - +--------------------------------functions for C generation local function func_header_impl_generate(FP) local outtab = {} - for _,t in ipairs(FP.cdefs) do + for _,t in ipairs(FP.funcdefs) do if t.cimguiname then local cimf = FP.defsT[t.cimguiname] local def = cimf[t.signature] if def.ret then --not constructor local addcoment = def.comment or "" if def.stname == "" then --ImGui namespace or top level - table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args..";"..addcoment.."\n") + table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..def.ov_cimguiname..def.args..";"..addcoment.."\n") else error("class function in implementations") end @@ -1230,39 +218,39 @@ local function func_header_generate(FP) local outtab = {} table.insert(outtab,"#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") for k,v in pairs(FP.embeded_structs) do - --print(k,v) table.insert(outtab,"typedef "..v.." "..k..";\n") end - for k,v in pairs(FP.ImVector_templates) do - table.insert(outtab,"typedef ImVector<"..k.."> ImVector_"..k..";\n") + for ttype,v in pairs(FP.templates) do + for ttypein,_ in pairs(v) do + local te = ttypein:gsub("%s","_") + te = te:gsub("%*","Ptr") + table.insert(outtab,"typedef "..ttype.."<"..ttypein.."> "..ttype.."_"..te..";\n") + end end - -- table.insert(outtab,"#else //CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") - -- for k,v in pairs(FP.ImVector_templates) do - -- table.insert(outtab,"typedef ImVector ImVector_"..k..";\n") - -- end + table.insert(outtab,"#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") - for _,t in ipairs(FP.cdefs) do + for _,t in ipairs(FP.funcdefs) do + if t.cimguiname then local cimf = FP.defsT[t.cimguiname] local def = cimf[t.signature] assert(def,t.signature..t.cimguiname) - local manual = get_manuals(def) - if not manual then + local manual = FP.get_manuals(def) + if not manual and not def.templated then + local addcoment = def.comment or "" local empty = def.args:match("^%(%)") --no args if def.constructor then - assert(def.stname ~= "ImGui" and def.stname ~= "","constructor without struct") - table.insert(outtab,"CIMGUI_API "..def.stname.."* "..(def.ov_cimguiname or def.cimguiname)..(empty and "(void)" or def.args)..";"..addcoment.."\n") + assert(def.stname ~= "","constructor without struct") + table.insert(outtab,"CIMGUI_API "..def.stname.."* "..def.ov_cimguiname ..(empty and "(void)" or def.args)..";"..addcoment.."\n") elseif def.destructor then table.insert(outtab,"CIMGUI_API void "..def.ov_cimguiname..def.args..";"..addcoment.."\n") else --not constructor - if def.stname == "ImGui" or def.stname == "" then --ImGui namespace or top level - table.insert(outtab,"CIMGUI_API "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..(empty and "(void)" or def.args)..";"..addcoment.."\n") + + if def.stname == "" then --ImGui namespace or top level + table.insert(outtab,"CIMGUI_API "..def.ret.." ".. def.ov_cimguiname ..(empty and "(void)" or def.args)..";"..addcoment.."\n") else - --local imgui_stname = embeded_structs[def.stname] or def.stname - local imgui_stname = def.stname - --local args = def.args:gsub("^%(","("..imgui_stname.."* self"..(empty and "" or ",")) - table.insert(outtab,"CIMGUI_API "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args..";"..addcoment.."\n") + table.insert(outtab,"CIMGUI_API "..def.ret.." "..def.ov_cimguiname..def.args..";"..addcoment.."\n") end end end @@ -1275,9 +263,11 @@ local function func_header_generate(FP) cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line return cfuncsstr end + + local function ImGui_f_implementation(outtab,def) local ptret = def.retref and "&" or "" - table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args.."\n") + table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..def.ov_cimguiname..def.args.."\n") table.insert(outtab,"{\n") if def.isvararg then local call_args = def.call_args:gsub("%.%.%.","args") @@ -1308,10 +298,10 @@ end local function struct_f_implementation(outtab,def) local empty = def.args:match("^%(%)") --no args local ptret = def.retref and "&" or "" - --local imgui_stname = embeded_structs[def.stname] or def.stname + local imgui_stname = def.stname - --local args = def.args:gsub("^%(","("..imgui_stname.."* self"..(empty and "" or ",")) - table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args.."\n") + + table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..def.ov_cimguiname..def.args.."\n") table.insert(outtab,"{\n") if def.isvararg then local call_args = def.call_args:gsub("%.%.%.","args") @@ -1342,18 +332,18 @@ end local function func_implementation(FP) local outtab = {} - for _,t in ipairs(FP.cdefs) do + for _,t in ipairs(FP.funcdefs) do repeat -- continue simulation if not t.cimguiname then break end local cimf = FP.defsT[t.cimguiname] local def = cimf[t.signature] assert(def) - local manual = get_manuals(def) - if not manual then + local manual = FP.get_manuals(def) + if not manual and not def.templated then if def.constructor then - assert(def.stname ~= "ImGui" and def.stname ~= "","constructor without struct") + assert(def.stname ~= "","constructor without struct") local empty = def.args:match("^%(%)") --no args - table.insert(outtab,"CIMGUI_API "..def.stname.."* "..(def.ov_cimguiname or def.cimguiname)..(empty and "(void)" or def.args).."\n") + table.insert(outtab,"CIMGUI_API "..def.stname.."* "..def.ov_cimguiname..(empty and "(void)" or def.args).."\n") table.insert(outtab,"{\n") table.insert(outtab," return IM_NEW("..def.stname..")"..def.call_args..";\n") table.insert(outtab,"}\n") @@ -1364,7 +354,7 @@ local function func_implementation(FP) table.insert(outtab,"{\n") table.insert(outtab," IM_DELETE(self);\n") table.insert(outtab,"}\n") - elseif def.stname == "ImGui" then + elseif def.stname == "" then ImGui_f_implementation(outtab,def) else -- stname struct_f_implementation(outtab,def) @@ -1374,33 +364,7 @@ local function func_implementation(FP) end return table.concat(outtab) end ---only basic ending -local c_types = { - ["char"]=true, - ["int"]=true, - ["float"]=true, - ["double"]=true, - ["short"]=true, - ["long"]=true, - ["signed"]=true, - ["unsigned"]=true, - ["size_t"]=true, - ["ptrdiff_t"]=true, -} -local function check_arg_detection(fdefs,typedefs) - print"-----------------check arg detection---------------------------" - for k,defT in pairs(fdefs) do - for i,def in ipairs(defT) do - for j,arg in ipairs(def.argsT) do - --check name is not type, which happens in declaration without name - if arg.name=="*" or not arg.type or not arg.name or c_types[arg.name] or typedefs[arg.name] then - print("bad argument name",arg.name, "in",def.funcname,def.args) - end - end - end - end - print"-----------------end check arg detection-----------------------" -end +-------------------functions for getting and setting defines local function get_defines(t) if COMPILER == "cl" then print"can't get defines with cl compiler"; return {} end local pipe,err = io.popen(COMPILER..[[ -E -dM -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ../imgui/imgui.h]],"r") @@ -1434,7 +398,7 @@ local function get_defines(t) end return ret end ---subtitution of FLT_MAX value for FLT_MAX + --subtitution of FLT_MAX value for FLT_MAX local function set_defines(fdefs) for k,defT in pairs(fdefs) do for i,def in ipairs(defT) do @@ -1446,6 +410,7 @@ local function set_defines(fdefs) end end end +--this creates defsBystruct in case you need to list by struct container local function DefsByStruct(FP) local structs = {} for fun,defs in pairs(FP.defsT) do @@ -1453,54 +418,77 @@ local function DefsByStruct(FP) structs[stname] = structs[stname] or {} table.insert(structs[stname],defs)--fun) end - -- for st,funs in pairs(struct) do - -- struct[st] = table.sort(funs) - -- end - FP.defsBystruct = struct + FP.defsBystruct = structs end -local function AdjustArguments(FP) - for fun,defs in pairs(FP.defsT) do - --struct function but no constructors - if defs[1].stname~="ImGui" and defs[1].stname~="" and defs[1].ret then - --print("adjusting",fun) - for i,def in ipairs(defs) do - local empty = def.args:match("^%(%)") --no args - --local ptret = def.retref and "&" or "" - def.args = def.args:gsub("^%(","("..def.stname.."* self"..(empty and "" or ",")) - table.insert(def.argsT,1,{type=def.stname.."*",name="self"}) - end - end + + +--load parser module +local cpp2ffi = require"cpp2ffi" +local read_data = cpp2ffi.read_data +local save_data = cpp2ffi.save_data +local copyfile = cpp2ffi.copyfile +local serializeTableF = cpp2ffi.serializeTableF + +----------custom ImVector templates +local function generate_templates(code,templates) + table.insert(code,[[typedef struct ImVector{int Size;int Capacity;void* Data;} ImVector;]].."\n") + for ttype,v in pairs(templates) do + --local te = k:gsub("%s","_") + --te = te:gsub("%*","Ptr") + if ttype == "ImVector" then + for te,newte in pairs(v) do + table.insert(code,"typedef struct ImVector_"..newte.." {int Size;int Capacity;"..te.."* Data;} ImVector_"..newte..";\n") + end + end end end ---generate cimgui.cpp cimgui.h and auto versions depending on postfix -local function cimgui_generation(postfix,STP,FP) - --get all ImVector templates - local ImVector_templates = mergeT(STP.ImVector_templates,FP.ImVector_templates) - --merge it in cimgui_template.h to cimgui.h - local hfile = io.open("./cimgui_template.h","r") - local hstrfile = hfile:read"*a" - hfile:close() - local cstructsstr,typedefs_dict = gen_structs_and_enums(STP.lines,ImVector_templates) - --for not gcc parsing - if postfix == "_nopreprocess" then - cstructsstr = "typedef unsigned short ImDrawIdx;\ntypedef void* ImTextureID;\n"..cstructsstr - end - +--generate cimgui.cpp cimgui.h +local function cimgui_generation(parser) + cpp2ffi.prtable(parser.templates) + cpp2ffi.prtable(parser.typenames) + -- clean ImVector:contains() for not applicable types + local clean_f = {} + for k,v in pairs(parser.defsT) do + if k:match"ImVector" and k:match"contains" then + --cpp2ffi.prtable(k,v) + local stname = v[1].stname + if not(stname:match"float" or stname:match"int" or stname:match"char") then + parser.defsT[k] = nil + --delete also from funcdefs + for i,t in ipairs(parser.funcdefs) do + if t.cimguiname == k then + table.remove(parser.funcdefs, i) + break + end + end + end + end + end + + -------------------------------------------------- + local hstrfile = read_data"./cimgui_template.h" + + local outpre,outpost = parser:gen_structs_and_enums() + --parser.templates get completely defined here + --cpp2ffi.prtable(parser.templates) + + local outtab = {} + generate_templates(outtab,parser.templates) + local cstructsstr = outpre..table.concat(outtab,"")..outpost + hstrfile = hstrfile:gsub([[#include "imgui_structs%.h"]],cstructsstr) - local cfuncsstr = func_header_generate(FP) + local cfuncsstr = func_header_generate(parser) hstrfile = hstrfile:gsub([[#include "auto_funcs%.h"]],cfuncsstr) - save_data("./output/cimgui"..postfix..".h",cimgui_header,hstrfile) - + save_data("./output/cimgui.h",cimgui_header,hstrfile) --merge it in cimgui_template.cpp to cimgui.cpp - local cimplem = func_implementation(FP) - local hfile = io.open("./cimgui_template.cpp","r") - local hstrfile = hfile:read"*a" - hfile:close() + local cimplem = func_implementation(parser) + + local hstrfile = read_data"./cimgui_template.cpp" + hstrfile = hstrfile:gsub([[#include "auto_funcs%.cpp"]],cimplem) - hstrfile = hstrfile:gsub([[#include "cimgui%.h"]],[[#include "cimgui]]..postfix..[[.h"]]) - save_data("./output/cimgui"..postfix..".cpp",cimgui_header,hstrfile) - return typedefs_dict + save_data("./output/cimgui.cpp",cimgui_header,hstrfile) + end -------------------------------------------------------- -----------------------------do it---------------------- @@ -1526,7 +514,16 @@ end --generation print("------------------generation with "..COMPILER.."------------------------") -local pFP,pSTP,typedefs_dict2 +local typedefs_dict2 +--prepare parser +local parser1 = cpp2ffi.Parser() +parser1.getCname = function(stname,funcname) + local pre = (stname == "") and "ig" or stname.."_" + return pre..funcname +end +parser1.cname_overloads = cimgui_overloads +parser1.manuals = cimgui_manuals +parser1.UDTs = {"ImVec2","ImVec4","ImColor"} local pipe,err if HAVE_COMPILER then @@ -1539,49 +536,54 @@ if not pipe then error("could not execute gcc "..err) end -pSTP = struct_parser() --overwrite -pFP = func_parser() --overwrite +--local file,err = io.open("output_compiler.txt","w") +--if not file then error(err) end -local iterator = (HAVE_COMPILER and location) or filelines +local iterator = (HAVE_COMPILER and cpp2ffi.location) or filelines -for line in iterator(pipe,{"imgui"}) do - local line, comment = split_comment(line) - --line = clean_spaces(line) - --comment = "" - pSTP.insert(line,comment) - pFP.insert(line,comment) +for line in iterator(pipe,{"imgui"},{}) do + parser1:insert(line) + --file:write(line) end +--file:close() pipe:close() -local ovstr = pFP:compute_overloads() -AdjustArguments(pFP) -ADDnonUDT(pFP) -ADDdestructors(pFP) - -save_data("./output/overloads.txt",ovstr) -typedefs_dict2 = cimgui_generation("",pSTP,pFP) ---check arg detection failure if no name in function declaration -check_arg_detection(pFP.defsT,typedefs_dict2) +parser1:do_parse() +--table.sort(parser1.funcdefs, function(a,b) return a.cimguiname < b.cimguiname end) +--parser1:dump_alltypes() +--parser1:printItems() +save_data("./output/overloads.txt",parser1.overloadstxt) +cimgui_generation(parser1) ----------save fundefs in definitions.lua for using in bindings --DefsByStruct(pFP) -set_defines(pFP.defsT) -save_data("./output/definitions.lua",serializeTable("defs",pFP.defsT),"\nreturn defs") +set_defines(parser1.defsT) +save_data("./output/definitions.lua",serializeTableF(parser1.defsT)) ----------save struct and enums lua table in structs_and_enums.lua for using in bindings -local structs_and_enums_table,typedefs_dict = gen_structs_and_enums_table(pSTP.lines) -save_data("./output/structs_and_enums.lua",serializeTable("defs",structs_and_enums_table),"\nreturn defs") -typedefs_dict = mergeT(typedefs_dict,typedefs_dict2) -save_data("./output/typedefs_dict.lua",serializeTable("defs",typedefs_dict),"\nreturn defs") +local structs_and_enums_table = parser1:gen_structs_and_enums_table() +--correct Pair union member +structs_and_enums_table["structs"]["Pair"][2]["name"] = "" +structs_and_enums_table["structs"]["Pair"][2]["type"] = structs_and_enums_table["structs"]["Pair"][2]["type"] .. "}" +----------------------- +save_data("./output/structs_and_enums.lua",serializeTableF(structs_and_enums_table)) +save_data("./output/typedefs_dict.lua",serializeTableF(parser1.typedefs_dict)) + +--check every function has ov_cimguiname +-- for k,v in pairs(parser1.defsT) do + -- for _,def in ipairs(v) do + -- assert(def.ov_cimguiname) + -- end +-- end --=================================Now implementations -local iFP,iSTP +local parser2 if #implementations > 0 then - iFP = func_parser() - iSTP = struct_parser() + parser2 = cpp2ffi.Parser() + for i,impl in ipairs(implementations) do local source = [[../imgui/examples/imgui_impl_]].. impl .. ".h " @@ -1596,23 +598,23 @@ if #implementations > 0 then error("could not get file: "..err) end - local iterator = (HAVE_COMPILER and location) or filelines + local iterator = (HAVE_COMPILER and cpp2ffi.location) or filelines - for line,locat in iterator(pipe,{locati}) do - local line, comment = split_comment(line) - iSTP.insert(line,comment) - iFP.insert(line,comment,locat) + for line,locat in iterator(pipe,{locati},{}) do + --local line, comment = split_comment(line) + parser2:insert(line) end pipe:close() end + parser2:do_parse() -- save ./cimgui_impl.h - local cfuncsstr = func_header_impl_generate(iFP) - local cstructstr = gen_structs_and_enums(iSTP.lines) - save_data("./output/cimgui_impl.h",cstructstr,cfuncsstr) + local cfuncsstr = func_header_impl_generate(parser2) + local cstructstr1,cstructstr2 = parser2:gen_structs_and_enums() + save_data("./output/cimgui_impl.h",cstructstr1,cstructstr2,cfuncsstr) ----------save fundefs in impl_definitions.lua for using in bindings - save_data("./output/impl_definitions.lua",serializeTable("defs",iFP.defsT),"\nreturn defs") + save_data("./output/impl_definitions.lua",serializeTableF(parser2.defsT)) end -- #implementations > 0 then @@ -1631,52 +633,14 @@ local function json_prepare(defs) end ---[[ local json = require"json" -save_data("./output/definitions.json",json.encode(json_prepare(pFP.defsT))) +save_data("./output/definitions.json",json.encode(json_prepare(parser1.defsT))) save_data("./output/structs_and_enums.json",json.encode(structs_and_enums_table)) -save_data("./output/typedefs_dict.json",json.encode(typedefs_dict)) -if iFP then - save_data("./output/impl_definitions.json",json.encode(json_prepare(iFP.defsT))) +save_data("./output/typedefs_dict.json",json.encode(parser1.typedefs_dict)) +if parser2 then + save_data("./output/impl_definitions.json",json.encode(json_prepare(parser2.defsT))) end --]] +-------------------copy C files to repo root copyfile("./output/cimgui.h", "../cimgui.h") copyfile("./output/cimgui.cpp", "../cimgui.cpp") print"all done!!" ---[[ ----dump some infos----------------------------------------------------------------------- ------------------------------------------------------------------------------------- -print"//-------alltypes--------------------------------------------------------------------" -pFP:dump_alltypes() -print"//embeded_structs---------------------------------------------------------------------------" -for k,v in pairs(pFP.embeded_structs) do - --print(k,v) - io.write("typedef ",v," ",k,";\n") -end -print"//templates---------------------------------------------------------------------------" -for k,v in pairs(pFP.ImVector_templates) do - --print(k,v) - io.write("typedef ImVector<",k,"> ImVector_",k,";\n") -end -for k,v in pairs(pSTP.ImVector_templates) do - --print(k,v) - io.write("typedef ImVector<",k,"> ImVector_",k,";\n") -end -require"anima.utils" -print"//constructors------------------------------------------------------------------" -for i,t in ipairs(pFP.cdefs) do - if t.cimguiname and not t.ret then - local cimf = pFP.defsT[t.cimguiname] - local def = cimf[t.signature] - if not def.ret then - print(t.cimguiname,"\t",t.signature,t.ret) - else - print"constructor error" - prtable(def) - end - end -end -print"//-------------------------------------------------------------------------------------" -for i,t in ipairs(pFP.cdefs) do - --print(t.cimguiname," ",t.funcname,"\t",t.signature,"\t",t.args,"\t",t.argsc,"\t",t.call_args,"\t",t.ret) -end ---------------------------------------------------------------------------------------------- ---]] \ No newline at end of file diff --git a/generator/generator2.lua b/generator/generator2.lua deleted file mode 100644 index 93cd1ae..0000000 --- a/generator/generator2.lua +++ /dev/null @@ -1,646 +0,0 @@ --------------------------------------------------------------------------- ---script for auto_funcs.h and auto_funcs.cpp generation ---expects LuaJIT --------------------------------------------------------------------------- -assert(_VERSION=='Lua 5.1',"Must use LuaJIT") -assert(bit,"Must use LuaJIT") -local script_args = {...} -local COMPILER = script_args[1] -local CPRE,CTEST -if COMPILER == "gcc" or COMPILER == "clang" then - CPRE = COMPILER..[[ -E -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ]] - CTEST = COMPILER.." --version" -elseif COMPILER == "cl" then - CPRE = COMPILER..[[ /E /DIMGUI_DISABLE_OBSOLETE_FUNCTIONS /DIMGUI_API="" /DIMGUI_IMPL_API="" ]] - CTEST = COMPILER -else - print("Working without compiler ") -end ---test compiler present -local HAVE_COMPILER = false -if CTEST then - local pipe,err = io.popen(CTEST,"r") - if pipe then - local str = pipe:read"*a" - print(str) - pipe:close() - if str=="" then - HAVE_COMPILER = false - else - HAVE_COMPILER = true - end - else - HAVE_COMPILER = false - print(err) - end - assert(HAVE_COMPILER,"gcc, clang or cl needed to run script") -end --CTEST - -print("HAVE_COMPILER",HAVE_COMPILER) ---get implementations -local implementations = {} -for i=2,#script_args do table.insert(implementations,script_args[i]) end - --------------------------------------------------------------------------- ---this table has the functions to be skipped in generation --------------------------------------------------------------------------- -local cimgui_manuals = { - igLogText = true, - ImGuiTextBuffer_appendf = true, - igColorConvertRGBtoHSV = true, - igColorConvertHSVtoRGB = true -} --------------------------------------------------------------------------- ---this table is a dictionary to force a naming of function overloading (instead of algorythmic generated) ---first level is cimguiname without postfix, second level is the signature of the function, value is the ---desired name ---------------------------------------------------------------------------- -local cimgui_overloads = { - igPushID = { - --["(const char*)"] = "igPushIDStr", - ["(const char*,const char*)"] = "igPushIDRange", - --["(const void*)"] = "igPushIDPtr", - --["(int)"] = "igPushIDInt" - }, - igGetID = { - ["(const char*,const char*)"] = "igGetIDRange", - }, - ImDrawList_AddText = { - ["(const ImVec2,ImU32,const char*,const char*)"] = "ImDrawList_AddText", - }, - igGetColorU32 = { - ["(ImGuiCol,float)"] = "igGetColorU32", - }, - igCollapsingHeader = { - ["(const char*,ImGuiTreeNodeFlags)"] = "igCollapsingHeader", - }, - igCombo = { - ["(const char*,int*,const char* const[],int,int)"] = "igCombo", - }, - igPlotLines = { - ["(const char*,const float*,int,int,const char*,float,float,ImVec2,int)"] = "igPlotLines", - }, - igBeginChild = { - ["(const char*,const ImVec2,bool,ImGuiWindowFlags)"] = "igBeginChild", - }, - igSelectable = { - ["(const char*,bool,ImGuiSelectableFlags,const ImVec2)"] = "igSelectable" - }, - igPushStyleColor = { - ["(ImGuiCol,const ImVec4)"] = "igPushStyleColor" - } -} - ---------------------------header definitions -local cimgui_header = -[[//This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui -//based on imgui.h file version XXX from Dear ImGui https://github.com/ocornut/imgui -]] -local gdefines = {} --for FLT_MAX and others --------------------------------------------------------------------------- ---helper functions - - ----------------------------minimal preprocessor without compiler for ImGui.h -local function filelines(file,locats) - local split_comment = require"cpp2ffi".split_comment - local iflevels = {} - --generated known prepros -local prepro = { -["#if"]={ - [ "defined(__clang__) || defined(__GNUC__)" ]=false, - [ "defined(__clang__)" ]=false, - [ "defined(_MSC_VER) && !defined(__clang__)" ]=false, - [ "!defined(IMGUI_DISABLE_INCLUDE_IMCONFIG_H) || defined(IMGUI_INCLUDE_IMCONFIG_H)" ]=false, - [ "!defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \\" ]=false, -}, -["#elif"]={ - [ "defined(__GNUC__) && __GNUC__ >= 8" ]=false, - [ "(defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)" ]=false, -}, -["#ifdef"]={ - [ "IM_VEC4_CLASS_EXTRA" ]=false, - [ "IMGUI_USER_CONFIG" ]=false, - [ "IMGUI_INCLUDE_IMGUI_USER_H" ]=false, - [ "IMGUI_USE_BGRA_PACKED_COLOR" ]=false, - [ "IM_VEC2_CLASS_EXTRA" ]=false, -}, -["#ifndef"]={ - [ "IMGUI_API" ]=false, - [ "IMGUI_IMPL_API" ]=false, - [ "IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT" ]=true, - [ "IM_ASSERT" ]=false, - [ "ImTextureID" ]=true, - [ "ImDrawIdx" ]=true, - [ "IMGUI_DISABLE_OBSOLETE_FUNCTIONS" ]=false, -}, -} - - local function prepro_boolif(pre,cond) - local conds = prepro[pre] - assert(conds,pre.." has no conds-----------------------------") - local res = conds[cond] - --assert(type(res)~="nil",cond.." not found") - if type(res)=="nil" then - print(pre,cond,"not found in precompiler database, returning false.") - res = false - end - return res - end - local function location_it() - repeat - local line = file:read"*l" - - if not line then return nil end - line,_ = split_comment(line) - --if line:sub(1,1) == "#" then - if line:match("^%s*#") then - - local pre,cond = line:match("^%s*(#%S*)%s+(.*)%s*$") - if line:match("#if") then - iflevels[#iflevels +1 ] = prepro_boolif(pre,cond) - elseif line:match("#endif") then - iflevels[#iflevels] = nil - elseif line:match("#elif") then - if not iflevels[#iflevels] then - iflevels[#iflevels] = prepro_boolif(pre,cond) - else --was true - iflevels[#iflevels] = false - end - elseif line:match("#else") then - iflevels[#iflevels] = not iflevels[#iflevels] - else - if not (pre:match("#define") or pre:match"#include" or pre:match"#pragma") then - print("not expected preprocessor directive ",pre) - end - end - -- skip - elseif #iflevels == 0 or iflevels[#iflevels] then - -- drop IMGUI_APIX - line = line:gsub("IMGUI_IMPL_API","") - -- drop IMGUI_API - line = line:gsub("IMGUI_API","") - return line,locats[1] - end - until false - end - return location_it -end - - ---------------------------------functions for C generation -local function func_header_impl_generate(FP) - - local outtab = {} - - for _,t in ipairs(FP.funcdefs) do - if t.cimguiname then - local cimf = FP.defsT[t.cimguiname] - local def = cimf[t.signature] - if def.ret then --not constructor - local addcoment = def.comment or "" - if def.stname == "" then --ImGui namespace or top level - table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..def.ov_cimguiname..def.args..";"..addcoment.."\n") - else - error("class function in implementations") - end - end - else --not cimguiname - table.insert(outtab,t.comment:gsub("%%","%%%%").."\n")-- %% substitution for gsub - end - end - local cfuncsstr = table.concat(outtab) - cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line - return cfuncsstr -end -local function func_header_generate(FP) - - local outtab = {} - table.insert(outtab,"#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") - for k,v in pairs(FP.embeded_structs) do - table.insert(outtab,"typedef "..v.." "..k..";\n") - end - for ttype,v in pairs(FP.templates) do - for ttypein,_ in pairs(v) do - local te = ttypein:gsub("%s","_") - te = te:gsub("%*","Ptr") - table.insert(outtab,"typedef "..ttype.."<"..ttypein.."> "..ttype.."_"..te..";\n") - end - end - - table.insert(outtab,"#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") - for _,t in ipairs(FP.funcdefs) do - - if t.cimguiname then - local cimf = FP.defsT[t.cimguiname] - local def = cimf[t.signature] - assert(def,t.signature..t.cimguiname) - local manual = FP.get_manuals(def) - if not manual and not def.templated then - - local addcoment = def.comment or "" - local empty = def.args:match("^%(%)") --no args - if def.constructor then - assert(def.stname ~= "","constructor without struct") - table.insert(outtab,"CIMGUI_API "..def.stname.."* "..def.ov_cimguiname ..(empty and "(void)" or def.args)..";"..addcoment.."\n") - elseif def.destructor then - table.insert(outtab,"CIMGUI_API void "..def.ov_cimguiname..def.args..";"..addcoment.."\n") - else --not constructor - - if def.stname == "" then --ImGui namespace or top level - table.insert(outtab,"CIMGUI_API "..def.ret.." ".. def.ov_cimguiname ..(empty and "(void)" or def.args)..";"..addcoment.."\n") - else - table.insert(outtab,"CIMGUI_API "..def.ret.." "..def.ov_cimguiname..def.args..";"..addcoment.."\n") - end - end - end - else --not cimguiname - table.insert(outtab,t.comment:gsub("%%","%%%%").."\n")-- %% substitution for gsub - end - end - - local cfuncsstr = table.concat(outtab) - cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line - return cfuncsstr -end - - -local function ImGui_f_implementation(outtab,def) - local ptret = def.retref and "&" or "" - table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..def.ov_cimguiname..def.args.."\n") - table.insert(outtab,"{\n") - if def.isvararg then - local call_args = def.call_args:gsub("%.%.%.","args") - table.insert(outtab," va_list args;\n") - table.insert(outtab," va_start(args, fmt);\n") - if def.ret~="void" then - table.insert(outtab," "..def.ret.." ret = ImGui::"..def.funcname.."V"..call_args..";\n") - else - table.insert(outtab," ImGui::"..def.funcname.."V"..call_args..";\n") - end - table.insert(outtab," va_end(args);\n") - if def.ret~="void" then - table.insert(outtab," return ret;\n") - end - elseif def.nonUDT then - if def.nonUDT == 1 then - table.insert(outtab," *pOut = ImGui::"..def.funcname..def.call_args..";\n") - else --nonUDT==2 - table.insert(outtab," "..def.retorig.." ret = ImGui::"..def.funcname..def.call_args..";\n") - table.insert(outtab," "..def.ret.." ret2 = "..def.retorig.."ToSimple(ret);\n") - table.insert(outtab," return ret2;\n") - end - else --standard ImGui - table.insert(outtab," return "..ptret.."ImGui::"..def.funcname..def.call_args..";\n") - end - table.insert(outtab,"}\n") -end -local function struct_f_implementation(outtab,def) - local empty = def.args:match("^%(%)") --no args - local ptret = def.retref and "&" or "" - - local imgui_stname = def.stname - - table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..def.ov_cimguiname..def.args.."\n") - table.insert(outtab,"{\n") - if def.isvararg then - local call_args = def.call_args:gsub("%.%.%.","args") - table.insert(outtab," va_list args;\n") - table.insert(outtab," va_start(args, fmt);\n") - if def.ret~="void" then - table.insert(outtab," "..def.ret.." ret = self->"..def.funcname.."V"..call_args..";\n") - else - table.insert(outtab," self->"..def.funcname.."V"..call_args..";\n") - end - table.insert(outtab," va_end(args);\n") - if def.ret~="void" then - table.insert(outtab," return ret;\n") - end - elseif def.nonUDT then - if def.nonUDT == 1 then - table.insert(outtab," *pOut = self->"..def.funcname..def.call_args..";\n") - else --nonUDT==2 - table.insert(outtab," "..def.retorig.." ret = self->"..def.funcname..def.call_args..";\n") - table.insert(outtab," "..def.ret.." ret2 = "..def.retorig.."ToSimple(ret);\n") - table.insert(outtab," return ret2;\n") - end - else --standard struct - table.insert(outtab," return "..ptret.."self->"..def.funcname..def.call_args..";\n") - end - table.insert(outtab,"}\n") -end -local function func_implementation(FP) - - local outtab = {} - for _,t in ipairs(FP.funcdefs) do - repeat -- continue simulation - if not t.cimguiname then break end - local cimf = FP.defsT[t.cimguiname] - local def = cimf[t.signature] - assert(def) - local manual = FP.get_manuals(def) - if not manual and not def.templated then - if def.constructor then - assert(def.stname ~= "","constructor without struct") - local empty = def.args:match("^%(%)") --no args - table.insert(outtab,"CIMGUI_API "..def.stname.."* "..def.ov_cimguiname..(empty and "(void)" or def.args).."\n") - table.insert(outtab,"{\n") - table.insert(outtab," return IM_NEW("..def.stname..")"..def.call_args..";\n") - table.insert(outtab,"}\n") - elseif def.destructor then - local args = "("..def.stname.."* self)" - local fname = def.stname.."_destroy" - table.insert(outtab,"CIMGUI_API void "..fname..args.."\n") - table.insert(outtab,"{\n") - table.insert(outtab," IM_DELETE(self);\n") - table.insert(outtab,"}\n") - elseif def.stname == "" then - ImGui_f_implementation(outtab,def) - else -- stname - struct_f_implementation(outtab,def) - end - end - until true - end - return table.concat(outtab) -end --------------------functions for getting and setting defines -local function get_defines(t) - if COMPILER == "cl" then print"can't get defines with cl compiler"; return {} end - local pipe,err = io.popen(COMPILER..[[ -E -dM -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ../imgui/imgui.h]],"r") - local defines = {} - while true do - local line = pipe:read"*l" - if not line then break end - local key,value = line:match([[#define%s+(%S+)%s+(.+)]]) - if not key or not value then - --print(line) - else - defines[key]=value - end - end - pipe:close() - --require"anima.utils" - --prtable(defines) - --FLT_MAX - local ret = {} - for i,v in ipairs(t) do - local aa = defines[v] - while true do - local tmp = defines[aa] - if not tmp then - break - else - aa = tmp - end - end - ret[v] = aa - end - return ret -end - --subtitution of FLT_MAX value for FLT_MAX -local function set_defines(fdefs) - for k,defT in pairs(fdefs) do - for i,def in ipairs(defT) do - for name,default in pairs(def.defaults) do - if default == gdefines.FLT_MAX then - def.defaults[name] = "FLT_MAX" - end - end - end - end -end ---this creates defsBystruct in case you need to list by struct container -local function DefsByStruct(FP) - local structs = {} - for fun,defs in pairs(FP.defsT) do - local stname = defs[1].stname - structs[stname] = structs[stname] or {} - table.insert(structs[stname],defs)--fun) - end - FP.defsBystruct = structs -end - - ---load parser module -local cpp2ffi = require"cpp2ffi" -local read_data = cpp2ffi.read_data -local save_data = cpp2ffi.save_data -local copyfile = cpp2ffi.copyfile -local serializeTableF = cpp2ffi.serializeTableF - -----------custom ImVector templates -local function generate_templates(code,templates) - table.insert(code,[[typedef struct ImVector{int Size;int Capacity;void* Data;} ImVector;]].."\n") - for ttype,v in pairs(templates) do - --local te = k:gsub("%s","_") - --te = te:gsub("%*","Ptr") - if ttype == "ImVector" then - for te,newte in pairs(v) do - table.insert(code,"typedef struct ImVector_"..newte.." {int Size;int Capacity;"..te.."* Data;} ImVector_"..newte..";\n") - end - end - end -end ---generate cimgui.cpp cimgui.h -local function cimgui_generation(parser) - cpp2ffi.prtable(parser.templates) - cpp2ffi.prtable(parser.typenames) - -- clean ImVector:contains() for not applicable types - local clean_f = {} - for k,v in pairs(parser.defsT) do - if k:match"ImVector" and k:match"contains" then - --cpp2ffi.prtable(k,v) - local stname = v[1].stname - if not(stname:match"float" or stname:match"int" or stname:match"char") then - parser.defsT[k] = nil - --delete also from funcdefs - for i,t in ipairs(parser.funcdefs) do - if t.cimguiname == k then - table.remove(parser.funcdefs, i) - break - end - end - end - end - end - - -------------------------------------------------- - local hstrfile = read_data"./cimgui_template.h" - - local outpre,outpost = parser:gen_structs_and_enums() - --parser.templates get completely defined here - --cpp2ffi.prtable(parser.templates) - - local outtab = {} - generate_templates(outtab,parser.templates) - local cstructsstr = outpre..table.concat(outtab,"")..outpost - - hstrfile = hstrfile:gsub([[#include "imgui_structs%.h"]],cstructsstr) - local cfuncsstr = func_header_generate(parser) - hstrfile = hstrfile:gsub([[#include "auto_funcs%.h"]],cfuncsstr) - save_data("./output/cimgui.h",cimgui_header,hstrfile) - - --merge it in cimgui_template.cpp to cimgui.cpp - local cimplem = func_implementation(parser) - - local hstrfile = read_data"./cimgui_template.cpp" - - hstrfile = hstrfile:gsub([[#include "auto_funcs%.cpp"]],cimplem) - save_data("./output/cimgui.cpp",cimgui_header,hstrfile) - -end --------------------------------------------------------- ------------------------------do it---------------------- --------------------------------------------------------- ---get imgui.h version-------------------------- -local pipe,err = io.open("../imgui/imgui.h","r") -if not pipe then - error("could not open file:"..err) -end -local imgui_version -while true do - local line = pipe:read"*l" - imgui_version = line:match([[#define%s+IMGUI_VERSION%s+(".+")]]) - if imgui_version then break end -end -pipe:close() -cimgui_header = cimgui_header:gsub("XXX",imgui_version) -print("IMGUI_VERSION",imgui_version) ---get some defines---------------------------- -if HAVE_COMPILER then - gdefines = get_defines{"IMGUI_VERSION","FLT_MAX"} -end - ---generation -print("------------------generation with "..COMPILER.."------------------------") -local typedefs_dict2 ---prepare parser -local parser1 = cpp2ffi.Parser() -parser1.getCname = function(stname,funcname) - local pre = (stname == "") and "ig" or stname.."_" - return pre..funcname -end -parser1.cname_overloads = cimgui_overloads -parser1.manuals = cimgui_manuals -parser1.UDTs = {"ImVec2","ImVec4","ImColor"} - -local pipe,err -if HAVE_COMPILER then - pipe,err = io.popen(CPRE..[[../imgui/imgui.h]],"r") -else - pipe,err = io.open([[../imgui/imgui.h]],"r") -end - -if not pipe then - error("could not execute gcc "..err) -end - ---local file,err = io.open("output_compiler.txt","w") ---if not file then error(err) end - -local iterator = (HAVE_COMPILER and cpp2ffi.location) or filelines - -for line in iterator(pipe,{"imgui"},{}) do - parser1:insert(line) - --file:write(line) -end ---file:close() -pipe:close() - -parser1:do_parse() ---table.sort(parser1.funcdefs, function(a,b) return a.cimguiname < b.cimguiname end) ---parser1:dump_alltypes() ---parser1:printItems() - -save_data("./output/overloads.txt",parser1.overloadstxt) -cimgui_generation(parser1) - -----------save fundefs in definitions.lua for using in bindings ---DefsByStruct(pFP) -set_defines(parser1.defsT) -save_data("./output/definitions.lua",serializeTableF(parser1.defsT)) - -----------save struct and enums lua table in structs_and_enums.lua for using in bindings -local structs_and_enums_table = parser1:gen_structs_and_enums_table() ---correct Pair union member -structs_and_enums_table["structs"]["Pair"][2]["name"] = "" -structs_and_enums_table["structs"]["Pair"][2]["type"] = structs_and_enums_table["structs"]["Pair"][2]["type"] .. "}" ------------------------ -save_data("./output/structs_and_enums.lua",serializeTableF(structs_and_enums_table)) -save_data("./output/typedefs_dict.lua",serializeTableF(parser1.typedefs_dict)) - ---check every function has ov_cimguiname --- for k,v in pairs(parser1.defsT) do - -- for _,def in ipairs(v) do - -- assert(def.ov_cimguiname) - -- end --- end ---=================================Now implementations - -local parser2 - -if #implementations > 0 then - - parser2 = cpp2ffi.Parser() - - - for i,impl in ipairs(implementations) do - local source = [[../imgui/examples/imgui_impl_]].. impl .. ".h " - local locati = [[imgui_impl_]].. impl - local pipe,err - if HAVE_COMPILER then - pipe,err = io.popen(CPRE..source,"r") - else - pipe,err = io.open(source,"r") - end - if not pipe then - error("could not get file: "..err) - end - - local iterator = (HAVE_COMPILER and cpp2ffi.location) or filelines - - for line,locat in iterator(pipe,{locati},{}) do - --local line, comment = split_comment(line) - parser2:insert(line) - end - pipe:close() - end - parser2:do_parse() - - -- save ./cimgui_impl.h - local cfuncsstr = func_header_impl_generate(parser2) - local cstructstr1,cstructstr2 = parser2:gen_structs_and_enums() - save_data("./output/cimgui_impl.h",cstructstr1,cstructstr2,cfuncsstr) - - ----------save fundefs in impl_definitions.lua for using in bindings - save_data("./output/impl_definitions.lua",serializeTableF(parser2.defsT)) - -end -- #implementations > 0 then - --------------------------------json saving ---avoid mixed tables (with string and integer keys) -local function json_prepare(defs) - --delete signatures in function - for k,def in pairs(defs) do - for k2,v in pairs(def) do - if type(k2)=="string" then - def[k2] = nil - end - end - end - return defs -end ----[[ -local json = require"json" -save_data("./output/definitions.json",json.encode(json_prepare(parser1.defsT))) -save_data("./output/structs_and_enums.json",json.encode(structs_and_enums_table)) -save_data("./output/typedefs_dict.json",json.encode(parser1.typedefs_dict)) -if parser2 then - save_data("./output/impl_definitions.json",json.encode(json_prepare(parser2.defsT))) -end ---]] --------------------copy C files to repo root -copyfile("./output/cimgui.h", "../cimgui.h") -copyfile("./output/cimgui.cpp", "../cimgui.cpp") -print"all done!!" diff --git a/generator/generator2.bat b/generator/generator_old.bat similarity index 94% rename from generator/generator2.bat rename to generator/generator_old.bat index b2979c2..10937a9 100644 --- a/generator/generator2.bat +++ b/generator/generator_old.bat @@ -16,7 +16,7 @@ set PATH=%PATH%;C:\luaGL;C:\mingw32\bin; ::process files :: arg[1] compiler name gcc, clang, cl or nocompiler :: arg[2..n] name of implementations to generate -luajit ./generator2.lua gcc glfw opengl3 opengl2 sdl +luajit ./generator_old.lua gcc glfw opengl3 opengl2 sdl ::leave console open cmd /k diff --git a/generator/generator_old.lua b/generator/generator_old.lua new file mode 100644 index 0000000..1e2da1a --- /dev/null +++ b/generator/generator_old.lua @@ -0,0 +1,1682 @@ +-------------------------------------------------------------------------- +--script for auto_funcs.h and auto_funcs.cpp generation +--expects LuaJIT +-------------------------------------------------------------------------- +assert(_VERSION=='Lua 5.1',"Must use LuaJIT") +assert(bit,"Must use LuaJIT") +local script_args = {...} +local COMPILER = script_args[1] +local CPRE,CTEST +if COMPILER == "gcc" or COMPILER == "clang" then + CPRE = COMPILER..[[ -E -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ]] + CTEST = COMPILER.." --version" +elseif COMPILER == "cl" then + CPRE = COMPILER..[[ /E /DIMGUI_DISABLE_OBSOLETE_FUNCTIONS /DIMGUI_API="" /DIMGUI_IMPL_API="" ]] + CTEST = COMPILER +else + print("Working without compiler ") +end +--test compiler present +local HAVE_COMPILER = false +if CTEST then + local pipe,err = io.popen(CTEST,"r") + if pipe then + local str = pipe:read"*a" + print(str) + pipe:close() + if str=="" then + HAVE_COMPILER = false + else + HAVE_COMPILER = true + end + else + HAVE_COMPILER = false + print(err) + end + assert(HAVE_COMPILER,"gcc, clang or cl needed to run script") +end --CTEST + +print("HAVE_COMPILER",HAVE_COMPILER) +--get implementations +local implementations = {} +for i=2,#script_args do table.insert(implementations,script_args[i]) end + +-------------------------------------------------------------------------- +--this table has the functions to be skipped in generation +-------------------------------------------------------------------------- +local cimgui_manuals = { + igLogText = true, + ImGuiTextBuffer_appendf = true, + igColorConvertRGBtoHSV = true, + igColorConvertHSVtoRGB = true +} +-------------------------------------------------------------------------- +--this table is a dictionary to force a naming of function overloading (instead of algorythmic generated) +--first level is cimguiname without postfix, second level is the signature of the function, value is the +--desired name +--------------------------------------------------------------------------- +local cimgui_overloads = { + igPushID = { + --["(const char*)"] = "igPushIDStr", + ["(const char*,const char*)"] = "igPushIDRange", + --["(const void*)"] = "igPushIDPtr", + --["(int)"] = "igPushIDInt" + }, + igGetID = { + ["(const char*,const char*)"] = "igGetIDRange", + }, + ImDrawList_AddText = { + ["(const ImVec2,ImU32,const char*,const char*)"] = "ImDrawList_AddText", + }, + igGetColorU32 = { + ["(ImGuiCol,float)"] = "igGetColorU32", + }, + igCollapsingHeader = { + ["(const char*,ImGuiTreeNodeFlags)"] = "igCollapsingHeader", + }, + igCombo = { + ["(const char*,int*,const char* const[],int,int)"] = "igCombo", + }, + igPlotLines = { + ["(const char*,const float*,int,int,const char*,float,float,ImVec2,int)"] = "igPlotLines", + }, + igBeginChild = { + ["(const char*,const ImVec2,bool,ImGuiWindowFlags)"] = "igBeginChild", + }, + igSelectable = { + ["(const char*,bool,ImGuiSelectableFlags,const ImVec2)"] = "igSelectable" + }, + igPushStyleColor = { + ["(ImGuiCol,const ImVec4)"] = "igPushStyleColor" + } +} + +--------------------------header definitions +local cimgui_header = +[[//This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui +//based on imgui.h file version XXX from Dear ImGui https://github.com/ocornut/imgui +]] +local gdefines = {} --for FLT_MAX and others +-------------------------------------------------------------------------- +--helper functions +-------------------------------------------------------------------------- + +local function split_comment(line) + local comment = line:match("(%s*//.*)") or "" + line = line:gsub("%s*//.*","") + line = line:gsub("%s*$","") + return line,comment +end +--minimal preprocessor +local function filelines(file,locats) + local iflevels = {} + --generated known prepros +local prepro = { +["#if"]={ + [ "defined(__clang__) || defined(__GNUC__)" ]=false, + [ "defined(__clang__)" ]=false, + [ "defined(_MSC_VER) && !defined(__clang__)" ]=false, + [ "!defined(IMGUI_DISABLE_INCLUDE_IMCONFIG_H) || defined(IMGUI_INCLUDE_IMCONFIG_H)" ]=false, + [ "!defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \\" ]=false, +}, +["#elif"]={ + [ "defined(__GNUC__) && __GNUC__ >= 8" ]=false, + [ "(defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)" ]=false, +}, +["#ifdef"]={ + [ "IM_VEC4_CLASS_EXTRA" ]=false, + [ "IMGUI_USER_CONFIG" ]=false, + [ "IMGUI_INCLUDE_IMGUI_USER_H" ]=false, + [ "IMGUI_USE_BGRA_PACKED_COLOR" ]=false, + [ "IM_VEC2_CLASS_EXTRA" ]=false, +}, +["#ifndef"]={ + [ "IMGUI_API" ]=false, + [ "IMGUI_IMPL_API" ]=false, + [ "IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT" ]=true, + [ "IM_ASSERT" ]=false, + [ "ImTextureID" ]=true, + [ "ImDrawIdx" ]=true, + [ "IMGUI_DISABLE_OBSOLETE_FUNCTIONS" ]=false, +}, +} + + local function prepro_boolif(pre,cond) + local conds = prepro[pre] + assert(conds,pre.." has no conds-----------------------------") + local res = conds[cond] + --assert(type(res)~="nil",cond.." not found") + if type(res)=="nil" then + print(pre,cond,"not found in precompiler database, returning false.") + res = false + end + return res + end + local function location_it() + repeat + local line = file:read"*l" + if not line then return nil end + --if line:sub(1,1) == "#" then + if line:match("^%s*#") then + line,_ = split_comment(line) + local pre,cond = line:match("^%s*(#%S*)%s+(.*)%s*$") + if line:match("#if") then + iflevels[#iflevels +1 ] = prepro_boolif(pre,cond) + elseif line:match("#endif") then + iflevels[#iflevels] = nil + elseif line:match("#elif") then + if not iflevels[#iflevels] then + iflevels[#iflevels] = prepro_boolif(pre,cond) + else --was true + iflevels[#iflevels] = false + end + elseif line:match("#else") then + iflevels[#iflevels] = not iflevels[#iflevels] + else + if not (pre:match("#define") or pre:match"#include" or pre:match"#pragma") then + print("not expected preprocessor directive ",pre) + end + end + -- skip + elseif #iflevels == 0 or iflevels[#iflevels] then + -- drop IMGUI_APIX + line = line:gsub("IMGUI_IMPL_API","") + -- drop IMGUI_API + line = line:gsub("IMGUI_API","") + return line,locats[1] + end + until false + end + return location_it +end +--iterates lines from a gcc/clang -E in a specific location +local function location(file,locpathT) + local location_re + if COMPILER == "cl" then + location_re = '^#line (%d+) "([^"]*)"' + else --gcc, clang + location_re = '^# (%d+) "([^"]*)"' + end + local path_reT = {} + for i,locpath in ipairs(locpathT) do + table.insert(path_reT,'^(.*[\\/])('..locpath..')%.h$') + end + local in_location = false + local which_location = "" + local loc_num + local loc_num_incr + local lineold = "" + local which_locationold,loc_num_realold + local lastdumped = false + local function location_it() + repeat + local line = file:read"*l" + if not line then + if not lastdumped then + lastdumped = true + return lineold, which_locationold,loc_num_realold + else + return nil + end + end + if #line==0 then --nothing on emptyline + elseif not line:match("%S") then --nothing if only spaces + elseif line:sub(1,1) == "#" then + -- Is this a location pragma? + local loc_num_t,location_match = line:match(location_re) + if location_match then + in_location = false + for i,path_re in ipairs(path_reT) do + if location_match:match(path_re) then + in_location = true; + loc_num = loc_num_t + loc_num_incr = 0 + which_location = locpathT[i] + break + end + end + end + elseif in_location then + local loc_num_real = loc_num + loc_num_incr + loc_num_incr = loc_num_incr + 1 + if loc_num_realold and loc_num_realold < loc_num_real then + --old line complete + local lineR,which_locationR,loc_num_realR = lineold, which_locationold,loc_num_realold + lineold, which_locationold,loc_num_realold = line,which_location,loc_num_real + return lineR,which_locationR,loc_num_realR + else + lineold=lineold..line + which_locationold,loc_num_realold = which_location,loc_num_real + --return line,loc_num_real, which_location + end + end + until false --forever + end + return location_it +end +local function copyfile(src,dst,blocksize) + blocksize = blocksize or 1024*4 + print( "copyfile", src, dst) + local srcf, err = io.open(src,"rb") + if not srcf then error(err) end + local dstf, err = io.open(dst,"wb") + if not dstf then error(err) end + while true do + local data = srcf:read(blocksize) + if not data then break end + dstf:write(data) + end + srcf:close() + dstf:close() +end +------serializeTable("anyname",table) gives a string that recreates the table with dofile(generated_string) +local function serializeTable(name, value, saved) + + local function basicSerialize (o) + if type(o) == "number" or type(o)=="boolean" then + return tostring(o) + elseif type(o) == "string" then + return string.format("%q", o) + else + return "nil" + end + end + + local string_table = {} + if not saved then + table.insert(string_table, "local "..name.." = ") + else + table.insert(string_table, name.." = ") + end + + saved = saved or {} -- initial value + + if type(value) == "number" or type(value) == "string" or type(value)=="boolean" then + table.insert(string_table,basicSerialize(value).."\n") + elseif type(value) == "table" then + if saved[value] then -- value already saved? + table.insert(string_table,saved[value].."\n") + else + saved[value] = name -- save name for next time + table.insert(string_table, "{}\n") +---[[ + local ordered_keys = {} + for k,v in pairs(value) do + table.insert(ordered_keys,k) + end + local function sorter(a,b) + if type(a)==type(b) then + return a") + if template then + local te = template:gsub("%s","_") + te = te:gsub("%*","Ptr") + ImVector_templates[template] = true + linea = linea:gsub("(%b<>)","_"..te) --comment template parameters + end + --linea = linea:gsub("(%b<>)","/*%1*/") --comment template parameters + --linea = linea:gsub("<([%w_]+)>","_%1") --ImVector expand templates + table.insert(structcdefs,linea..comment) + end + return + end + return STP +end + +local function typetoStr(typ) + --typ = typ:gsub("[^%(%)]+%(%*?(.+)%).+","%1") -- funcs + typ = typ:gsub("[^%(%)]+%(%*?(.+)%).+","FnPtr") + typ = typ:gsub("[%w_]+%[(%d*)%]","arr%1") + typ = typ:gsub("%*","Ptr") + typ = typ:gsub("void","") + typ = typ:gsub("unsigned%s","u") + typ = typ:gsub("const%s","")--"c") + typ = typ:gsub("%s+","_") + typ = typ:gsub("charPtr","Str") + typ = typ:gsub("int","Int") + typ = typ:gsub("bool","Bool") + typ = typ:gsub("float","Float") + typ = typ:gsub("uInt","Uint") + typ = typ:gsub("ImGui","") + typ = typ:gsub("Im","") + typ = typ:gsub("[<>]","") + return typ +end +local function name_overloadsAlgo(v) + local aa = {} + local bb = {} + local done = {} + local maxnum = 0 + for i,t in ipairs(v) do + bb[i] = "" + local signature = t.signature:sub(2,-2) -- without parenthesis + aa[i] = {} + local num = 1 + --for typec in t.signature:gmatch(".-([^,%(%s]+)[,%)]") do + --for typec in t.signature:gmatch(".-([^,%(]+)[,%)]") do + --for typec in signature:gmatch(".-([^,]+),?") do + for typec in signature:gsub("(%(.-%))", function(x) return x:gsub(",","\0") end):gmatch(".-([^,]+),?") do + --typec = typec:gsub + aa[i][num] = typec:gsub("%z+", ",") + num = num + 1 + end + num = num - 1 + maxnum = (num > maxnum) and num or maxnum + end + + for l=1,maxnum do + local keys = {} + local diferent = true + local equal = true + for i=1,#v do + aa[i][l] = aa[i][l] or "nil" + keys[aa[i][l]] = 1 + (aa[i][l] and keys[aa[i][l]] or 0) + if not done[i] then + for j=i+1,#v do + if not done[j] then + if aa[i][l] == aa[j][l] then + diferent = false + else + equal = false + end + end + end + end + end + if not equal then -- not all the same + for i=1,#v do + if not done[i] then + bb[i] = bb[i]..(aa[i][l]=="nil" and "" or aa[i][l]) + if keys[aa[i][l]] == 1 then + done[i] = true + end + end + end + end + end + return aa,bb +end + +local function func_parser() + local function_closing_re = "}" + --local function_re = "(%a*%w+%b())" --"(%a*%w+%s+%w+%b())" + local function_re = "(%a*[%w%[%]]+%s*%b())" + local function_closed_re = "[;}]$" + local namespace_re = "namespace ([^%s]+)" + local namespace_closing_re = "^}" + local struct_re = "^struct%s+([^%s;]+)$" + local struct_closing_re = "};" + local struct_op_close_re = "%b{}" + local functype_re = "^%s*[%w%s]+(%(%*)[%w_]+(%)%([^%(%)]*%))" + + local in_function = false + local line_in_function + local in_namespace = false + local cdefs = {} + local structnames = {} + local embeded_structs = {} + local stname = "" + local defsT = {} + local ImVector_templates = {} + + + local FP = {} + FP.cdefs = cdefs + FP.embeded_structs = embeded_structs + FP.defsT = defsT + FP.ImVector_templates = ImVector_templates + + function FP.insert(line,comment,locat) + local lineorig = line + if line:match"template" then return end + line = line:gsub("%S+",{class="struct",mutable="",inline=""}) --class -> struct + line = clean_spaces(line) + + if in_function then + if line:match(function_closing_re) then + in_function = false + end + return --discard + end + if line:match(function_re) and not line:match("typedef.*%b().*%b().*") then + if not line:match(function_closed_re) then + in_function = true + line_in_function = lineorig + end + end + if line:match(namespace_re) then + in_namespace = true + stname = line:match(namespace_re) + end + if in_namespace then + if line:match(namespace_closing_re) then + in_namespace = false + stname = "" + end + end + structnames[#structnames + 1] = line:match(struct_re) + if #structnames > 0 then + if line:match(struct_closing_re) and not line:match(struct_op_close_re) then + structnames[#structnames] = nil + end + stname = structnames[#structnames] or "" + if #structnames > 1 then + local embeded_name = table.concat(structnames,"::") + embeded_structs[stname] = embeded_name + end + end + local func = line:match(function_re) + if func and not in_function and not line:match("typedef.*%b().*%b().*") + and not line:match(functype_re) + then + --if line:match(functype_re) then print("ft",line) end + if stname~="ImVectorNO" + --and stname~="GlyphRangesBuilder" and stname~="CustomRect" and stname~="TextRange" and stname~="Pair" + and not line:match("operator") then + + --clean implemetation + line = line:gsub("%s*%b{}","") + --clean attribute + line = line:gsub("%s*__attribute__%b()","") + --clean static + line = line:gsub("static","") + + local ret = line:match("([^%(%)]+[%*%s])%s?~?[_%w]+%b()") + local funcname, args = line:match("(~?[_%w]+)(%b())") + + local argscsinpars = args:gsub("(=[^,%(%)]*)(%b())","%1") + argscsinpars = argscsinpars:gsub("(=[^,%(%)]*)([,%)])","%2") + -- if argscsinpars:match("&") then + -- for arg in argscsinpars:gmatch("[%(,]*([^,%(%)]+)[%),]") do + -- if arg:match("&") and not arg:match("const") then + -- print(funcname,argscsinpars) + -- end + -- end + -- end + --argscsinpars = argscsinpars:gsub("&","") + + local template = argscsinpars:match("ImVector<(.+)>") + if template then + --template = template:gsub("%s","_") + --template = template:gsub("%*","Ptr") + ImVector_templates[template] = true + end + + argscsinpars = argscsinpars:gsub("<([%w_]+)>","_%1") --ImVector + + local argsArr = {} + local functype_re = "^%s*[%w%s%*]+%(%*[%w_]+%)%([^%(%)]*%)" + local functype_reex = "^(%s*[%w%s%*]+)%(%*([%w_]+)%)(%([^%(%)]*%))" + local functype_arg_rest = "^(%s*[%w%s%*]+%(%*[%w_]+%)%([^%(%)]*%)),*(.*)" + local rest = argscsinpars:sub(2,-2) --strip () + + while true do + --local tt = strsplit(rest,",") + --for ii,arg in ipairs(tt) do + --for arg in argscsinpars:gmatch("[%(,]*([^,%(%)]+)[%),]") do + local type,name,retf,sigf + local arg,restt = rest:match(functype_arg_rest) + if arg then + local t1,namef,t2 = arg:match(functype_reex) + type=t1.."(*)"..t2;name=namef + retf = t1 + sigf = t2 + rest = restt + else + arg,restt = rest:match(",*([^,%(%)]+),*(.*)") + if not arg then break end + rest = restt + if arg:match("&") and arg:match("const") then + arg = arg:gsub("&","") + end + if arg:match("%.%.%.") then + type="...";name="..." + else + type,name = arg:match("(.+)%s([^%s]+)") + end + if not type or not name then + print("failure arg detection",funcname,type,name,argscsinpars,arg) + print(lineorig) + print(line_in_function) + else + --float name[2] to float[2] name + local siz = name:match("(%[%d*%])") + if siz then + type = type..siz + name = name:gsub("(%[%d*%])","") + end + end + end + table.insert(argsArr,{type=type,name=name,ret=retf,signature=sigf}) + if arg:match("&") and not arg:match("const") then + --only post error if not manual + local cname = getcimguiname(stname,funcname) + if not cimgui_manuals[cname] then + print("reference to no const arg in",funcname,argscsinpars) + end + end + end + argscsinpars = argscsinpars:gsub("&","") + + local signature = argscsinpars:gsub("([%w%s%*_]+)%s[%w_]+%s*([,%)])","%1%2") + signature = signature:gsub("%s*([,%)])","%1") --space before , and ) + signature = signature:gsub(",%s*",",")--space after , + signature = signature:gsub("([%w_]+)%s[%w_]+(%[%d*%])","%1%2") -- float[2] + signature = signature:gsub("(%(%*)[%w_]+(%)%([^%(%)]*%))","%1%2") --func defs + + local call_args = argscsinpars:gsub("([%w_]+%s[%w_]+)%[%d*%]","%1") --float[2] + call_args = call_args:gsub("%(%*([%w_]+)%)%([^%(%)]*%)"," %1") --func type + call_args = call_args:gsub("[^%(].-([%w_]+)%s*([,%)])","%1%2") + + if not ret then --must be constructors + if not (stname == funcname or "~"..stname==funcname) then --break end + print("false constructor:",line); + print("b2:",ret,stname,funcname,args) + return --are function defs + end + end + + local cimguiname = getcimguiname(stname,funcname) + table.insert(cdefs,{stname=stname,funcname=funcname,args=args,argsc=argscsinpars,signature=signature,cimguiname=cimguiname,call_args=call_args,ret =ret,comment=comment}) + + defsT[cimguiname] = defsT[cimguiname] or {} + table.insert(defsT[cimguiname],{}) + local defT = defsT[cimguiname][#defsT[cimguiname]] + defT.defaults = {} + --for k,def in args:gmatch("([%w%s%*_]+)=([%w_%(%)%s,%*]+)[,%)]") do + --for k,def in args:gmatch("([%w_]+)=([%w_%(%)%s,%*%.%-]+)[,%)]") do + for k,def in args:gmatch('([%w_]+)=([%w_%(%)%s,%*%.%-%+%%"]+)[,%)]') do + defT.defaults[k]=def + end + defT.cimguiname = cimguiname + defT.stname = stname + defT.funcname = funcname + defT.argsoriginal = args + defT.args=argscsinpars + defT.signature = signature + defT.call_args = call_args + defT.isvararg = signature:match("%.%.%.%)$") + defT.location = locat + defT.comment = comment + defT.argsT = argsArr + if get_manuals(defT) then + defT.manual = true + end + if ret then + defT.ret = clean_spaces(ret:gsub("&","*")) + defT.retref = ret:match("&") + -- if defT.ret=="ImVec2" or defT.ret=="ImVec4" or defT.ret=="ImColor" then + -- defT.ret = defT.ret.."_Simple" + -- end + end + defsT[cimguiname][signature] = defT + end + elseif line=="" and stname~="" then -- not funcdef must be comment + table.insert(cdefs,{stname=stname,comment=comment}) + end + end + FP.alltypes = {} + local function get_types(v) + for i,t in ipairs(v) do + local signature = t.signature:sub(2,-2) -- without parenthesis + for typec in signature:gsub("(%(.-%))", function(x) return x:gsub(",","\0") end):gmatch(".-([^,]+),?") do + local key = typec:gsub("%z+", ",") + FP.alltypes[key] = true + end + end + end + function FP:dump_alltypes() + for k,v in pairs(self.alltypes) do print(k, typetoStr(k) ) end + end + function FP:compute_overloads() + local strt = {} + local numoverloaded = 0 + FP.alltypes = {} + table.insert(strt,"----------------overloadings---------------------------") + --require"anima.utils" + for k,v in pairs(FP.defsT) do + get_types(v) + if #v > 1 then + numoverloaded = numoverloaded + #v + --print(k,#v) + table.insert(strt,string.format("%s\t%d",k,#v)) + local typesc,post = name_overloadsAlgo(v) + for i,t in ipairs(v) do + --take overloaded name from manual table or algorythm + t.ov_cimguiname = getcimguiname_overload(t.stname,t.funcname,t.signature) or k..typetoStr(post[i]) + --print(i,t.signature,t.ret,t.ov_cimguiname)--,post[i])--,typetoStr(post[i])) + table.insert(strt,string.format("%d\t%s\t%s %s",i,t.ret,t.ov_cimguiname,t.signature)) + --prtable(typesc[i]) + end + --check not two names are equal (produced by bad cimguiname_overload) + for i=1,#v-1 do + for j=i+1,#v-1 do + if v[i].ov_cimguiname == v[j].ov_cimguiname then + local t,tj = v[i],v[j] + print("Error caused by Bad overloading "..t.ov_cimguiname.." of function ",t.funcname,t.signature,"conflicts with ",tj.funcname,tj.signature) + error("Bad overloading:"..t.ov_cimguiname) + end + end + end + end + end + --print(numoverloaded, "overloaded") + table.insert(strt,string.format("%d overloaded",numoverloaded)) + return table.concat(strt,"\n") + end + return FP +end +local function ADDdestructors(FP) + local defsT = FP.defsT + local newcdefs = {} + --TODO add constructor = true + for numcdef,t in ipairs(FP.cdefs) do + newcdefs[#newcdefs+1] = t + if t.cimguiname then + local defT = defsT[t.cimguiname] + --local defT = cimf[t.signature] + --for fname,defT in pairs(FP.defsT) do + if not defT[1].ret and not defT[1].constructor then --if constructor not processed + if defT[1].funcname:match("~") then + defsT[t.cimguiname] = nil --clear destructor + newcdefs[#newcdefs] = nil + else + for j,cons in ipairs(defT) do + cons.constructor = true + end + assert(defT[1].stname==defT[1].funcname) + local def = {} + def.stname = defT[1].stname + def.ret = "void" + def.ov_cimguiname = def.stname.."_destroy" + def.cimguiname = def.ov_cimguiname + def.destructor = true + def.args = "("..def.stname.."* self)" + def.call_args = "(self)" + def.signature = "("..def.stname.."*)" + def.defaults = {} + def.argsT = {{type=def.stname.."*",name="self"}} + defsT[def.ov_cimguiname] = {def} + defsT[def.ov_cimguiname][def.signature] = def + newcdefs[#newcdefs+1]={stname=def.stname,funcname=def.ov_cimguiname,args=def.args,signature=def.signature,cimguiname=def.cimguiname,call_args=def.call_args,ret =def.ret} + end + end + end + end + FP.cdefs = newcdefs +end +local function ADDnonUDT(FP) + --for cimguiname,defs in pairs(defsT) do + --for i,defT in ipairs(defs) do + local defsT = FP.defsT + local newcdefs = {} + for numcdef,t in ipairs(FP.cdefs) do + if t.cimguiname then + local cimf = defsT[t.cimguiname] + local defT = cimf[t.signature] + --if UDT return generate nonUDT version + if defT.ret=="ImVec2" or defT.ret=="ImVec4" or defT.ret=="ImColor" then + --passing as a pointer arg + local defT2 = {} + --first strings + for k,v in pairs(defT) do + defT2[k] = v + end + --then argsT table + defT2.argsT = {{type=defT.ret.."*",name="pOut"}} + for k,v in ipairs(defT.argsT) do + table.insert(defT2.argsT,{type=v.type,name=v.name}) + end + local comma = (#defT.argsT > 0) and "," or "" + defT2.args = "("..defT.ret.." *pOut"..comma..defT.args:sub(2) + defT2.ret = "void" + defT2.ov_cimguiname = (defT2.ov_cimguiname or defT2.cimguiname).."_nonUDT" + defT2.nonUDT = 1 + defT2.retref = nil + defsT[t.cimguiname][#defsT[t.cimguiname] + 1] = defT2 + defsT[t.cimguiname][t.signature.."nonUDT"] = defT2 + table.insert(newcdefs,{stname=t.stname,funcname=t.funcname,args=args,argsc=argscsinpars,signature=t.signature.."nonUDT",cimguiname=t.cimguiname,call_args=call_args,ret =t.ret,comment=comment}) + --converting to Simple type---------------------------------------------------- + local defT3 = {} + --first strings + for k,v in pairs(defT) do + defT3[k] = v + end + --then argsT table + defT3.argsT = {} + for k,v in ipairs(defT.argsT) do + table.insert(defT3.argsT,{type=v.type,name=v.name}) + end + local comma = (#defT.argsT > 0) and "," or "" + --defT3.args = "("..defT.ret.." *pOut"..comma..defT.args:sub(2) + defT3.ret = defT.ret.."_Simple" + defT3.retorig = defT.ret + defT3.ov_cimguiname = (defT3.ov_cimguiname or defT3.cimguiname).."_nonUDT2" + defT3.nonUDT = 2 + defT3.retref = nil + defsT[t.cimguiname][#defsT[t.cimguiname] + 1] = defT3 + defsT[t.cimguiname][t.signature.."nonUDT2"] = defT3 + table.insert(newcdefs,{stname=t.stname,funcname=t.funcname,args=args,argsc=argscsinpars,signature=t.signature.."nonUDT2",cimguiname=t.cimguiname,call_args=call_args,ret =t.ret,comment=comment}) + end + end + end + for i,v in ipairs(newcdefs) do + table.insert(FP.cdefs,v) + end +end + +local function gen_structs_and_enums_table(cdefs) + local function_closing_re = "}" + local namespace_re = "namespace" + local in_namespace = false + local struct_re = "^%s*struct%s+([^%s;]+)$" + local in_struct = false + local struct_closed_re = "^%s*struct%s+([^%s]+);$" + local struct_closing_re = "};" + local struct_op_close_re = "%b{}" + local structnames = {} + local enumnames = {} + local enums_re = "^%s*enum%s+([^%s;]+)" + local outtab = {structs={},enums={}} + local typedefs_dict = {} + + for i,line in ipairs(cdefs) do + repeat -- simulating continue with break + -- separate comments from code + local linecom = line + local line, comment = split_comment(line) + line = clean_spaces(line) + --typedefs dictionary + if line:match("typedef") then + local value,key = line:match("typedef%s+(.+)%s+([%w_]+);") + if key and value then + typedefs_dict[key] = value + else --try function typedef + local key = line:match("%(%*([%w_]+)%)%([^%(%)]*%)") + if key then + local linet = line + linet = linet:gsub("typedef ","") + linet = linet:gsub("%(%*("..key..")%)","(*)") + typedefs_dict[key] = linet + else + print(key,value,line) + end + end + end + if line:match(namespace_re) then + in_namespace = true + end + + local structbegin = line:match(struct_re) + if structbegin then + structnames[#structnames + 1] = structbegin + outtab.structs[structbegin] = outtab.structs[structbegin] or {} + break + end + + local enumname = line:match(enums_re) + if enumname then + enumnames[#enumnames + 1] = enumname + outtab.enums[enumname] = outtab.enums[enumname] or {} + break + end + + if in_namespace then + if line:match(function_closing_re) then + in_namespace = false + end + break -- dont write anything inside + end + + if (#enumnames > 0) then + assert(#structnames==0,"enum in struct") + -- if #structnames~=0 then + -- print(line,#line) + -- print(linecom,#linecom) + -- error"enuminstruct" + -- end + if line:match(struct_closing_re) and not line:match(struct_op_close_re) then + enumnames[#enumnames] = nil + break + end + if line=="" or line:match("^{") then + break + else + local name,value = line:match("%s*([%w_]+)%s*=%s*([^,]+)") + if value then + table.insert(outtab.enums[enumnames[#enumnames]],{name=name,value=value}) + else --increment by one + local name = line:match("%s*([^,]+)") + local enum_table = outtab.enums[enumnames[#enumnames]] + local value = enum_table[#enum_table] and (enum_table[#enum_table].value + 1) or 0 + table.insert(outtab.enums[enumnames[#enumnames]],{name=name,value=value}) + end + end + end + + if (#structnames > 0) then + if line:match(struct_closing_re) and not line:match(struct_op_close_re) then + structnames[#structnames] = nil + break + end + if line=="" or line:match("^{") then + break + elseif structnames[#structnames] ~="ImVectorNO" then --avoid ImVector + --local functype_re = "^%s*[%w%s%*]+(%(%*)[%w_]+(%)%([^%(%)]*%))" + local functype_re = "^%s*[%w%s%*]+%(%*[%w_]+%)%([^%(%)]*%)" + local functype_reex = "^(%s*[%w%s%*]+%(%*)([%w_]+)(%)%([^%(%)]*%))" + if line:match(functype_re) then + local t1,name,t2 = line:match(functype_reex) + table.insert(outtab.structs[structnames[#structnames]],{type=t1..t2,name=name}) + break + end + --split type name1,name2; in several lines + local typen,rest = line:match("([^,]+)%s(%S+[,;])") + if not typen then -- Lets try Type*name + typen,rest = line:match("([^,]+%*)(%S+[,;])") + end + --local template_type = typen:match("/%*<(.+)>%*/") + --if template_type then typen = typen:match("(.+)/%*") end + local template_type = typen:match("ImVector_(.+)") + if template_type then + --typen = "ImVector" + template_type = template_type:gsub("_"," ") + template_type = template_type:gsub("Ptr","%*") + end + for name in rest:gmatch("([^%s,;]+)%s?[,;]") do + table.insert(outtab.structs[structnames[#structnames]],{type=typen,template_type=template_type,name=name}) + end + end + end + until true + end + --calcule size of name[16+1] [xxx_COUNT] + local allenums = {} + --first calc_value in enums + for enumname,enum in pairs(outtab.enums) do + for i,t in ipairs(enum) do + local val = tonumber(t.value) + if val then + t.calc_value = val + elseif t.value:match"<<" then + local v1,v2 = t.value:match("(%d+)%s*<<%s*(%d+)") + t.calc_value = bit.lshift(v1,v2) + elseif t.value:match"|" then --or several enums + local ens = t.value + ens = strsplit(ens,"|") + for i,v in ipairs(ens) do ens[i] = allenums[clean_spaces(v)] end + t.calc_value = bit.bor(unpack(ens)) + elseif allenums[t.value] then + t.calc_value = allenums[t.value] + else + print("Error unknown value in enums",t.value) + end + assert(t.calc_value) + allenums[t.name] = t.calc_value + end + end + --then calcsize in struct members + for stname,struct in pairs(outtab.structs) do + for i,t in ipairs(struct) do + local val = t.name:match"%[([^%[%]]+)%]" + if val then + if tonumber(val) then + t.size = tonumber(val) + elseif allenums[val] then + t.size = allenums[val] + elseif val:match"%+" then + local s1,s2 = val:match("(%d+)%s*%+%s*(%d+)") + t.size = s1+s2 + else + print("Error size is",val) + end + assert(t.size) + end + end + end + return outtab, typedefs_dict +end + +local function generate_templates(code,templates) + for k,v in pairs(templates) do + local te = k:gsub("%s","_") + te = te:gsub("%*","Ptr") + table.insert(code,"typedef struct ImVector_"..te.." {int Size;int Capacity;"..k.."* Data;} ImVector_"..te..";\n") + end +end + +local function gen_structs_and_enums(cdefs,templates) + local function_closing_re = "}" + local namespace_re = "namespace" + local in_namespace = false + local struct_re = "^%s*struct%s+([^%s;]+)$" + local struct_closed_re = "^%s*struct%s+([^%s]+);$" + local struct_closing_re = "};" + local struct_op_close_re = "%b{}" + local structnames = {} + local innerstructs = {} + local typedefs_table = {} + local typedefs_dict = {} + local outtab = {} + -- Output the file + --table.insert(outtab,"/////////////// BEGIN AUTOGENERATED SEGMENT\n") + + for i,line in ipairs(cdefs) do + repeat -- simulating continue with break + -- separate comments from code and try to add them with same tab + local line, comment = split_comment(line) + local linelen = #line + local desired_linelen = (linelen==0) and 0 or math.max(math.ceil(linelen/10)*10,40) + local spaces_to_add = 0 --desired_linelen - linelen + local linecom = line..string.rep(" ",spaces_to_add)..comment + + -- ImNewDummy drop for MSVC + if line:match"ImNewDummy" then break end + + if line:match(namespace_re) then + in_namespace = true + end + local structbegin = line:match(struct_re) + if structbegin then + structnames[#structnames + 1] = structbegin + if #structnames < 2 and structbegin~= "ImVectorNO" then --not inner and not ImVector + table.insert(outtab,linecom.."\n") + break + end + end + + -- ImVector special treatment + if structnames[#structnames] == "ImVector" then + if line:match(struct_closing_re) then + table.insert(outtab,[[typedef struct ImVector{int Size;int Capacity;void* Data;} ImVector;]].."\n") + generate_templates(outtab,templates) + structnames[#structnames] = nil + end + break -- dont write + end + + if in_namespace then + if line:match(function_closing_re) then + in_namespace = false + end + break -- dont write anything inside + end + + if #structnames < 2 then -- not inner + if line:match("typedef") and line:match("ImDrawIdx") then --save typedefs of ImDrawIdx + table.insert(typedefs_table,line..";\n") + break + end + if (#structnames > 0) then + if line:match("typedef") then --dont allow inner typedefs + break --already saved + elseif not line:match("^{$") and not line:match(struct_closing_re) then --avoid tab { and }; + --line = " "..line + end + end + table.insert(outtab,linecom.."\n") + local struct_closed_name = line:match(struct_closed_re) + if struct_closed_name then + table.insert(typedefs_table,"typedef struct "..struct_closed_name.." "..struct_closed_name..";\n") + typedefs_dict[struct_closed_name] = "struct "..struct_closed_name + end + end + + if #structnames > 0 then + if #structnames > 1 then --inner structs + innerstructs[structnames[#structnames]] = innerstructs[structnames[#structnames]] or {} + local st = innerstructs[structnames[#structnames]] + -- if not line:match("struct") and not line:match("^{$") and not line:match(struct_closing_re) then --avoid tab in struct { and }; + --line = " "..line + -- end + st[#st + 1] = line + if line:match(struct_closing_re) and not line:match(struct_op_close_re) then + local structname = structnames[#structnames] + --st[#st + 1] = string.format("typedef struct %s %s;\n",structname,structname) + table.insert(typedefs_table,string.format("typedef struct %s %s;\n",structname,structname)) + typedefs_dict[structname] = "struct "..structname + structnames[#structnames] = nil + end + elseif line:match(struct_closing_re) and not line:match(struct_op_close_re) then + local structname = structnames[#structnames] + --table.insert(outtab,"typedef struct "..structname.." "..structname..";\n") + table.insert(typedefs_table,"typedef struct "..structname.." "..structname..";\n") + typedefs_dict[structname] = "struct "..structname + structnames[#structnames] = nil + end + end + + + until true + end + for k,v in pairs(innerstructs) do + for i,line in ipairs(v) do + table.insert(outtab,line.."\n") + end + end + + --table.insert(outtab,"//////////////// END AUTOGENERATED SEGMENT \n") + local uniques = {} + for i,l in ipairs(typedefs_table) do + if not uniques[l] then + uniques[l] = true + table.insert(outtab,1,l) + end + end + --if templates then generate_templates(outtab,templates) end + local cstructsstr = table.concat(outtab) + cstructsstr = cstructsstr:gsub("\n+","\n") --several empty lines to one empty line + return cstructsstr, typedefs_dict +end + +local function func_header_impl_generate(FP) + + local outtab = {} + + for _,t in ipairs(FP.cdefs) do + if t.cimguiname then + local cimf = FP.defsT[t.cimguiname] + local def = cimf[t.signature] + if def.ret then --not constructor + local addcoment = def.comment or "" + if def.stname == "" then --ImGui namespace or top level + table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args..";"..addcoment.."\n") + else + error("class function in implementations") + end + end + else --not cimguiname + table.insert(outtab,t.comment:gsub("%%","%%%%").."\n")-- %% substitution for gsub + end + end + local cfuncsstr = table.concat(outtab) + cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line + return cfuncsstr +end +local function func_header_generate(FP) + + local outtab = {} + table.insert(outtab,"#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") + for k,v in pairs(FP.embeded_structs) do + --print(k,v) + table.insert(outtab,"typedef "..v.." "..k..";\n") + end + for k,v in pairs(FP.ImVector_templates) do + table.insert(outtab,"typedef ImVector<"..k.."> ImVector_"..k..";\n") + end + -- table.insert(outtab,"#else //CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") + -- for k,v in pairs(FP.ImVector_templates) do + -- table.insert(outtab,"typedef ImVector ImVector_"..k..";\n") + -- end + table.insert(outtab,"#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n") + for _,t in ipairs(FP.cdefs) do + if t.cimguiname then + local cimf = FP.defsT[t.cimguiname] + local def = cimf[t.signature] + assert(def,t.signature..t.cimguiname) + local manual = get_manuals(def) + if not manual then + local addcoment = def.comment or "" + local empty = def.args:match("^%(%)") --no args + if def.constructor then + assert(def.stname ~= "ImGui" and def.stname ~= "","constructor without struct") + table.insert(outtab,"CIMGUI_API "..def.stname.."* "..(def.ov_cimguiname or def.cimguiname)..(empty and "(void)" or def.args)..";"..addcoment.."\n") + elseif def.destructor then + table.insert(outtab,"CIMGUI_API void "..def.ov_cimguiname..def.args..";"..addcoment.."\n") + else --not constructor + if def.stname == "ImGui" or def.stname == "" then --ImGui namespace or top level + table.insert(outtab,"CIMGUI_API "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..(empty and "(void)" or def.args)..";"..addcoment.."\n") + else + --local imgui_stname = embeded_structs[def.stname] or def.stname + local imgui_stname = def.stname + --local args = def.args:gsub("^%(","("..imgui_stname.."* self"..(empty and "" or ",")) + table.insert(outtab,"CIMGUI_API "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args..";"..addcoment.."\n") + end + end + end + else --not cimguiname + table.insert(outtab,t.comment:gsub("%%","%%%%").."\n")-- %% substitution for gsub + end + end + + local cfuncsstr = table.concat(outtab) + cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line + return cfuncsstr +end +local function ImGui_f_implementation(outtab,def) + local ptret = def.retref and "&" or "" + table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args.."\n") + table.insert(outtab,"{\n") + if def.isvararg then + local call_args = def.call_args:gsub("%.%.%.","args") + table.insert(outtab," va_list args;\n") + table.insert(outtab," va_start(args, fmt);\n") + if def.ret~="void" then + table.insert(outtab," "..def.ret.." ret = ImGui::"..def.funcname.."V"..call_args..";\n") + else + table.insert(outtab," ImGui::"..def.funcname.."V"..call_args..";\n") + end + table.insert(outtab," va_end(args);\n") + if def.ret~="void" then + table.insert(outtab," return ret;\n") + end + elseif def.nonUDT then + if def.nonUDT == 1 then + table.insert(outtab," *pOut = ImGui::"..def.funcname..def.call_args..";\n") + else --nonUDT==2 + table.insert(outtab," "..def.retorig.." ret = ImGui::"..def.funcname..def.call_args..";\n") + table.insert(outtab," "..def.ret.." ret2 = "..def.retorig.."ToSimple(ret);\n") + table.insert(outtab," return ret2;\n") + end + else --standard ImGui + table.insert(outtab," return "..ptret.."ImGui::"..def.funcname..def.call_args..";\n") + end + table.insert(outtab,"}\n") +end +local function struct_f_implementation(outtab,def) + local empty = def.args:match("^%(%)") --no args + local ptret = def.retref and "&" or "" + --local imgui_stname = embeded_structs[def.stname] or def.stname + local imgui_stname = def.stname + --local args = def.args:gsub("^%(","("..imgui_stname.."* self"..(empty and "" or ",")) + table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args.."\n") + table.insert(outtab,"{\n") + if def.isvararg then + local call_args = def.call_args:gsub("%.%.%.","args") + table.insert(outtab," va_list args;\n") + table.insert(outtab," va_start(args, fmt);\n") + if def.ret~="void" then + table.insert(outtab," "..def.ret.." ret = self->"..def.funcname.."V"..call_args..";\n") + else + table.insert(outtab," self->"..def.funcname.."V"..call_args..";\n") + end + table.insert(outtab," va_end(args);\n") + if def.ret~="void" then + table.insert(outtab," return ret;\n") + end + elseif def.nonUDT then + if def.nonUDT == 1 then + table.insert(outtab," *pOut = self->"..def.funcname..def.call_args..";\n") + else --nonUDT==2 + table.insert(outtab," "..def.retorig.." ret = self->"..def.funcname..def.call_args..";\n") + table.insert(outtab," "..def.ret.." ret2 = "..def.retorig.."ToSimple(ret);\n") + table.insert(outtab," return ret2;\n") + end + else --standard struct + table.insert(outtab," return "..ptret.."self->"..def.funcname..def.call_args..";\n") + end + table.insert(outtab,"}\n") +end +local function func_implementation(FP) + + local outtab = {} + for _,t in ipairs(FP.cdefs) do + repeat -- continue simulation + if not t.cimguiname then break end + local cimf = FP.defsT[t.cimguiname] + local def = cimf[t.signature] + assert(def) + local manual = get_manuals(def) + if not manual then + if def.constructor then + assert(def.stname ~= "ImGui" and def.stname ~= "","constructor without struct") + local empty = def.args:match("^%(%)") --no args + table.insert(outtab,"CIMGUI_API "..def.stname.."* "..(def.ov_cimguiname or def.cimguiname)..(empty and "(void)" or def.args).."\n") + table.insert(outtab,"{\n") + table.insert(outtab," return IM_NEW("..def.stname..")"..def.call_args..";\n") + table.insert(outtab,"}\n") + elseif def.destructor then + local args = "("..def.stname.."* self)" + local fname = def.stname.."_destroy" + table.insert(outtab,"CIMGUI_API void "..fname..args.."\n") + table.insert(outtab,"{\n") + table.insert(outtab," IM_DELETE(self);\n") + table.insert(outtab,"}\n") + elseif def.stname == "ImGui" then + ImGui_f_implementation(outtab,def) + else -- stname + struct_f_implementation(outtab,def) + end + end + until true + end + return table.concat(outtab) +end +--only basic ending +local c_types = { + ["char"]=true, + ["int"]=true, + ["float"]=true, + ["double"]=true, + ["short"]=true, + ["long"]=true, + ["signed"]=true, + ["unsigned"]=true, + ["size_t"]=true, + ["ptrdiff_t"]=true, +} +local function check_arg_detection(fdefs,typedefs) + print"-----------------check arg detection---------------------------" + for k,defT in pairs(fdefs) do + for i,def in ipairs(defT) do + for j,arg in ipairs(def.argsT) do + --check name is not type, which happens in declaration without name + if arg.name=="*" or not arg.type or not arg.name or c_types[arg.name] or typedefs[arg.name] then + print("bad argument name",arg.name, "in",def.funcname,def.args) + end + end + end + end + print"-----------------end check arg detection-----------------------" +end +local function get_defines(t) + if COMPILER == "cl" then print"can't get defines with cl compiler"; return {} end + local pipe,err = io.popen(COMPILER..[[ -E -dM -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ../imgui/imgui.h]],"r") + local defines = {} + while true do + local line = pipe:read"*l" + if not line then break end + local key,value = line:match([[#define%s+(%S+)%s+(.+)]]) + if not key or not value then + --print(line) + else + defines[key]=value + end + end + pipe:close() + --require"anima.utils" + --prtable(defines) + --FLT_MAX + local ret = {} + for i,v in ipairs(t) do + local aa = defines[v] + while true do + local tmp = defines[aa] + if not tmp then + break + else + aa = tmp + end + end + ret[v] = aa + end + return ret +end +--subtitution of FLT_MAX value for FLT_MAX +local function set_defines(fdefs) + for k,defT in pairs(fdefs) do + for i,def in ipairs(defT) do + for name,default in pairs(def.defaults) do + if default == gdefines.FLT_MAX then + def.defaults[name] = "FLT_MAX" + end + end + end + end +end +local function DefsByStruct(FP) + local structs = {} + for fun,defs in pairs(FP.defsT) do + local stname = defs[1].stname + structs[stname] = structs[stname] or {} + table.insert(structs[stname],defs)--fun) + end + -- for st,funs in pairs(struct) do + -- struct[st] = table.sort(funs) + -- end + FP.defsBystruct = struct +end +local function AdjustArguments(FP) + for fun,defs in pairs(FP.defsT) do + --struct function but no constructors + if defs[1].stname~="ImGui" and defs[1].stname~="" and defs[1].ret then + --print("adjusting",fun) + for i,def in ipairs(defs) do + local empty = def.args:match("^%(%)") --no args + --local ptret = def.retref and "&" or "" + def.args = def.args:gsub("^%(","("..def.stname.."* self"..(empty and "" or ",")) + table.insert(def.argsT,1,{type=def.stname.."*",name="self"}) + end + end + end +end +--generate cimgui.cpp cimgui.h and auto versions depending on postfix +local function cimgui_generation(postfix,STP,FP) + --get all ImVector templates + local ImVector_templates = mergeT(STP.ImVector_templates,FP.ImVector_templates) + --merge it in cimgui_template.h to cimgui.h + local hfile = io.open("./cimgui_template.h","r") + local hstrfile = hfile:read"*a" + hfile:close() + local cstructsstr,typedefs_dict = gen_structs_and_enums(STP.lines,ImVector_templates) + --for not gcc parsing + if postfix == "_nopreprocess" then + cstructsstr = "typedef unsigned short ImDrawIdx;\ntypedef void* ImTextureID;\n"..cstructsstr + end + + hstrfile = hstrfile:gsub([[#include "imgui_structs%.h"]],cstructsstr) + local cfuncsstr = func_header_generate(FP) + hstrfile = hstrfile:gsub([[#include "auto_funcs%.h"]],cfuncsstr) + save_data("./output/cimgui"..postfix..".h",cimgui_header,hstrfile) + + + --merge it in cimgui_template.cpp to cimgui.cpp + local cimplem = func_implementation(FP) + local hfile = io.open("./cimgui_template.cpp","r") + local hstrfile = hfile:read"*a" + hfile:close() + hstrfile = hstrfile:gsub([[#include "auto_funcs%.cpp"]],cimplem) + hstrfile = hstrfile:gsub([[#include "cimgui%.h"]],[[#include "cimgui]]..postfix..[[.h"]]) + save_data("./output/cimgui"..postfix..".cpp",cimgui_header,hstrfile) + return typedefs_dict +end +-------------------------------------------------------- +-----------------------------do it---------------------- +-------------------------------------------------------- +--get imgui.h version-------------------------- +local pipe,err = io.open("../imgui/imgui.h","r") +if not pipe then + error("could not open file:"..err) +end +local imgui_version +while true do + local line = pipe:read"*l" + imgui_version = line:match([[#define%s+IMGUI_VERSION%s+(".+")]]) + if imgui_version then break end +end +pipe:close() +cimgui_header = cimgui_header:gsub("XXX",imgui_version) +print("IMGUI_VERSION",imgui_version) +--get some defines---------------------------- +if HAVE_COMPILER then + gdefines = get_defines{"IMGUI_VERSION","FLT_MAX"} +end + +--generation +print("------------------generation with "..COMPILER.."------------------------") +local pFP,pSTP,typedefs_dict2 + +local pipe,err +if HAVE_COMPILER then + pipe,err = io.popen(CPRE..[[../imgui/imgui.h]],"r") +else + pipe,err = io.open([[../imgui/imgui.h]],"r") +end + +if not pipe then + error("could not execute gcc "..err) +end + +pSTP = struct_parser() --overwrite +pFP = func_parser() --overwrite + +local iterator = (HAVE_COMPILER and location) or filelines + +for line in iterator(pipe,{"imgui"}) do + local line, comment = split_comment(line) + --line = clean_spaces(line) + --comment = "" + pSTP.insert(line,comment) + pFP.insert(line,comment) +end +pipe:close() + +local ovstr = pFP:compute_overloads() +AdjustArguments(pFP) +ADDnonUDT(pFP) +ADDdestructors(pFP) + +save_data("./output/overloads.txt",ovstr) +typedefs_dict2 = cimgui_generation("",pSTP,pFP) +--check arg detection failure if no name in function declaration +check_arg_detection(pFP.defsT,typedefs_dict2) + + +----------save fundefs in definitions.lua for using in bindings +--DefsByStruct(pFP) +set_defines(pFP.defsT) +save_data("./output/definitions.lua",serializeTable("defs",pFP.defsT),"\nreturn defs") + +----------save struct and enums lua table in structs_and_enums.lua for using in bindings +local structs_and_enums_table,typedefs_dict = gen_structs_and_enums_table(pSTP.lines) +save_data("./output/structs_and_enums.lua",serializeTable("defs",structs_and_enums_table),"\nreturn defs") +typedefs_dict = mergeT(typedefs_dict,typedefs_dict2) +save_data("./output/typedefs_dict.lua",serializeTable("defs",typedefs_dict),"\nreturn defs") +--=================================Now implementations + +local iFP,iSTP + +if #implementations > 0 then + + iFP = func_parser() + iSTP = struct_parser() + + for i,impl in ipairs(implementations) do + local source = [[../imgui/examples/imgui_impl_]].. impl .. ".h " + local locati = [[imgui_impl_]].. impl + local pipe,err + if HAVE_COMPILER then + pipe,err = io.popen(CPRE..source,"r") + else + pipe,err = io.open(source,"r") + end + if not pipe then + error("could not get file: "..err) + end + + local iterator = (HAVE_COMPILER and location) or filelines + + for line,locat in iterator(pipe,{locati}) do + local line, comment = split_comment(line) + iSTP.insert(line,comment) + iFP.insert(line,comment,locat) + end + pipe:close() + end + + -- save ./cimgui_impl.h + local cfuncsstr = func_header_impl_generate(iFP) + local cstructstr = gen_structs_and_enums(iSTP.lines) + save_data("./output/cimgui_impl.h",cstructstr,cfuncsstr) + + ----------save fundefs in impl_definitions.lua for using in bindings + save_data("./output/impl_definitions.lua",serializeTable("defs",iFP.defsT),"\nreturn defs") + +end -- #implementations > 0 then + +-------------------------------json saving +--avoid mixed tables (with string and integer keys) +local function json_prepare(defs) + --delete signatures in function + for k,def in pairs(defs) do + for k2,v in pairs(def) do + if type(k2)=="string" then + def[k2] = nil + end + end + end + return defs +end +---[[ +local json = require"json" +save_data("./output/definitions.json",json.encode(json_prepare(pFP.defsT))) +save_data("./output/structs_and_enums.json",json.encode(structs_and_enums_table)) +save_data("./output/typedefs_dict.json",json.encode(typedefs_dict)) +if iFP then + save_data("./output/impl_definitions.json",json.encode(json_prepare(iFP.defsT))) +end +--]] +copyfile("./output/cimgui.h", "../cimgui.h") +copyfile("./output/cimgui.cpp", "../cimgui.cpp") +print"all done!!" +--[[ +---dump some infos----------------------------------------------------------------------- +------------------------------------------------------------------------------------ +print"//-------alltypes--------------------------------------------------------------------" +pFP:dump_alltypes() +print"//embeded_structs---------------------------------------------------------------------------" +for k,v in pairs(pFP.embeded_structs) do + --print(k,v) + io.write("typedef ",v," ",k,";\n") +end +print"//templates---------------------------------------------------------------------------" +for k,v in pairs(pFP.ImVector_templates) do + --print(k,v) + io.write("typedef ImVector<",k,"> ImVector_",k,";\n") +end +for k,v in pairs(pSTP.ImVector_templates) do + --print(k,v) + io.write("typedef ImVector<",k,"> ImVector_",k,";\n") +end +require"anima.utils" +print"//constructors------------------------------------------------------------------" +for i,t in ipairs(pFP.cdefs) do + if t.cimguiname and not t.ret then + local cimf = pFP.defsT[t.cimguiname] + local def = cimf[t.signature] + if not def.ret then + print(t.cimguiname,"\t",t.signature,t.ret) + else + print"constructor error" + prtable(def) + end + end +end +print"//-------------------------------------------------------------------------------------" +for i,t in ipairs(pFP.cdefs) do + --print(t.cimguiname," ",t.funcname,"\t",t.signature,"\t",t.args,"\t",t.argsc,"\t",t.call_args,"\t",t.ret) +end +--------------------------------------------------------------------------------------------- +--]] \ No newline at end of file