bgfx-codegen.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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 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. m[#m+1] = cppdecl(func)
  160. end
  161. methods = m
  162. end
  163. return add_doxygen(typedef, codegen.gen_struct_define(typedef, methods))
  164. end
  165. end
  166. function typegen.cstructs(typedef)
  167. if typedef.struct then
  168. return add_doxygen(typedef, codegen.gen_struct_cdefine(typedef), true)
  169. end
  170. end
  171. function typegen.handles(typedef)
  172. if typedef.handle then
  173. return codegen.gen_handle(typedef)
  174. end
  175. end
  176. function typegen.chandles(typedef)
  177. if typedef.handle then
  178. return codegen.gen_chandle(typedef)
  179. end
  180. end
  181. function typegen.funcptrs(typedef)
  182. if typedef.args then
  183. return add_doxygen(typedef, codegen.gen_funcptr(typedef))
  184. end
  185. end
  186. function typegen.cfuncptrs(typedef)
  187. if typedef.args then
  188. return add_doxygen(typedef, codegen.gen_cfuncptr(typedef), true)
  189. end
  190. end
  191. local function codes()
  192. local temp = {}
  193. for k in pairs(func_actions) do
  194. temp[k] = {}
  195. end
  196. for k in pairs(type_actions) do
  197. temp[k] = {}
  198. end
  199. -- call actions with func
  200. for _, f in ipairs(idl.funcs) do
  201. for k in pairs(func_actions) do
  202. local funcgen = funcgen[k]
  203. if funcgen then
  204. table.insert(temp[k], (funcgen(f)))
  205. end
  206. end
  207. end
  208. -- call actions with type
  209. for _, typedef in ipairs(idl.types) do
  210. for k in pairs(type_actions) do
  211. local typegen = typegen[k]
  212. if typegen then
  213. table.insert(temp[k], (typegen(typedef)))
  214. end
  215. end
  216. end
  217. for k, indent in pairs(func_actions) do
  218. temp[k] = table.concat(temp[k], indent)
  219. end
  220. for k, indent in pairs(type_actions) do
  221. temp[k] = table.concat(temp[k], indent)
  222. end
  223. temp.version = string.format("#define BGFX_API_VERSION UINT32_C(%d)", idl._version or 0)
  224. return temp
  225. end
  226. local codes_tbl = codes()
  227. local function add_path(filename)
  228. local path
  229. if type(paths) == "string" then
  230. path = paths
  231. else
  232. path = assert(paths[filename])
  233. end
  234. return path .. "/" .. filename
  235. end
  236. local function change_indent(str, indent)
  237. if indent == "\t" then
  238. -- strip trailing space only
  239. return (str:gsub("(.-)\n", function (line)
  240. return line:gsub("([ \t]*)$","\n") end))
  241. else
  242. return (str:gsub("(.-)\n", function (line)
  243. return line:gsub("^(\t*)(.-)[ \t]*$",
  244. function (tabs, content)
  245. return indent:rep(#tabs) .. content .. "\n"
  246. end)
  247. end))
  248. end
  249. end
  250. local gen = {}
  251. function gen.apply(tempfile)
  252. local f = assert(io.open(tempfile, "rb"))
  253. local temp = f:read "a"
  254. f:close()
  255. codes_tbl.source = tempfile
  256. return (temp:gsub("$([%l%d_]+)", codes_tbl))
  257. end
  258. function gen.format(codes, f)
  259. return change_indent(codes, f.indent)
  260. end
  261. function gen.changed(codes, outputfile)
  262. local out = io.open(outputfile, "rb")
  263. if out then
  264. local origin = out:read "a"
  265. out:close()
  266. return origin ~= codes
  267. end
  268. return true
  269. end
  270. function gen.write(codes, outputfile)
  271. local out = assert(io.open(outputfile, "wb"))
  272. out:write(codes)
  273. out:close()
  274. end
  275. function gen.gen(tempfile, outputfile, indent)
  276. print ("Generate", outputfile, "from", tempfile)
  277. local codes = gen.apply(tempfile)
  278. codes = change_indent(codes, indent)
  279. if not gen.changed(codes, outputfile) then
  280. print("No change")
  281. end
  282. gen.write(codes, outputfile)
  283. end
  284. return gen