apply ocornut suggested cimgui structure

This commit is contained in:
sonoro1234
2018-06-26 10:51:55 +02:00
parent ac0aaba306
commit 73a6da9451
13 changed files with 75 additions and 3810 deletions

View File

@@ -0,0 +1,34 @@
#include "../imgui/imgui.h"
#include "cimgui.h"
#include "../imgui/imgui_internal.h"
#include "auto_funcs.cpp"
/////////////////////////////manual written functions
CIMGUI_API void igLogText(CONST char *fmt, ...)
{
char buffer[256];
va_list args;
va_start(args, fmt);
vsnprintf(buffer, 256, fmt, args);
va_end(args);
ImGui::LogText("%s", buffer);
}
CIMGUI_API void ImGuiTextBuffer_appendf(struct ImGuiTextBuffer *buffer, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
buffer->appendfv(fmt, args);
va_end(args);
}
CIMGUI_API void ImFontConfig_DefaultConstructor(ImFontConfig *config)
{
*config = ImFontConfig();
}
CIMGUI_API float igGET_FLT_MAX()
{
return FLT_MAX;
}

View File

@@ -0,0 +1,57 @@
#include <stdio.h>
#if defined _WIN32 || defined __CYGWIN__
#ifdef CIMGUI_NO_EXPORT
#define API
#else
#define API __declspec(dllexport)
#endif
#ifndef __GNUC__
#define snprintf sprintf_s
#endif
#else
#define API
#endif
#if defined __cplusplus
#define EXTERN extern "C"
#else
#include <stdarg.h>
#include <stdbool.h>
#define EXTERN extern
#endif
#define CIMGUI_API EXTERN API
#define CONST const
#ifdef _MSC_VER
typedef unsigned __int64 ImU64;
#else
typedef unsigned long long ImU64;
#endif
//struct GLFWwindow;
//struct SDL_Window;
#ifdef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#include "imgui_structs.h"
#else
struct GLFWwindow;
struct SDL_Window;
typedef union SDL_Event SDL_Event;
#endif // CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#include "auto_funcs.h"
/////////////////////////hand written functions
//no LogTextV
CIMGUI_API void igLogText(CONST char *fmt, ...);
//no appendfV
CIMGUI_API void ImGuiTextBuffer_appendf(struct ImGuiTextBuffer *buffer, const char *fmt, ...);
CIMGUI_API void ImFontConfig_DefaultConstructor(ImFontConfig *config);
//for getting FLT_MAX in bindings
CIMGUI_API float igGET_FLT_MAX();

21
generator/generator.bat Normal file
View File

@@ -0,0 +1,21 @@
:: this is used to rebuild cimgui.h and cimgui.cpp and must be executed in this directory
:: definitions.lua for function definitions
:: structs_and_enums.lua with struct and enum information-definitions
:: impl_definitions.lua for implementation function definitions
:: cimgui_impl.h with implementation function cdefs
:: set your PATH if necessary for LuaJIT or Lua5.1 or luajit with: (for example)
:: set PATH=%PATH%;C:\luaGL;
::process files
:: arg[1] true=use gcc false=dont use gcc
:: arg[2..] name of implementation to generate
luajit.exe ./generator.lua false glfw opengl3 opengl2 sdl
::copy cimgui.h and cimgui.cpp
copy .\cimgui.h ..\cimgui.h
copy .\cimgui.cpp ..\cimgui.cpp
::leave console open
cmd /k

997
generator/generator.lua Normal file
View File

