bgfx-codegen.lua 6.8 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 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. 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. do
  28. local source = doxygen.load "bgfx.idl"
  29. local f = assert(load(source, "bgfx.idl" , "t", idl))
  30. f()
  31. end
  32. codegen.nameconversion(idl.types, idl.funcs)
  33. local function cfunc(f)
  34. return function(func)
  35. if not func.cpponly then
  36. return f(func)
  37. end
  38. end
  39. end
  40. local funcgen = {}
  41. local functemp = {}
  42. functemp.interface_struct = "$CRET (*$CFUNCNAME)($CARGS);"
  43. functemp.interface_import = "bgfx_$CFUNCNAME"
  44. functemp.c99_interface = [[
  45. BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS)
  46. {
  47. $CONVERSIONCTOC
  48. $PRERETCTOCg_interface->$CFUNCNAME($CALLARGS);
  49. $POSTRETCTOC
  50. }
  51. ]]
  52. functemp.c99_functionid = "BGFX_FUNCTION_ID_$CFUNCNAMEUPPER,"
  53. functemp.cpp_functionid = "$CFUNCNAMECAML,"
  54. for action,temp in pairs(functemp) do
  55. funcgen[action] = cfunc(function(func)
  56. return codegen.apply_functemp(func, temp)
  57. end)
  58. end
  59. funcgen.cpp_interface= cfunc(function(func)
  60. if not func.cfunc and not func.conly then
  61. return codegen.apply_functemp(func, [[
  62. $RET $CLASSNAME$FUNCNAME($CPPARGS)$CONST
  63. {
  64. $CONVERSIONCTOCPP
  65. $PRERETCPPTOCg_interface->$CFUNCNAME($CALLARGSCPPTOC);
  66. $POSTRETCPPTOC
  67. }
  68. ]])
  69. end
  70. end)
  71. funcgen.c99 = cfunc(function(func)
  72. local temp
  73. if func.cfunc then
  74. temp = "/* BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS) */\n"
  75. else
  76. temp = [[
  77. BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS)
  78. {
  79. $CONVERSION
  80. $PRERET$CPPFUNC($CALLARGSCTOCPP);
  81. $POSTRET
  82. }
  83. ]]
  84. end
  85. return codegen.apply_functemp(func, temp)
  86. end)
  87. local function cppdecl(func)
  88. local doc = func.comments
  89. if not doc and func.comment then
  90. doc = { func.comment }
  91. end
  92. if doc then
  93. local cname
  94. if not func.cpponly then
  95. if func.multicfunc then
  96. cname = {}
  97. for _, name in ipairs(func.multicfunc) do
  98. cname[#cname+1] = "bgfx_" .. name
  99. end
  100. else
  101. cname = "bgfx_" .. func.cname
  102. end
  103. end
  104. doc = codegen.doxygen_type(doc, func, cname)
  105. end
  106. local funcdecl = codegen.apply_functemp(func, "$RET $FUNCNAME($ARGS)$CONST;\n")
  107. if doc then
  108. return doc .. "\n" .. funcdecl
  109. else
  110. return funcdecl
  111. end
  112. end
  113. function funcgen.cppdecl(func)
  114. -- Don't generate member functions here
  115. if not func.class and not func.conly then
  116. return cppdecl(func)
  117. end
  118. end
  119. funcgen.c99decl = cfunc(function(func)
  120. local doc = func.comments
  121. if not doc and func.comment then
  122. doc = { func.comment }
  123. end
  124. if doc then
  125. doc = codegen.doxygen_ctype(doc, func)
  126. end
  127. local funcdecl = codegen.apply_functemp(func, "BGFX_C_API $CRET bgfx_$CFUNCNAME($CARGS);")
  128. if doc then
  129. return "\n" .. doc .. "\n" .. funcdecl
  130. else
  131. return funcdecl
  132. end
  133. end)
  134. local typegen = {}
  135. local function add_doxygen(typedef, define, cstyle, cname)
  136. local func = cstyle and codegen.doxygen_ctype or codegen.doxygen_type
  137. local doc = func(typedef.comments, typedef, cname or typedef.cname)
  138. if doc then
  139. return doc .. "\n" .. define
  140. else
  141. return define
  142. end
  143. end
  144. function typegen.enums(typedef)
  145. if typedef.enum then
  146. return add_doxygen(typedef, codegen.gen_enum_define(typedef), false, "bgfx_" .. typedef.cname)
  147. end
  148. end
  149. function typegen.cenums(typedef)
  150. if typedef.enum then
  151. return add_doxygen(typedef, codegen.gen_enum_cdefine(typedef), true)
  152. end
  153. end
  154. function typegen.structs(typedef)
  155. if typedef.struct and not typedef.namespace then
  156. local methods = typedef.methods
  157. if methods then
  158. local m = {}
  159. for _, func in ipairs(methods) do
  160. m[#m+1] = cppdecl(func)
  161. end
  162. methods = m
  163. end
  164. return add_doxygen(typedef, codegen.gen_struct_define(typedef, methods))
  165. end
  166. end
  167. function typegen.cstructs(typedef)
  168. if typedef.struct then
  169. return add_doxygen(typedef, codegen.gen_struct_cdefine(typedef), true)
  170. end
  171. end
  172. function typegen.handles(typedef)
  173. if typedef.handle then
  174. return codegen.gen_handle(typedef)
  175. end
  176. end
  177. function typegen.chandles(typedef)
  178. if typedef.handle then
  179. return codegen.gen_chandle(typedef)
  180. end
  181. end
  182. function typegen.funcptrs(typedef)
  183. if typedef.args then
  184. return add_doxygen(typedef, codegen.gen_funcptr(typedef))
  185. end
  186. end
  187. function typegen.cfuncptrs(typedef)
  188. if typedef.args then
  189. return add_doxygen(typedef, codegen.gen_cfuncptr(typedef), true)
  190. end
  191. end
  192. local function codes()
  193. local temp = {}
  194. for k in pairs(func_actions) do
  195. temp[k] = {}
  196. end
  197. for k in pairs(type_actions) do
  198. temp[k] = {}
  199. end
  200. -- call actions with func
  201. for _, f in ipairs(idl.funcs) do
  202. for k in pairs(func_actions) do
  203. local funcgen = funcgen[k]
  204. if funcgen then
  205. table.insert(temp[k], (funcgen(f)))
  206. end
  207. end
  208. end
  209. -- call actions with type
  210. for _, typedef in ipairs(idl.types) do
  211. for k in pairs(type_actions) do
  212. local typegen = typegen[k]
  213. if typegen then
  214. table.insert(temp[k], (typegen(typedef)))
  215. end
  216. end
  217. end
  218. for k, indent in pairs(func_actions) do
  219. temp[k] = table.concat(temp[k], indent)
  220. end
  221. for k, indent in pairs(type_actions) do
  222. temp[k] = table.concat(temp[k], indent)
  223. end
  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