| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996 |
- -- Copyright 2019 云风 https://github.com/cloudwu . All rights reserved.
- -- License (the same with bgfx) : https://github.com/bkaradzic/bgfx/blob/master/LICENSE
- local codegen = {}
- local DEFAULT_NAME_ALIGN = 20
- local DEFINE_NAME_ALIGN = 41
- local function namealign(name, align)
- align = align or DEFAULT_NAME_ALIGN
- return string.rep(" ", align - #name)
- end
- local function camelcase_to_underscorecase(name)
- local tmp = {}
- for v in name:gmatch "[%u%d]+%l*" do
- tmp[#tmp+1] = v:lower()
- end
- return table.concat(tmp, "_")
- end
- local function to_underscorecase(name)
- local tmp = {}
- for v in name:gmatch "[_%u][%l%d]*" do
- if v:byte() == 95 then -- '_'
- v = v:sub(2) -- remove _
- end
- tmp[#tmp+1] = v
- end
- return table.concat(tmp, "_")
- end
- local function underscorecase_to_camelcase(name)
- local tmp = {}
- for v in name:gmatch "[^_]+" do
- tmp[#tmp+1] = v:sub(1,1):upper() .. v:sub(2)
- end
- return table.concat(tmp)
- end
- local function convert_funcname(name)
- name = name:gsub("^%l", string.upper) -- Change to upper CamlCase
- return camelcase_to_underscorecase(name)
- end
- local function convert_arg(all_types, arg, namespace)
- local fulltype, array = arg.fulltype:match "(.-)%s*(%[%s*[%d%a_:]*%s*%])"
- if array then
- arg.fulltype = fulltype
- arg.array = array
- local enum, value = array:match "%[%s*([%a%d]+)::([%a%d]+)%]"
- if enum then
- local typedef = all_types[ enum .. "::Enum" ]
- if typedef == nil then
- error ("Unknown Enum " .. enum)
- end
- arg.carray = "[BGFX_" .. camelcase_to_underscorecase(enum):upper() .. "_" .. value:upper() .. "]"
- end
- end
- local t, postfix = arg.fulltype:match "(%a[%a%d_:]*)%s*([*&]+)%s*$"
- if t then
- arg.type = t
- if postfix == "&" then
- arg.ref = true
- end
- else
- local prefix, t = arg.fulltype:match "^%s*(%a+)%s+(%S+)"
- if prefix then
- arg.type = t
- else
- arg.type = arg.fulltype
- end
- end
- local ctype
- local substruct = namespace.substruct
- if substruct then
- ctype = substruct[arg.type]
- end
- if not ctype then
- ctype = all_types[arg.type]
- end
- if not ctype then
- error ("Undefined type " .. arg.fulltype .. " in " .. namespace.name)
- end
- arg.ctype = arg.fulltype:gsub(arg.type, ctype.cname):gsub("&", "*")
- if ctype.cname ~= arg.type then
- arg.cpptype = arg.fulltype:gsub(arg.type, "bgfx::"..arg.type)
- else
- arg.cpptype = arg.fulltype
- end
- if arg.ref then
- arg.ptype = arg.cpptype:gsub("&", "*")
- end
- end
- local function alternative_name(name)
- if name:sub(1,1) == "_" then
- return name:sub(2)
- else
- return name .. "_"
- end
- end
- local function gen_arg_conversion(all_types, arg)
- if arg.ctype == arg.fulltype then
- -- do not need conversion
- return
- end
- local ctype = all_types[arg.type]
- if ctype.handle and arg.type == arg.fulltype then
- local aname = alternative_name(arg.name)
- arg.aname = aname .. ".cpp"
- arg.aname_cpp2c = aname .. ".c"
- arg.conversion = string.format(
- "union { %s c; bgfx::%s cpp; } %s = { %s };" ,
- ctype.cname, arg.type, aname, arg.name)
- arg.conversion_back = string.format(
- "union { bgfx::%s cpp; %s c; } %s = { %s };" ,
- arg.type, ctype.cname, aname, arg.name)
- elseif arg.ref then
- if ctype.cname == arg.type then
- arg.aname = "*" .. arg.name
- arg.aname_cpp2c = "&" .. arg.name
- elseif arg.out and ctype.enum then
- local aname = alternative_name(arg.name)
- local cpptype = arg.cpptype:match "(.-)%s*&" -- remove &
- local c99type = arg.ctype:match "(.-)%s*%*" -- remove *
- arg.aname = aname
- arg.aname_cpp2c = "&" .. aname
- arg.conversion = string.format("%s %s;", cpptype, aname)
- arg.conversion_back = string.format("%s %s;", c99type, aname);
- arg.out_conversion = string.format("*%s = (%s)%s;", arg.name, ctype.cname, aname)
- arg.out_conversion_back = string.format("%s = (%s)%s;", arg.name, c99type, aname)
- else
- arg.aname = alternative_name(arg.name)
- arg.aname_cpp2c = string.format("(%s)&%s" , arg.ctype , arg.name)
- arg.conversion = string.format(
- "%s %s = *(%s)%s;",
- arg.cpptype, arg.aname, arg.ptype, arg.name)
- end
- else
- local cpptype = arg.cpptype
- local ctype = arg.ctype
- if arg.array then
- cpptype = cpptype .. "*"
- ctype = ctype .. "*"
- end
- arg.aname = string.format(
- "(%s)%s",
- cpptype, arg.name)
- arg.aname_cpp2c = string.format(
- "(%s)%s",
- ctype, arg.name)
- end
- end
- local function gen_ret_conversion(all_types, func)
- local postfix = { func.vararg and "va_end(argList);" }
- local postfix_cpp2c = { postfix[1] }
- func.ret_postfix = postfix
- func.ret_postfix_cpp2c = postfix_cpp2c
- for _, arg in ipairs(func.args) do
- if arg.out_conversion then
- postfix[#postfix+1] = arg.out_conversion
- postfix_cpp2c[#postfix_cpp2c+1] = arg.out_conversion_back
- end
- end
- local ctype = all_types[func.ret.type]
- if ctype.handle then
- func.ret_conversion = string.format(
- "union { %s c; bgfx::%s cpp; } handle_ret;" ,
- ctype.cname, ctype.name)
- func.ret_conversion_cpp2c = string.format(
- "union { bgfx::%s cpp; %s c; } handle_ret;" ,
- ctype.name, ctype.cname)
- func.ret_prefix = "handle_ret.cpp = "
- func.ret_prefix_cpp2c = "handle_ret.c = "
- postfix[#postfix+1] = "return handle_ret.c;"
- postfix_cpp2c[#postfix_cpp2c+1] = "return handle_ret.cpp;"
- elseif func.ret.fulltype ~= "void" then
- local ctype_conversion = ""
- local conversion_back = ""
- if ctype.name ~= ctype.cname then
- if func.ret.ref then
- ctype_conversion = "(" .. func.ret.ctype .. ")&"
- conversion_back = "*(" .. func.ret.ptype .. ")"
- else
- ctype_conversion = "(" .. func.ret.ctype .. ")"
- conversion_back = "(" .. func.ret.cpptype .. ")"
- end
- end
- if #postfix > 0 then
- func.ret_prefix = string.format("%s retValue = %s", func.ret.ctype , ctype_conversion)
- func.ret_prefix_cpp2c = string.format("%s retValue = %s", func.ret.cpptype , conversion_back)
- local ret = "return retValue;"
- postfix[#postfix+1] = ret
- postfix_cpp2c[#postfix_cpp2c+1] = ret
- else
- func.ret_prefix = string.format("return %s", ctype_conversion)
- func.ret_prefix_cpp2c = string.format("return %s", conversion_back)
- end
- end
- end
- local function convert_vararg(v)
- if v.vararg then
- local args = v.args
- local vararg = {
- name = "",
- fulltype = "...",
- type = "...",
- ctype = "...",
- aname = "argList",
- conversion = string.format(
- "va_list argList;\n\tva_start(argList, %s);",
- args[#args].name),
- }
- args[#args + 1] = vararg
- v.alter_name = v.vararg
- end
- end
- local function calc_flag_values(flag)
- local shift = flag.shift
- local base = flag.base or 0
- local cap = 1 << (flag.range or 0)
- if flag.range then
- if flag.range == 64 then
- flag.mask = 0xffffffffffffffff
- else
- flag.mask = ((1 << flag.range) - 1) << shift
- end
- end
- local values = {}
- for index, item in ipairs(flag.flag) do
- local value = item.value
- if flag.const then
- -- use value directly
- elseif shift then
- if value then
- if value > 0 then
- value = value - 1
- end
- else
- value = index + base - 1
- end
- if value >= cap then
- error (string.format("Out of range for %s.%s (%d/%d)", flag.name, item.name, value, cap))
- end
- value = value << shift
- elseif #item == 0 then
- if value then
- if value > 0 then
- value = 1 << (value - 1)
- end
- else
- local s = index + base - 2
- if s >= 0 then
- value = 1 << s
- else
- value = 0
- end
- end
- end
- if not value then
- -- It's a combine flags
- value = 0
- for _, name in ipairs(item) do
- local v = values[name]
- if v then
- value = value | v
- else
- -- todo : it's a undefined flag
- value = nil
- break
- end
- end
- end
- item.value = value
- values[item.name] = value
- end
- end
- function codegen.nameconversion(all_types, all_funcs)
- for _,v in ipairs(all_types) do
- local name = v.name
- local cname = v.cname
- if cname == nil then
- if name:match "^%u" then
- cname = camelcase_to_underscorecase(name)
- elseif not v.flag then
- v.cname = name
- end
- end
- if cname and not v.flag then
- if v.namespace then
- cname = camelcase_to_underscorecase(v.namespace) .. "_" .. cname
- end
- v.cname = "bgfx_".. cname .. "_t"
- end
- if v.enum then
- v.typename = v.name
- v.name = v.name .. "::Enum"
- end
- if v.flag then
- calc_flag_values(v)
- end
- end
- -- make index
- for _,v in ipairs(all_types) do
- if not v.namespace then
- if all_types[v.name] then
- error ("Duplicate type " .. v.name)
- elseif not v.flag then
- all_types[v.name] = v
- end
- end
- end
- -- make sub struct index
- for _,v in ipairs(all_types) do
- if v.namespace then
- local super = all_types[v.namespace]
- if not super then
- error ("Define " .. v.namespace .. " first")
- end
- local substruct = super.substruct
- if not substruct then
- substruct = {}
- super.substruct = substruct
- end
- if substruct[v.name] then
- error ( "Duplicate sub struct " .. v.name .. " in " .. v.namespace)
- end
- v.parent_class = super
- substruct[#substruct+1] = v
- substruct[v.name] = v
- end
- end
- for _,v in ipairs(all_types) do
- if v.struct then
- for _, item in ipairs(v.struct) do
- convert_arg(all_types, item, v)
- end
- elseif v.args then
- -- funcptr
- for _, arg in ipairs(v.args) do
- convert_arg(all_types, arg, v)
- end
- convert_vararg(v)
- convert_arg(all_types, v.ret, v)
- end
- end
- local funcs = {}
- local funcs_conly = {}
- local funcs_alter = {}
- for _,v in ipairs(all_funcs) do
- if v.cname == nil then
- v.cname = convert_funcname(v.name)
- end
- if v.class then
- v.cname = convert_funcname(v.class) .. "_" .. v.cname
- local classtype = all_types[v.class]
- if classtype then
- local methods = classtype.methods
- if not methods then
- methods = {}
- classtype.methods = methods
- end
- methods[#methods+1] = v
- end
- elseif not v.conly then
- funcs[v.name] = v
- end
- if v.conly then
- table.insert(funcs_conly, v)
- end
- for _, arg in ipairs(v.args) do
- convert_arg(all_types, arg, v)
- gen_arg_conversion(all_types, arg)
- end
- convert_vararg(v)
- if v.alter_name then
- funcs_alter[#funcs_alter+1] = v
- end
- convert_arg(all_types, v.ret, v)
- gen_ret_conversion(all_types, v)
- local namespace = v.class
- if namespace then
- local classname = namespace
- if v.const then
- classname = "const " .. classname
- end
- local classtype = { fulltype = classname .. "*" }
- convert_arg(all_types, classtype, v)
- v.this = classtype.ctype
- v.this_type = classtype
- v.this_conversion = string.format( "%s This = (%s)_this;", classtype.cpptype, classtype.cpptype)
- v.this_to_c = string.format("(%s)this", classtype.ctype)
- end
- end
- for _, v in ipairs(funcs_conly) do
- local func = funcs[v.name]
- if func then
- func.multicfunc = func.multicfunc or { func.cname }
- table.insert(func.multicfunc, v.cname)
- end
- end
- for _, v in ipairs(funcs_alter) do
- local func = funcs[v.alter_name]
- v.alter_cname = func.cname
- end
- end
- local function lines(tbl)
- if not tbl or #tbl == 0 then
- return "//EMPTYLINE"
- else
- return table.concat(tbl, "\n\t")
- end
- end
- local function remove_emptylines(txt)
- return (txt:gsub("\t//EMPTYLINE\n", ""))
- end
- local function codetemp(func)
- local conversion = {}
- local conversion_c2cpp = {}
- local args = {}
- local cargs = {}
- local callargs_conversion = {}
- local callargs_conversion_back = {}
- local callargs = {}
- local cppfunc
- local classname
- if func.class then
- -- It's a member function
- cargs[1] = func.this .. " _this"
- conversion[1] = func.this_conversion
- cppfunc = "This->" .. func.name
- callargs[1] = "_this"
- callargs_conversion_back[1] = func.this_to_c
- classname = func.class .. "::"
- else
- cppfunc = "bgfx::" .. tostring(func.alter_name or func.name)
- classname = ""
- end
- for _, arg in ipairs(func.args) do
- conversion[#conversion+1] = arg.conversion
- conversion_c2cpp[#conversion_c2cpp+1] = arg.conversion_back
- local cname = arg.ctype .. " " .. arg.name
- if arg.array then
- cname = cname .. (arg.carray or arg.array)
- end
- local name = arg.fulltype .. " " .. arg.name
- if arg.array then
- name = name .. arg.array
- end
- if arg.default ~= nil then
- name = name .. " = " .. tostring(arg.default)
- end
- cargs[#cargs+1] = cname
- args[#args+1] = name
- callargs_conversion[#callargs_conversion+1] = arg.aname or arg.name
- callargs_conversion_back[#callargs_conversion_back+1] = arg.aname_cpp2c or arg.name
- callargs[#callargs+1] = arg.name
- end
- conversion[#conversion+1] = func.ret_conversion
- conversion_c2cpp[#conversion_c2cpp+1] = func.ret_conversion_cpp2c
- local ARGS
- local args_n = #args
- if args_n == 0 then
- ARGS = ""
- elseif args_n == 1 then
- ARGS = args[1]
- else
- ARGS = "\n\t " .. table.concat(args, "\n\t, ") .. "\n\t"
- end
- local preret_c2c
- local postret_c2c = {}
- local conversion_c2c = {}
- local callfunc_c2c
- if func.vararg then
- postret_c2c[1] = "va_end(argList);"
- local vararg = func.args[#func.args]
- callargs[#callargs] = vararg.aname
- callargs_conversion_back[#callargs_conversion_back] = vararg.aname
- conversion_c2c[1] = vararg.conversion
- conversion_c2cpp[1] = vararg.conversion
- if func.ret.fulltype == "void" then
- preret_c2c = ""
- else
- preret_c2c = func.ret.ctype .. " retValue = "
- postret_c2c[#postret_c2c+1] = "return retValue;"
- end
- callfunc_c2c = func.alter_cname or func.cname
- else
- if func.ret.fulltype == "void" then
- preret_c2c = ""
- else
- preret_c2c = "return "
- end
- callfunc_c2c = func.cname
- end
- outCargs = table.concat(cargs, ", ")
- if outCargs == "" then
- outCargs = "void"
- end
- return {
- RET = func.ret.fulltype,
- CRET = func.ret.ctype,
- CFUNCNAME = func.cname,
- CFUNCNAMEUPPER = func.cname:upper(),
- CFUNCNAMECAML = underscorecase_to_camelcase(func.cname),
- FUNCNAME = func.name,
- CARGS = outCargs,
- CPPARGS = table.concat(args, ", "),
- ARGS = ARGS,
- CONVERSION = lines(conversion),
- CONVERSIONCTOC = lines(conversion_c2c),
- CONVERSIONCTOCPP = lines(conversion_c2cpp),
- PRERET = func.ret_prefix or "",
- PRERETCPPTOC = func.ret_prefix_cpp2c or "",
- CPPFUNC = cppfunc,
- CALLFUNCCTOC = callfunc_c2c,
- CALLARGSCTOCPP = table.concat(callargs_conversion, ", "),
- CALLARGSCPPTOC = table.concat(callargs_conversion_back, ", "),
- CALLARGS = table.concat(callargs, ", "),
- POSTRET = lines(func.ret_postfix),
- POSTRETCPPTOC = lines(func.ret_postfix_cpp2c),
- PRERETCTOC = preret_c2c,
- POSTRETCTOC = lines(postret_c2c),
- CLASSNAME = classname,
- CONST = func.const and " const" or "",
- }
- end
- local function apply_template(func, temp)
- func.codetemp = func.codetemp or codetemp(func)
- return (temp:gsub("$(%u+)", func.codetemp))
- end
- function codegen.apply_functemp(func, temp)
- return remove_emptylines(apply_template(func, temp))
- end
- function codegen.gen_funcptr(funcptr)
- return apply_template(funcptr, "typedef $RET (*$FUNCNAME)($ARGS);")
- end
- function codegen.gen_cfuncptr(funcptr)
- return apply_template(funcptr, "typedef $CRET (*$CFUNCNAME)($CARGS);")
- end
- local function doxygen_funcret(r, func, prefix)
- if not func or func.ret.fulltype == "void" or func.ret.comment == nil then
- return
- end
- r[#r+1] = prefix
- r[#r+1] = string.format("%s @returns %s", prefix, func.ret.comment[1])
- for i = 2,#func.ret.comment do
- r[#r+1] = string.format("%s %s", prefix, func.ret.comment[i])
- end
- return r
- end
- local function doxygen_func(r, func, prefix)
- if not func or not func.args or #func.args == 0 then
- return
- end
- r[#r+1] = prefix
- for _, arg in ipairs(func.args) do
- local inout
- if arg.out then
- inout = "out"
- elseif arg.inout then
- inout = "inout"
- else
- inout = "in"
- end
- local comment = string.format("%s @param[%s] %s", prefix, inout, arg.name)
- if arg.comment then
- r[#r+1] = comment .. " " .. arg.comment[1]
- for i = 2,#arg.comment do
- r[#r+1] = string.format("%s %s", prefix, arg.comment[i])
- end
- else
- r[#r+1] = comment
- end
- end
- doxygen_funcret(r, func, prefix)
- return r
- end
- function codegen.doxygen_type(doxygen, func, cname)
- if doxygen == nil then
- return
- end
- local result = {}
- for _, line in ipairs(doxygen) do
- result[#result+1] = "/// " .. line
- end
- doxygen_func(result, func, "///")
- if cname then
- result[#result+1] = "///"
- if type(cname) == "string" then
- result[#result+1] = string.format("/// @attention C99's equivalent binding is `%s`.", cname)
- else
- local names = {}
- for _, v in ipairs(cname) do
- names[#names+1] = "`" .. v .. "`"
- end
- result[#result+1] = string.format("/// @attention C99's equivalent bindings are %s.", table.concat(names, ","))
- end
- end
- result[#result+1] = "///"
- return table.concat(result, "\n")
- end
- function codegen.doxygen_ctype(doxygen, func)
- if doxygen == nil then
- return
- end
- local result = {
- "/**",
- }
- for _, line in ipairs(doxygen) do
- result[#result+1] = " * " .. line
- end
- doxygen_func(result, func, " *")
- result[#result+1] = " *"
- result[#result+1] = " */"
- return table.concat(result, "\n")
- end
- local enum_temp = [[
- struct $NAME
- {
- $COMMENT
- enum Enum
- {
- $ITEMS
- Count
- };
- };
- ]]
- function codegen.gen_enum_define(enum)
- assert(type(enum.enum) == "table", "Not an enum")
- local items = {}
- for _, item in ipairs(enum.enum) do
- local text
- if not item.comment then
- text = item.name .. ","
- else
- local comment = table.concat(item.comment, " ")
- text = string.format("%s,%s //!< %s",
- item.name, namealign(item.name), comment)
- end
- items[#items+1] = text
- end
- local comment = ""
- if enum.comment then
- comment = "/// " .. enum.comment
- end
- local temp = {
- NAME = enum.typename,
- COMMENT = comment,
- ITEMS = table.concat(items, "\n\t\t"),
- }
- return (enum_temp:gsub("$(%u+)", temp))
- end
- local cenum_temp = [[
- typedef enum $NAME
- {
- $ITEMS
- $COUNT
- } $NAME_t;
- ]]
- function codegen.gen_enum_cdefine(enum)
- assert(type(enum.enum) == "table", "Not an enum")
- local cname = enum.cname:match "(.-)_t$"
- local uname = cname:upper()
- local items = {}
- for index , item in ipairs(enum.enum) do
- local comment = ""
- if item.comment then
- comment = table.concat(item.comment, " ")
- end
- local ename = item.cname
- if not ename then
- if enum.underscore then
- ename = camelcase_to_underscorecase(item.name)
- else
- ename = item.name
- end
- ename = ename:upper()
- end
- local name = uname .. "_" .. ename
- items[#items+1] = string.format("%s,%s /** (%2d) %s%s */",
- name,
- namealign(name, 40),
- index - 1,
- comment,
- namealign(comment, 30))
- end
- local temp = {
- NAME = cname,
- COUNT = uname .. "_COUNT",
- ITEMS = table.concat(items, "\n\t"),
- }
- return (cenum_temp:gsub("$(%u+)", temp))
- end
- local function flag_format(flag)
- if not flag.format then
- flag.format = "%0" .. (flag.bits // 4) .. "x"
- end
- end
- function codegen.gen_flag_cdefine(flag)
- assert(type(flag.flag) == "table", "Not a flag")
- flag_format(flag)
- local cname = "BGFX_" .. (flag.cname or to_underscorecase(flag.name):upper())
- local s = {}
- local shift = flag.shift
- for index, item in ipairs(flag.flag) do
- local name
- if item.cname then
- name = cname .. "_" .. item.cname
- else
- name = cname .. "_" .. to_underscorecase(item.name):upper()
- end
- local value = item.value
- -- combine flags
- if #item > 0 then
- if item.comment then
- for _, c in ipairs(item.comment) do
- s[#s+1] = "/// " .. c
- end
- end
- local sets = { "" }
- for _, v in ipairs(item) do
- sets[#sets+1] = cname .. "_" .. to_underscorecase(v):upper()
- end
- s[#s+1] = string.format("#define %s (0%s \\\n\t)\n", name, table.concat(sets, " \\\n\t| "))
- else
- local comment = ""
- if item.comment then
- if #item.comment > 1 then
- s[#s+1] = ""
- for _, c in ipairs(item.comment) do
- s[#s+1] = "/// " .. c
- end
- else
- comment = " //!< " .. item.comment[1]
- end
- end
- value = string.format(flag.format, value)
- local code = string.format("#define %s %sUINT%d_C(0x%s)%s",
- name, namealign(name, DEFINE_NAME_ALIGN), flag.bits, value, comment)
- s[#s+1] = code
- end
- end
- local mask
- if flag.mask then
- mask = string.format(flag.format, flag.mask)
- mask = string.format("UINT%d_C(0x%s)", flag.bits, mask)
- end
- if shift then
- local name = cname .. "_SHIFT"
- local comment = flag.desc or ""
- local shift_align = tostring(shift)
- shift_align = shift_align .. namealign(shift_align, #mask)
- local comment = ""
- if flag.desc then
- comment = string.format(" //!< %s bit shift", flag.desc)
- end
- local code = string.format("#define %s %s%s%s", name, namealign(name, DEFINE_NAME_ALIGN), shift_align, comment)
- s[#s+1] = code
- end
- if flag.range then
- local name = cname .. "_MASK"
- local comment = ""
- if flag.desc then
- comment = string.format(" //!< %s bit mask", flag.desc)
- end
- local code = string.format("#define %s %s%s%s", name, namealign(name, DEFINE_NAME_ALIGN), mask, comment)
- s[#s+1] = code
- end
- if flag.helper then
- s[#s+1] = string.format(
- "#define %s(v) ( ( (uint%d_t)(v)<<%s )&%s)",
- cname,
- flag.bits,
- (cname .. "_SHIFT"),
- (cname .. "_MASK"))
- end
- s[#s+1] = ""
- return table.concat(s, "\n")
- end
- local function text_with_comments(items, item, cstyle, is_classmember)
- local name = item.name
- if item.array then
- if cstyle then
- name = name .. (item.carray or item.array)
- else
- name = name .. item.array
- end
- end
- local typename
- if cstyle then
- typename = item.ctype
- else
- typename = item.fulltype
- end
- if is_classmember then
- name = "m_" .. name
- end
- local text = string.format("%s%s %s;", typename, namealign(typename), name)
- if item.comment then
- if #item.comment > 1 then
- table.insert(items, "")
- if cstyle then
- table.insert(items, "/**")
- for _, c in ipairs(item.comment) do
- table.insert(items, " * " .. c)
- end
- table.insert(items, " */")
- else
- for _, c in ipairs(item.comment) do
- table.insert(items, "/// " .. c)
- end
- end
- else
- text = string.format(
- cstyle and "%s %s/** %s%s */" or "%s %s//!< %s",
- text, namealign(text, 40), item.comment[1], namealign(item.comment[1], 40))
- end
- end
- items[#items+1] = text
- end
- local struct_temp = [[
- struct $NAME
- {
- $METHODS
- $SUBSTRUCTS
- $ITEMS
- };
- ]]
- function codegen.gen_struct_define(struct, methods)
- assert(type(struct.struct) == "table", "Not a struct")
- local items = {}
- for _, item in ipairs(struct.struct) do
- text_with_comments(items, item, false, methods ~= nil and not struct.shortname)
- end
- local ctor = {}
- if struct.ctor then
- ctor[1] = struct.name .. "();"
- ctor[2] = ""
- end
- if methods then
- for _, m in ipairs(methods) do
- if m:sub(-1) ~= "\n" then
- m = m .. "\n"
- end
- for line in m:gmatch "(.-)\n" do
- ctor[#ctor+1] = line
- end
- ctor[#ctor+1] = ""
- end
- end
- local subs = {}
- if struct.substruct then
- for _, v in ipairs(struct.substruct) do
- local s = codegen.gen_struct_define(v)
- s = s:gsub("\n", "\n\t")
- subs[#subs+1] = s
- end
- end
- local temp = {
- NAME = struct.name,
- SUBSTRUCTS = lines(subs),
- ITEMS = table.concat(items, "\n\t"),
- METHODS = lines(ctor),
- }
- return remove_emptylines(struct_temp:gsub("$(%u+)", temp))
- end
- local cstruct_temp = [[
- typedef struct $NAME_s
- {
- $ITEMS
- } $NAME_t;
- ]]
- local cstruct_empty_temp = [[
- struct $NAME_s;
- typedef struct $NAME_s $NAME_t;
- ]]
- function codegen.gen_struct_cdefine(struct)
- assert(type(struct.struct) == "table", "Not a struct")
- local cname = struct.cname:match "(.-)_t$"
- local items = {}
- for _, item in ipairs(struct.struct) do
- text_with_comments(items, item, true)
- end
- local temp = {
- NAME = cname,
- ITEMS = table.concat(items, "\n\t"),
- }
- local codetemp = #struct.struct == 0 and cstruct_empty_temp or cstruct_temp
- return (codetemp:gsub("$(%u+)", temp))
- end
- local chandle_temp = [[
- typedef struct $NAME_s { uint16_t idx; } $NAME_t;
- ]]
- function codegen.gen_chandle(handle)
- assert(handle.handle, "Not a handle")
- return (chandle_temp:gsub("$(%u+)", { NAME = handle.cname:match "(.-)_t$" }))
- end
- local handle_temp = [[
- struct $NAME { uint16_t idx; };
- inline bool isValid($NAME _handle) { return bgfx::kInvalidHandle != _handle.idx; }
- ]]
- function codegen.gen_handle(handle)
- assert(handle.handle, "Not a handle")
- return (handle_temp:gsub("$(%u+)", { NAME = handle.name }))
- end
- local idl = require "idl"
- local doxygen = require "doxygen"
- local conversion
- local idlfile = {}
- function codegen.load(filename)
- assert(conversion == nil, "Don't call codegen.load() after codegen.idl()")
- assert(idlfile[filename] == nil, "Duplicate load " .. filename)
- local source = doxygen.load(filename)
- local f = assert(load(source, filename , "t", idl))
- f()
- idlfile[filename] = true
- end
- function codegen.idl(filename)
- if conversion == nil then
- if filename and not idlfile[filename] then
- codegen.load(filename)
- end
- assert(next(idlfile), "call codegen.load() first")
- conversion = true
- codegen.nameconversion(idl.types, idl.funcs)
- end
- return idl
- end
- return codegen
|