LuaBindingsGenerator.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import ConfigParser
  2. import io
  3. import os
  4. import re
  5. class LuaBindingsGenerator(object):
  6. def __init__(self, config):
  7. self.config = config
  8. self.wrappersHeaderList = ""
  9. self.wrappersHeaderBody = ""
  10. self.cppRegisterOut = ""
  11. self.disableGC = self.config.get('lua', 'DisableGarbageCollection').replace(" ", "").split(",")
  12. self.libName = self.config.get('global', 'LibraryName')
  13. def processTargetFile(self, targetFile):
  14. self.wrappersHeaderList += "#include \"%s/%s\"\n" % (self.config.get('global', 'HeaderIncludeDirectory'), targetFile)
  15. def processClass(self, c):
  16. for method in c["methods"]:
  17. idx = 1
  18. if method["name"] == c["name"]:
  19. self.cppRegisterOut += "\t\t{\"%s\", %s_%s},\n" % (c["name"], self.libName, c["name"])
  20. self.wrappersHeaderBody += "\tstatic int %s_%s(lua_State *L) {\n" % (self.libName, c["name"])
  21. else:
  22. self.cppRegisterOut += "\t\t{\"%s_%s\", %s_%s_%s},\n" % (c["name"], method["name"], self.libName, c["name"], method["name"])
  23. self.wrappersHeaderBody += "\tstatic int %s_%s_%s(lua_State *L) {\n" % (self.libName, c["name"], method["name"])
  24. # if this is not a static method, get the class pointer being passed
  25. if method["type"].find("static ") == -1:
  26. self.wrappersHeaderBody += "\t\tluaL_checktype(L, 1, LUA_TUSERDATA);\n"
  27. self.wrappersHeaderBody += "\t\t%s *inst = (%s*) *((PolyBase**)lua_touserdata(L, 1));\n" % (c["name"], c["name"])
  28. idx = 2
  29. paramlist = []
  30. lparamlist = []
  31. for param in method["parameters"]:
  32. luatype = "LUA_TUSERDATA"
  33. checkfunc = "lua_isuserdata"
  34. if param["type"].find("*") > -1:
  35. luafunc = "(%s) *((PolyBase**)lua_touserdata" % (param["type"].replace("Polygon", "Polycode::Polygon").replace("Rectangle", "Polycode::Rectangle"))
  36. elif param["type"].find("&") > -1:
  37. luafunc = "*(%s*) *((PolyBase**)lua_touserdata" % (param["type"].replace("const", "").replace("&", "").replace("Polygon", "Polycode::Polygon").replace("Rectangle", "Polycode::Rectangle"))
  38. else:
  39. luafunc = "*(%s*) *((PolyBase**)lua_touserdata" % (param["type"].replace("Polygon", "Polycode::Polygon").replace("Rectangle", "Polycode::Rectangle"))
  40. lend = ".__ptr"
  41. luafuncsuffix = ")"
  42. if param["type"] == "int" or param["type"] == "unsigned int" or param["type"] == "short":
  43. luafunc = "lua_tointeger"
  44. luatype = "LUA_TNUMBER"
  45. checkfunc = "lua_isnumber"
  46. luafuncsuffix = ""
  47. lend = ""
  48. if param["type"] == "PolyKEY":
  49. luafunc = "(PolyKEY)lua_tointeger"
  50. luatype = "LUA_TNUMBER"
  51. checkfunc = "lua_isnumber"
  52. luafuncsuffix = ""
  53. lend = ""
  54. if param["type"] == "bool":
  55. luafunc = "lua_toboolean"
  56. luatype = "LUA_TBOOLEAN"
  57. checkfunc = "lua_isboolean"
  58. luafuncsuffix = " != 0"
  59. lend = ""
  60. if param["type"] == "Number":
  61. luatype = "LUA_TNUMBER"
  62. luafunc = "lua_tonumber"
  63. checkfunc = "lua_isnumber"
  64. luafuncsuffix = ""
  65. lend = ""
  66. if param["type"] == "String":
  67. luatype = "LUA_TSTRING"
  68. luafunc = "lua_tostring"
  69. checkfunc = "lua_isstring"
  70. luafuncsuffix = ""
  71. lend = ""
  72. param["type"] = param["type"].replace("Polygon", "Polycode::Polygon").replace("Rectangle", "Polycode::Rectangle")
  73. if "defaltValue" in param:
  74. if checkfunc != "lua_isuserdata" or (checkfunc == "lua_isuserdata" and param["defaltValue"] == "NULL"):
  75. #param["defaltValue"] = param["defaltValue"].replace(" 0f", ".0f")
  76. param["defaltValue"] = param["defaltValue"].replace(": :", "::")
  77. #param["defaltValue"] = param["defaltValue"].replace("0 ", "0.")
  78. param["defaltValue"] = re.sub(r'([0-9]+) ([0-9])+', r'\1.\2', param["defaltValue"])
  79. self.wrappersHeaderBody += "\t\t%s %s;\n" % (param["type"], param["name"])
  80. self.wrappersHeaderBody += "\t\tif(%s(L, %d)) {\n" % (checkfunc, idx)
  81. self.wrappersHeaderBody += "\t\t\t%s = %s(L, %d)%s;\n" % (param["name"], luafunc, idx, luafuncsuffix)
  82. self.wrappersHeaderBody += "\t\t} else {\n"
  83. self.wrappersHeaderBody += "\t\t\t%s = %s;\n" % (param["name"], param["defaltValue"])
  84. self.wrappersHeaderBody += "\t\t}\n"
  85. else:
  86. self.wrappersHeaderBody += "\t\tluaL_checktype(L, %d, %s);\n" % (idx, luatype);
  87. if param["type"] == "String":
  88. self.wrappersHeaderBody += "\t\t%s %s = String(%s(L, %d));\n" % (param["type"], param["name"], luafunc, idx)
  89. else:
  90. self.wrappersHeaderBody += "\t\t%s %s = %s(L, %d)%s;\n" % (param["type"], param["name"], luafunc, idx,luafuncsuffix)
  91. else:
  92. self.wrappersHeaderBody += "\t\tluaL_checktype(L, %d, %s);\n" % (idx, luatype);
  93. if param["type"] == "String":
  94. self.wrappersHeaderBody += "\t\t%s %s = String(%s(L, %d));\n" % (param["type"], param["name"], luafunc, idx)
  95. else:
  96. self.wrappersHeaderBody += "\t\t%s %s = %s(L, %d)%s;\n" % (param["type"], param["name"], luafunc, idx, luafuncsuffix)
  97. paramlist.append(param["name"])
  98. lparamlist.append(param["name"]+lend)
  99. idx = idx +1 # Param parse success-- mark the increased stack
  100. # Generate C++-side method call / generate return value
  101. if method["name"] == c["name"]: # If constructor
  102. if c["name"] == "EventHandler": # See LuaEventHandler above
  103. self.wrappersHeaderBody += "\t\tLuaEventHandler *inst = new LuaEventHandler();\n"
  104. self.wrappersHeaderBody += "\t\tinst->wrapperIndex = luaL_ref(L, LUA_REGISTRYINDEX );\n"
  105. self.wrappersHeaderBody += "\t\tinst->L = L;\n"
  106. else:
  107. self.wrappersHeaderBody += "\t\t%s *inst = new %s(%s);\n" % (c["name"], c["name"], ", ".join(paramlist))
  108. self.wrappersHeaderBody += "\t\tPolyBase **userdataPtr = (PolyBase**)lua_newuserdata(L, sizeof(PolyBase*));\n"
  109. self.wrappersHeaderBody += "\t\t*userdataPtr = (PolyBase*)inst;\n"
  110. self.wrappersHeaderBody += "\t\tluaL_getmetatable(L, \"%s.%s\");\n" % (self.libName, c["name"])
  111. self.wrappersHeaderBody += "\t\tlua_setmetatable(L, -2);\n"
  112. self.wrappersHeaderBody += "\t\treturn 1;\n"
  113. else: #If non-constructor
  114. if method["type"].find("static ") == -1: # If non-static
  115. call = "inst->%s(%s)" % (method["name"], ", ".join(paramlist))
  116. else: # If static (FIXME: Why doesn't this work?)
  117. call = "%s::%s(%s)" % (c["name"], method["name"], ", ".join(paramlist))
  118. #check if returning a template
  119. if method["type"].find("<") > -1:
  120. #if returning a vector, convert to lua table
  121. if method["type"].find("std::vector") > -1:
  122. vectorReturnClass = method["type"].replace("std::vector<", "").replace(">","").replace(" ", "")
  123. if vectorReturnClass.find("&") == -1 and vectorReturnClass.find("*") > -1: #FIXME: return references to std::vectors and basic types
  124. vectorReturn = True
  125. self.wrappersHeaderBody += "\t\tstd::vector<%s> retVector = %s;\n" % (vectorReturnClass,call)
  126. self.wrappersHeaderBody += "\t\tlua_newtable(L);\n"
  127. self.wrappersHeaderBody += "\t\tfor(int i=0; i < retVector.size(); i++) {\n"
  128. self.wrappersHeaderBody += "\t\t\tPolyBase **userdataPtr = (PolyBase**)lua_newuserdata(L, sizeof(PolyBase*));\n"
  129. self.wrappersHeaderBody += "\t\t\t*userdataPtr = (PolyBase*)retVector[i];\n"
  130. self.wrappersHeaderBody += "\t\t\tlua_rawseti(L, -2, i+1);\n"
  131. self.wrappersHeaderBody += "\t\t}\n"
  132. self.wrappersHeaderBody += "\t\treturn 1;\n"
  133. else:
  134. self.wrappersHeaderBody += "\t\treturn 0;\n"
  135. # else If void-typed:
  136. elif method["type"] == "void" or method["type"] == "static void" or method["type"] == "virtual void" or method["type"] == "inline void":
  137. self.wrappersHeaderBody += "\t\t%s;\n" % (call)
  138. basicType = True
  139. voidRet = True
  140. vectorReturn = False
  141. self.wrappersHeaderBody += "\t\treturn 0;\n" # 0 arguments returned
  142. else: # If there is a return value:
  143. # What type is the return value? Default to pointer
  144. outfunc = "this_shouldnt_happen"
  145. retFunc = ""
  146. basicType = False
  147. vectorReturn = False
  148. if method["type"] == "Number" or method["type"] == "inline Number":
  149. outfunc = "lua_pushnumber"
  150. basicType = True
  151. if method["type"] == "String" or method["type"] == "static String": # TODO: Path for STL strings?
  152. outfunc = "lua_pushstring"
  153. basicType = True
  154. retFunc = ".c_str()"
  155. if method["type"] == "int" or method["type"] == "unsigned int" or method["type"] == "static int" or method["type"] == "size_t" or method["type"] == "static size_t" or method["type"] == "long" or method["type"] == "unsigned int" or method["type"] == "static long" or method["type"] == "short" or method["type"] == "PolyKEY" or method["type"] == "wchar_t":
  156. outfunc = "lua_pushinteger"
  157. basicType = True
  158. if method["type"] == "bool" or method["type"] == "static bool" or method["type"] == "virtual bool":
  159. outfunc = "lua_pushboolean"
  160. basicType = True
  161. if method["type"].find("*") > -1: # Returned var is definitely a pointer.
  162. self.wrappersHeaderBody += "\t\tPolyBase *ptrRetVal = (PolyBase*)%s%s;\n" % (call, retFunc)
  163. self.wrappersHeaderBody += "\t\tif(ptrRetVal == NULL) {\n"
  164. self.wrappersHeaderBody += "\t\t\tlua_pushnil(L);\n"
  165. self.wrappersHeaderBody += "\t\t} else {\n"
  166. self.wrappersHeaderBody += "\t\t\tPolyBase **userdataPtr = (PolyBase**)lua_newuserdata(L, sizeof(PolyBase*));\n"
  167. self.wrappersHeaderBody += "\t\t\t*userdataPtr = ptrRetVal;\n"
  168. self.wrappersHeaderBody += "\t\t}\n"
  169. elif basicType == True: # Returned var has been flagged as a recognized primitive type
  170. self.wrappersHeaderBody += "\t\t%s(L, %s%s);\n" % (outfunc, call, retFunc)
  171. else: # Some static object is being returned. Convert it to a pointer, then return that.
  172. className = method["type"].replace("const", "").replace("&", "").replace("inline", "").replace("virtual", "").replace("static", "")
  173. if className == "Polygon": # Deal with potential windows.h conflict
  174. className = "Polycode::Polygon"
  175. if className == "Rectangle":
  176. className = "Polycode::Rectangle"
  177. if className == "Polycode : : Rectangle":
  178. className = "Polycode::Rectangle"
  179. self.wrappersHeaderBody += "\t\t%s *retInst = new %s();\n" % (className, className)
  180. self.wrappersHeaderBody += "\t\t*retInst = %s;\n" % (call)
  181. self.wrappersHeaderBody += "\t\tPolyBase **userdataPtr = (PolyBase**)lua_newuserdata(L, sizeof(PolyBase*));\n"
  182. self.wrappersHeaderBody += "\t\tluaL_getmetatable(L, \"%s.%s\");\n" % (self.libName, className)
  183. self.wrappersHeaderBody += "\t\tlua_setmetatable(L, -2);\n"
  184. self.wrappersHeaderBody += "\t\t*userdataPtr = (PolyBase*)retInst;\n"
  185. self.wrappersHeaderBody += "\t\treturn 1;\n"
  186. self.wrappersHeaderBody += "\t}\n"
  187. def finalize(self):
  188. with open(self.config.get('lua', 'WrapperHeaderTemplate'), 'r') as f:
  189. out = f.read().replace("%HEADERS%", self.wrappersHeaderList)
  190. out = out.replace("%BODY%", self.wrappersHeaderBody)
  191. fout = open(self.config.get('lua', 'WrapperHeaderTarget'), "w")
  192. fout.write(out)
  193. fout.close()