townengine/apps/twnlua/bindgen.py

113 lines
4.8 KiB
Python
Executable File

#!/bin/env python3
import sys, json
with open(sys.argv[1], 'r') if sys.argv[1] != "-" else sys.stdin as f:
api_source = f.read()
api = json.loads(api_source)
def default(parameter):
basetype = parameter["type"].rsplit(' *', 1)[0]
if parameter["type"] == "float":
return parameter["default"]
elif parameter["type"] == "bool":
return "true" if parameter["default"] else "false"
elif parameter["type"] == "char *":
if parameter["default"] == {}:
return "NULL"
else: return '"' + parameter["default"] + '"'
elif basetype in api["types"]:
if parameter["type"].endswith("*"):
if parameter["default"] == {}:
return "NULL"
else:
return "&(%s){\n%s\n }" % \
(parameter["type"], ", \n".join(" .%s = %s" % (n, v) for n, v in parameter["default"].items()))
else:
return "(%s){\n%s\n }" % \
(parameter["type"], ", \n".join(" .%s = %s" % (n, v) for n, v in parameter["default"].items()))
raise BaseException("Unhandled default value of type '%s'" % parameter["type"])
print('#include "twn_game_api.h"')
print('#include <lua.h>')
print('#include <lualib.h>')
print('#include <lauxlib.h>\n')
for typename, typedesc in api["types"].items():
converter = "static %s table_to_%s(lua_State *L, int idx) {\n" % (typename, typename.lower())
converter += " %s %s;\n" % (typename, typename.lower());
if not "fields" in typedesc:
continue
for field in typedesc["fields"]:
converter += " lua_getfield(L, idx, \"%s\");\n" % (field["name"]);
if field["type"] == "float":
converter += " %s.%s = (float)lua_tonumber(L, -1);\n" % (typename.lower(), field["name"]);
elif field["type"] == "uint8_t":
converter += " %s.%s = (uint8_t)lua_tointeger(L, -1);\n" % (typename.lower(), field["name"]);
else:
raise BaseException("Unhandled converter field type '%s'" % (field["type"]))
converter += " lua_pop(L, 1);\n";
converter += " return %s;\n}\n" % (typename.lower())
print(converter)
for procedure, procedure_desc in api["procedures"].items():
binding = "static int binding_%s(lua_State *L) {\n" % procedure
binding += " luaL_checktype(L, 1, LUA_TTABLE);\n"
if "params" in procedure_desc:
for parameter in procedure_desc["params"]:
basetype = parameter["type"].rsplit(' *', 1)[0]
if parameter["type"].endswith("*"):
binding += " %s %s_value;\n" % (basetype, parameter["name"])
binding += " %s %s;\n" % (parameter["type"], parameter["name"])
binding += " lua_getfield(L, 1, \"%s\");\n" % parameter["name"]
if "default" in parameter:
binding += " if (lua_isnoneornil(L, -1))\n"
binding += " %s = %s;\n" % (parameter["name"], default(parameter))
binding += " else\n "
if parameter["type"] == "float":
binding += " %s = (float)lua_tonumber(L, -1);\n" % (parameter["name"]);
elif parameter["type"] == "bool":
binding += " %s = lua_toboolean(L, -1);\n" % (parameter["name"]);
elif parameter["type"] == "char *":
binding += " %s = lua_tostring(L, -1);\n" % (parameter["name"]);
elif basetype in api["types"]:
if "enums" in api["types"][basetype]:
binding += " %s = lua_tointeger(L, -1);\n" % (parameter["name"]);
elif parameter["type"].endswith("*"):
binding += " { %s_value = table_to_%s(L, -1); %s = &%s_value; }\n" % (parameter["name"], basetype.lower(), parameter["name"], parameter["name"]);
else:
binding += " %s = table_to_%s(L, -1);\n" % (parameter["name"], basetype.lower());
else:
raise BaseException("Unhandled parameter type '%s'" % (parameter["type"]))
binding += " %s(%s);\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"]))
binding += "}\n"
print(binding)
loader = "void bindgen_load_%s(lua_State *L) {\n" % api["name"]
modules = set(api["procedures"][procedure]["module"] for procedure in api["procedures"])
for module in modules:
loader += " lua_newtable(L);\n"
for procedure, procedure_desc in api["procedures"].items():
if procedure_desc["module"] == module:
loader += " lua_pushstring(L, \"%s\");\n" % procedure_desc["symbol"]
loader += " lua_pushcfunction(L, binding_%s);\n" % procedure
loader += " lua_settable(L, -3);\n"
loader += " lua_setglobal(L, \"%s\");\n" % module
loader += "}"
print(loader)