@@ -0,0 +1,997 @@
--------------------------------------------------------------------------
--script for auto_funcs.h and auto_funcs.cpp generation
--expects Lua 5.1 or luajit
--------------------------------------------------------------------------
local script_args = {...}
local implementations = {}
for i=2,#script_args do table.insert(implementations,script_args[i]) end
-- first script argument to use gcc or not
local USEGCC = script_args[1] == "true"
--------------------------------------------------------------------------
--this table has the functions to be skipped in generation
--------------------------------------------------------------------------
local cimgui_manuals = {
igLogText = true,
ImGuiTextBuffer_appendf = 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"
},
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"
}
}
--------------------------------------------------------------------------
--helper functions
--------------------------------------------------------------------------
--iterates lines from a .h file and discards between #if.. and #endif
local function filelines(file)
local iflevels = {}
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("#if") then
iflevels[#iflevels +1 ] = true
elseif line:match("#endif") then
iflevels[#iflevels] = nil
end
-- skip
elseif #iflevels == 0 then
-- drop IMGUI_APIX
line = line:gsub("IMGUI_APIX","")
-- drop IMGUI_API
line = line:gsub("IMGUI_API","")
return line
end
until false
end
return location_it
end
--iterates lines from a gcc -E in a specific location
local function location(file,locpathT)
local location_re = '^# %d+ "([^"]*)"'
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 function location_it()
repeat
local line = file:read"*l"
if not line then return nil end
if line:sub(1,1) == "#" then
-- Is this a location pragma?
local 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;
which_location = locpathT[i]
break
end
end
end
elseif in_location then
return line, which_location
end
until false
end
return location_it
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")
for k,v in pairs(value) do -- save its fields
local fieldname = string.format("%s[%s]", name,basicSerialize(k))
table.insert(string_table, serializeTable(fieldname, v, saved))
end
end
--else
--error("cannot save a " .. type(value))
end
return table.concat(string_table)
end
local function save_data(filename,data)
local file = io.open(filename,"w")
file:write(data)
file:close()
end
local function strip(cad)
return cad:gsub("^%s*(.-)%s*$","%1") --remove initial and final spaces
end
local function clean_spaces(cad)
cad = strip(cad)
--cad = cad:gsub("%s+","%s") --not more than one space
cad = cad:gsub("%s*([%(%),=])%s*","%1") --not spaces with ( , )
return cad
end
local function split_comment(line)
local comment = line:match("(%s*//.*)") or ""
return line:gsub("%s*//.*",""),comment
end
local function get_manuals(def)
return cimgui_manuals[def.ov_cimguiname] or cimgui_manuals[def.cimguiname]
end
local function getcimguiname(stname,funcname)
if #stname == 0 then return funcname end --top level
local pre = (stname == "ImGui") and "ig" or stname.."_"
return pre..funcname
end
local function getcimguiname_overload(stname,funcname,signature)
local cname = getcimguiname(stname,funcname)
local ov_cname = cimgui_overloads[cname] and cimgui_overloads[cname][signature] --or cname
return ov_cname
end
local function struct_parser()
local function_re = "(%a*%w+%b())" --"(%a*%w+%s+%w+%b())"
local function_closing_re = "}"
local function_closed_re = "[;}]$"
local operator_re = "operator.-%b()"
local functype_re = "(%(%*)[%w_]+(%)%([^%(%)]*%))"
local initial_comment_re = [[^%s*//.*]]
local in_functionst = false
local structcdefs = {}
local STP = {}
STP.lines = structcdefs
function STP.insert(line,comment)
--dont process initial comments but keep it
if line:match(initial_comment_re) then
table.insert(structcdefs,line)
return
end
--if in_function discard
if in_functionst then
if line:match(function_closing_re) then
in_functionst = false
print("in function:",line)
end
return
end
if (line:match(function_re) or line:match(operator_re)) and not line:match("typedef.*%b().*%b().*")
and not line:match(functype_re) then
if not line:match(function_closed_re) then
print("match:",line)
in_functionst = true
end
--else
--table.insert(structcdefs,linecommented)
elseif line:match("template") then
--nothing
elseif line:match("public:") then
--nothing
else
local linea = line:gsub("%S+",{class="struct",mutable=""})
linea = linea:gsub("(%b<>)","/%*%1%*/") --comment template parameters
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_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 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)
line = clean_spaces(line)
if line:match"template" then return end
line = line:gsub("%S+",{class="struct",mutable=""}) --class -> struct
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
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~="ImVector"
--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")
argscsinpars = argscsinpars:gsub("&","")
local template = argscsinpars:match("ImVector<([%w_]+)>")
if template then
ImVector_templates[template] = true
end
argscsinpars = argscsinpars:gsub("<([%w_]+)>","_%1") --ImVector
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
if ret then
defT.ret = ret:gsub("&","*")
defT.retref = ret:match("&")
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 numoverloaded = 0
FP.alltypes = {}
print"----------------overloadings---------------------------"
for k,v in pairs(FP.defsT) do
get_types(v)
if #v > 1 then
numoverloaded = numoverloaded + #v
print(k,#v)
local typesc,post = name_overloadsAlgo(v)
for i,t in ipairs(v) do
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]))
--prtable(typesc[i])
end
end
end
print(numoverloaded, "overloaded")
end
return FP
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={}}
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)
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 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
local name = line:match("%s*([^,]+)")
local value = #outtab.enums[enumnames[#enumnames]]
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] ~="ImVector" 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+[,;])")
for name in rest:gmatch("([^%s,;]+)%s?[,;]") do
table.insert(outtab.structs[structnames[#structnames]],{type=typen,name=name})
end
end
end
until true
end
return outtab
end
local function gen_structs_and_enums(cdefs)
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 outtab = {}
-- Output the file
table.insert(outtab,"/////////////// BEGIN AUTOGENERATED SEGMENT\n")
if not USEGCC then
table.insert(outtab,[[typedef unsigned short ImDrawIdx;]])
table.insert(outtab,[[typedef void* ImTextureID;]])
end
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
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~= "ImVector" then --not inner and not ImVector
table.insert(outtab,linecom.."\n")
break
end
end
if structnames[#structnames] == "ImVector" then
if line:match(struct_closing_re) then
table.insert(outtab,[[struct ImVector
{
int Size;
int Capacity;
void* Data;
};
typedef struct ImVector ImVector;]])
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 (#structnames > 0) then
if line:match("typedef") then --dont allow inner typedefs
break
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")
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))
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")
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")
for i,l in ipairs(typedefs_table) do
table.insert(outtab,2,l)
end
return outtab
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
--hfile:close()
return outtab
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]
local manual = get_manuals(def)
if not manual and def.ret then --not constructor
local addcoment = def.comment or ""
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)..def.args..";"..addcoment.."\n")
else
local empty = def.args:match("^%(%)") --no args
--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)..args..";"..addcoment.."\n")
end
end
else --not cimguiname
table.insert(outtab,t.comment:gsub("%%","%%%%").."\n")-- %% substitution for gsub
end
end
--hfile:close()
return outtab
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]
local manual = get_manuals(def)
if not manual and def.ret and def.stname~="" then --not constructor or manual or top level
local ptret = def.retref and "&" or ""
-- local castret = def.ret:gsub("[^%s]+",function(x)
-- local y = x:gsub("%*","")
-- local typ = embeded_structs[y]
-- if typ then return "("..x..")" else return "" end
-- end)
local castret = ""
if def.stname == "ImGui" then
if def.isvararg then
local call_args = def.call_args:gsub("%.%.%.","args")
table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args.."\n")
table.insert(outtab,"{\n")
table.insert(outtab," va_list args;\n")
table.insert(outtab," va_start(args, fmt);\n")
table.insert(outtab," ImGui::"..def.funcname.."V"..call_args..";\n")
table.insert(outtab," va_end(args);\n")
--cppfile:write(" return ImGui::",def.funcname,def.call_args,";\n")
table.insert(outtab,"}\n")
else
table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..def.args.."\n")
table.insert(outtab,"{\n")
table.insert(outtab," return "..castret..ptret.."ImGui::"..def.funcname..def.call_args..";\n")
table.insert(outtab,"}\n")
end
else
local empty = def.args:match("^%(%)") --no args
--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 ","))
if def.isvararg then
local call_args = def.call_args:gsub("%.%.%.","args")
table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..args.."\n")
table.insert(outtab,"{\n")
table.insert(outtab," va_list args;\n")
table.insert(outtab," va_start(args, fmt);\n")
table.insert(outtab," self->"..def.funcname.."V"..call_args..";\n")
table.insert(outtab," va_end(args);\n")
--cppfile:write(" return self->",def.funcname,def.call_args,";\n")
table.insert(outtab,"}\n")
else
table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..(def.ov_cimguiname or def.cimguiname)..args.."\n")
table.insert(outtab,"{\n")
table.insert(outtab," return "..castret..ptret.."self->"..def.funcname..def.call_args..";\n")
table.insert(outtab,"}\n")
end
end
end
until true
end
--cppfile:close()
return outtab
end
--------------------------------------------------------
-----------------------------do it----------------------
--------------------------------------------------------
print("USEGCC",USEGCC)
local pipe,err
if USEGCC then
pipe,err = io.popen([[gcc -E -C -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ../../imgui/imgui.h]],"r")
if not pipe then
error("could not execute gcc "..err)
end
else
pipe,err = io.open("../../imgui/imgui.h","r")
if not pipe then
error("could not execute gcc "..err)
end
end
print"goint to iterate"
local STP = struct_parser()
local FP = func_parser()
local iterator = (USEGCC and location) or filelines
for line in iterator(pipe,{"imgui"}) do
local line, comment = split_comment(line)
STP.insert(line,comment)
FP.insert(line,comment)
end
pipe:close()
--output after insert
-- local hfile = io.open("./outstructs.h","w")
-- hfile:write(table.concat(STP.lines,"\n"))
-- hfile:close()
--do return end
FP:compute_overloads()
local cstructs = gen_structs_and_enums(STP.lines)
local cfuncs = func_header_generate(FP)
--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 = table.concat(cstructs)
cstructsstr = cstructsstr:gsub("\n+","\n") --several empty lines to one empty line
hstrfile = hstrfile:gsub([[#include "imgui_structs%.h"]],cstructsstr)
local cfuncsstr = table.concat(cfuncs)
cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line
hstrfile = hstrfile:gsub([[#include "auto_funcs%.h"]],cfuncsstr)
save_data("./cimgui.h",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"]],table.concat(cimplem))
save_data("./cimgui.cpp",hstrfile)
----------save fundefs in definitions.lua for using in bindings
save_data("./definitions.lua",serializeTable("defs",FP.defsT).."\nreturn defs")
----------save struct and enums lua table in structs_and_enums.lua for using in bindings
save_data("./structs_and_enums.lua",serializeTable("defs",gen_structs_and_enums_table(STP.lines)).."\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 USEGCC then
pipe,err = io.popen([[gcc -E -C -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ]] ..source,"r")
else
pipe,err = io.open(source,"r")
end
if not pipe then
error("could not get file: "..err)
end
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 impl_cfuncs = func_header_impl_generate(iFP)
local impl_cstructs = gen_structs_and_enums(iSTP.lines)
local cstructstr = table.concat(impl_cstructs)
cstructstr = cstructstr:gsub("\n+","\n") --several empty lines to one empty line
local cfuncsstr = table.concat(impl_cfuncs)
cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line
save_data("./cimgui_impl.h",cstructstr..cfuncsstr)
----------save fundefs in impl_definitions.lua for using in bindings
save_data("./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("./definitions.json",json.encode(json_prepare(FP.defsT)))
save_data("./structs_and_enums.json",json.encode(structs_and_enums_table))
if iFP then
save_data("./impl_definitions.json",json.encode(json_prepare(iFP.defsT)))
end
print"all done!!"
--[[
---dump some infos-----------------------------------------------------------------------
------------------------------------------------------------------------------------
print"//-------alltypes--------------------------------------------------------------------"
FP:dump_alltypes()
print"//embeded_structs---------------------------------------------------------------------------"
for k,v in pairs(FP.embeded_structs) do
--print(k,v)
io.write("typedef ",v," ",k,";\n")
end
print"//templates---------------------------------------------------------------------------"
for k,v in pairs(FP.ImVector_templates) do
--print(k,v)
io.write("typedef ImVector<",k,"> ImVector_",k,";\n")
end
print"//constructors------------------------------------------------------------------"
for i,t in ipairs(FP.cdefs) do
if t.cimguiname and not t.ret then
print(t.cimguiname,"\t",t.signature,"\t",t.args,"\t",t.argsc,"\t",t.call_args,"\t",t.ret)
end
end
print"//-------------------------------------------------------------------------------------"
for i,t in ipairs(FP.cdefs) do
--print(t.cimguiname," ",t.funcname,"\t",t.signature,"\t",t.args,"\t",t.argsc,"\t",t.call_args,"\t",t.ret)
end
---------------------------------------------------------------------------------------------
--]]

View File

@@ -0,0 +1,21 @@
:: this is used to rebuild cimgui.h and cimgui.cpp and must be executed in this directory
:: definitions.lua for function definitions
:: structs_and_enums.lua with struct and enum information-definitions
:: impl_definitions.lua for implementation function definitions
:: cimgui_impl.h with implementation function cdefs
:: set your PATH if necessary for gcc and LuaJIT or Lua 5.1 with: (for example)
:: set PATH=%PATH%;C:\mingw32\bin;C:\luaGL;
::process files
:: arg[1] true=use gcc false=dont use gcc
:: arg[2..] name of implementation to generate
luajit.exe ./generator.lua true glfw opengl3 opengl2 sdl
::copy cimgui.h and cimgui.cpp
copy .\cimgui.h ..\cimgui.h
copy .\cimgui.cpp ..\cimgui.cpp
::leave console open
cmd /k

400
generator/json.lua Normal file
View File

@@ -0,0 +1,400 @@
--
-- json.lua
--
-- Copyright (c) 2018 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
local json = { _version = "0.1.1" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
[ "\\" ] = "\\\\",
[ "\"" ] = "\\\"",
[ "\b" ] = "\\b",
[ "\f" ] = "\\f",
[ "\n" ] = "\\n",
[ "\r" ] = "\\r",
[ "\t" ] = "\\t",
}
local escape_char_map_inv = { [ "\\/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return escape_char_map[c] or string.format("\\u%04x", c:byte())
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if val[1] ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return ( encode(val) )
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end
local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(3, 6), 16 )
local n2 = tonumber( s:sub(9, 12), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local has_unicode_escape = false
local has_surrogate_escape = false
local has_escape = false
local last
for j = i + 1, #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
end
if last == 92 then -- "\\" (escape char)
if x == 117 then -- "u" (unicode escape sequence)
local hex = str:sub(j + 1, j + 5)
if not hex:find("%x%x%x%x") then
decode_error(str, j, "invalid unicode escape in string")
end
if hex:find("^[dD][89aAbB]") then
has_surrogate_escape = true
else
has_unicode_escape = true
end
else
local c = string.char(x)
if not escape_chars[c] then
decode_error(str, j, "invalid escape char '" .. c .. "' in string")
end
has_escape = true
end
last = nil
elseif x == 34 then -- '"' (end of string)
local s = str:sub(i + 1, j - 1)
if has_surrogate_escape then
s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape)
end
if has_unicode_escape then
s = s:gsub("\\u....", parse_unicode_escape)
end
if has_escape then
s = s:gsub("\\.", escape_char_map_inv)
end
return s, j + 1
else
last = x
end
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
return json