From 02677f96918cdcb7d32210e9510303d189f6097c Mon Sep 17 00:00:00 2001 From: Victor Bombi Date: Sat, 29 Feb 2020 14:06:48 +0100 Subject: [PATCH] more robust parsing of enum values --- generator/cpp2ffi.lua | 149 +++++++++++++++++++++++++++++++--------- generator/generator.lua | 83 +++------------------- 2 files changed, 126 insertions(+), 106 deletions(-) diff --git a/generator/cpp2ffi.lua b/generator/cpp2ffi.lua index 9fb4e93..ad26eb0 100644 --- a/generator/cpp2ffi.lua +++ b/generator/cpp2ffi.lua @@ -93,6 +93,26 @@ local function str_split(str, pat) end return t end +local function strsplit(str, pat) + local t = {} + local t2 = {} + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap, cap2 = str:find(fpat, 1) + while s do + table.insert(t,cap) + table.insert(t2,cap2) + last_end = e+1 + s, e, cap, cap2 = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + elseif str:sub(-1)==pat then + table.insert(t, "") + end + return t,t2 +end local function split_comment(line) local comment = line:match("(%s*//.*)") or "" line = line:gsub("%s*//.*","") @@ -112,23 +132,101 @@ local function clean_spaces(cad) cad = cad:gsub("%s*([%(%),=:])%s*","%1") --not spaces with ( , ) or ( = ) or ( : ) return cad end -function strsplit(str, pat) - local t = {} - local fpat = "(.-)" .. pat - local last_end = 1 - local s, e, cap = str:find(fpat, 1) - while s do - table.insert(t,cap) - last_end = e+1 - s, e, cap = str:find(fpat, last_end) - end - if last_end <= #str then - cap = str:sub(last_end) - table.insert(t, cap) - elseif str:sub(-1)==pat then - table.insert(t, "") - end - return t + +------------------------------------ +local function parse_enum_value(value, allenums) + local function clean(val) + if type(val)=="string" then + return clean_spaces(val) + else + return val + end + end + + if type(value)=="number" then + return value + elseif type(value)=="string" then + --numbers + local numval = tonumber(value) + if numval then return numval end + --already in allenums + if allenums[clean(value)] then return allenums[clean(value)] end + --must be several and operators + --precedence order (hope not ()) + assert(not value:match("[%(%)]")) + local several,seps = strsplit(value,"([<>&|~]+)") + --M.prtable(t.value,several,seps) + assert(#seps+1==#several) + + local i = 1 + local ik = 1 + local sepk = {"~","<<",">>","&","^","|"} + while(#seps>0) do + local sep = sepk[ik] + local v = seps[i] + if sep==v then + if v=="~" then + local val = clean(several[i+1]) + if allenums[val] then val = allenums[val] end + assert(several[i]==" " or several[i]=="") + several[i] = bit.bnot(val) + table.remove(several,i+1) + table.remove(seps,i) + elseif v=="<<" then + local val1 = clean(several[i]) + local val2 = clean(several[i+1]) + if allenums[val1] then val1 = allenums[val1] end + if allenums[val2] then val2 = allenums[val2] end + several[i] = bit.lshift(val1,val2) + table.remove(several,i+1) + table.remove(seps,i) + elseif v==">>" then + local val1 = clean(several[i]) + local val2 = clean(several[i+1]) + if allenums[val1] then val1 = allenums[val1] end + if allenums[val2] then val2 = allenums[val2] end + several[i] = bit.rshift(val1,val2) + table.remove(several,i+1) + table.remove(seps,i) + elseif v=="&" then + local val1 = clean(several[i]) + local val2 = clean(several[i+1]) + if allenums[val1] then val1 = allenums[val1] end + if allenums[val2] then val2 = allenums[val2] end + several[i] = bit.band(val1,val2) + table.remove(several,i+1) + table.remove(seps,i) + elseif v=="^" then + error"^ operator still not done" + elseif v=="|" then + local val1 = clean(several[i]) + local val2 = clean(several[i+1]) + if allenums[val1] then val1 = allenums[val1] end + if allenums[val2] then val2 = allenums[val2] end + several[i] = bit.bor(val1,val2) + table.remove(several,i+1) + table.remove(seps,i) + else + error("unknown operator "..v) + end + else + i = i + 1 + end + + if i>#seps then + ik = ik + 1 --next operator + if ik > #sepk then break end + i = 1 + end + end + if #seps>0 then + print("value",value) + M.prtable(several,seps) + end + assert(#seps==0) + assert(type(several[1])=="number") + return several[1] + end end -------------------------------------------------------------------------- local function save_data(filename,...) @@ -1043,22 +1141,7 @@ function M.Parser() --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 + t.calc_value = parse_enum_value(t.value,allenums) assert(t.calc_value) allenums[t.name] = t.calc_value end diff --git a/generator/generator.lua b/generator/generator.lua index 5c03460..ed6616d 100644 --- a/generator/generator.lua +++ b/generator/generator.lua @@ -605,82 +605,18 @@ local cstructsstr = outpre..table.concat(outtab,"")..outpost..(extra or "") local cfuncsstr = func_header_generate(parser1i) save_data("./output/cimgui_internal.h",cimgui_header,"#ifdef CIMGUI_DEFINE_ENUMS_AND_STRUCTS\n",cstructsstr,"\n#endif\n")--,cfuncsstr) copyfile("./output/cimgui_internal.h", "../cimgui_internal.h") ---local structs_and_enums_table_i = parser1i:gen_structs_and_enums_table() ---save_data("./output/structs_and_enums_i.lua",serializeTableF(structs_and_enums_table_i)) --]=] ------------ add only ImGuiContext from imgui_internal.h to parser1 ---[=[ -local parser1i = parseImGuiHeader([[../imgui/imgui_internal.h]],{[[imgui_internal]],[[imstb_textedit]]}) +---------- generate now structs_and_enums_i +---[=[ +save_data([[../imgui/temp.h]],[[#include "imgui.h" +#include "imgui_internal.h"]]) +local parser1i = parseImGuiHeader([[../imgui/temp.h]],{[[imgui]],[[imgui_internal]],[[imstb_textedit]]}) +os.remove([[../imgui/temp.h]]) parser1i:do_parse() -local p1isten = parser1i:gen_structs_and_enums_table() ---parser1i:printItems() -print"typedefs_table---------------------------" -cpp2ffi.prtable(parser1i.typedefs_table) -print"typedefs_table end---------------------------" -local needed = {ImGuiContext = {type = "ImGuiContext", kind = "structs", order = parser1i.order["ImGuiContext"]}} -local seen = {} -local function RecurseNeeded(Ini,IniKind,level) - --if level > 5 then return end - if seen[Ini] then return end - seen[Ini] = true - print("RecurseNeeded",Ini,IniKind,level) - for i,v in ipairs(p1isten[IniKind][Ini]) do - --if not v.type then print("nil type in",Ini,IniKind) end - --dont want pointers - local type = v.type:match"([^%*]+)" - --ImVector out - if type:match"ImVector_" then type=type:match"ImVector_(.+)" end - - local kind = p1isten.enums[type] and "enums" or p1isten.structs[type] and "structs" or nil - if kind=="structs" then - if not needed[type] then RecurseNeeded(type,kind,level+1) end - needed[type] = {type = type, kind = kind, order = parser1i.order[type]} - elseif kind=="enums" then - needed[type] = {type = type, kind = kind, order = parser1i.order[type]} - elseif parser1i.typedefs_table[type] then - needed[type] = {type = type, kind = "typedef", order = parser1i.order[type]} - elseif parser1i.vardefs[type] then - needed[type] = {type = type, kind = "vardef", order = parser1i.order[type]} - elseif not cpp2ffi.c_types[type] then - print("RecurseNeded failed",type) - --error"failed recurse" - end - end -end - -RecurseNeeded("ImGuiContext","structs",0) - - -local ordered_needed = {} -for k,v in pairs(needed) do - table.insert(ordered_needed,v) -end -table.sort(ordered_needed, function(a,b) return a.order < b.order end) - -print"needed are-----------------------" -for i,vv in ipairs(ordered_needed) do - print(vv.order,vv.type,vv.kind) - local v = parser1i.itemsarr[vv.order] - - --if v.item:match"^[%s\n\r]*struct%s*ImGuiContext" then - if vv.kind=="structs" then - --add enum keyword where necessary - --print"setting enum keyword------------------------" - local newitem = "" - for line in v.item:gmatch("([^\n]+)") do - local typen = line:match"^%s*(%S+)" - if p1isten.enums[typen] then - print("add enum",typen) - newitem = newitem.."\nenum"..line - else - newitem = newitem.."\n"..line - end - end - v.item = newitem - end - table.insert(parser1.itemsarr,v) -end +local structs_and_enums_table_i = parser1i:gen_structs_and_enums_table() +save_data("./output/structs_and_enums_i.lua",serializeTableF(structs_and_enums_table_i)) --]=] + ---------------------- save_data("./output/overloads.txt",parser1.overloadstxt) @@ -782,6 +718,7 @@ 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/structs_and_enums_i.json",json.encode(structs_and_enums_table_i)) 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)))