diff --git a/scripts/bgfx-codegen.lua b/scripts/bgfx-codegen.lua new file mode 100644 index 000000000..11bc96b95 --- /dev/null +++ b/scripts/bgfx-codegen.lua @@ -0,0 +1,328 @@ +-- Copyright 2019 云风 https://github.com/cloudwu . All rights reserved. +-- License (the same with bgfx) : https://github.com/bkaradzic/bgfx/blob/master/LICENSE + +local idl = require "idl" +local codegen = require "codegen" +local doxygen = require "doxygen" + +local func_actions = { + c99 = "\n", + c99decl = "\n", + cppdecl = "\n", + interface_struct = "\n\t", + interface_import = ",\n\t\t\t", + c99_interface = "\n", + cpp_interface = "\n", + c99_functionid = "\n\t", + cpp_functionid = "\n\t\t", +} + +local type_actions = { + enums = "\n", + cenums = "\n", + structs = "\n", + cstructs = "\n", + handles = "\n", + chandles = "\n", + funcptrs = "\n", + cfuncptrs = "\n", +} + +do + local source = doxygen.load "bgfx.idl" + local f = assert(load(source, "bgfx.idl" , "t", idl)) + f() +end + +codegen.nameconversion(idl.types, idl.funcs) + +local function cfunc(f) + return function(func) + if not func.cpponly then + return f(func) + end + end +end + +local funcgen = {} + +local functemp = {} + +functemp.interface_struct = "$CRET (*$CFUNCNAME)($CARGS);" +functemp.interface_import = "bgfx_$CFUNCNAME" +functemp.c99_interface = [[ +BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) +{ + $CONVERSIONCTOC + $PRERETCTOCg_interface->$CFUNCNAME($CALLARGS); + $POSTRETCTOC +} +]] +functemp.c99_functionid = "BGFX_FUNCTION_ID_$CFUNCNAMEUPPER," +functemp.cpp_functionid = "$CFUNCNAMECAML," + +for action,temp in pairs(functemp) do + funcgen[action] = cfunc(function(func) + return codegen.apply_functemp(func, temp) + end) +end + +funcgen.cpp_interface= cfunc(function(func) + if not func.cfunc and not func.conly then + return codegen.apply_functemp(func, [[ +$RET $CLASSNAME$FUNCNAME($CPPARGS)$CONST +{ + $CONVERSIONCTOCPP + $PRERETCPPTOCg_interface->$CFUNCNAME($CALLARGSCPPTOC); + $POSTRETCPPTOC +} +]]) + end +end) + +funcgen.c99 = cfunc(function(func) + local temp + if func.cfunc then + temp = "/* BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) */\n" + else + temp = [[ +BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) +{ + $CONVERSION + $PRERET$CPPFUNC($CALLARGSCTOCPP); + $POSTRET +} +]] + end + return codegen.apply_functemp(func, temp) +end) + +local function cppdecl(func) + local doc = func.comments + if not doc and func.comment then + doc = { func.comment } + end + if doc then + local cname + if not func.cpponly then + if func.multicfunc then + cname = {} + for _, name in ipairs(func.multicfunc) do + cname[#cname+1] = "bgfx_" .. name + end + else + cname = "bgfx_" .. func.cname + end + end + doc = codegen.doxygen_type(doc, func, cname) + end + local funcdecl = codegen.apply_functemp(func, "$RET $FUNCNAME($ARGS)$CONST;\n") + if doc then + return doc .. "\n" .. funcdecl + else + return funcdecl + end +end + +function funcgen.cppdecl(func) + -- Don't generate member functions here + if not func.class and not func.conly then + return cppdecl(func) + end +end + +funcgen.c99decl = cfunc(function(func) + local doc = func.comments + if not doc and func.comment then + doc = { func.comment } + end + if doc then + doc = codegen.doxygen_ctype(doc, func) + end + local funcdecl = codegen.apply_functemp(func, "BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS);") + if doc then + return "\n" .. doc .. "\n" .. funcdecl + else + return funcdecl + end +end) + +local typegen = {} + +local function add_doxygen(typedef, define, cstyle, cname) + local func = cstyle and codegen.doxygen_ctype or codegen.doxygen_type + local doc = func(typedef.comments, typedef, cname or typedef.cname) + if doc then + return doc .. "\n" .. define + else + return define + end +end + +function typegen.enums(typedef) + if typedef.enum then + return add_doxygen(typedef, codegen.gen_enum_define(typedef), false, "bgfx_" .. typedef.cname) + end +end + +function typegen.cenums(typedef) + if typedef.enum then + return add_doxygen(typedef, codegen.gen_enum_cdefine(typedef), true) + end +end + +function typegen.structs(typedef) + if typedef.struct and not typedef.namespace then + local methods = typedef.methods + if methods then + local m = {} + for _, func in ipairs(methods) do + m[#m+1] = cppdecl(func) + end + methods = m + end + return add_doxygen(typedef, codegen.gen_struct_define(typedef, methods)) + end +end + +function typegen.cstructs(typedef) + if typedef.struct then + return add_doxygen(typedef, codegen.gen_struct_cdefine(typedef), true) + end +end + +function typegen.handles(typedef) + if typedef.handle then + return codegen.gen_handle(typedef) + end +end + +function typegen.chandles(typedef) + if typedef.handle then + return codegen.gen_chandle(typedef) + end +end + +function typegen.funcptrs(typedef) + if typedef.args then + return add_doxygen(typedef, codegen.gen_funcptr(typedef)) + end +end + +function typegen.cfuncptrs(typedef) + if typedef.args then + return add_doxygen(typedef, codegen.gen_cfuncptr(typedef), true) + end +end + +local function codes() + local temp = {} + for k in pairs(func_actions) do + temp[k] = {} + end + + for k in pairs(type_actions) do + temp[k] = {} + end + + -- call actions with func + for _, f in ipairs(idl.funcs) do + for k in pairs(func_actions) do + local funcgen = funcgen[k] + if funcgen then + table.insert(temp[k], (funcgen(f))) + end + end + end + + -- call actions with type + + for _, typedef in ipairs(idl.types) do + for k in pairs(type_actions) do + local typegen = typegen[k] + if typegen then + table.insert(temp[k], (typegen(typedef))) + end + end + end + + for k, indent in pairs(func_actions) do + temp[k] = table.concat(temp[k], indent) + end + for k, indent in pairs(type_actions) do + temp[k] = table.concat(temp[k], indent) + end + + return temp +end + +local codes_tbl = codes() + +local function add_path(filename) + local path + if type(paths) == "string" then + path = paths + else + path = assert(paths[filename]) + end + return path .. "/" .. filename +end + +local function change_indent(str, indent) + if indent == "\t" then + -- strip trailing space only + return (str:gsub("(.-)\n", function (line) + return line:gsub("([ \t]*)$","\n") end)) + else + return (str:gsub("(.-)\n", function (line) + return line:gsub("^(\t*)(.-)[ \t]*$", + function (tabs, content) + return indent:rep(#tabs) .. content .. "\n" + end) + end)) + end +end + +local gen = {} + +function gen.apply(tempfile) + local f = assert(io.open(tempfile, "rb")) + local temp = f:read "a" + f:close() + codes_tbl.source = tempfile + return (temp:gsub("$([%l%d_]+)", codes_tbl)) +end + +function gen.format(codes, f) + return change_indent(codes, f.indent) +end + +function gen.changed(codes, outputfile) + local out = io.open(outputfile, "rb") + if out then + local origin = out:read "a" + out:close() + return origin ~= codes + end + return true +end + +function gen.write(codes, outputfile) + local out = assert(io.open(outputfile, "wb")) + out:write(codes) + out:close() +end + +function gen.gen(tempfile, outputfile, indent) + print ("Generate", outputfile, "from", tempfile) + local codes = gen.apply(tempfile) + codes = change_indent(codes, indent) + + if not gen.changed(codes, outputfile) then + print("No change") + end + + gen.write(codes, outputfile) +end + +return gen diff --git a/scripts/bgfx-idl.lua b/scripts/bgfx-idl.lua deleted file mode 100644 index d1d4cc8ef..000000000 --- a/scripts/bgfx-idl.lua +++ /dev/null @@ -1,305 +0,0 @@ --- Copyright 2019 云风 https://github.com/cloudwu . All rights reserved. --- License (the same with bgfx) : https://github.com/bkaradzic/bgfx/blob/master/LICENSE - -function doIdl() - - local idl = require "idl" - local codegen = require "codegen" - local doxygen = require "doxygen" - - local func_actions = { - c99 = "\n", - c99decl = "\n", - cppdecl = "\n", - interface_struct = "\n\t", - interface_import = ",\n\t\t\t", - c99_interface = "\n", - cpp_interface = "\n", - c99_functionid = "\n\t", - cpp_functionid = "\n\t\t", - } - - local type_actions = { - enums = "\n", - cenums = "\n", - structs = "\n", - cstructs = "\n", - handles = "\n", - chandles = "\n", - funcptrs = "\n", - cfuncptrs = "\n", - } - - do - local source = doxygen.load "bgfx.idl" - local f = assert(load(source, "bgfx.idl" , "t", idl)) - f() - end - - codegen.nameconversion(idl.types, idl.funcs) - - local function cfunc(f) - return function(func) - if not func.cpponly then - return f(func) - end - end - end - - local funcgen = {} - - local functemp = {} - - functemp.interface_struct = "$CRET (*$CFUNCNAME)($CARGS);" - functemp.interface_import = "bgfx_$CFUNCNAME" - functemp.c99_interface = [[ - BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) - { - $CONVERSIONCTOC - $PRERETCTOCg_interface->$CFUNCNAME($CALLARGS); - $POSTRETCTOC - } - ]] - functemp.c99_functionid = "BGFX_FUNCTION_ID_$CFUNCNAMEUPPER," - functemp.cpp_functionid = "$CFUNCNAMECAML," - - for action,temp in pairs(functemp) do - funcgen[action] = cfunc(function(func) - return codegen.apply_functemp(func, temp) - end) - end - - funcgen.cpp_interface= cfunc(function(func) - if not func.cfunc and not func.conly then - return codegen.apply_functemp(func, [[ - $RET $CLASSNAME$FUNCNAME($CPPARGS)$CONST - { - $CONVERSIONCTOCPP - $PRERETCPPTOCg_interface->$CFUNCNAME($CALLARGSCPPTOC); - $POSTRETCPPTOC - } - ]]) - end - end) - - funcgen.c99 = cfunc(function(func) - local temp - if func.cfunc then - temp = "/* BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) */\n" - else - temp = [[ - BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) - { - $CONVERSION - $PRERET$CPPFUNC($CALLARGSCTOCPP); - $POSTRET - } - ]] - end - return codegen.apply_functemp(func, temp) - end) - - local function cppdecl(func) - local doc = func.comments - if not doc and func.comment then - doc = { func.comment } - end - if doc then - local cname - if not func.cpponly then - if func.multicfunc then - cname = {} - for _, name in ipairs(func.multicfunc) do - cname[#cname+1] = "bgfx_" .. name - end - else - cname = "bgfx_" .. func.cname - end - end - doc = codegen.doxygen_type(doc, func, cname) - end - local funcdecl = codegen.apply_functemp(func, "$RET $FUNCNAME($ARGS)$CONST;\n") - if doc then - return doc .. "\n" .. funcdecl - else - return funcdecl - end - end - - function funcgen.cppdecl(func) - -- Don't generate member functions here - if not func.class and not func.conly then - return cppdecl(func) - end - end - - funcgen.c99decl = cfunc(function(func) - local doc = func.comments - if not doc and func.comment then - doc = { func.comment } - end - if doc then - doc = codegen.doxygen_ctype(doc, func) - end - local funcdecl = codegen.apply_functemp(func, "BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS);") - if doc then - return "\n" .. doc .. "\n" .. funcdecl - else - return funcdecl - end - end) - - local typegen = {} - - local function add_doxygen(typedef, define, cstyle, cname) - local func = cstyle and codegen.doxygen_ctype or codegen.doxygen_type - local doc = func(typedef.comments, typedef, cname or typedef.cname) - if doc then - return doc .. "\n" .. define - else - return define - end - end - - function typegen.enums(typedef) - if typedef.enum then - return add_doxygen(typedef, codegen.gen_enum_define(typedef), false, "bgfx_" .. typedef.cname) - end - end - - function typegen.cenums(typedef) - if typedef.enum then - return add_doxygen(typedef, codegen.gen_enum_cdefine(typedef), true) - end - end - - function typegen.structs(typedef) - if typedef.struct and not typedef.namespace then - local methods = typedef.methods - if methods then - local m = {} - for _, func in ipairs(methods) do - m[#m+1] = cppdecl(func) - end - methods = m - end - return add_doxygen(typedef, codegen.gen_struct_define(typedef, methods)) - end - end - - function typegen.cstructs(typedef) - if typedef.struct then - return add_doxygen(typedef, codegen.gen_struct_cdefine(typedef), true) - end - end - - function typegen.handles(typedef) - if typedef.handle then - return codegen.gen_handle(typedef) - end - end - - function typegen.chandles(typedef) - if typedef.handle then - return codegen.gen_chandle(typedef) - end - end - - function typegen.funcptrs(typedef) - if typedef.args then - return add_doxygen(typedef, codegen.gen_funcptr(typedef)) - end - end - - function typegen.cfuncptrs(typedef) - if typedef.args then - return add_doxygen(typedef, codegen.gen_cfuncptr(typedef), true) - end - end - - local function codes() - local temp = {} - for k in pairs(func_actions) do - temp[k] = {} - end - - for k in pairs(type_actions) do - temp[k] = {} - end - - -- call actions with func - for _, f in ipairs(idl.funcs) do - for k in pairs(func_actions) do - local funcgen = funcgen[k] - if funcgen then - table.insert(temp[k], (funcgen(f))) - end - end - end - - -- call actions with type - - for _, typedef in ipairs(idl.types) do - for k in pairs(type_actions) do - local typegen = typegen[k] - if typegen then - table.insert(temp[k], (typegen(typedef))) - end - end - end - - for k, indent in pairs(func_actions) do - temp[k] = table.concat(temp[k], indent) - end - for k, indent in pairs(type_actions) do - temp[k] = table.concat(temp[k], indent) - end - - return temp - end - - local codes_tbl = codes() - - local function add_path(filename) - local path - if type(paths) == "string" then - path = paths - else - path = assert(paths[filename]) - end - return path .. "/" .. filename - end - - local function change_indent(str, indent) - return (str:gsub("(.-)\n", function (line) - return line:gsub("^(\t*)(.-)[ \t]*$", - function (tabs, content) - return indent:rep(#tabs) .. content .. "\n" - end) - end)) - end - - local function genidl(filename, outputfile, indent) - local tempfile = "temp." .. filename - print ("Generate", outputfile, "from", tempfile) - local f = assert(io.open(tempfile, "rb")) - local temp = f:read "a" - f:close() - local out = assert(io.open(outputfile, "wb")) - codes_tbl.source = tempfile - local codes = temp:gsub("$([%l%d_]+)", codes_tbl) - out:write(change_indent(codes, indent)) - out:close() - end - - - genidl("bgfx.h", "../include/bgfx/c99/bgfx.h", " ") - genidl("bgfx.idl.inl", "../src/bgfx.idl.inl", "\t") - --genidl("bgfx.h", "../include/bgfx/bgfx.h", "\t") - --genidl("bgfx.shim.cpp", "../src/bgfx.shim.cpp", "\t") - - os.exit() - -end - - diff --git a/scripts/genie.lua b/scripts/genie.lua index ff7c78280..39e48ec5a 100644 --- a/scripts/genie.lua +++ b/scripts/genie.lua @@ -53,12 +53,25 @@ newoption { description = "Enable building examples.", } -dofile "bgfx-idl.lua" - newaction { trigger = "idl", description = "Generate bgfx interface source code", - execute = doIdl + execute = function () + + local gen = require "bgfx-codegen" + + local function generate(tempfile, outputfile, indent) + local codes = gen.apply(tempfile) + codes = gen.format(codes, {indent = indent}) + gen.write(codes, outputfile) + print("Generating: " .. outputfile) + end + + generate("temp.bgfx.h" , "../include/bgfx/c99/bgfx.h", " ") + generate("temp.bgfx.idl.inl", "../src/bgfx.idl.inl", "\t") + + os.exit() + end } solution "bgfx"