272 lines
6.6 KiB
Lua
272 lines
6.6 KiB
Lua
-- 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 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 convert_typename(name)
|
|
if name:match "^%u" then
|
|
return "bgfx_" .. camelcase_to_underscorecase(name) .. "_t"
|
|
else
|
|
return name
|
|
end
|
|
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, what)
|
|
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
|
|
arg.type = arg.fulltype
|
|
end
|
|
local ctype = all_types[arg.type]
|
|
if not ctype then
|
|
error ("Undefined type " .. arg.fulltype .. " for " .. what)
|
|
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
|
|
arg.aname = arg.name
|
|
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.conversion = string.format(
|
|
"union { %s c; bgfx::%s cpp; } %s = { %s };" ,
|
|
ctype.cname, arg.type, aname, arg.name)
|
|
elseif arg.ref then
|
|
if ctype.cname == arg.type then
|
|
arg.aname = "*" .. arg.name
|
|
elseif arg.out and ctype.enum then
|
|
local aname = alternative_name(arg.name)
|
|
local cpptype = arg.cpptype:match "(.-)%s*&" -- remove &
|
|
arg.aname = aname
|
|
arg.conversion = string.format("%s %s;", cpptype, aname)
|
|
arg.out_conversion = string.format("*%s = (%s)%s;", arg.name, ctype.cname, aname)
|
|
else
|
|
arg.aname = alternative_name(arg.name)
|
|
arg.conversion = string.format(
|
|
"%s %s = *(%s)%s;",
|
|
arg.cpptype, arg.aname, arg.ptype, arg.name)
|
|
end
|
|
else
|
|
arg.aname = string.format(
|
|
"(%s)%s",
|
|
arg.cpptype, arg.name)
|
|
end
|
|
end
|
|
|
|
local function gen_ret_conversion(all_types, func)
|
|
local postfix = { func.vararg and "va_end(argList);" }
|
|
func.ret_postfix = postfix
|
|
|
|
for _, arg in ipairs(func.args) do
|
|
if arg.out_conversion then
|
|
postfix[#postfix+1] = arg.out_conversion
|
|
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, func.ret.type)
|
|
func.ret_prefix = "handle_ret.cpp = "
|
|
postfix[#postfix+1] = "return handle_ret.c;"
|
|
elseif func.ret.fulltype ~= "void" then
|
|
local ctype_conversion = func.ret.type == func.ret.ctype and "" or ("(" .. func.ret.ctype .. ")")
|
|
if #postfix > 0 then
|
|
func.ret_prefix = string.format("%s retValue = %s", func.ret.ctype , ctype_conversion)
|
|
postfix[#postfix+1] = "return retValue;"
|
|
else
|
|
func.ret_prefix = string.format("return %s", ctype_conversion)
|
|
end
|
|
end
|
|
end
|
|
|
|
function codegen.nameconversion(all_types, all_funcs)
|
|
local enums = {}
|
|
for k,v in pairs(all_types) do
|
|
if not v.cname then
|
|
v.cname = convert_typename(k)
|
|
end
|
|
if v.enum then
|
|
enums[#enums+1] = k
|
|
end
|
|
end
|
|
for _, e in ipairs(enums) do
|
|
local t = all_types[e]
|
|
all_types[e] = nil
|
|
all_types[e .. "::Enum"] = t
|
|
end
|
|
|
|
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
|
|
end
|
|
for _, arg in ipairs(v.args) do
|
|
convert_arg(all_types, arg, v.name)
|
|
gen_arg_conversion(all_types, arg)
|
|
end
|
|
if v.vararg then
|
|
local args = v.args
|
|
local vararg = {
|
|
name = "",
|
|
ctype = "...",
|
|
aname = "argList",
|
|
conversion = string.format(
|
|
"va_list argList;\n\tva_start(argList, %s);",
|
|
args[#args].name),
|
|
}
|
|
args[#args + 1] = vararg
|
|
v.implname = v.vararg
|
|
else
|
|
v.implname = v.name
|
|
end
|
|
convert_arg(all_types, v.ret, v.name .. "@rettype")
|
|
gen_ret_conversion(all_types, v)
|
|
if v.class then
|
|
local classname = v.class
|
|
if v.const then
|
|
classname = "const " .. classname
|
|
end
|
|
local classtype = { fulltype = classname .. "*" }
|
|
convert_arg(all_types, classtype, "class member " .. v.name)
|
|
v.this = classtype.ctype .. " _this"
|
|
v.this_conversion = string.format( "%s This = (%s)_this;", classtype.cpptype, classtype.cpptype)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function lines(tbl)
|
|
if #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 args = {}
|
|
local callargs = {}
|
|
local cppfunc
|
|
if func.class then
|
|
-- It's a member function
|
|
args[1] = func.this
|
|
conversion[1] = func.this_conversion
|
|
cppfunc = "This->" .. func.name
|
|
else
|
|
cppfunc = "bgfx::" .. func.implname
|
|
end
|
|
for _, arg in ipairs(func.args) do
|
|
conversion[#conversion+1] = arg.conversion
|
|
args[#args+1] = arg.ctype .. " " .. arg.name
|
|
callargs[#callargs+1] = arg.aname
|
|
end
|
|
conversion[#conversion+1] = func.ret_conversion
|
|
|
|
return {
|
|
RET = func.ret.ctype,
|
|
FUNCNAME = func.cname,
|
|
ARGS = table.concat(args, ", "),
|
|
CONVERSION = lines(conversion),
|
|
PRERET = func.ret_prefix or "",
|
|
CPPFUNC = cppfunc,
|
|
CALLARGS = table.concat(callargs, ", "),
|
|
POSTRET = lines(func.ret_postfix),
|
|
CODE = func.cfunc,
|
|
}
|
|
end
|
|
|
|
local function apply_template(func, temp)
|
|
func.codetemp = func.codetemp or codetemp(func)
|
|
return (temp:gsub("$(%u+)", func.codetemp))
|
|
end
|
|
|
|
local c99temp = [[
|
|
BGFX_C_API $RET bgfx_$FUNCNAME($ARGS)
|
|
{
|
|
$CONVERSION
|
|
$PRERET$CPPFUNC($CALLARGS);
|
|
$POSTRET
|
|
}
|
|
]]
|
|
|
|
local c99usertemp = [[
|
|
BGFX_C_API $RET bgfx_$FUNCNAME($ARGS)
|
|
{
|
|
$CODE
|
|
}
|
|
]]
|
|
|
|
function codegen.gen_c99(func)
|
|
if func.cfunc then
|
|
return apply_template(func, c99usertemp)
|
|
else
|
|
return remove_emptylines(apply_template(func, c99temp))
|
|
end
|
|
end
|
|
|
|
local template_function_declaration = [[
|
|
/**/
|
|
BGFX_C_API $RET bgfx_$FUNCNAME($ARGS);
|
|
]]
|
|
|
|
function codegen.gen_c99decl(func)
|
|
return apply_template(func, template_function_declaration)
|
|
end
|
|
|
|
function codegen.gen_interface_struct(func)
|
|
return apply_template(func, "$RET (*$FUNCNAME)($ARGS);")
|
|
end
|
|
|
|
function codegen.gen_interface_import(func)
|
|
return "bgfx_" .. func.cname
|
|
end
|
|
|
|
return codegen
|