lua_bridge.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include "lua_bridge.hpp"
  2. namespace pkpy{
  3. static lua_State* _L;
  4. static void lua_push_from_python(VM*, PyObject*);
  5. static PyObject* lua_popx_to_python(VM*);
  6. template<typename T>
  7. static void table_apply(VM* vm, T f){
  8. PK_ASSERT(lua_istable(_L, -1));
  9. lua_pushnil(_L); // [key]
  10. while(lua_next(_L, -2) != 0){ // [key, val]
  11. lua_pushvalue(_L, -2); // [key, val, key]
  12. PyObject* key = lua_popx_to_python(vm);
  13. PyObject* val = lua_popx_to_python(vm);
  14. f(key, val); // [key]
  15. }
  16. lua_pop(_L, 1); // []
  17. }
  18. struct LuaExceptionGuard{
  19. int base_size;
  20. LuaExceptionGuard(){ base_size = lua_gettop(_L); }
  21. ~LuaExceptionGuard(){
  22. int delta = lua_gettop(_L) - base_size;
  23. if(delta > 0) lua_pop(_L, delta);
  24. }
  25. };
  26. #define LUA_PROTECTED(__B) { LuaExceptionGuard __guard; __B; }
  27. struct PyLuaObject{
  28. PK_ALWAYS_PASS_BY_POINTER(PyLuaObject)
  29. int r;
  30. PyLuaObject(){ r = luaL_ref(_L, LUA_REGISTRYINDEX); }
  31. ~PyLuaObject(){ luaL_unref(_L, LUA_REGISTRYINDEX, r); }
  32. };
  33. struct PyLuaTable: PyLuaObject{
  34. PY_CLASS(PyLuaTable, lua, Table)
  35. static void _register(VM* vm, PyObject* mod, PyObject* type){
  36. Type t = PK_OBJ_GET(Type, type);
  37. PyTypeInfo* ti = &vm->_all_types[t];
  38. ti->subclass_enabled = false;
  39. ti->m__getattr__ = [](VM* vm, PyObject* obj, StrName name){
  40. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  41. LUA_PROTECTED(
  42. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  43. std::string_view name_sv = name.sv();
  44. lua_pushlstring(_L, name_sv.data(), name_sv.size());
  45. lua_gettable(_L, -2);
  46. PyObject* ret = lua_popx_to_python(vm);
  47. lua_pop(_L, 1);
  48. return ret;
  49. )
  50. };
  51. ti->m__setattr__ = [](VM* vm, PyObject* obj, StrName name, PyObject* val){
  52. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  53. LUA_PROTECTED(
  54. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  55. std::string_view name_sv = name.sv();
  56. lua_pushlstring(_L, name_sv.data(), name_sv.size());
  57. lua_push_from_python(vm, val);
  58. lua_settable(_L, -3);
  59. lua_pop(_L, 1);
  60. )
  61. };
  62. ti->m__delattr__ = [](VM* vm, PyObject* obj, StrName name){
  63. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  64. LUA_PROTECTED(
  65. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  66. std::string_view name_sv = name.sv();
  67. lua_pushlstring(_L, name_sv.data(), name_sv.size());
  68. lua_pushnil(_L);
  69. lua_settable(_L, -3);
  70. lua_pop(_L, 1);
  71. )
  72. return true;
  73. };
  74. vm->bind_constructor<1>(type, [](VM* vm, ArgsView args){
  75. lua_newtable(_L); // push an empty table onto the stack
  76. PyObject* obj = vm->heap.gcnew<PyLuaTable>(PK_OBJ_GET(Type, args[0]));
  77. return obj;
  78. });
  79. vm->bind__len__(t, [](VM* vm, PyObject* obj){
  80. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  81. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  82. i64 len = 0;
  83. lua_pushnil(_L);
  84. while(lua_next(_L, -2) != 0){ len += 1; lua_pop(_L, 1); }
  85. lua_pop(_L, 1);
  86. return len;
  87. });
  88. vm->bind__getitem__(t, [](VM* vm, PyObject* obj, PyObject* key){
  89. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  90. LUA_PROTECTED(
  91. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  92. lua_push_from_python(vm, key);
  93. lua_gettable(_L, -2);
  94. PyObject* ret = lua_popx_to_python(vm);
  95. lua_pop(_L, 1);
  96. return ret;
  97. )
  98. });
  99. vm->bind__setitem__(t, [](VM* vm, PyObject* obj, PyObject* key, PyObject* val){
  100. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  101. LUA_PROTECTED(
  102. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  103. lua_push_from_python(vm, key);
  104. lua_push_from_python(vm, val);
  105. lua_settable(_L, -3);
  106. lua_pop(_L, 1);
  107. )
  108. });
  109. vm->bind__delitem__(t, [](VM* vm, PyObject* obj, PyObject* key){
  110. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  111. LUA_PROTECTED(
  112. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  113. lua_push_from_python(vm, key);
  114. lua_pushnil(_L);
  115. lua_settable(_L, -3);
  116. lua_pop(_L, 1);
  117. )
  118. });
  119. vm->bind__contains__(t, [](VM* vm, PyObject* obj, PyObject* key){
  120. const PyLuaTable& self = _CAST(PyLuaTable&, obj);
  121. LUA_PROTECTED(
  122. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  123. lua_push_from_python(vm, key);
  124. lua_gettable(_L, -2);
  125. bool ret = lua_isnil(_L, -1) == 0;
  126. lua_pop(_L, 2);
  127. return ret ? vm->True : vm->False;
  128. )
  129. });
  130. vm->bind(type, "keys(self) -> list", [](VM* vm, ArgsView args){
  131. const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
  132. LUA_PROTECTED(
  133. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  134. List ret;
  135. table_apply(vm, [&](PyObject* key, PyObject* val){ ret.push_back(key); });
  136. lua_pop(_L, 1);
  137. return VAR(std::move(ret));
  138. )
  139. });
  140. vm->bind(type, "values(self) -> list", [](VM* vm, ArgsView args){
  141. const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
  142. LUA_PROTECTED(
  143. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  144. List ret;
  145. table_apply(vm, [&](PyObject* key, PyObject* val){ ret.push_back(val); });
  146. lua_pop(_L, 1);
  147. return VAR(std::move(ret));
  148. )
  149. });
  150. vm->bind(type, "items(self) -> list[tuple]", [](VM* vm, ArgsView args){
  151. const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
  152. LUA_PROTECTED(
  153. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  154. List ret;
  155. table_apply(vm, [&](PyObject* key, PyObject* val){
  156. PyObject* item = VAR(Tuple(key, val));
  157. ret.push_back(item);
  158. });
  159. lua_pop(_L, 1);
  160. return VAR(std::move(ret));
  161. )
  162. });
  163. }
  164. };
  165. static PyObject* lua_popx_multi_to_python(VM* vm, int count){
  166. if(count == 0){
  167. return vm->None;
  168. }else if(count == 1){
  169. return lua_popx_to_python(vm);
  170. }else if(count > 1){
  171. Tuple ret(count);
  172. for(int i=0; i<count; i++){
  173. ret[i] = lua_popx_to_python(vm);
  174. }
  175. return VAR(std::move(ret));
  176. }
  177. PK_FATAL_ERROR()
  178. }
  179. struct PyLuaFunction: PyLuaObject{
  180. PY_CLASS(PyLuaFunction, lua, Function)
  181. static void _register(VM* vm, PyObject* mod, PyObject* type){
  182. vm->bind_notimplemented_constructor<PyLuaFunction>(type);
  183. vm->_all_types[PK_OBJ_GET(Type, type)].subclass_enabled = false;
  184. vm->bind_method<-1>(type, "__call__", [](VM* vm, ArgsView args){
  185. if(args.size() < 1) vm->TypeError("__call__ takes at least 1 argument");
  186. const PyLuaFunction& self = _CAST(PyLuaFunction&, args[0]);
  187. int base_size = lua_gettop(_L);
  188. LUA_PROTECTED(
  189. lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
  190. for(int i=1; i<args.size(); i++){
  191. lua_push_from_python(vm, args[i]);
  192. }
  193. if(lua_pcall(_L, args.size()-1, LUA_MULTRET, 0)){
  194. const char* error = lua_tostring(_L, -1);
  195. lua_pop(_L, 1);
  196. vm->RuntimeError(error);
  197. }
  198. return lua_popx_multi_to_python(vm, lua_gettop(_L) - base_size);
  199. )
  200. });
  201. }
  202. };
  203. void lua_push_from_python(VM* vm, PyObject* val){
  204. if(val == vm->None){
  205. lua_pushnil(_L);
  206. return;
  207. }
  208. Type t = vm->_tp(val);
  209. switch(t.index){
  210. case VM::tp_bool.index:
  211. lua_pushboolean(_L, val == vm->True);
  212. return;
  213. case VM::tp_int.index:
  214. lua_pushinteger(_L, _CAST(i64, val));
  215. return;
  216. case VM::tp_float.index:
  217. lua_pushnumber(_L, _CAST(f64, val));
  218. return;
  219. case VM::tp_str.index: {
  220. std::string_view sv = _CAST(Str, val).sv();
  221. lua_pushlstring(_L, sv.data(), sv.size());
  222. return;
  223. }
  224. case VM::tp_tuple.index: {
  225. lua_newtable(_L);
  226. int i = 1;
  227. for(PyObject* obj: PK_OBJ_GET(Tuple, val)){
  228. lua_push_from_python(vm, obj);
  229. lua_rawseti(_L, -2, i++);
  230. }
  231. return;
  232. }
  233. case VM::tp_list.index: {
  234. lua_newtable(_L);
  235. int i = 1;
  236. for(PyObject* obj: PK_OBJ_GET(List, val)){
  237. lua_push_from_python(vm, obj);
  238. lua_rawseti(_L, -2, i++);
  239. }
  240. return;
  241. }
  242. case VM::tp_dict.index: {
  243. lua_newtable(_L);
  244. PK_OBJ_GET(Dict, val).apply([&](PyObject* key, PyObject* val){
  245. lua_push_from_python(vm, key);
  246. lua_push_from_python(vm, val);
  247. lua_settable(_L, -3);
  248. });
  249. return;
  250. }
  251. }
  252. if(is_non_tagged_type(val, PyLuaTable::_type(vm))){
  253. const PyLuaTable& table = _CAST(PyLuaTable&, val);
  254. lua_rawgeti(_L, LUA_REGISTRYINDEX, table.r);
  255. return;
  256. }
  257. if(is_non_tagged_type(val, PyLuaFunction::_type(vm))){
  258. const PyLuaFunction& func = _CAST(PyLuaFunction&, val);
  259. lua_rawgeti(_L, LUA_REGISTRYINDEX, func.r);
  260. return;
  261. }
  262. vm->RuntimeError(_S("unsupported python type: ", _type_name(vm, t).escape()));
  263. }
  264. PyObject* lua_popx_to_python(VM* vm) {
  265. int type = lua_type(_L, -1);
  266. switch (type) {
  267. case LUA_TNIL: {
  268. lua_pop(_L, 1);
  269. return vm->None;
  270. }
  271. case LUA_TBOOLEAN: {
  272. bool val = lua_toboolean(_L, -1);
  273. lua_pop(_L, 1);
  274. return val ? vm->True : vm->False;
  275. }
  276. case LUA_TNUMBER: {
  277. double val = lua_tonumber(_L, -1);
  278. lua_pop(_L, 1);
  279. return VAR(val);
  280. }
  281. case LUA_TSTRING: {
  282. const char* val = lua_tostring(_L, -1);
  283. lua_pop(_L, 1);
  284. return VAR(val);
  285. }
  286. case LUA_TTABLE: {
  287. PyObject* obj = vm->heap.gcnew<PyLuaTable>(PyLuaTable::_type(vm));
  288. return obj;
  289. }
  290. case LUA_TFUNCTION: {
  291. PyObject* obj = vm->heap.gcnew<PyLuaFunction>(PyLuaFunction::_type(vm));
  292. return obj;
  293. }
  294. default: {
  295. const char* type_name = lua_typename(_L, type);
  296. lua_pop(_L, 1);
  297. vm->RuntimeError(_S("unsupported lua type: '", type_name, "'"));
  298. }
  299. }
  300. PK_UNREACHABLE()
  301. }
  302. void initialize_lua_bridge(VM* vm, lua_State* newL){
  303. PyObject* mod = vm->new_module("lua");
  304. if(_L != nullptr){
  305. throw std::runtime_error("lua bridge already initialized");
  306. }
  307. _L = newL;
  308. PyLuaTable::register_class(vm, mod);
  309. PyLuaFunction::register_class(vm, mod);
  310. vm->bind(mod, "dostring(__source: str)", [](VM* vm, ArgsView args){
  311. const char* source = CAST(CString, args[0]);
  312. int base_size = lua_gettop(_L);
  313. if (luaL_dostring(_L, source)) {
  314. const char* error = lua_tostring(_L, -1);
  315. lua_pop(_L, 1); // pop error message from the stack
  316. vm->RuntimeError(error);
  317. }
  318. return lua_popx_multi_to_python(vm, lua_gettop(_L) - base_size);
  319. });
  320. }
  321. } // namespace pkpy