LuaGlueGen.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  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("lua_pushstring(l, \"Glue code returned nullptr\");")
  100. wglue("return -1;")
  101. ident(-1)
  102. wglue("}")
  103. wglue("")
  104. if type_is_bool(type):
  105. wglue("lua_pushboolean(l, ret);")
  106. elif type_is_number(type):
  107. wglue("lua_pushnumber(l, lua_Number(ret));")
  108. elif type == "char" or type == "CString":
  109. wglue("lua_pushstring(l, &ret[0]);")
  110. elif type == "Error":
  111. wglue("if(ret) [[unlikely]]")
  112. wglue("{")
  113. ident(1)
  114. wglue("lua_pushstring(l, \"Glue code returned an error\");")
  115. wglue("return -1;")
  116. ident(-1)
  117. wglue("}")
  118. wglue("")
  119. wglue("lua_pushnumber(l, lua_Number(!!ret));")
  120. else:
  121. if is_ptr or is_ref:
  122. wglue("voidp = lua_newuserdata(l, sizeof(LuaUserData));")
  123. wglue("ud = static_cast<LuaUserData*>(voidp);")
  124. wglue("luaL_setmetatable(l, \"%s\");" % type)
  125. wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
  126. if is_ptr:
  127. wglue("ud->initPointed(&luaUserDataTypeInfo%s, ret);" % type)
  128. elif is_ref:
  129. wglue("ud->initPointed(&luaUserDataTypeInfo%s, &ret);" % type)
  130. else:
  131. wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % type)
  132. wglue("voidp = lua_newuserdata(l, size);")
  133. wglue("luaL_setmetatable(l, \"%s\");" % type)
  134. wglue("ud = static_cast<LuaUserData*>(voidp);")
  135. wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
  136. wglue("ud->initGarbageCollected(&luaUserDataTypeInfo%s);" % type)
  137. wglue("::new(ud->getData<%s>()) %s(std::move(ret));" % (type, type))
  138. wglue("")
  139. wglue("return 1;")
  140. def arg(arg_txt, stack_index, index):
  141. """ Write the pop code for a single argument """
  142. (type, is_ref, is_ptr, is_const) = parse_type_decl(arg_txt)
  143. if type_is_bool(type) or type_is_number(type):
  144. wglue("%s arg%d;" % (type, index))
  145. wglue("if(LuaBinder::checkNumber(l, %d, arg%d)) [[unlikely]]" % (stack_index, index))
  146. wglue("{")
  147. ident(1)
  148. wglue("return -1;")
  149. ident(-1)
  150. wglue("}")
  151. elif type == "char" or type == "CString":
  152. wglue("const char* arg%d;" % index)
  153. wglue("if(LuaBinder::checkString(l, %d, arg%d)) [[unlikely]]" % (stack_index, index))
  154. wglue("{")
  155. ident(1)
  156. wglue("return -1;")
  157. ident(-1)
  158. wglue("}")
  159. elif type_is_enum(type):
  160. wglue("lua_Number arg%dTmp;" % index)
  161. wglue("if(LuaBinder::checkNumber(l, %d, arg%dTmp)) [[unlikely]]" % (stack_index, index))
  162. wglue("{")
  163. ident(1)
  164. wglue("return -1;")
  165. ident(-1)
  166. wglue("}")
  167. wglue("const %s arg%d = %s(arg%dTmp);" % (type, index, type, index))
  168. else:
  169. # Must be user type
  170. wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
  171. wglue("if(LuaBinder::checkUserData(l, %d, luaUserDataTypeInfo%s, ud)) [[unlikely]]" % (stack_index, type))
  172. wglue("{")
  173. ident(1)
  174. wglue("return -1;")
  175. ident(-1)
  176. wglue("}")
  177. wglue("")
  178. wglue("%s* iarg%d = ud->getData<%s>();" % (type, index, type))
  179. if is_ptr:
  180. wglue("%s arg%d(iarg%d);" % (arg_txt, index, index))
  181. else:
  182. wglue("%s arg%d(*iarg%d);" % (arg_txt, index, index))
  183. def args(args_el, stack_index):
  184. """ Write the pop code for argument parsing and return the arg list """
  185. if args_el is None:
  186. return ""
  187. wglue("// Pop arguments")
  188. arg_index = 0
  189. # Do the work
  190. args_str = ""
  191. arg_index = 0
  192. for arg_el in args_el.iter("arg"):
  193. arg(arg_el.text, stack_index, arg_index)
  194. args_str += "arg%d, " % arg_index
  195. wglue("")
  196. stack_index += 1
  197. arg_index += 1
  198. if len(args_str) > 0:
  199. args_str = args_str[:-2]
  200. return args_str
  201. def count_args(args_el):
  202. """ Count the number of arguments """
  203. if args_el is None:
  204. return 0
  205. count = 0
  206. for arg_el in args_el.iter("arg"):
  207. count += 1
  208. return count
  209. def check_args(args_el, bias):
  210. """ Check number of args. Call that first because it throws error """
  211. if args_el is not None:
  212. count = bias + count_args(args_el)
  213. else:
  214. count = bias
  215. wglue("if(LuaBinder::checkArgsCount(l, %d)) [[unlikely]]" % count)
  216. wglue("{")
  217. ident(1)
  218. wglue("return -1;")
  219. ident(-1)
  220. wglue("}")
  221. wglue("")
  222. def get_meth_alias(meth_el):
  223. """ Return the method alias """
  224. meth_name = meth_el.get("name")
  225. if meth_name == "operator+":
  226. meth_alias = "__add"
  227. elif meth_name == "operator-":
  228. meth_alias = "__sub"
  229. elif meth_name == "operator*":
  230. meth_alias = "__mul"
  231. elif meth_name == "operator/":
  232. meth_alias = "__div"
  233. elif meth_name == "operator==":
  234. meth_alias = "__eq"
  235. elif meth_name == "operator<":
  236. meth_alias = "__lt"
  237. elif meth_name == "operator<=":
  238. meth_alias = "__le"
  239. elif meth_name == "operator>":
  240. meth_alias = "__gt"
  241. elif meth_name == "operator>=":
  242. meth_alias = "__ge"
  243. elif meth_name == "operator=":
  244. meth_alias = "copy"
  245. else:
  246. meth_alias = meth_name
  247. meth_alias_txt = meth_el.get("alias")
  248. if meth_alias_txt is not None:
  249. meth_alias = meth_alias_txt
  250. return meth_alias
  251. def write_local_vars():
  252. wglue("[[maybe_unused]] LuaUserData* ud;")
  253. wglue("[[maybe_unused]] void* voidp;")
  254. wglue("[[maybe_unused]] PtrSize size;")
  255. wglue("")
  256. def method(class_name, meth_el):
  257. """ Handle a method """
  258. meth_name = meth_el.get("name")
  259. meth_alias = get_meth_alias(meth_el)
  260. wglue("/// Pre-wrap method %s::%s." % (class_name, meth_name))
  261. wglue("static inline int pwrap%s%s(lua_State* l)" % (class_name, meth_alias))
  262. wglue("{")
  263. ident(1)
  264. write_local_vars()
  265. check_args(meth_el.find("args"), 1)
  266. # Get this pointer
  267. wglue("// Get \"this\" as \"self\"")
  268. wglue("if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfo%s, ud))" % class_name)
  269. wglue("{")
  270. ident(1)
  271. wglue("return -1;")
  272. ident(-1)
  273. wglue("}")
  274. wglue("")
  275. wglue("%s* self = ud->getData<%s>();" % (class_name, class_name))
  276. wglue("")
  277. args_str = args(meth_el.find("args"), 2)
  278. # Return value
  279. ret_txt = None
  280. ret_el = meth_el.find("return")
  281. if ret_el is not None:
  282. ret_txt = ret_el.text
  283. # Method call
  284. wglue("// Call the method")
  285. call = meth_el.find("overrideCall")
  286. if call is not None:
  287. call = call.text
  288. if call is not None:
  289. wglue("%s" % call)
  290. else:
  291. if ret_txt is None:
  292. wglue("self->%s(%s);" % (meth_name, args_str))
  293. else:
  294. wglue("%s ret = self->%s(%s);" % (ret_txt, meth_name, args_str))
  295. wglue("")
  296. ret(ret_el)
  297. ident(-1)
  298. wglue("}")
  299. wglue("")
  300. # Write the actual function
  301. wglue("/// Wrap method %s::%s." % (class_name, meth_name))
  302. wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
  303. wglue("{")
  304. ident(1)
  305. wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
  306. wglue("if(res >= 0)")
  307. wglue("{")
  308. ident(1)
  309. wglue("return res;")
  310. ident(-1)
  311. wglue("}")
  312. wglue("")
  313. wglue("lua_error(l);")
  314. wglue("return 0;")
  315. ident(-1)
  316. wglue("}")
  317. wglue("")
  318. def static_method(class_name, meth_el):
  319. """ Handle a static method """
  320. meth_name = meth_el.get("name")
  321. meth_alias = get_meth_alias(meth_el)
  322. wglue("/// Pre-wrap static method %s::%s." % (class_name, meth_name))
  323. wglue("static inline int pwrap%s%s(lua_State* l)" % (class_name, meth_alias))
  324. wglue("{")
  325. ident(1)
  326. write_local_vars()
  327. check_args(meth_el.find("args"), 0)
  328. # Args
  329. args_str = args(meth_el.find("args"), 1)
  330. # Return value
  331. ret_txt = None
  332. ret_el = meth_el.find("return")
  333. if ret_el is not None:
  334. ret_txt = ret_el.text
  335. # Method call
  336. wglue("// Call the method")
  337. if ret_txt is None:
  338. wglue("%s::%s(%s);" % (class_name, meth_name, args_str))
  339. else:
  340. wglue("%s ret = %s::%s(%s);" % (ret_txt, class_name, meth_name, args_str))
  341. wglue("")
  342. ret(ret_el)
  343. ident(-1)
  344. wglue("}")
  345. wglue("")
  346. # Write the actual function
  347. wglue("/// Wrap static method %s::%s." % (class_name, meth_name))
  348. wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
  349. wglue("{")
  350. ident(1)
  351. wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
  352. wglue("if(res >= 0)")
  353. wglue("{")
  354. ident(1)
  355. wglue("return res;")
  356. ident(-1)
  357. wglue("}")
  358. wglue("")
  359. wglue("lua_error(l);")
  360. wglue("return 0;")
  361. ident(-1)
  362. wglue("}")
  363. wglue("")
  364. def constructor(constr_el, class_name, constructor_idx):
  365. """ Handle constructor """
  366. wglue("/// Pre-wrap constructor for %s." % (class_name))
  367. wglue("static inline int pwrap%sCtor%d(lua_State* l)" % (class_name, constructor_idx))
  368. wglue("{")
  369. ident(1)
  370. write_local_vars()
  371. check_args(constr_el.find("args"), 0)
  372. # Args
  373. args_str = args(constr_el.find("args"), 1)
  374. # Create new userdata
  375. wglue("// Create user data")
  376. wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % class_name)
  377. wglue("voidp = lua_newuserdata(l, size);")
  378. wglue("luaL_setmetatable(l, luaUserDataTypeInfo%s.m_typeName);" % class_name)
  379. wglue("ud = static_cast<LuaUserData*>(voidp);")
  380. wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % class_name)
  381. wglue("ud->initGarbageCollected(&luaUserDataTypeInfo%s);" % class_name)
  382. wglue("::new(ud->getData<%s>()) %s(%s);" % (class_name, class_name, args_str))
  383. wglue("")
  384. wglue("return 1;")
  385. ident(-1)
  386. wglue("}")
  387. wglue("")
  388. def constructors(constructors_el, class_name):
  389. """ Wrap all constructors """
  390. idx = 0
  391. func_names_and_arg_counts = []
  392. # Create the pre-wrap C functions
  393. for constructor_el in constructors_el.iter("constructor"):
  394. arg_count = count_args(constructor_el.find("args"))
  395. # Iterate all arg counts and make sure there are no duplicates
  396. for i in range(idx):
  397. if func_names_and_arg_counts[i][1] == arg_count:
  398. raise Exception("Every constructor overload should have a unique arg count. class: %s" % class_name)
  399. constructor(constructor_el, class_name, idx)
  400. func_names_and_arg_counts.append(["pwrap%sCtor%d" % (class_name, idx), arg_count])
  401. idx += 1
  402. if idx == 0:
  403. raise Exception("Found no <constructor>")
  404. # Create the landing function
  405. wglue("/// Wrap constructors for %s." % class_name)
  406. wglue("static int wrap%sCtor(lua_State* l)" % class_name)
  407. wglue("{")
  408. ident(1)
  409. if idx == 1:
  410. wglue("int res = pwrap%sCtor0(l);" % class_name)
  411. else:
  412. wglue("// Chose the right overload")
  413. wglue("const int argCount = lua_gettop(l);")
  414. wglue("int res = 0;")
  415. wglue("switch(argCount)")
  416. wglue("{")
  417. for name_and_arg_count in func_names_and_arg_counts:
  418. func_name = name_and_arg_count[0]
  419. arg_count = name_and_arg_count[1]
  420. wglue("case %d:" % arg_count)
  421. wglue("res = %s(l); break;" % func_name)
  422. wglue("default:")
  423. wglue("lua_pushfstring(l, \"Wrong overloaded new. Wrong number of arguments: %d\", argCount);")
  424. wglue("res = -1;")
  425. wglue("}")
  426. wglue("")
  427. wglue("if(res >= 0)")
  428. wglue("{")
  429. ident(1)
  430. wglue("return res;")
  431. ident(-1)
  432. wglue("}")
  433. wglue("")
  434. wglue("lua_error(l);")
  435. wglue("return 0;")
  436. ident(-1)
  437. wglue("}")
  438. wglue("")
  439. def destructor(class_name):
  440. """ Create a destructor """
  441. wglue("/// Wrap destructor for %s." % (class_name))
  442. wglue("static int wrap%sDtor(lua_State* l)" % class_name)
  443. wglue("{")
  444. ident(1)
  445. write_local_vars()
  446. check_args(None, 1)
  447. wglue("if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfo%s, ud)) [[unlikely]]" % class_name)
  448. wglue("{")
  449. ident(1)
  450. wglue("return -1;")
  451. ident(-1)
  452. wglue("}")
  453. wglue("")
  454. wglue("if(ud->isGarbageCollected())")
  455. wglue("{")
  456. ident(1)
  457. wglue("%s* inst = ud->getData<%s>();" % (class_name, class_name))
  458. wglue("inst->~%s();" % class_name)
  459. ident(-1)
  460. wglue("}")
  461. wglue("")
  462. wglue("return 0;")
  463. ident(-1)
  464. wglue("}")
  465. wglue("")
  466. def class_(class_el):
  467. """ Create a class """
  468. class_name = class_el.get("name")
  469. # Write serializer
  470. serialize = class_el.get("serialize") is not None and class_el.get("serialize") == "true"
  471. if serialize:
  472. # Serialize
  473. serialize_cb_name = "serialize%s" % class_name
  474. wglue("/// Serialize %s" % class_name)
  475. wglue("static void %s(LuaUserData& self, void* data, PtrSize& size)" % serialize_cb_name)
  476. wglue("{")
  477. ident(1)
  478. wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
  479. wglue("obj->serialize(data, size);")
  480. ident(-1)
  481. wglue("}")
  482. wglue("")
  483. # Deserialize
  484. deserialize_cb_name = "deserialize%s" % class_name
  485. wglue("/// De-serialize %s" % class_name)
  486. wglue("static void %s(const void* data, LuaUserData& self)" % deserialize_cb_name)
  487. wglue("{")
  488. ident(1)
  489. wglue("ANKI_ASSERT(data);")
  490. wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
  491. wglue("::new(obj) %s();" % class_name)
  492. wglue("obj->deserialize(data);")
  493. ident(-1)
  494. wglue("}")
  495. wglue("")
  496. else:
  497. serialize_cb_name = "nullptr"
  498. deserialize_cb_name = "nullptr"
  499. # Write the type info
  500. wglue("LuaUserDataTypeInfo luaUserDataTypeInfo%s = {" % class_name)
  501. ident(1)
  502. wglue("%d, \"%s\", LuaUserData::computeSizeForGarbageCollected<%s>(), %s, %s" %
  503. (type_sig(class_name), class_name, class_name, serialize_cb_name, deserialize_cb_name))
  504. ident(-1)
  505. wglue("};")
  506. wglue("")
  507. # Specialize the getDataTypeInfoFor
  508. wglue("template<>")
  509. wglue("const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<%s>()" % class_name)
  510. wglue("{")
  511. ident(1)
  512. wglue("return luaUserDataTypeInfo%s;" % class_name)
  513. ident(-1)
  514. wglue("}")
  515. wglue("")
  516. # Constructor declarations
  517. has_constructor = False
  518. constructors_el = class_el.find("constructors")
  519. if constructors_el is not None:
  520. has_constructor = True
  521. constructors(constructors_el, class_name)
  522. # Destructor declarations
  523. if has_constructor:
  524. destructor(class_name)
  525. # Methods LUA C functions declarations
  526. meth_names_aliases = []
  527. meths_el = class_el.find("methods")
  528. if meths_el is not None:
  529. for meth_el in meths_el.iter("method"):
  530. is_static = meth_el.get("static")
  531. is_static = is_static is not None and is_static == "1"
  532. if is_static:
  533. static_method(class_name, meth_el)
  534. else:
  535. method(class_name, meth_el)
  536. meth_name = meth_el.get("name")
  537. meth_alias = get_meth_alias(meth_el)
  538. meth_names_aliases.append([meth_name, meth_alias, is_static])
  539. # Start class declaration
  540. wglue("/// Wrap class %s." % class_name)
  541. wglue("static inline void wrap%s(lua_State* l)" % class_name)
  542. wglue("{")
  543. ident(1)
  544. wglue("LuaBinder::createClass(l, &luaUserDataTypeInfo%s);" % class_name)
  545. # Register constructor
  546. if has_constructor:
  547. wglue("LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfo%s.m_typeName, \"new\", wrap%sCtor);" %
  548. (class_name, class_name))
  549. # Register destructor
  550. if has_constructor:
  551. wglue("LuaBinder::pushLuaCFuncMethod(l, \"__gc\", wrap%sDtor);" % class_name)
  552. # Register methods
  553. if len(meth_names_aliases) > 0:
  554. for meth_name_alias in meth_names_aliases:
  555. meth_alias = meth_name_alias[1]
  556. is_static = meth_name_alias[2]
  557. if is_static:
  558. wglue("LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfo%s.m_typeName, \"%s\", wrap%s%s);" %
  559. (class_name, meth_alias, class_name, meth_alias))
  560. else:
  561. wglue("LuaBinder::pushLuaCFuncMethod(l, \"%s\", wrap%s%s);" % (meth_alias, class_name, meth_alias))
  562. wglue("lua_settop(l, 0);")
  563. ident(-1)
  564. wglue("}")
  565. wglue("")
  566. def function(func_el):
  567. """ Handle a plain function """
  568. func_name = func_el.get("name")
  569. func_alias = get_meth_alias(func_el)
  570. wglue("/// Pre-wrap function %s." % func_name)
  571. wglue("static inline int pwrap%s(lua_State* l)" % func_alias)
  572. wglue("{")
  573. ident(1)
  574. write_local_vars()
  575. check_args(func_el.find("args"), 0)
  576. # Args
  577. args_str = args(func_el.find("args"), 1)
  578. # Return value
  579. ret_txt = None
  580. ret_el = func_el.find("return")
  581. if ret_el is not None:
  582. ret_txt = ret_el.text
  583. # Call
  584. wglue("// Call the function")
  585. call = func_el.find("overrideCall")
  586. if call is not None:
  587. call = call.text
  588. if call is not None:
  589. wglue("%s" % call)
  590. else:
  591. if ret_txt is None:
  592. wglue("%s(%s);" % (func_name, args_str))
  593. else:
  594. wglue("%s ret = %s(%s);" % (ret_txt, func_name, args_str))
  595. wglue("")
  596. ret(ret_el)
  597. ident(-1)
  598. wglue("}")
  599. wglue("")
  600. # Write the actual function
  601. wglue("/// Wrap function %s." % func_name)
  602. wglue("static int wrap%s(lua_State* l)" % func_alias)
  603. wglue("{")
  604. ident(1)
  605. wglue("int res = pwrap%s(l);" % func_alias)
  606. wglue("if(res >= 0)")
  607. wglue("{")
  608. ident(1)
  609. wglue("return res;")
  610. ident(-1)
  611. wglue("}")
  612. wglue("")
  613. wglue("lua_error(l);")
  614. wglue("return 0;")
  615. ident(-1)
  616. wglue("}")
  617. wglue("")
  618. def enum(enum_el):
  619. enum_name = enum_el.get("name")
  620. # Write the type info
  621. wglue("LuaUserDataTypeInfo luaUserDataTypeInfo%s = {" % enum_name)
  622. ident(1)
  623. wglue("%d, \"%s\", 0, nullptr, nullptr" % (type_sig(enum_name), enum_name))
  624. ident(-1)
  625. wglue("};")
  626. wglue("")
  627. # Specialize the getDataTypeInfoFor
  628. wglue("template<>")
  629. wglue("const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<%s>()" % enum_name)
  630. wglue("{")
  631. ident(1)
  632. wglue("return luaUserDataTypeInfo%s;" % enum_name)
  633. ident(-1)
  634. wglue("}")
  635. wglue("")
  636. # Start declaration
  637. wglue("/// Wrap enum %s." % enum_name)
  638. wglue("static inline void wrap%s(lua_State* l)" % enum_name)
  639. wglue("{")
  640. ident(1)
  641. wglue("lua_newtable(l);") # Push new table
  642. wglue("lua_setglobal(l, luaUserDataTypeInfo%s.m_typeName);" % enum_name) # Pop and make global
  643. wglue("lua_getglobal(l, luaUserDataTypeInfo%s.m_typeName);" % enum_name) # Push the table again
  644. wglue("")
  645. # Now the table is at the top of the stack
  646. for enumerant_el in enum_el.iter("enumerant"):
  647. enumerant_name = enumerant_el.get("name")
  648. wglue("lua_pushstring(l, \"%s\");" % enumerant_name) # Push key
  649. wglue("ANKI_ASSERT(%s(lua_Number(%s::%s)) == %s::%s && \"Can't map the enumerant to a lua_Number\");" %
  650. (enum_name, enum_name, enumerant_name, enum_name, enumerant_name))
  651. wglue("lua_pushnumber(l, lua_Number(%s::%s));" % (enum_name, enumerant_name)) # Push value
  652. wglue("lua_settable(l, -3);") # Do table[key]=value and pop 2. The table is at the top of the stack
  653. wglue("")
  654. # Done
  655. wglue("lua_settop(l, 0);")
  656. ident(-1)
  657. wglue("}")
  658. wglue("")
  659. def main():
  660. """ Main function """
  661. global g_out_file
  662. filenames = parse_commandline()
  663. for filename in filenames:
  664. out_filename = get_base_fname(filename) + ".cpp"
  665. g_out_file = open(out_filename, "w", newline="\n")
  666. tree = et.parse(filename)
  667. root = tree.getroot()
  668. # Head
  669. head = root.find("head")
  670. if head is not None:
  671. wglue("%s" % head.text)
  672. wglue("")
  673. # Enums (First because others use the g_enum_names)
  674. global g_enum_names
  675. for enums in root.iter("enums"):
  676. for enum_el in enums.iter("enum"):
  677. enum(enum_el)
  678. g_enum_names.append(enum_el.get("name"))
  679. # Classes
  680. class_names = []
  681. for cls in root.iter("classes"):
  682. for cl in cls.iter("class"):
  683. class_(cl)
  684. class_names.append(cl.get("name"))
  685. # Functions
  686. func_names = []
  687. for fs in root.iter("functions"):
  688. for f in fs.iter("function"):
  689. function(f)
  690. func_names.append(f.get("name"))
  691. # Wrap function
  692. wglue("/// Wrap the module.")
  693. wglue("void wrapModule%s(lua_State* l)" % get_base_fname(filename))
  694. wglue("{")
  695. ident(1)
  696. for class_name in class_names:
  697. wglue("wrap%s(l);" % class_name)
  698. for func_name in func_names:
  699. wglue("LuaBinder::pushLuaCFunc(l, \"%s\", wrap%s);" % (func_name, func_name))
  700. for enum_name in g_enum_names:
  701. wglue("wrap%s(l);" % enum_name)
  702. ident(-1)
  703. wglue("}")
  704. wglue("")
  705. # Tail
  706. tail = root.find("tail")
  707. if tail is not None:
  708. wglue("%s" % tail.text)
  709. wglue("")
  710. g_out_file.close()
  711. if __name__ == "__main__":
  712. main()