bgfx-codegen.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. -- Copyright 2019 云风 https://github.com/cloudwu . All rights reserved.
  2. -- License (the same with bgfx) : https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  3. local codegen = require "codegen"
  4. local idl = codegen.idl "bgfx.idl"
  5. local func_actions = {
  6. c99 = "\n",
  7. c99decl = "\n",
  8. cppdecl = "\n",
  9. interface_struct = "\n\t",
  10. interface_import = ",\n\t\t\t",
  11. c99_interface = "\n",
  12. cpp_interface = "\n",
  13. c99_functionid = "\n\t",
  14. cpp_functionid = "\n\t\t",
  15. }
  16. local type_actions = {
  17. cflags = "\n",
  18. enums = "\n",
  19. cenums = "\n",
  20. structs = "\n",
  21. cstructs = "\n",
  22. handles = "\n",
  23. chandles = "\n",
  24. funcptrs = "\n",
  25. cfuncptrs = "\n",
  26. }
  27. local function cfunc(f)
  28. return function(func)
  29. if (not func.cpponly) or func.conly then
  30. return f(func)
  31. end
  32. end
  33. end
  34. local funcgen = {}
  35. local functemp = {}
  36. functemp.interface_struct = "$CRET (*$CFUNCNAME)($CARGS);"
  37. functemp.interface_import = "bgfx_$CFUNCNAME"
  38. functemp.c99_interface = [[
  39. BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS)
  40. {
  41. $CONVERSIONCTOC
  42. $PRERETCTOCg_interface->$CFUNCNAME($CALLARGS);
  43. $POSTRETCTOC
  44. }
  45. ]]
  46. functemp.c99_functionid = "BGFX_FUNCTION_ID_$CFUNCNAMEUPPER,"
  47. functemp.cpp_functionid = "$CFUNCNAMECAML,"
  48. for action,temp in pairs(functemp) do
  49. funcgen[action] = cfunc(function(func)
  50. return codegen.apply_functemp(func, temp)
  51. end)
  52. end
  53. funcgen.cpp_interface= cfunc(function(func)
  54. if not func.cfunc and not func.conly then
  55. return codegen.apply_functemp(func, [[
  56. $RET $CLASSNAME$FUNCNAME($CPPARGS)$CONST
  57. {
  58. $CONVERSIONCTOCPP
  59. $PRERETCPPTOCg_interface->$CFUNCNAME($CALLARGSCPPTOC);
  60. $POSTRETCPPTOC
  61. }
  62. ]])
  63. end
  64. end)
  65. funcgen.c99 = cfunc(function(func)
  66. local temp
  67. if func.cfunc then
  68. temp = "/* BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) */\n"
  69. else
  70. temp = [[
  71. BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS)
  72. {
  73. $CONVERSION
  74. $PRERET$CPPFUNC($CALLARGSCTOCPP);
  75. $POSTRET
  76. }
  77. ]]
  78. end
  79. return codegen.apply_functemp(func, temp)
  80. end)
  81. local function cppdecl(func)
  82. local doc = func.comments
  83. if not doc and func.comment then
  84. doc = { func.comment }
  85. end
  86. if doc then
  87. local cname
  88. if not func.cpponly then
  89. if func.multicfunc then
  90. cname = {}
  91. for _, name in ipairs(func.multicfunc) do
  92. cname[#cname+1] = "bgfx_" .. name
  93. end
  94. else
  95. cname = "bgfx_" .. func.cname
  96. end
  97. end
  98. doc = codegen.doxygen_type(doc, func, cname)
  99. end
  100. local funcdecl = codegen.apply_functemp(func, "$RET $FUNCNAME($ARGS)$CONST;\n")
  101. if doc then
  102. return doc .. "\n" .. funcdecl
  103. else
  104. return funcdecl
  105. end
  106. end
  107. function funcgen.cppdecl(func)
  108. -- Don't generate member functions here
  109. if not func.class and not func.conly then
  110. return cppdecl(func)
  111. end
  112. end
  113. funcgen.c99decl = cfunc(function(func)
  114. local doc = func.comments
  115. if not doc and func.comment then
  116. doc = { func.comment }
  117. end
  118. if doc then
  119. doc = codegen.doxygen_ctype(doc, func)
  120. end
  121. local funcdecl = codegen.apply_functemp(func, "BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS);")
  122. if doc then
  123. return "\n" .. doc .. "\n" .. funcdecl
  124. else
  125. return funcdecl
  126. end
  127. end)
  128. local typegen = {}
  129. local function add_doxygen(typedef, define, cstyle, cname)
  130. local func = cstyle and codegen.doxygen_ctype or codegen.doxygen_type
  131. local doc = func(typedef.comments, typedef, cname or typedef.cname)
  132. if doc then
  133. return doc .. "\n" .. define
  134. else
  135. return define
  136. end
  137. end
  138. function typegen.enums(typedef)
  139. if typedef.enum then
  140. return add_doxygen(typedef, codegen.gen_enum_define(typedef), false, "bgfx_" .. typedef.cname)
  141. end
  142. end
  143. function typegen.cenums(typedef)
  144. if typedef.enum then
  145. return add_doxygen(typedef, codegen.gen_enum_cdefine(typedef), true)
  146. end
  147. end
  148. function typegen.cflags(typedef)
  149. if typedef.flag then
  150. return add_doxygen(typedef, codegen.gen_flag_cdefine(typedef), true)
  151. end
  152. end
  153. function typegen.structs(typedef)
  154. if typedef.struct and not typedef.namespace then
  155. local methods = typedef.methods
  156. if methods then
  157. local m = {}
  158. for _, func in ipairs(methods) do
  159. if not func.conly then
  160. m[#m+1] = cppdecl(func)
  161. end
  162. end
  163. methods = m
  164. end
  165. return add_doxygen(typedef, codegen.gen_struct_define(typedef, methods))
  166. end
  167. end
  168. function typegen.cstructs(typedef)
  169. if typedef.struct then
  170. return add_doxygen(typedef, codegen.gen_struct_cdefine(typedef), true)
  171. end
  172. end
  173. function typegen.handles(typedef)
  174. if typedef.handle then
  175. return codegen.gen_handle(typedef)
  176. end
  177. end
  178. function typegen.chandles(typedef)
  179. if typedef.handle then
  180. return codegen.gen_chandle(typedef)
  181. end
  182. end
  183. function typegen.funcptrs(typedef)
  184. if typedef.args then
  185. return add_doxygen(typedef, codegen.gen_funcptr(typedef))
  186. end
  187. end
  188. function typegen.cfuncptrs(typedef)
  189. if typedef.args then
  190. return add_doxygen(typedef, codegen.gen_cfuncptr(typedef), true)
  191. end
  192. end
  193. local function codes()
  194. local temp = {}
  195. for k in pairs(func_actions) do
  196. temp[k] = {}
  197. end
  198. for k in pairs(type_actions) do
  199. temp[k] = {}
  200. end
  201. -- call actions with func
  202. for _, f in ipairs(idl.funcs) do
  203. for k in pairs(func_actions) do
  204. local funcgen = funcgen[k]
  205. if funcgen then
  206. table.insert(temp[k], (funcgen(f)))
  207. end
  208. end
  209. end
  210. -- call actions with type
  211. for _, typedef in ipairs(idl.types) do
  212. for k in pairs(type_actions) do
  213. local typegen = typegen[k]
  214. if typegen then
  215. table.insert(temp[k], (typegen(typedef)))
  216. end
  217. end
  218. end
  219. for k, indent in pairs(func_actions) do
  220. temp[k] = table.concat(temp[k], indent)
  221. end
  222. for k, indent in pairs(type_actions) do
  223. temp[k] = table.concat(temp[k], indent)
  224. end
  225. temp.version = string.format("#define BGFX_API_VERSION UINT32_C(%d)", idl._version or 0)
  226. return temp
  227. end
  228. local codes_tbl = codes()
  229. local function add_path(filename)
  230. local path
  231. if type(paths) == "string" then
  232. path = paths
  233. else
  234. path = assert(paths[filename])
  235. end
  236. return path .. "/" .. filename
  237. end
  238. local function change_indent(str, indent)
  239. if indent == "\t" then
  240. -- strip trailing space only
  241. return (str:gsub("(.-)\n", function (line)
  242. return line:gsub("([ \t]*)$","\n") end))
  243. else
  244. return (str:gsub("(.-)\n", function (line)
  245. return line:gsub("^(\t*)(.-)[ \t]*$",
  246. function (tabs, content)
  247. return indent:rep(#tabs) .. content .. "\n"
  248. end)
  249. end))
  250. end
  251. end
  252. local gen = {}
  253. function gen.apply(tempfile)
  254. local f = assert(io.open(tempfile, "rb"))
  255. local temp = f:read "a"
  256. f:close()
  257. codes_tbl.source = tempfile
  258. return (temp:gsub("$([%l%d_]+)", codes_tbl))
  259. end
  260. function gen.format(codes, f)
  261. return change_indent(codes, f.indent)
  262. end
  263. function gen.changed(codes, outputfile)
  264. local out = io.open(outputfile, "rb")
  265. if out then
  266. local origin = out:read "a"
  267. out:close()
  268. return origin ~= codes
  269. end
  270. return true
  271. end
  272. function gen.write(codes, outputfile)
  273. local out = assert(io.open(outputfile, "wb"))
  274. out:write(codes)
  275. out:close()
  276. end
  277. function gen.gen(tempfile, outputfile, indent)
  278. print ("Generate", outputfile, "from", tempfile)
  279. local codes = gen.apply(tempfile)
  280. codes = change_indent(codes, indent)
  281. if not gen.changed(codes, outputfile) then
  282. print("No change")
  283. end
  284. gen.write(codes, outputfile)
  285. end
  286. return gen