bindings-d.lua 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. local codegen = require "codegen"
  2. local idl = codegen.idl "bgfx.idl"
  3. local d_types_template = [[
  4. /*
  5. *
  6. * AUTO GENERATED! DO NOT EDIT!
  7. *
  8. */
  9. module bindbc.bgfx.types;
  10. public import core.stdc.stdarg : va_list;
  11. extern(C) @nogc nothrow:
  12. $version
  13. alias bgfx_view_id_t = ushort;
  14. $types
  15. ]]
  16. local d_funcs_template = [[
  17. /*
  18. *
  19. * AUTO GENERATED! DO NOT EDIT!
  20. *
  21. */
  22. module bindbc.bgfx.funcs;
  23. private import bindbc.bgfx.types;
  24. extern(C) @nogc nothrow:
  25. version(BindBgfx_Static)
  26. {
  27. $funcs_static
  28. }
  29. else
  30. {
  31. __gshared
  32. {
  33. $funcs_dynamic
  34. }
  35. }
  36. ]]
  37. local function hasPrefix(str, prefix)
  38. return prefix == "" or str:sub(1, #prefix) == prefix
  39. end
  40. local function hasSuffix(str, suffix)
  41. return suffix == "" or str:sub(-#suffix) == suffix
  42. end
  43. local function to_underscorecase(name)
  44. local tmp = {}
  45. for v in name:gmatch "[_%u][%l%d]*" do
  46. if v:byte() == 95 then -- '_'
  47. v = v:sub(2) -- remove _
  48. end
  49. tmp[#tmp+1] = v
  50. end
  51. return table.concat(tmp, "_")
  52. end
  53. local function convert_array(member)
  54. if string.find(member.array, "::") then
  55. local name = "bgfx_" .. to_underscorecase(string.gsub(member.array, "::.*", "")):lower() .. "_t"
  56. return "[" .. name .. ".BGFX_" .. to_underscorecase(member.array):upper() .. "]"
  57. else
  58. return member.array
  59. end
  60. end
  61. local function convert_type(arg)
  62. local ctype = arg.ctype:gsub("%s%*", "*")
  63. if arg.fulltype == "bx::AllocatorI*" or arg.fulltype == "CallbackI*" or arg.fulltype == "ReleaseFn" then
  64. ctype = "void*"
  65. elseif hasPrefix(ctype, "uint64_t") then
  66. ctype = ctype:gsub("uint64_t", "ulong")
  67. elseif hasPrefix(ctype, "int64_t") then
  68. ctype = ctype:gsub("int64_t", "long")
  69. elseif hasPrefix(ctype, "uint32_t") then
  70. ctype = ctype:gsub("uint32_t", "uint")
  71. elseif hasPrefix(ctype, "int32_t") then
  72. ctype = ctype:gsub("int32_t", "int")
  73. elseif hasPrefix(ctype, "uint16_t") then
  74. ctype = ctype:gsub("uint16_t", "ushort")
  75. elseif hasPrefix(ctype, "uint8_t") then
  76. ctype = ctype:gsub("uint8_t", "byte")
  77. elseif hasPrefix(ctype, "uintptr_t") then
  78. ctype = ctype:gsub("uintptr_t", "ulong")
  79. elseif hasPrefix(ctype, "const ") and hasSuffix(ctype, "*") then
  80. ctype = "const(" .. string.sub(ctype:gsub("const ", "", 1), 1, -2) .. ")*"
  81. end
  82. if arg.array ~= nil then
  83. ctype = ctype .. convert_array(arg)
  84. end
  85. return ctype
  86. end
  87. local function convert_struct_type(arg)
  88. return convert_type(arg)
  89. end
  90. local function convert_ret_type(arg)
  91. return convert_type(arg)
  92. end
  93. local function convert_name(arg)
  94. if arg == "debug" then
  95. return arg .. "_"
  96. end
  97. return arg
  98. end
  99. local function convert_struct_member(member)
  100. return convert_struct_type(member) .. " " .. convert_name(member.name)
  101. end
  102. local function gen_version()
  103. return "enum uint BGFX_API_VERSION = " .. (idl._version or 0) .. ";"
  104. end
  105. local converter = {}
  106. local yield = coroutine.yield
  107. local gen = {}
  108. function gen.gen(template)
  109. local indent = ""
  110. local idx = 1;
  111. local r = template:gsub("$([a-zA-Z_]+)", function(what)
  112. local tmp = {}
  113. local ind_end = template:find("$"..what, idx, true)
  114. local ind_start = ind_end
  115. for j = 1, ind_end-1 do
  116. local i = 1+ind_end-1-j
  117. local c = string.sub(template, i, i)
  118. if c ~= ' ' and c ~= '\t' then
  119. ind_start = i
  120. break
  121. end
  122. end
  123. indent = string.sub(template, ind_start+1, ind_end-1)
  124. local what_idl = what:gsub("funcs_dynamic", "funcs"):gsub("funcs_static", "funcs")
  125. if (what == "version") then
  126. return gen_version()
  127. end
  128. for _, object in ipairs(idl[what_idl]) do
  129. local co = coroutine.create(converter[what])
  130. local any
  131. while true do
  132. local ok, v = coroutine.resume(co, object)
  133. assert(ok, debug.traceback(co, v))
  134. if not v then
  135. break
  136. end
  137. table.insert(tmp, v)
  138. any = true
  139. end
  140. if any and tmp[#tmp] ~= "" then
  141. table.insert(tmp, "")
  142. end
  143. end
  144. return table.concat(tmp, "\n" .. indent)
  145. end)
  146. return r
  147. end
  148. function gen.gen_types()
  149. return gen.gen(d_types_template)
  150. end
  151. function gen.gen_funcs()
  152. return gen.gen(d_funcs_template)
  153. end
  154. function converter.types(typ)
  155. if typ.comments ~= nil then
  156. if #typ.comments == 1 then
  157. yield("/// " .. typ.comments[1])
  158. else
  159. yield("/**")
  160. for _, comment in ipairs(typ.comments) do
  161. yield(" * " .. comment)
  162. end
  163. yield(" */")
  164. end
  165. end
  166. if typ.handle then
  167. yield("struct " .. typ.cname .. " { ushort idx; }")
  168. elseif typ.enum then
  169. local prefix = "BGFX_" .. to_underscorecase(string.gsub(typ.name, "::Enum", "")):upper()
  170. yield("enum " .. typ.cname)
  171. yield("{")
  172. for idx, enum in ipairs(typ.enum) do
  173. local comments = ""
  174. if enum.comment ~= nil then
  175. if #enum.comment == 1 then
  176. comments = " /// " .. enum.comment[1];
  177. else
  178. yield("\t/**")
  179. for _, comment in ipairs(enum.comment) do
  180. yield("\t * " .. comment)
  181. end
  182. yield("\t */")
  183. end
  184. end
  185. local enumname
  186. if enum.underscore then
  187. enumname = to_underscorecase(enum.name):upper()
  188. else
  189. enumname = enum.name:upper()
  190. end
  191. yield("\t" .. prefix .. "_" .. enumname .. "," .. comments)
  192. end
  193. yield("");
  194. --yield("\t" .. prefix .. "_COUNT = " .. #typ.enum)
  195. yield("\t" .. prefix .. "_COUNT")
  196. yield("}")
  197. elseif typ.bits ~= nil then
  198. local prefix = "BGFX_" .. to_underscorecase(typ.name):upper()
  199. local enumType = "uint"
  200. format = "%u"
  201. if typ.bits == 64 then
  202. format = "0x%016x"
  203. enumType = "ulong"
  204. elseif typ.bits == 32 then
  205. format = "0x%08x"
  206. enumType = "uint"
  207. elseif typ.bits == 16 then
  208. format = "0x%04x"
  209. enumType = "ushort"
  210. elseif typ.bits == 8 then
  211. format = "0x%02x"
  212. enumType = "ubyte"
  213. end
  214. for idx, flag in ipairs(typ.flag) do
  215. local value = flag.value
  216. if value ~= nil then
  217. value = string.format(flag.format or format, value)
  218. else
  219. for _, name in ipairs(flag) do
  220. local fixedname = prefix .. "_" .. to_underscorecase(name):upper()
  221. if value ~= nil then
  222. value = value .. " | " .. fixedname
  223. else
  224. value = fixedname
  225. end
  226. end
  227. end
  228. local comments = ""
  229. if flag.comment ~= nil then
  230. if #flag.comment == 1 then
  231. comments = " /// " .. flag.comment[1]
  232. else
  233. yield("/**")
  234. for _, comment in ipairs(flag.comment) do
  235. yield(" * " .. comment)
  236. end
  237. yield(" */")
  238. end
  239. end
  240. yield("enum " .. enumType .. " " .. prefix .. "_" .. to_underscorecase(flag.name):upper() .. " = " .. value .. ";" .. comments)
  241. end
  242. if typ.shift then
  243. local name = prefix .. "_SHIFT"
  244. local value = typ.shift
  245. local comments = ""
  246. if typ.desc then
  247. comments = string.format(" /// %s bit shift", typ.desc)
  248. end
  249. yield("enum " .. enumType .. " " .. name .. " = " .. value .. ";" .. comments)
  250. end
  251. if typ.range then
  252. local name = prefix .. "_MASK"
  253. local value = string.format(format, typ.mask)
  254. local comments = ""
  255. if typ.desc then
  256. comments = string.format(" /// %s bit mask", typ.desc)
  257. end
  258. yield("enum " .. enumType .. " " .. name .. " = " .. value .. ";" .. comments)
  259. end
  260. if typ.helper then
  261. yield(string.format(
  262. "%s %s (%s v) { return (v << %s) & %s; }",
  263. enumType,
  264. prefix,
  265. enumType,
  266. (prefix .. "_SHIFT"),
  267. (prefix .. "_MASK")))
  268. end
  269. elseif typ.struct ~= nil then
  270. yield("struct " .. typ.cname)
  271. yield("{")
  272. for _, member in ipairs(typ.struct) do
  273. local comments = ""
  274. if member.comment ~= nil then
  275. if #member.comment == 1 then
  276. comments = " /// " .. member.comment[1]
  277. else
  278. yield("\n\t/**")
  279. for _, comment in ipairs(member.comment) do
  280. yield("\t * " .. comment)
  281. end
  282. yield("\t */")
  283. end
  284. end
  285. yield("\t" .. convert_struct_member(member) .. ";" .. comments)
  286. end
  287. yield("}")
  288. end
  289. end
  290. function converter.funcs_static(func)
  291. return converter.funcs(func, true)
  292. end
  293. function converter.funcs_dynamic(func)
  294. return converter.funcs(func, false)
  295. end
  296. function converter.funcs(func, static)
  297. if func.cpponly then
  298. return
  299. end
  300. if func.comments ~= nil then
  301. yield("/**")
  302. for _, line in ipairs(func.comments) do
  303. local line = line:gsub("@remarks", "Remarks:")
  304. line = line:gsub("@remark", "Remarks:")
  305. line = line:gsub("@(%l)(%l+)", function(a, b) return a:upper()..b..":" end)
  306. yield(" * " .. line)
  307. end
  308. local hasParamsComments = false
  309. for _, arg in ipairs(func.args) do
  310. if arg.comment ~= nil then
  311. hasParamsComments = true
  312. break
  313. end
  314. end
  315. if hasParamsComments then
  316. yield(" * Params:")
  317. end
  318. for _, arg in ipairs(func.args) do
  319. if arg.comment ~= nil then
  320. yield(" * " .. convert_name(arg.name) .. " = " .. arg.comment[1])
  321. for i, comment in ipairs(arg.comment) do
  322. if (i > 1) then
  323. yield(" * " .. comment)
  324. end
  325. end
  326. end
  327. end
  328. yield(" */")
  329. end
  330. local args = {}
  331. if func.this ~= nil then
  332. args[1] = convert_type(func.this_type) .. " _this"
  333. end
  334. for _, arg in ipairs(func.args) do
  335. table.insert(args, convert_type(arg) .. " " .. convert_name(arg.name))
  336. end
  337. if static then
  338. yield(convert_ret_type(func.ret) .. " bgfx_" .. func.cname .. "(" .. table.concat(args, ", ") .. ");")
  339. else
  340. yield("alias da_bgfx_" .. func.cname .. " = " .. convert_ret_type(func.ret) .. " function(" .. table.concat(args, ", ") .. ");")
  341. yield("da_bgfx_" .. func.cname .. " bgfx_" .. func.cname .. ";")
  342. end
  343. end
  344. -- printtable("idl types", idl.types)
  345. -- printtable("idl funcs", idl.funcs)
  346. function gen.write(codes, outputfile)
  347. local out = assert(io.open(outputfile, "wb"))
  348. out:write(codes)
  349. out:close()
  350. print("Generating: " .. outputfile)
  351. end
  352. if (...) == nil then
  353. -- run `lua bindings-d.lua` in command line
  354. print(gen.gen_types())
  355. print(gen.gen_funcs())
  356. end
  357. return gen