bgfx-codegen.lua 7.0 KB

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