lua_glue_gen.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. #!/usr/bin/python
  2. # Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos.
  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. identation_level = 0
  11. out_file = None
  12. separator = "//=============================================================" \
  13. "================="
  14. def parse_commandline():
  15. """ Parse the command line arguments """
  16. parser = optparse.OptionParser(usage = "usage: %prog [options]", \
  17. description = "Create LUA bindings using XML")
  18. parser.add_option("-i", "--input", dest = "inp",
  19. type = "string", help = "specify the XML files to parse. " \
  20. "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. return hash(value)
  28. def get_base_fname(path):
  29. """ From path/to/a/file.ext return the "file" """
  30. return os.path.splitext(os.path.basename(path))[0]
  31. def wglue(txt):
  32. """ Write glue code to the output """
  33. global out_file
  34. global identation_level
  35. out_file.write("%s%s\n" % ("\t" * identation_level, txt))
  36. def ident(number):
  37. """ Increase or recrease identation for the wglue """
  38. global identation_level
  39. identation_level += number
  40. def type_is_bool(type):
  41. """ Check if a type is boolean """
  42. return type == "Bool" or type == "Bool8" or type == "bool"
  43. def type_is_number(type):
  44. """ Check if a type is number """
  45. numbers = ["U8", "U16", "U32", "U64", "I8", "I16", "I32", "I64", \
  46. "U", "I", "PtrSize", "F32", "F64", \
  47. "int", "unsigned", "unsigned int", "short", "unsigned short", "uint", \
  48. "float", "double"]
  49. it_is = False
  50. for num in numbers:
  51. if num == type:
  52. it_is = True
  53. break
  54. return it_is
  55. def parse_type_decl(arg_txt):
  56. """ Parse an arg text """
  57. tokens = arg_txt.split(" ")
  58. tokens_size = len(tokens)
  59. type = tokens[tokens_size - 1]
  60. type_len = len(type)
  61. is_ptr = False
  62. is_ref = False
  63. if type[type_len - 1] == "&":
  64. is_ref = True
  65. elif type[type_len - 1] == "*":
  66. is_ptr = True
  67. if is_ref or is_ptr:
  68. type = type[:-1]
  69. is_const = False
  70. if tokens[0] == "const":
  71. is_const = True
  72. return (type, is_ref, is_ptr, is_const)
  73. def ret(ret_el):
  74. """ Push return value """
  75. if ret_el is None:
  76. wglue("return 0;")
  77. return
  78. wglue("// Push return value")
  79. type_txt = ret_el.text
  80. (type, is_ref, is_ptr, is_const) = parse_type_decl(type_txt)
  81. if is_ptr:
  82. wglue("if(ANKI_UNLIKELY(ret == nullptr))")
  83. wglue("{")
  84. ident(1)
  85. wglue("lua_pushstring(l, \"Glue code returned nullptr\");")
  86. wglue("return -1;")
  87. ident(-1)
  88. wglue("}")
  89. wglue("")
  90. if type_is_bool(type):
  91. wglue("lua_pushboolean(l, ret);")
  92. elif type_is_number(type):
  93. wglue("lua_pushnumber(l, ret);")
  94. elif type == "char" or type == "CString":
  95. wglue("lua_pushstring(l, &ret[0]);")
  96. elif type == "Error":
  97. wglue("if(ANKI_UNLIKELY(ret))")
  98. wglue("{")
  99. ident(1)
  100. wglue("lua_pushstring(l, \"Glue code returned an error\");")
  101. wglue("return -1;")
  102. ident(-1)
  103. wglue("}")
  104. wglue("")
  105. wglue("lua_pushnumber(l, ret);")
  106. else:
  107. if is_ptr or is_ref:
  108. wglue("voidp = lua_newuserdata(l, sizeof(UserData));")
  109. wglue("ud = static_cast<UserData*>(voidp);")
  110. wglue("luaL_setmetatable(l, \"%s\");" % type)
  111. if is_ptr:
  112. wglue("ud->initPointed(%d, const_cast<%s*>(ret));"
  113. % (type_sig(type), type))
  114. elif is_ref:
  115. wglue("ud->initPointed(%d, const_cast<%s*>(&ret));"
  116. % (type_sig(type), type))
  117. else:
  118. wglue("size = UserData::computeSizeForGarbageCollected<%s>();" \
  119. % type)
  120. wglue("voidp = lua_newuserdata(l, size);")
  121. wglue("luaL_setmetatable(l, \"%s\");" % type)
  122. wglue("ud = static_cast<UserData*>(voidp);")
  123. wglue("ud->initGarbageCollected(%d);" % type_sig(type))
  124. wglue("::new(ud->getData<%s>()) %s(std::move(ret));" % (type, type))
  125. wglue("")
  126. wglue("return 1;")
  127. def arg(arg_txt, stack_index, index):
  128. """ Write the pop code for a single argument """
  129. (type, is_ref, is_ptr, is_const) = parse_type_decl(arg_txt)
  130. if type_is_bool(type) or type_is_number(type):
  131. wglue("%s arg%d;" % (type, index))
  132. wglue("if(LuaBinder::checkNumber(l, %d, arg%d))" \
  133. % (stack_index, index))
  134. wglue("{")
  135. ident(1)
  136. wglue("return -1;")
  137. ident(-1)
  138. wglue("}")
  139. elif type == "char" or type == "CString":
  140. wglue("const char* arg%d;" % index)
  141. wglue("if(LuaBinder::checkString(l, %d, arg%d))" \
  142. % (stack_index, index))
  143. wglue("{")
  144. ident(1)
  145. wglue("return -1;")
  146. ident(-1)
  147. wglue("}")
  148. else:
  149. wglue("if(LuaBinder::checkUserData(l, %d, \"%s\", %d, ud))" \
  150. % (stack_index, type, type_sig(type)))
  151. wglue("{")
  152. ident(1)
  153. wglue("return -1;")
  154. ident(-1)
  155. wglue("}")
  156. wglue("")
  157. wglue("%s* iarg%d = ud->getData<%s>();" \
  158. % (type, index, type))
  159. if is_ptr:
  160. wglue("%s arg%d(iarg%d);" % (arg_txt, index, index))
  161. else:
  162. wglue("%s arg%d(*iarg%d);" % (arg_txt, index, index))
  163. def args(args_el, stack_index):
  164. """ Write the pop code for argument parsing and return the arg list """
  165. if args_el is None:
  166. return ""
  167. wglue("// Pop arguments")
  168. arg_index = 0
  169. # Do the work
  170. args_str = ""
  171. arg_index = 0
  172. for arg_el in args_el.iter("arg"):
  173. arg(arg_el.text, stack_index, arg_index)
  174. args_str += "arg%d, " % arg_index
  175. wglue("")
  176. stack_index += 1
  177. arg_index += 1
  178. if len(args_str) > 0:
  179. args_str = args_str[:-2]
  180. return args_str
  181. def check_args(args_el, bias):
  182. """ Check number of args. Call that first because it throws error """
  183. if args_el is None:
  184. wglue("LuaBinder::checkArgsCount(l, %d);" % bias)
  185. else:
  186. count = 0
  187. for arg_el in args_el.iter("arg"):
  188. count += 1
  189. wglue("LuaBinder::checkArgsCount(l, %d);" % (bias + count))
  190. wglue("")
  191. def get_meth_alias(meth_el):
  192. """ Return the method alias """
  193. meth_name = meth_el.get("name")
  194. if meth_name == "operator+":
  195. meth_alias = "__add"
  196. elif meth_name == "operator-":
  197. meth_alias = "__sub"
  198. elif meth_name == "operator*":
  199. meth_alias = "__mul"
  200. elif meth_name == "operator/":
  201. meth_alias = "__div"
  202. elif meth_name == "operator==":
  203. meth_alias = "__eq"
  204. elif meth_name == "operator<":
  205. meth_alias = "__lt"
  206. elif meth_name == "operator<=":
  207. meth_alias = "__le"
  208. elif meth_name == "operator>":
  209. meth_alias = "__gt"
  210. elif meth_name == "operator>=":
  211. meth_alias = "__ge"
  212. elif meth_name == "operator=":
  213. meth_alias = "copy"
  214. else:
  215. meth_alias = meth_name
  216. meth_alias_txt = meth_el.get("alias")
  217. if meth_alias_txt is not None:
  218. meth_alias = meth_alias_txt
  219. return meth_alias
  220. def write_local_vars():
  221. wglue("UserData* ud;")
  222. wglue("(void)ud;")
  223. wglue("void* voidp;")
  224. wglue("(void)voidp;")
  225. wglue("PtrSize size;")
  226. wglue("(void)size;")
  227. wglue("")
  228. def method(class_name, meth_el):
  229. """ Handle a method """
  230. meth_name = meth_el.get("name")
  231. meth_alias = get_meth_alias(meth_el)
  232. global separator
  233. wglue(separator)
  234. wglue("/// Pre-wrap method %s::%s." % (class_name, meth_name))
  235. wglue("static inline int pwrap%s%s(lua_State* l)" \
  236. % (class_name, meth_alias))
  237. wglue("{")
  238. ident(1)
  239. write_local_vars()
  240. check_args(meth_el.find("args"), 1)
  241. # Get this pointer
  242. wglue("// Get \"this\" as \"self\"")
  243. wglue("if(LuaBinder::checkUserData(l, 1, classname%s, %d, ud))" \
  244. % (class_name, type_sig(class_name)))
  245. wglue("{")
  246. ident(1)
  247. wglue("return -1;")
  248. ident(-1)
  249. wglue("}")
  250. wglue("")
  251. wglue("%s* self = ud->getData<%s>();" % (class_name, class_name))
  252. wglue("")
  253. args_str = args(meth_el.find("args"), 2)
  254. # Return value
  255. ret_txt = None
  256. ret_el = meth_el.find("return")
  257. if ret_el is not None:
  258. ret_txt = ret_el.text
  259. # Method call
  260. wglue("// Call the method")
  261. call = meth_el.find("overrideCall")
  262. if call is not None:
  263. call = call.text
  264. if call is not None:
  265. wglue("%s" % call)
  266. else:
  267. if ret_txt is None:
  268. wglue("self->%s(%s);" % (meth_name, args_str))
  269. else:
  270. wglue("%s ret = self->%s(%s);" % (ret_txt, meth_name, args_str))
  271. wglue("")
  272. ret(ret_el)
  273. ident(-1)
  274. wglue("}")
  275. wglue("")
  276. # Write the actual function
  277. wglue(separator)
  278. wglue("/// Wrap method %s::%s." % (class_name, meth_name))
  279. wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
  280. wglue("{")
  281. ident(1)
  282. wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
  283. wglue("if(res >= 0)")
  284. wglue("{")
  285. ident(1)
  286. wglue("return res;")
  287. ident(-1)
  288. wglue("}")
  289. wglue("")
  290. wglue("lua_error(l);")
  291. wglue("return 0;")
  292. ident(-1)
  293. wglue("}")
  294. wglue("")
  295. def static_method(class_name, meth_el):
  296. """ Handle a static method """
  297. meth_name = meth_el.get("name")
  298. meth_alias = get_meth_alias(meth_el)
  299. global separator
  300. wglue(separator)
  301. wglue("/// Pre-wrap static method %s::%s." % (class_name, meth_name))
  302. wglue("static inline int pwrap%s%s(lua_State* l)" \
  303. % (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);" \
  321. % (ret_txt, class_name, meth_name, args_str))
  322. wglue("")
  323. ret(ret_el)
  324. ident(-1)
  325. wglue("}")
  326. wglue("")
  327. # Write the actual function
  328. wglue(separator)
  329. wglue("/// Wrap static method %s::%s." % (class_name, meth_name))
  330. wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
  331. wglue("{")
  332. ident(1)
  333. wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
  334. wglue("if(res >= 0)")
  335. wglue("{")
  336. ident(1)
  337. wglue("return res;")
  338. ident(-1)
  339. wglue("}")
  340. wglue("")
  341. wglue("lua_error(l);")
  342. wglue("return 0;")
  343. ident(-1)
  344. wglue("}")
  345. wglue("")
  346. def constructor(constr_el, class_name):
  347. """ Handle constructor """
  348. global separator
  349. wglue(separator)
  350. wglue("/// Pre-wrap constructor for %s." % (class_name))
  351. wglue("static inline int pwrap%sCtor(lua_State* l)" % class_name)
  352. wglue("{")
  353. ident(1)
  354. write_local_vars()
  355. check_args(constr_el.find("args"), 0)
  356. # Args
  357. args_str = args(constr_el.find("args"), 1)
  358. # Create new userdata
  359. wglue("// Create user data")
  360. wglue("size = UserData::computeSizeForGarbageCollected<%s>();" % class_name)
  361. wglue("voidp = lua_newuserdata(l, size);")
  362. wglue("luaL_setmetatable(l, classname%s);" % class_name)
  363. wglue("ud = static_cast<UserData*>(voidp);")
  364. wglue("ud->initGarbageCollected(%d);" % type_sig(class_name))
  365. wglue("::new(ud->getData<%s>()) %s(%s);" \
  366. % (class_name, class_name, args_str))
  367. wglue("")
  368. wglue("return 1;")
  369. ident(-1)
  370. wglue("}")
  371. wglue("")
  372. # Write the actual function
  373. wglue(separator)
  374. wglue("/// Wrap constructor for %s." % class_name)
  375. wglue("static int wrap%sCtor(lua_State* l)" % class_name)
  376. wglue("{")
  377. ident(1)
  378. wglue("int res = pwrap%sCtor(l);" % class_name)
  379. wglue("if(res >= 0)")
  380. wglue("{")
  381. ident(1)
  382. wglue("return res;")
  383. ident(-1)
  384. wglue("}")
  385. wglue("")
  386. wglue("lua_error(l);")
  387. wglue("return 0;")
  388. ident(-1)
  389. wglue("}")
  390. wglue("")
  391. def destructor(class_name):
  392. """ Create a destroctor """
  393. global separator
  394. wglue(separator)
  395. wglue("/// Wrap destructor for %s." % (class_name))
  396. wglue("static int wrap%sDtor(lua_State* l)" % class_name)
  397. wglue("{")
  398. ident(1)
  399. write_local_vars();
  400. wglue("LuaBinder::checkArgsCount(l, 1);")
  401. wglue("if(LuaBinder::checkUserData(l, 1, classname%s, %d, ud))" \
  402. % (class_name, type_sig(class_name)))
  403. wglue("{")
  404. ident(1)
  405. wglue("return -1;")
  406. ident(-1)
  407. wglue("}")
  408. wglue("");
  409. wglue("if(ud->isGarbageCollected())")
  410. wglue("{")
  411. ident(1)
  412. wglue("%s* inst = ud->getData<%s>();" \
  413. % (class_name, class_name))
  414. wglue("inst->~%s();" % class_name)
  415. ident(-1)
  416. wglue("}")
  417. wglue("")
  418. wglue("return 0;")
  419. ident(-1)
  420. wglue("}")
  421. wglue("")
  422. def class_(class_el):
  423. """ Create a class """
  424. global separator
  425. class_name = class_el.get("name")
  426. # Write class decoration and stuff
  427. wglue(separator)
  428. cmnt = "// %s" % class_name
  429. cmnt += (79 - len(cmnt)) * " "
  430. cmnt += "="
  431. wglue(cmnt)
  432. wglue(separator)
  433. wglue("")
  434. wglue(separator)
  435. wglue("static const char* classname%s = \"%s\";" \
  436. % (class_name, class_name))
  437. wglue("")
  438. wglue("template<>")
  439. wglue("I64 LuaBinder::getWrappedTypeSignature<%s>()" % class_name)
  440. wglue("{")
  441. ident(1)
  442. wglue("return %d;" % type_sig(class_name))
  443. ident(-1)
  444. wglue("}")
  445. wglue("")
  446. wglue("template<>")
  447. wglue("const char* LuaBinder::getWrappedTypeName<%s>()" % class_name)
  448. wglue("{")
  449. ident(1)
  450. wglue("return classname%s;" % class_name)
  451. ident(-1)
  452. wglue("}")
  453. wglue("")
  454. # Constructor declarations
  455. has_constructor = False
  456. constructor_el = class_el.find("constructor")
  457. if constructor_el is not None:
  458. constructor(constructor_el, class_name)
  459. has_constructor = True
  460. # Destructor declarations
  461. if has_constructor:
  462. destructor(class_name)
  463. # Methods LUA C functions declarations
  464. meth_names_aliases = []
  465. meths_el = class_el.find("methods")
  466. if meths_el is not None:
  467. for meth_el in meths_el.iter("method"):
  468. is_static = meth_el.get("static")
  469. is_static = is_static is not None and is_static == "1"
  470. if is_static:
  471. static_method(class_name, meth_el)
  472. else:
  473. method(class_name, meth_el)
  474. meth_name = meth_el.get("name")
  475. meth_alias = get_meth_alias(meth_el)
  476. meth_names_aliases.append([meth_name, meth_alias, is_static])
  477. # Start class declaration
  478. wglue(separator)
  479. wglue("/// Wrap class %s." % class_name)
  480. wglue("static inline void wrap%s(lua_State* l)" % class_name)
  481. wglue("{")
  482. ident(1)
  483. wglue("LuaBinder::createClass(l, classname%s);" % class_name)
  484. # Register constructor
  485. if has_constructor:
  486. wglue("LuaBinder::pushLuaCFuncStaticMethod(l, classname%s, \"new\", " \
  487. "wrap%sCtor);" % (class_name, class_name))
  488. # Register destructor
  489. if has_constructor:
  490. wglue("LuaBinder::pushLuaCFuncMethod(l, \"__gc\", wrap%sDtor);" \
  491. % class_name)
  492. # Register methods
  493. if len(meth_names_aliases) > 0:
  494. for meth_name_alias in meth_names_aliases:
  495. meth_alias = meth_name_alias[1]
  496. is_static = meth_name_alias[2]
  497. if is_static:
  498. wglue("LuaBinder::pushLuaCFuncStaticMethod(l, classname%s, " \
  499. "\"%s\", wrap%s%s);" \
  500. % (class_name, meth_alias, class_name, meth_alias))
  501. else:
  502. wglue("LuaBinder::pushLuaCFuncMethod(l, \"%s\", wrap%s%s);" \
  503. % (meth_alias, class_name, meth_alias))
  504. wglue("lua_settop(l, 0);")
  505. ident(-1)
  506. wglue("}")
  507. wglue("")
  508. def function(func_el):
  509. """ Handle a plain function """
  510. func_name = func_el.get("name")
  511. func_alias = get_meth_alias(func_el)
  512. global separator
  513. wglue(separator)
  514. wglue("/// Pre-wrap function %s." % func_name)
  515. wglue("static inline int pwrap%s(lua_State* l)" % func_alias)
  516. wglue("{")
  517. ident(1)
  518. write_local_vars()
  519. check_args(func_el.find("args"), 0)
  520. # Args
  521. args_str = args(func_el.find("args"), 1)
  522. # Return value
  523. ret_txt = None
  524. ret_el = func_el.find("return")
  525. if ret_el is not None:
  526. ret_txt = ret_el.text
  527. # Call
  528. wglue("// Call the function")
  529. call = func_el.find("overrideCall")
  530. if call is not None:
  531. call = call.text
  532. if call is not None:
  533. wglue("%s" % call)
  534. else:
  535. if ret_txt is None:
  536. wglue("%s(%s);" % (func_name, args_str))
  537. else:
  538. wglue("%s ret = %s(%s);" % (ret_txt, func_name, args_str))
  539. wglue("")
  540. ret(ret_el)
  541. ident(-1)
  542. wglue("}")
  543. wglue("")
  544. # Write the actual function
  545. wglue(separator)
  546. wglue("/// Wrap function %s." % func_name)
  547. wglue("static int wrap%s(lua_State* l)" % func_alias)
  548. wglue("{")
  549. ident(1)
  550. wglue("int res = pwrap%s(l);" % func_alias)
  551. wglue("if(res >= 0)")
  552. wglue("{")
  553. ident(1)
  554. wglue("return res;")
  555. ident(-1)
  556. wglue("}")
  557. wglue("")
  558. wglue("lua_error(l);")
  559. wglue("return 0;")
  560. ident(-1)
  561. wglue("}")
  562. wglue("")
  563. def main():
  564. """ Main function """
  565. global out_file
  566. global separator
  567. filenames = parse_commandline()
  568. for filename in filenames:
  569. out_filename = get_base_fname(filename) + ".cpp"
  570. out_file = open(out_filename, "w")
  571. tree = et.parse(filename)
  572. root = tree.getroot()
  573. # Head
  574. head = root.find("head")
  575. if head is not None:
  576. wglue("%s" % head.text)
  577. wglue("")
  578. # Classes
  579. class_names = []
  580. for cls in root.iter("classes"):
  581. for cl in cls.iter("class"):
  582. class_(cl)
  583. class_names.append(cl.get("name"))
  584. # Functions
  585. func_names = []
  586. for fs in root.iter("functions"):
  587. for f in fs.iter("function"):
  588. function(f)
  589. func_names.append(f.get("name"))
  590. # Wrap function
  591. wglue(separator)
  592. wglue("/// Wrap the module.")
  593. wglue("void wrapModule%s(lua_State* l)" % get_base_fname(filename))
  594. wglue("{")
  595. ident(1)
  596. for class_name in class_names:
  597. wglue("wrap%s(l);" % class_name)
  598. for func_name in func_names:
  599. wglue("LuaBinder::pushLuaCFunc(l, \"%s\", wrap%s);" \
  600. % (func_name, func_name))
  601. ident(-1)
  602. wglue("}")
  603. wglue("")
  604. # Tail
  605. tail = root.find("tail")
  606. if tail is not None:
  607. wglue("%s" % tail.text)
  608. wglue("")
  609. out_file.close()
  610. if __name__ == "__main__":
  611. main()