LuaGlueGen.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971
  1. #!/usr/bin/python
  2. # Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  3. # All rights reserved.
  4. # Code licensed under the BSD License.
  5. # http://www.anki3d.org/LICENSE
  6. import os
  7. import optparse
  8. import xml.etree.ElementTree as et
  9. # Globals
  10. g_identation_level = 0
  11. g_out_file = None
  12. g_enum_names = []
  13. def parse_commandline():
  14. """ Parse the command line arguments """
  15. parser = optparse.OptionParser(usage="usage: %prog [options]", description="Create LUA bindings using XML")
  16. parser.add_option("-i",
  17. "--input",
  18. dest="inp",
  19. type="string",
  20. help="specify the XML files to parse. Seperate with :")
  21. (options, args) = parser.parse_args()
  22. if not options.inp:
  23. parser.error("argument is missing")
  24. return options.inp.split(":")
  25. def type_sig(value):
  26. """ Calculate the signature of a type """
  27. if not isinstance(value, str):
  28. raise Exception("Expecting string")
  29. return hash(value)
  30. def get_base_fname(path):
  31. """ From path/to/a/file.ext return the "file" """
  32. return os.path.splitext(os.path.basename(path))[0]
  33. def wglue(txt):
  34. """ Write glue code to the output """
  35. global g_out_file
  36. global g_identation_level
  37. g_out_file.write("%s%s\n" % ("\t" * g_identation_level, txt))
  38. def ident(number):
  39. """ Increase or recrease identation for the wglue """
  40. global g_identation_level
  41. g_identation_level += number
  42. def type_is_bool(type):
  43. """ Check if a type is boolean """
  44. return type == "Bool" or type == "bool"
  45. def type_is_enum(type):
  46. """ Check if a type string is an enum """
  47. global g_enum_names
  48. return type in g_enum_names
  49. def type_is_number(type):
  50. """ Check if a type is number """
  51. numbers = [
  52. "U8", "U16", "U32", "U64", "I8", "I16", "I32", "I64", "U", "I", "PtrSize", "F32", "F64", "int", "unsigned",
  53. "unsigned int", "short", "unsigned short", "uint", "float", "double"
  54. ]
  55. it_is = False
  56. for num in numbers:
  57. if num == type:
  58. it_is = True
  59. break
  60. return it_is
  61. def parse_type_decl(arg_txt):
  62. """ Parse an arg text """
  63. tokens = arg_txt.split(" ")
  64. tokens_size = len(tokens)
  65. type = tokens[tokens_size - 1]
  66. type_len = len(type)
  67. is_ptr = False
  68. is_ref = False
  69. if type[type_len - 1] == "&":
  70. is_ref = True
  71. elif type[type_len - 1] == "*":
  72. is_ptr = True
  73. if is_ref or is_ptr:
  74. type = type[:-1]
  75. is_const = False
  76. if tokens[0] == "const":
  77. is_const = True
  78. return (type, is_ref, is_ptr, is_const)
  79. def ret(ret_el):
  80. """ Push return value """
  81. if ret_el is None:
  82. wglue("return 0;")
  83. return
  84. wglue("// Push return value")
  85. type_txt = ret_el.text
  86. (type, is_ref, is_ptr, is_const) = parse_type_decl(type_txt)
  87. if is_ptr:
  88. if ret_el.get("canBeNullptr") is not None and ret_el.get("canBeNullptr") == "1":
  89. can_be_nullptr = True
  90. else:
  91. can_be_nullptr = False
  92. wglue("if(ret == nullptr) [[unlikely]]")
  93. wglue("{")
  94. ident(1)
  95. if can_be_nullptr:
  96. wglue("lua_pushnil(l);")
  97. wglue("return 1;")
  98. else:
  99. wglue("return luaL_error(l, \"Returned nullptr. Location %s:%d %s\", ANKI_FILE, __LINE__, ANKI_FUNC);")
  100. ident(-1)
  101. wglue("}")
  102. wglue("")
  103. if type_is_bool(type):
  104. wglue("lua_pushboolean(l, ret);")
  105. elif type_is_number(type):
  106. wglue("lua_pushnumber(l, lua_Number(ret));")
  107. elif type == "char" or type == "CString":
  108. wglue("lua_pushstring(l, &ret[0]);")
  109. elif type == "Error":
  110. wglue("if(ret) [[unlikely]]")
  111. wglue("{")
  112. ident(1)
  113. wglue("return luaL_error(l, \"Returned an error. Location %s:%d %s\", ANKI_FILE, __LINE__, ANKI_FUNC);")
  114. ident(-1)
  115. wglue("}")
  116. wglue("")
  117. wglue("lua_pushnumber(l, lua_Number(!!ret));")
  118. else:
  119. if is_ptr or is_ref:
  120. wglue("voidp = lua_newuserdata(l, sizeof(LuaUserData));")
  121. wglue("ud = static_cast<LuaUserData*>(voidp);")
  122. wglue("luaL_setmetatable(l, \"%s\");" % type)
  123. wglue("extern LuaUserDataTypeInfo g_luaUserDataTypeInfo%s;" % type)
  124. if is_ptr:
  125. wglue("ud->initPointed(&g_luaUserDataTypeInfo%s, ret);" % type)
  126. elif is_ref:
  127. wglue("ud->initPointed(&g_luaUserDataTypeInfo%s, &ret);" % type)
  128. else:
  129. wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % type)
  130. wglue("voidp = lua_newuserdata(l, size);")
  131. wglue("luaL_setmetatable(l, \"%s\");" % type)
  132. wglue("ud = static_cast<LuaUserData*>(voidp);")
  133. wglue("extern LuaUserDataTypeInfo g_luaUserDataTypeInfo%s;" % type)
  134. wglue("ud->initGarbageCollected(&g_luaUserDataTypeInfo%s);" % type)
  135. wglue("::new(ud->getData<%s>()) %s(std::move(ret));" % (type, type))
  136. wglue("")
  137. wglue("return 1;")
  138. def arg(arg_txt, stack_index, index):
  139. """ Write the pop code for a single argument """
  140. (type, is_ref, is_ptr, is_const) = parse_type_decl(arg_txt)
  141. if type_is_bool(type) or type_is_number(type):
  142. wglue("%s arg%d;" % (type, index))
  143. wglue("if(LuaBinder::checkNumber(l, ANKI_FILE, __LINE__, ANKI_FUNC, %d, arg%d)) [[unlikely]]" % (stack_index, index))
  144. wglue("{")
  145. ident(1)
  146. wglue("return lua_error(l);")
  147. ident(-1)
  148. wglue("}")
  149. elif type == "char" or type == "CString":
  150. wglue("const char* arg%d;" % index)
  151. wglue("if(LuaBinder::checkString(l, ANKI_FILE, __LINE__, ANKI_FUNC, %d, arg%d)) [[unlikely]]" % (stack_index, index))
  152. wglue("{")
  153. ident(1)
  154. wglue("return lua_error(l);")
  155. ident(-1)
  156. wglue("}")
  157. elif type_is_enum(type):
  158. wglue("lua_Number arg%dTmp;" % index)
  159. wglue("if(LuaBinder::checkNumber(l, ANKI_FILE, __LINE__, ANKI_FUNC, %d, arg%dTmp)) [[unlikely]]" % (stack_index, index))
  160. wglue("{")
  161. ident(1)
  162. wglue("return lua_error(l);")
  163. ident(-1)
  164. wglue("}")
  165. wglue("const %s arg%d = %s(arg%dTmp);" % (type, index, type, index))
  166. else:
  167. # Must be user type
  168. wglue("extern LuaUserDataTypeInfo g_luaUserDataTypeInfo%s;" % type)
  169. wglue("if(LuaBinder::checkUserData(l, ANKI_FILE, __LINE__, ANKI_FUNC, %d, g_luaUserDataTypeInfo%s, ud)) [[unlikely]]" % (stack_index, type))
  170. wglue("{")
  171. ident(1)
  172. wglue("return lua_error(l);")
  173. ident(-1)
  174. wglue("}")
  175. wglue("")
  176. wglue("%s* iarg%d = ud->getData<%s>();" % (type, index, type))
  177. if is_ptr:
  178. wglue("%s arg%d(iarg%d);" % (arg_txt, index, index))
  179. else:
  180. wglue("%s arg%d(*iarg%d);" % (arg_txt, index, index))
  181. def args(args_el, stack_index):
  182. """ Write the pop code for argument parsing and return the arg list """
  183. if args_el is None:
  184. return ""
  185. wglue("// Pop arguments")
  186. arg_index = 0
  187. # Do the work
  188. args_str = ""
  189. arg_index = 0
  190. for arg_el in args_el.iter("arg"):
  191. arg(arg_el.text, stack_index, arg_index)
  192. args_str += "arg%d, " % arg_index
  193. wglue("")
  194. stack_index += 1
  195. arg_index += 1
  196. if len(args_str) > 0:
  197. args_str = args_str[:-2]
  198. return args_str
  199. def count_args(args_el):
  200. """ Count the number of arguments """
  201. if args_el is None:
  202. return 0
  203. count = 0
  204. for arg_el in args_el.iter("arg"):
  205. count += 1
  206. return count
  207. def check_args(args_el, bias):
  208. """ Check number of args. Call that first because it throws error """
  209. if args_el is not None:
  210. count = bias + count_args(args_el)
  211. else:
  212. count = bias
  213. wglue("if(LuaBinder::checkArgsCount(l, ANKI_FILE, __LINE__, ANKI_FUNC, %d)) [[unlikely]]" % count)
  214. wglue("{")
  215. ident(1)
  216. wglue("return lua_error(l);")
  217. ident(-1)
  218. wglue("}")
  219. wglue("")
  220. def get_meth_alias(meth_el):
  221. """ Return the method alias """
  222. meth_name = meth_el.get("name")
  223. if meth_name == "operator+":
  224. meth_alias = "__add"
  225. elif meth_name == "operator-":
  226. meth_alias = "__sub"
  227. elif meth_name == "operator*":
  228. meth_alias = "__mul"
  229. elif meth_name == "operator/":
  230. meth_alias = "__div"
  231. elif meth_name == "operator==":
  232. meth_alias = "__eq"
  233. elif meth_name == "operator<":
  234. meth_alias = "__lt"
  235. elif meth_name == "operator<=":
  236. meth_alias = "__le"
  237. elif meth_name == "operator>":
  238. meth_alias = "__gt"
  239. elif meth_name == "operator>=":
  240. meth_alias = "__ge"
  241. elif meth_name == "operator=":
  242. meth_alias = "copy"
  243. else:
  244. meth_alias = meth_name
  245. meth_alias_txt = meth_el.get("alias")
  246. if meth_alias_txt is not None:
  247. meth_alias = meth_alias_txt
  248. return meth_alias
  249. def write_local_vars():
  250. wglue("[[maybe_unused]] LuaUserData* ud;")
  251. wglue("[[maybe_unused]] void* voidp;")
  252. wglue("[[maybe_unused]] PtrSize size;")
  253. wglue("")
  254. def method(class_name, meth_el):
  255. """ Handle a method """
  256. meth_name = meth_el.get("name")
  257. meth_alias = get_meth_alias(meth_el)
  258. wglue("// Wrap method %s::%s." % (class_name, meth_name))
  259. wglue("static inline int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
  260. wglue("{")
  261. ident(1)
  262. write_local_vars()
  263. check_args(meth_el.find("args"), 1)
  264. # Get this pointer
  265. wglue("// Get \"this\" as \"self\"")
  266. wglue("if(LuaBinder::checkUserData(l, ANKI_FILE, __LINE__, ANKI_FUNC, 1, g_luaUserDataTypeInfo%s, ud)) [[unlikely]]" % class_name)
  267. wglue("{")
  268. ident(1)
  269. wglue("return lua_error(l);")
  270. ident(-1)
  271. wglue("}")
  272. wglue("")
  273. wglue("%s* self = ud->getData<%s>();" % (class_name, class_name))
  274. wglue("")
  275. args_str = args(meth_el.find("args"), 2)
  276. # Return value
  277. ret_txt = None
  278. ret_el = meth_el.find("return")
  279. if ret_el is not None:
  280. ret_txt = ret_el.text
  281. # Method call
  282. wglue("// Call the method")
  283. call = meth_el.find("overrideCall")
  284. if call is not None:
  285. call = call.text
  286. if call is not None:
  287. wglue("%s" % call)
  288. else:
  289. if ret_txt is None:
  290. wglue("self->%s(%s);" % (meth_name, args_str))
  291. else:
  292. wglue("%s ret = self->%s(%s);" % (ret_txt, meth_name, args_str))
  293. wglue("")
  294. ret(ret_el)
  295. ident(-1)
  296. wglue("}")
  297. wglue("")
  298. def static_method(class_name, meth_el):
  299. """ Handle a static method """
  300. meth_name = meth_el.get("name")
  301. meth_alias = get_meth_alias(meth_el)
  302. wglue("// Wrap static method %s::%s." % (class_name, meth_name))
  303. wglue("static inline int pwrap%s%s(lua_State* l)" % (class_name, meth_alias))
  304. wglue("{")
  305. ident(1)
  306. write_local_vars()
  307. check_args(meth_el.find("args"), 0)
  308. # Args
  309. args_str = args(meth_el.find("args"), 1)
  310. # Return value
  311. ret_txt = None
  312. ret_el = meth_el.find("return")
  313. if ret_el is not None:
  314. ret_txt = ret_el.text
  315. # Method call
  316. wglue("// Call the method")
  317. if ret_txt is None:
  318. wglue("%s::%s(%s);" % (class_name, meth_name, args_str))
  319. else:
  320. wglue("%s ret = %s::%s(%s);" % (ret_txt, class_name, meth_name, args_str))
  321. wglue("")
  322. ret(ret_el)
  323. ident(-1)
  324. wglue("}")
  325. wglue("")
  326. def constructor(constr_el, class_name, constructor_idx):
  327. """ Handle constructor """
  328. wglue("// Pre-wrap constructor for %s." % (class_name))
  329. wglue("static inline int pwrap%sCtor%d(lua_State* l)" % (class_name, constructor_idx))
  330. wglue("{")
  331. ident(1)
  332. write_local_vars()
  333. check_args(constr_el.find("args"), 0)
  334. # Args
  335. args_str = args(constr_el.find("args"), 1)
  336. # Create new userdata
  337. wglue("// Create user data")
  338. wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % class_name)
  339. wglue("voidp = lua_newuserdata(l, size);")
  340. wglue("luaL_setmetatable(l, g_luaUserDataTypeInfo%s.m_typeName);" % class_name)
  341. wglue("ud = static_cast<LuaUserData*>(voidp);")
  342. wglue("extern LuaUserDataTypeInfo g_luaUserDataTypeInfo%s;" % class_name)
  343. wglue("ud->initGarbageCollected(&g_luaUserDataTypeInfo%s);" % class_name)
  344. wglue("::new(ud->getData<%s>()) %s(%s);" % (class_name, class_name, args_str))
  345. wglue("")
  346. wglue("return 1;")
  347. ident(-1)
  348. wglue("}")
  349. wglue("")
  350. def constructors(constructors_el, class_name):
  351. """ Wrap all constructors """
  352. idx = 0
  353. func_names_and_arg_counts = []
  354. # Create the pre-wrap C functions
  355. for constructor_el in constructors_el.iter("constructor"):
  356. arg_count = count_args(constructor_el.find("args"))
  357. # Iterate all arg counts and make sure there are no duplicates
  358. for i in range(idx):
  359. if func_names_and_arg_counts[i][1] == arg_count:
  360. raise Exception("Every constructor overload should have a unique arg count. class: %s" % class_name)
  361. constructor(constructor_el, class_name, idx)
  362. func_names_and_arg_counts.append(["pwrap%sCtor%d" % (class_name, idx), arg_count])
  363. idx += 1
  364. if idx == 0:
  365. raise Exception("Found no <constructor>")
  366. # Create the landing function
  367. wglue("// Wrap constructors for %s." % class_name)
  368. wglue("static int wrap%sCtor(lua_State* l)" % class_name)
  369. wglue("{")
  370. ident(1)
  371. if idx == 1:
  372. wglue("int res = pwrap%sCtor0(l);" % class_name)
  373. else:
  374. wglue("// Chose the right overload")
  375. wglue("const int argCount = lua_gettop(l);")
  376. wglue("int res = 0;")
  377. wglue("switch(argCount)")
  378. wglue("{")
  379. for name_and_arg_count in func_names_and_arg_counts:
  380. func_name = name_and_arg_count[0]
  381. arg_count = name_and_arg_count[1]
  382. wglue("case %d:" % arg_count)
  383. wglue("res = %s(l); break;" % func_name)
  384. wglue("default:")
  385. wglue("lua_pushfstring(l, \"Wrong overloaded new. Wrong number of arguments: %d\", argCount);")
  386. wglue("res = -1;")
  387. wglue("}")
  388. wglue("")
  389. wglue("if(res >= 0)")
  390. wglue("{")
  391. ident(1)
  392. wglue("return res;")
  393. ident(-1)
  394. wglue("}")
  395. wglue("")
  396. wglue("lua_error(l);")
  397. wglue("return 0;")
  398. ident(-1)
  399. wglue("}")
  400. wglue("")
  401. def destructor(class_name):
  402. """ Create a destructor """
  403. wglue("// Wrap destructor for %s." % (class_name))
  404. wglue("static int wrap%sDtor(lua_State* l)" % class_name)
  405. wglue("{")
  406. ident(1)
  407. write_local_vars()
  408. check_args(None, 1)
  409. wglue("if(LuaBinder::checkUserData(l, ANKI_FILE, __LINE__, ANKI_FUNC, 1, g_luaUserDataTypeInfo%s, ud)) [[unlikely]]" % class_name)
  410. wglue("{")
  411. ident(1)
  412. wglue("return lua_error(l);")
  413. ident(-1)
  414. wglue("}")
  415. wglue("")
  416. wglue("if(ud->isGarbageCollected())")
  417. wglue("{")
  418. ident(1)
  419. wglue("%s* inst = ud->getData<%s>();" % (class_name, class_name))
  420. wglue("inst->~%s();" % class_name)
  421. ident(-1)
  422. wglue("}")
  423. wglue("")
  424. wglue("return 0;")
  425. ident(-1)
  426. wglue("}")
  427. wglue("")
  428. def do__newindex(vars_el, class_name):
  429. """ Write the __newindex cfunction which is called when assigning to a class instance """
  430. wglue("// Wrap writing the member vars of %s" % class_name)
  431. wglue("static int wrap%s__newindex(lua_State* l)" % class_name)
  432. wglue("{")
  433. ident(1)
  434. write_local_vars()
  435. check_args(None, 3)
  436. wglue("// Get \"this\" as \"self\"")
  437. wglue("if(LuaBinder::checkUserData(l, ANKI_FILE, __LINE__, ANKI_FUNC, 1, g_luaUserDataTypeInfo%s, ud)) [[unlikely]]" % class_name)
  438. wglue("{")
  439. ident(1)
  440. wglue("return lua_error(l);")
  441. ident(-1)
  442. wglue("}")
  443. wglue("")
  444. wglue("%s* self = ud->getData<%s>();" % (class_name, class_name))
  445. wglue("")
  446. wglue("// Get the member variable name")
  447. wglue("const Char* ckey;")
  448. wglue("if(LuaBinder::checkString(l, ANKI_FILE, __LINE__, ANKI_FUNC, 2, ckey)) [[unlikely]]")
  449. wglue("{")
  450. ident(1)
  451. wglue("return lua_error(l);")
  452. ident(-1)
  453. wglue("}")
  454. wglue("")
  455. wglue("CString key = ckey;")
  456. wglue("")
  457. wglue("// Try to find the member variable")
  458. count = 0
  459. for var_el in vars_el.iter("var"):
  460. wglue("%sif(key == \"%s\")" % (("else " if count > 0 else ""), var_el.get("name")))
  461. count = count + 1
  462. wglue("{")
  463. ident(1)
  464. arg(var_el.text, 3, 0)
  465. wglue("self->%s = arg0;" % var_el.get("name"))
  466. wglue("return 0;")
  467. ident(-1)
  468. wglue("}")
  469. wglue("")
  470. wglue("return luaL_error(l, \"Unknown field %s. Location %s:%d %s\", key.cstr(), ANKI_FILE, __LINE__, ANKI_FUNC);")
  471. ident(-1)
  472. wglue("}")
  473. wglue("")
  474. def do__index(vars_el, class_name):
  475. """ Write the __index cfunction which is called when assigning to a class instance """
  476. wglue("// Wrap reading the member vars of %s" % class_name)
  477. wglue("static int wrap%s__index(lua_State* l)" % class_name)
  478. wglue("{")
  479. ident(1)
  480. write_local_vars()
  481. check_args(None, 2)
  482. wglue("// Get \"this\" as \"self\"")
  483. wglue("if(LuaBinder::checkUserData(l, ANKI_FILE, __LINE__, ANKI_FUNC, 1, g_luaUserDataTypeInfo%s, ud)) [[unlikely]]" % class_name)
  484. wglue("{")
  485. ident(1)
  486. wglue("return lua_error(l);")
  487. ident(-1)
  488. wglue("}")
  489. wglue("")
  490. wglue("%s* self = ud->getData<%s>();" % (class_name, class_name))
  491. wglue("")
  492. wglue("// Get the member variable name")
  493. wglue("const Char* ckey;")
  494. wglue("if(LuaBinder::checkString(l, ANKI_FILE, __LINE__, ANKI_FUNC, 2, ckey)) [[unlikely]]")
  495. wglue("{")
  496. ident(1)
  497. wglue("return lua_error(l);")
  498. ident(-1)
  499. wglue("}")
  500. wglue("")
  501. wglue("CString key = ckey;")
  502. wglue("")
  503. wglue("// Try to find the member variable")
  504. count = 0
  505. for var_el in vars_el.iter("var"):
  506. wglue("%sif(key == \"%s\")" % (("else " if count > 0 else ""), var_el.get("name")))
  507. count = count + 1
  508. wglue("{")
  509. ident(1)
  510. wglue("%s ret = self->%s;" % (var_el.text, var_el.get("name")))
  511. ret(var_el)
  512. ident(-1)
  513. wglue("}")
  514. wglue("")
  515. wglue("// Fallback to methods")
  516. wglue("luaL_getmetatable(l, \"%s\");" % class_name)
  517. wglue("lua_getfield(l, -1, ckey);")
  518. wglue("if (!lua_isnil(l, -1))")
  519. wglue("{")
  520. ident(1)
  521. wglue("return 1;")
  522. ident(-1)
  523. wglue("}")
  524. wglue("")
  525. wglue("return luaL_error(l, \"Unknown field %s. Location %s:%d %s\", key.cstr(), ANKI_FILE, __LINE__, ANKI_FUNC);")
  526. ident(-1)
  527. wglue("}")
  528. wglue("")
  529. def class_(class_el):
  530. """ Create a class """
  531. class_name = class_el.get("name")
  532. # Write serializer
  533. serialize = class_el.get("serialize") is not None and class_el.get("serialize") == "true"
  534. if serialize:
  535. # Serialize
  536. serialize_cb_name = "serialize%s" % class_name
  537. wglue("// Serialize %s" % class_name)
  538. wglue("static void %s(LuaUserData& self, void* data, PtrSize& size)" % serialize_cb_name)
  539. wglue("{")
  540. ident(1)
  541. wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
  542. wglue("obj->serialize(data, size);")
  543. ident(-1)
  544. wglue("}")
  545. wglue("")
  546. # Deserialize
  547. deserialize_cb_name = "deserialize%s" % class_name
  548. wglue("// De-serialize %s" % class_name)
  549. wglue("static void %s(const void* data, LuaUserData& self)" % deserialize_cb_name)
  550. wglue("{")
  551. ident(1)
  552. wglue("ANKI_ASSERT(data);")
  553. wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
  554. wglue("::new(obj) %s();" % class_name)
  555. wglue("obj->deserialize(data);")
  556. ident(-1)
  557. wglue("}")
  558. wglue("")
  559. else:
  560. serialize_cb_name = "nullptr"
  561. deserialize_cb_name = "nullptr"
  562. # Write the type info
  563. wglue("LuaUserDataTypeInfo g_luaUserDataTypeInfo%s = {" % class_name)
  564. ident(1)
  565. wglue("%d, \"%s\", LuaUserData::computeSizeForGarbageCollected<%s>(), %s, %s" %
  566. (type_sig(class_name), class_name, class_name, serialize_cb_name, deserialize_cb_name))
  567. ident(-1)
  568. wglue("};")
  569. wglue("")
  570. # Specialize the getDataTypeInfoFor
  571. wglue("template<>")
  572. wglue("const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<%s>()" % class_name)
  573. wglue("{")
  574. ident(1)
  575. wglue("return g_luaUserDataTypeInfo%s;" % class_name)
  576. ident(-1)
  577. wglue("}")
  578. wglue("")
  579. # Constructor declarations
  580. has_constructor = False
  581. constructors_el = class_el.find("constructors")
  582. if constructors_el is not None:
  583. has_constructor = True
  584. constructors(constructors_el, class_name)
  585. # Destructor declarations
  586. if has_constructor:
  587. destructor(class_name)
  588. # Member variables
  589. has_member_vars = False
  590. vars_el = class_el.find("vars")
  591. if vars_el is not None:
  592. has_member_vars = True
  593. do__newindex(vars_el, class_name)
  594. do__index(vars_el, class_name)
  595. # Methods LUA C functions declarations
  596. meth_names_aliases = []
  597. meths_el = class_el.find("methods")
  598. if meths_el is not None:
  599. for meth_el in meths_el.iter("method"):
  600. is_static = meth_el.get("static")
  601. is_static = is_static is not None and is_static == "1"
  602. if is_static:
  603. static_method(class_name, meth_el)
  604. else:
  605. method(class_name, meth_el)
  606. meth_name = meth_el.get("name")
  607. meth_alias = get_meth_alias(meth_el)
  608. meth_names_aliases.append([meth_name, meth_alias, is_static])
  609. # Start class declaration
  610. wglue("// Wrap class %s." % class_name)
  611. wglue("static inline void wrap%s(lua_State* l)" % class_name)
  612. wglue("{")
  613. ident(1)
  614. wglue("LuaBinder::createClass(l, &g_luaUserDataTypeInfo%s);" % class_name)
  615. # Register constructor
  616. if has_constructor:
  617. wglue("LuaBinder::pushLuaCFuncStaticMethod(l, g_luaUserDataTypeInfo%s.m_typeName, \"new\", wrap%sCtor);" %
  618. (class_name, class_name))
  619. # Register destructor
  620. if has_constructor:
  621. wglue("LuaBinder::pushLuaCFuncMethod(l, \"__gc\", wrap%sDtor);" % class_name)
  622. # Register methods
  623. if len(meth_names_aliases) > 0:
  624. for meth_name_alias in meth_names_aliases:
  625. meth_alias = meth_name_alias[1]
  626. is_static = meth_name_alias[2]
  627. if is_static:
  628. wglue("LuaBinder::pushLuaCFuncStaticMethod(l, g_luaUserDataTypeInfo%s.m_typeName, \"%s\", wrap%s%s);" %
  629. (class_name, meth_alias, class_name, meth_alias))
  630. else:
  631. wglue("LuaBinder::pushLuaCFuncMethod(l, \"%s\", wrap%s%s);" % (meth_alias, class_name, meth_alias))
  632. # Register member vars
  633. if has_member_vars:
  634. wglue("LuaBinder::pushLuaCFuncMethod(l, \"__newindex\", wrap%s__newindex);" % class_name)
  635. wglue("LuaBinder::pushLuaCFuncMethod(l, \"__index\", wrap%s__index);" % class_name)
  636. wglue("lua_settop(l, 0);")
  637. ident(-1)
  638. wglue("}")
  639. wglue("")
  640. def function(func_el):
  641. """ Handle a plain function """
  642. func_name = func_el.get("name")
  643. func_alias = get_meth_alias(func_el)
  644. wglue("// Wrap function %s." % func_name)
  645. wglue("static inline int wrap%s(lua_State* l)" % func_alias)
  646. wglue("{")
  647. ident(1)
  648. write_local_vars()
  649. check_args(func_el.find("args"), 0)
  650. # Args
  651. args_str = args(func_el.find("args"), 1)
  652. # Return value
  653. ret_txt = None
  654. ret_el = func_el.find("return")
  655. if ret_el is not None:
  656. ret_txt = ret_el.text
  657. # Call
  658. wglue("// Call the function")
  659. call = func_el.find("overrideCall")
  660. if call is not None:
  661. call = call.text
  662. if call is not None:
  663. wglue("%s" % call)
  664. else:
  665. if ret_txt is None:
  666. wglue("%s(%s);" % (func_name, args_str))
  667. else:
  668. wglue("%s ret = %s(%s);" % (ret_txt, func_name, args_str))
  669. wglue("")
  670. ret(ret_el)
  671. ident(-1)
  672. wglue("}")
  673. wglue("")
  674. def enum(enum_el):
  675. enum_name = enum_el.get("name")
  676. # Write the type info
  677. wglue("LuaUserDataTypeInfo g_luaUserDataTypeInfo%s = {" % enum_name)
  678. ident(1)
  679. wglue("%d, \"%s\", 0, nullptr, nullptr" % (type_sig(enum_name), enum_name))
  680. ident(-1)
  681. wglue("};")
  682. wglue("")
  683. # Specialize the getDataTypeInfoFor
  684. wglue("template<>")
  685. wglue("const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<%s>()" % enum_name)
  686. wglue("{")
  687. ident(1)
  688. wglue("return g_luaUserDataTypeInfo%s;" % enum_name)
  689. ident(-1)
  690. wglue("}")
  691. wglue("")
  692. # Start declaration
  693. wglue("// Wrap enum %s." % enum_name)
  694. wglue("static inline void wrap%s(lua_State* l)" % enum_name)
  695. wglue("{")
  696. ident(1)
  697. wglue("lua_newtable(l);") # Push new table
  698. wglue("lua_setglobal(l, g_luaUserDataTypeInfo%s.m_typeName);" % enum_name) # Pop and make global
  699. wglue("lua_getglobal(l, g_luaUserDataTypeInfo%s.m_typeName);" % enum_name) # Push the table again
  700. wglue("")
  701. # Now the table is at the top of the stack
  702. for enumerant_el in enum_el.iter("enumerant"):
  703. enumerant_name = enumerant_el.get("name")
  704. wglue("lua_pushstring(l, \"%s\");" % enumerant_name) # Push key
  705. wglue("ANKI_ASSERT(%s(lua_Number(%s::%s)) == %s::%s && \"Can't map the enumerant to a lua_Number\");" %
  706. (enum_name, enum_name, enumerant_name, enum_name, enumerant_name))
  707. wglue("lua_pushnumber(l, lua_Number(%s::%s));" % (enum_name, enumerant_name)) # Push value
  708. wglue("lua_settable(l, -3);") # Do table[key]=value and pop 2. The table is at the top of the stack
  709. wglue("")
  710. # Done
  711. wglue("lua_settop(l, 0);")
  712. ident(-1)
  713. wglue("}")
  714. wglue("")
  715. def main():
  716. """ Main function """
  717. global g_out_file
  718. filenames = parse_commandline()
  719. for filename in filenames:
  720. out_filename = get_base_fname(filename) + ".cpp"
  721. g_out_file = open(out_filename, "w", newline="\n")
  722. tree = et.parse(filename)
  723. root = tree.getroot()
  724. # Head
  725. head = root.find("head")
  726. if head is not None:
  727. wglue("%s" % head.text)
  728. wglue("")
  729. # Enums (First because others use the g_enum_names)
  730. global g_enum_names
  731. for enums in root.iter("enums"):
  732. for enum_el in enums.iter("enum"):
  733. enum(enum_el)
  734. g_enum_names.append(enum_el.get("name"))
  735. # Classes
  736. class_names = []
  737. for cls in root.iter("classes"):
  738. for cl in cls.iter("class"):
  739. class_(cl)
  740. class_names.append(cl.get("name"))
  741. # Functions
  742. func_names = []
  743. for fs in root.iter("functions"):
  744. for f in fs.iter("function"):
  745. function(f)
  746. func_names.append(f.get("name"))
  747. # Wrap function
  748. wglue("// Wrap the module.")
  749. wglue("void wrapModule%s(lua_State* l)" % get_base_fname(filename))
  750. wglue("{")
  751. ident(1)
  752. for class_name in class_names:
  753. wglue("wrap%s(l);" % class_name)
  754. for func_name in func_names:
  755. wglue("LuaBinder::pushLuaCFunc(l, \"%s\", wrap%s);" % (func_name, func_name))
  756. for enum_name in g_enum_names:
  757. wglue("wrap%s(l);" % enum_name)
  758. ident(-1)
  759. wglue("}")
  760. wglue("")
  761. # Tail
  762. tail = root.find("tail")
  763. if tail is not None:
  764. wglue("%s" % tail.text)
  765. wglue("")
  766. g_out_file.close()
  767. if __name__ == "__main__":
  768. main()