From adbc843e6309b8e78b6b48a1e1e63615af5b7b7a Mon Sep 17 00:00:00 2001 From: Adnan Yaqoob Virk Date: Thu, 3 Mar 2016 14:26:50 +0500 Subject: [PATCH 01/52] Fix: Symbol not found error while loading dynamic python extensions. --- src/pythoninlua.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index c13530e..0d31a21 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -21,6 +21,7 @@ */ #include +#include /* need this to build with Lua 5.2: defines luaL_register() macro */ #define LUA_COMPAT_MODULE @@ -578,6 +579,20 @@ LUA_API int luaopen_python(lua_State *L) #endif Py_SetProgramName(argv[0]); PyImport_AppendInittab("lua", PyInit_lua); + + /* Loading python library symbols so that dynamic extensions don't throw symbol not found error. + Ref Link: http://stackoverflow.com/questions/29880931/importerror-and-pyexc-systemerror-while-embedding-python-script-within-c-for-pam + */ + char str_python_lib[17]; +#ifdef _WIN32 + sprintf(str_python_lib, "libpython%d.%d.dll", PY_MAJOR_VERSION, PY_MINOR_VERSION); +#elif defined __unix__ + sprintf(str_python_lib, "libpython%d.%d.so", PY_MAJOR_VERSION, PY_MINOR_VERSION); +#elif defined __APPLE__ + sprintf(str_python_lib, "libpython%d.%d.dylib", PY_MAJOR_VERSION, PY_MINOR_VERSION); +#endif + dlopen(str_python_lib, RTLD_NOW | RTLD_GLOBAL); + Py_Initialize(); PySys_SetArgv(1, argv); /* Import 'lua' automatically. */ From 4584aa779b0b78e8b01ae76fc51ce00d7551ba23 Mon Sep 17 00:00:00 2001 From: Adnan Yaqoob Virk Date: Thu, 3 Mar 2016 14:31:55 +0500 Subject: [PATCH 02/52] Buffer overflow fix while loading python library. --- src/pythoninlua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 0d31a21..7c39b0a 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -583,7 +583,7 @@ LUA_API int luaopen_python(lua_State *L) /* Loading python library symbols so that dynamic extensions don't throw symbol not found error. Ref Link: http://stackoverflow.com/questions/29880931/importerror-and-pyexc-systemerror-while-embedding-python-script-within-c-for-pam */ - char str_python_lib[17]; + char str_python_lib[20]; #ifdef _WIN32 sprintf(str_python_lib, "libpython%d.%d.dll", PY_MAJOR_VERSION, PY_MINOR_VERSION); #elif defined __unix__ From d6c4e538b8b40b34761fbaa0ae1e064836f36fed Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 12 Dec 2016 15:16:39 -0800 Subject: [PATCH 03/52] Turn on warnings. Compile using C99 mode for long long, declaration initialization and other useful stuff. --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d273ade..b81bd88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,10 @@ find_package(PythonLibs REQUIRED) include_directories(${LUA_INCLUDE_DIR}) include_directories(${PYTHON_INCLUDE_DIR}) +if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + set(CMAKE_C_FLAGS "-Wall -pedantic -std=c99 ${CMAKE_C_FLAGS}") +endif () + add_subdirectory(src) add_library(python MODULE $) From a09c6c9441002800f3841e82ab38c7c9688b9700 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 10 Feb 2017 02:29:44 -0800 Subject: [PATCH 04/52] Don't wrap PyFunc in a lua closure by default. User can always wrap it manually using 'asfunc' if needed, but the reverse is not true. --- src/pythoninlua.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 0069201..e50e538 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -104,9 +104,6 @@ int py_convert(lua_State *L, PyObject *o, int withnone) if (PyDict_Check(o) || PyList_Check(o) || PyTuple_Check(o)) asindx = 1; ret = py_convert_custom(L, o, asindx); - if (ret && !asindx && - (PyFunction_Check(o) || PyCFunction_Check(o))) - lua_pushcclosure(L, py_asfunc_call, 1); } return ret; } From 9f4f8ca5a410b1dfd70b7214e8a2808d71db4dc0 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 10 Feb 2017 03:44:28 -0800 Subject: [PATCH 05/52] Refactored operators to use a python lambda instead. This is cached to avoid recreating a new lambda on every call. Major reduction in code dup. --- src/pythoninlua.c | 160 +++++++++++++--------------------------------- 1 file changed, 44 insertions(+), 116 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index e50e538..402f895 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -31,7 +31,8 @@ #include "pythoninlua.h" #include "luainpython.h" -static int py_asfunc_call(lua_State *L); +static int py_asfunc_call(lua_State *); +static int py_eval(lua_State *); static int py_convert_custom(lua_State *L, PyObject *o, int asindx) { @@ -202,46 +203,6 @@ static int py_object_call(lua_State *L) return ret; } -static int py_object_call2(lua_State *L, PyObject *obj) -{ - PyObject *args; - PyObject *value; - int nargs = lua_gettop(L); - int ret = 0; - int i; - - if (!PyCallable_Check(obj)) { - return luaL_error(L, "object is not callable"); - } - - args = PyTuple_New(nargs); - if (!args) { - PyErr_Print(); - return luaL_error(L, "failed to create arguments tuple"); - } - - for (i = 0; i != nargs; i++) { - PyObject *arg = LuaConvert(L, i+1); - if (!arg) { - Py_DECREF(args); - return luaL_error(L, "failed to convert argument #%d", i+1); - } - PyTuple_SetItem(args, i, arg); - } - - value = PyObject_Call(obj, args, NULL); - Py_DECREF(args); - if (value) { - ret = py_convert(L, value, 0); - Py_DECREF(value); - } else { - PyErr_Print(); - luaL_error(L, "error calling python function"); - } - - return ret; -} - static int _p_object_newindex_set(lua_State *L, py_object *obj, int keyn, int valuen) { @@ -428,99 +389,66 @@ static int py_object_tostring(lua_State *L) return 1; } +static int py_operator_lambda(lua_State *L, const char *op) +{ + static char script_buff[] = "lambda a, b: a b"; + static size_t len = sizeof(script_buff) / sizeof(script_buff[0]); + snprintf(script_buff, len, "lambda a, b: a %s b", op); + + lua_pushcfunction(L, py_eval); + lua_pushlstring(L, script_buff, len); + lua_call(L, 1, 1); + return luaL_ref(L, LUA_REGISTRYINDEX); +} + static int py_object_mul(lua_State *L) { - int r=0; - PyObject *value; - if (lua_isuserdata(L, 1)) - { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - lua_remove(L, 1); - value = PyObject_GetAttrString(obj->o, "__mul__"); - } - else - { py_object *obj = (py_object*) luaL_checkudata(L, 2, POBJECT); - lua_remove(L, 2); - value = PyObject_GetAttrString(obj->o, "__rmul__"); - } - r = py_object_call2(L, value); - Py_DECREF(value); - return r; + static int op_ref = LUA_REFNIL; + if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "*"); + + lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); + lua_insert(L, 1); + return py_object_call(L); } static int py_object_div(lua_State *L) { - int r=0; - PyObject *value; - if (lua_isuserdata(L, 1)) - { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - lua_remove(L, 1); - value = PyObject_GetAttrString(obj->o, "__div__"); - } - else - { py_object *obj = (py_object*) luaL_checkudata(L, 2, POBJECT); - lua_remove(L, 2); - value = PyObject_GetAttrString(obj->o, "__rdiv__"); - } - r = py_object_call2(L, value); - Py_DECREF(value); - return r; + static int op_ref = LUA_REFNIL; + if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "/"); + + lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); + lua_insert(L, 1); + return py_object_call(L); } static int py_object_add(lua_State *L) { - int r=0; - PyObject *value; - if (lua_isuserdata(L, 1)) - { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - lua_remove(L, 1); - value = PyObject_GetAttrString(obj->o, "__add__"); - } - else - { py_object *obj = (py_object*) luaL_checkudata(L, 2, POBJECT); - lua_remove(L, 2); - value = PyObject_GetAttrString(obj->o, "__radd__"); - } - r = py_object_call2(L, value); - Py_DECREF(value); - return r; + static int op_ref = LUA_REFNIL; + if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "+"); + + lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); + lua_insert(L, 1); + return py_object_call(L); } static int py_object_sub(lua_State *L) { - int r=0; - PyObject *value; - if (lua_isuserdata(L, 1)) - { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - lua_remove(L, 1); - value = PyObject_GetAttrString(obj->o, "__sub__"); - } - else - { py_object *obj = (py_object*) luaL_checkudata(L, 2, POBJECT); - lua_remove(L, 2); - value = PyObject_GetAttrString(obj->o, "__rsub__"); - } - r = py_object_call2(L, value); - Py_DECREF(value); - return r; + static int op_ref = LUA_REFNIL; + if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "-"); + + lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); + lua_insert(L, 1); + return py_object_call(L); } static int py_object_pow(lua_State *L) { - int r=0; - PyObject *value; - if (lua_isuserdata(L, 1)) - { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - lua_remove(L, 1); - value = PyObject_GetAttrString(obj->o, "__pow__"); - } - else - { py_object *obj = (py_object*) luaL_checkudata(L, 2, POBJECT); - lua_remove(L, 2); - value = PyObject_GetAttrString(obj->o, "__rpow__"); - } - r = py_object_call2(L, value); - Py_DECREF(value); - return r; + static int op_ref = LUA_REFNIL; + if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "**"); + + lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); + lua_insert(L, 1); + return py_object_call(L); } static const luaL_Reg py_object_lib[] = { From 099898501823ebd6bc305b47912a40a549daa70d Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 10 Feb 2017 04:11:20 -0800 Subject: [PATCH 06/52] Minor refactor. --- src/luainpython.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/luainpython.c b/src/luainpython.c index 0c2647b..1e2a64b 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -50,8 +50,8 @@ PyObject *LuaConvert(lua_State *L, int n) break; case LUA_TSTRING: { - const char *s = lua_tostring(L, n); - int len = lua_strlen(L, n); + size_t len; + const char *s = lua_tolstring(L, n, &len); ret = PyUnicode_FromStringAndSize(s, len); break; } @@ -67,13 +67,8 @@ PyObject *LuaConvert(lua_State *L, int n) } case LUA_TBOOLEAN: - if (lua_toboolean(L, n)) { - Py_INCREF(Py_True); - ret = Py_True; - } else { - Py_INCREF(Py_False); - ret = Py_False; - } + ret = lua_toboolean(L, n) ? Py_True : Py_False; + Py_INCREF(ret); break; case LUA_TUSERDATA: { From 0f993f64a7fbf68864c246df475a83a6d5e836d1 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 10 Feb 2017 14:58:01 -0800 Subject: [PATCH 07/52] Slight cleanup. --- src/pythoninlua.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 402f895..f08f1b7 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -713,17 +713,14 @@ LUA_API int luaopen_python(lua_State *L) } /* Register 'none' */ - lua_pushliteral(L, "Py_None"); rc = py_convert_custom(L, Py_None, 0); - if (rc) { - lua_pushliteral(L, "none"); - lua_pushvalue(L, -2); - lua_rawset(L, -5); /* python.none */ - lua_rawset(L, LUA_REGISTRYINDEX); /* registry.Py_None */ - } else { - lua_pop(L, 1); - luaL_error(L, "failed to convert none object"); - } + if (!rc) + return luaL_error(L, "failed to convert none object"); - return 0; + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, "Py_None"); /* registry.Py_None */ + + lua_setfield(L, -2, "none"); /* python.none */ + + return 1; } From 43c3c98ad59ea6a3fda45be0db9d50800b5b6992 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 10 Feb 2017 15:02:35 -0800 Subject: [PATCH 08/52] Compatibility changes to make it buildable under Lua 5.3 and 5.1. 'require'ing the module no longer dumps it into lua's global table. --- src/luainpython.c | 2 +- src/luainpython.h | 6 ++++++ src/pythoninlua.c | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/luainpython.c b/src/luainpython.c index 1e2a64b..49c5798 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -336,7 +336,7 @@ static int LuaObject_length(LuaObject *obj) { int len; lua_rawgeti(LuaState, LUA_REGISTRYINDEX, ((LuaObject*)obj)->ref); - len = lua_objlen(LuaState, -1); + len = luaL_len(LuaState, -1); lua_settop(LuaState, 0); return len; } diff --git a/src/luainpython.h b/src/luainpython.h index bf9d88c..8ea33cf 100644 --- a/src/luainpython.h +++ b/src/luainpython.h @@ -23,6 +23,12 @@ #ifndef LUAINPYTHON_H #define LUAINPYTHON_H +#if LUA_VERSION_NUM == 501 + #define luaL_len lua_objlen + #define luaL_setfuncs(L, l, nup) luaL_register(L, NULL, (l)) + #define luaL_newlib(L, l) (lua_newtable(L), luaL_register(L, NULL, (l))) +#endif + typedef struct { PyObject_HEAD int ref; diff --git a/src/pythoninlua.c b/src/pythoninlua.c index f08f1b7..dfc1c43 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -674,11 +674,11 @@ LUA_API int luaopen_python(lua_State *L) int rc; /* Register module */ - luaL_register(L, "python", py_lib); + luaL_newlib(L, py_lib); /* Register python object metatable */ luaL_newmetatable(L, POBJECT); - luaL_register(L, NULL, py_object_lib); + luaL_setfuncs(L, py_object_lib, 0); lua_pop(L, 1); /* Initialize Lua state in Python territory */ From 8c9d8c47b0927c0df797534b7979db941e511059 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 10 Feb 2017 18:40:20 -0800 Subject: [PATCH 09/52] Reduce indent level. Fixed bracing style. --- src/pythoninlua.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index dfc1c43..5e96764 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -685,7 +685,8 @@ LUA_API int luaopen_python(lua_State *L) if (!LuaState) LuaState = L; /* Initialize Python interpreter */ - if (!Py_IsInitialized()) { + if (!Py_IsInitialized()) + { PyObject *luam, *mainm, *maind; #if PY_MAJOR_VERSION >= 3 wchar_t *argv[] = {L"", 0}; @@ -698,18 +699,16 @@ LUA_API int luaopen_python(lua_State *L) PySys_SetArgv(1, argv); /* Import 'lua' automatically. */ luam = PyImport_ImportModule("lua"); - if (!luam) { - luaL_error(L, "Can't import lua module"); - } else { - mainm = PyImport_AddModule("__main__"); - if (!mainm) { - luaL_error(L, "Can't get __main__ module"); - } else { - maind = PyModule_GetDict(mainm); - PyDict_SetItemString(maind, "lua", luam); - Py_DECREF(luam); - } - } + if (!luam) + return luaL_error(L, "Can't import lua module"); + + mainm = PyImport_AddModule("__main__"); + if (!mainm) + return luaL_error(L, "Can't get __main__ module"); + + maind = PyModule_GetDict(mainm); + PyDict_SetItemString(maind, "lua", luam); + Py_DECREF(luam); } /* Register 'none' */ From 49a5c1d8e2ec369e33191a4f03636510d0eea594 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 10 Feb 2017 18:41:09 -0800 Subject: [PATCH 10/52] Fixed reference leak. --- src/pythoninlua.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 5e96764..ad84d7e 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -704,7 +704,10 @@ LUA_API int luaopen_python(lua_State *L) mainm = PyImport_AddModule("__main__"); if (!mainm) + { + Py_DECREF(luam); return luaL_error(L, "Can't get __main__ module"); + } maind = PyModule_GetDict(mainm); PyDict_SetItemString(maind, "lua", luam); From d84ed8e97f2dee0debf175b34341b861fa983a86 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sun, 12 Feb 2017 04:19:01 -0800 Subject: [PATCH 11/52] Fix for issue #50 - coroutine param passing bug. --- src/luainpython.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/luainpython.c b/src/luainpython.c index 49c5798..5e20c8d 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -35,7 +35,17 @@ lua_State *LuaState = NULL; -static PyObject *LuaObject_New(int n); +static PyObject *LuaObject_New(lua_State *L, int n) +{ + LuaObject *obj = PyObject_New(LuaObject, &LuaObject_Type); + if (obj) + { + lua_pushvalue(L, n); + obj->ref = luaL_ref(L, LUA_REGISTRYINDEX); + obj->refiter = 0; + } + return (PyObject*) obj; +} PyObject *LuaConvert(lua_State *L, int n) { @@ -84,7 +94,7 @@ PyObject *LuaConvert(lua_State *L, int n) } default: - ret = LuaObject_New(n); + ret = LuaObject_New(L, n); break; } @@ -166,17 +176,6 @@ static PyObject *LuaCall(lua_State *L, PyObject *args) return ret; } -static PyObject *LuaObject_New(int n) -{ - LuaObject *obj = PyObject_New(LuaObject, &LuaObject_Type); - if (obj) { - lua_pushvalue(LuaState, n); - obj->ref = luaL_ref(LuaState, LUA_REGISTRYINDEX); - obj->refiter = 0; - } - return (PyObject*) obj; -} - static void LuaObject_dealloc(LuaObject *self) { luaL_unref(LuaState, LUA_REGISTRYINDEX, self->ref); From 93dbdb5d755c38c3c68ccb229e148246a0cf8490 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 13 Feb 2017 15:47:17 -0800 Subject: [PATCH 12/52] Removed unused reference increase. Condensed init logic. More Brace fixing. --- src/luainpython.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/luainpython.c b/src/luainpython.c index 5e20c8d..abb0b5f 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -483,7 +483,8 @@ static PyObject *Lua_require(PyObject *self, PyObject *args) return LuaCall(LuaState, args); } -static PyMethodDef lua_methods[] = { +static PyMethodDef lua_methods[] = +{ {"execute", Lua_execute, METH_VARARGS, NULL}, {"eval", Lua_eval, METH_VARARGS, NULL}, {"globals", Lua_globals, METH_NOARGS, NULL}, @@ -492,7 +493,8 @@ static PyMethodDef lua_methods[] = { }; #if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef lua_module = { +static struct PyModuleDef lua_module = +{ PyModuleDef_HEAD_INIT, "lua", "Lunatic-Python Python-Lua bridge", @@ -503,22 +505,19 @@ static struct PyModuleDef lua_module = { PyMODINIT_FUNC PyInit_lua(void) { - PyObject *m; - + PyObject *m; + if (PyType_Ready(&LuaObject_Type) < 0 || #if PY_MAJOR_VERSION >= 3 - if (PyType_Ready(&LuaObject_Type) < 0) return NULL; - m = PyModule_Create(&lua_module); - if (m == NULL) return NULL; + (m = PyModule_Create(&lua_module)) == NULL) + return NULL; #else - if (PyType_Ready(&LuaObject_Type) < 0) return; - m = Py_InitModule3("lua", lua_methods, - "Lunatic-Python Python-Lua bridge"); - if (m == NULL) return; + (m = Py_InitModule3("lua", lua_methods, + "Lunatic-Python Python-Lua bridge")) == NULL) + return; #endif - Py_INCREF(&LuaObject_Type); - - if (!LuaState) { + if (!LuaState) + { LuaState = luaL_newstate(); luaL_openlibs(LuaState); luaopen_python(LuaState); From cb4787d4fab3ef37accd2361c950c6d5a7863905 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Thu, 16 Feb 2017 02:24:32 -0800 Subject: [PATCH 13/52] Refactored not-so-good practice in cmake. --- CMakeLists.txt | 9 +++------ src/CMakeLists.txt | 13 ++++++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b81bd88..b46aea0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,9 +12,6 @@ find_package(PythonLibs REQUIRED) include_directories(${LUA_INCLUDE_DIR}) include_directories(${PYTHON_INCLUDE_DIR}) -if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - set(CMAKE_C_FLAGS "-Wall -pedantic -std=c99 ${CMAKE_C_FLAGS}") -endif () add_subdirectory(src) @@ -23,14 +20,14 @@ set_target_properties(python PROPERTIES PREFIX "") add_library(lua MODULE $) -if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") +if (WIN32) set_target_properties(lua PROPERTIES PREFIX "" SUFFIX ".pyd") -else () +else (WIN32) set_target_properties(lua PROPERTIES PREFIX "") -endif () +endif (WIN32) target_link_libraries(lua ${LUA_LIBRARIES} ${PYTHON_LIBRARIES}) target_link_libraries(python ${LUA_LIBRARIES} ${PYTHON_LIBRARIES}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 586b66b..a9e8358 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,12 @@ -if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - add_definitions(-DLUA_BUILD_AS_DLL) -endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") -add_definitions(-DLUA_LIB) - add_library(src OBJECT luainpython.c pythoninlua.c) set_target_properties(src PROPERTIES POSITION_INDEPENDENT_CODE TRUE) +if (WIN32) + target_compile_definitions(src PRIVATE LUA_BUILD_AS_DLL) +endif (WIN32) +target_compile_definitions(src PRIVATE LUA_LIB) + +if (CMAKE_COMPILER_IS_GNUCC) + target_compile_options(src PUBLIC -Wall -pedantic -std=c99) +endif (CMAKE_COMPILER_IS_GNUCC) From 7451aa8aa32dacf78edb637eb2ac8553a5da06b8 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 17 Feb 2017 02:05:52 -0800 Subject: [PATCH 14/52] Prefer 'target_include_directories'; moved to src/CMakeLists.txt --- CMakeLists.txt | 3 --- src/CMakeLists.txt | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b46aea0..4fcf249 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,6 @@ project(Lunatic) find_package(Lua 5.1 REQUIRED) find_package(PythonLibs REQUIRED) -include_directories(${LUA_INCLUDE_DIR}) -include_directories(${PYTHON_INCLUDE_DIR}) - add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9e8358..b4664b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,10 +2,12 @@ add_library(src OBJECT luainpython.c pythoninlua.c) set_target_properties(src PROPERTIES POSITION_INDEPENDENT_CODE TRUE) +target_include_directories(src PRIVATE ${LUA_INCLUDE_DIR} ${PYTHON_INCLUDE_DIR}) + +target_compile_definitions(src PRIVATE LUA_LIB) if (WIN32) target_compile_definitions(src PRIVATE LUA_BUILD_AS_DLL) endif (WIN32) -target_compile_definitions(src PRIVATE LUA_LIB) if (CMAKE_COMPILER_IS_GNUCC) target_compile_options(src PUBLIC -Wall -pedantic -std=c99) From cc22c31f0fcba07abce1c18c4f3373b652e4c7c7 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 17 Feb 2017 14:14:22 -0800 Subject: [PATCH 15/52] Added Python min version; formatting. --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fcf249..1422914 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,11 @@ set(CMAKE_BUILD_TYPE_INIT "Release") set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH}) + project(Lunatic) -find_package(Lua 5.1 REQUIRED) -find_package(PythonLibs REQUIRED) +find_package(Lua 5.1 REQUIRED) +find_package(PythonLibs 2.7 REQUIRED) add_subdirectory(src) @@ -26,5 +27,5 @@ else (WIN32) PREFIX "") endif (WIN32) -target_link_libraries(lua ${LUA_LIBRARIES} ${PYTHON_LIBRARIES}) -target_link_libraries(python ${LUA_LIBRARIES} ${PYTHON_LIBRARIES}) +target_link_libraries(lua ${LUA_LIBRARIES} ${PYTHON_LIBRARIES}) +target_link_libraries(python ${LUA_LIBRARIES} ${PYTHON_LIBRARIES}) From 6762b5d1b1ac2f0c344c6b41d76ccf7fb96cd3f3 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 17 Feb 2017 14:21:16 -0800 Subject: [PATCH 16/52] travis CI. --- .travis.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fd11441 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +language: c + +sudo: required +dist: trusty + +compiler: + - gcc + +env: + - LUA_ENV=lua5.1 PY_ENV=python2.7 m_SUFFIX= + - LUA_ENV=lua5.3 PY_ENV=python2.7 m_SUFFIX= + - LUA_ENV=lua5.1 PY_ENV=python3.6 m_SUFFIX=m + - LUA_ENV=lua5.3 PY_ENV=python3.6 m_SUFFIX=m + + +before_install: + - sudo add-apt-repository -y "deb http://ppa.launchpad.net/grilo-team/travis/ubuntu trusty main" + - sudo add-apt-repository -y "deb http://ppa.launchpad.net/fkrull/deadsnakes/ubuntu trusty main" + - sudo apt-get update -qq + +install: + - sudo apt-get install -qq --force-yes lib${LUA_ENV}-dev + - sudo apt-get install -qq --force-yes lib${PY_ENV}-dev + +script: + - cmake -B./build -H. -DPYTHON_INCLUDE_DIR=/usr/include/${PY_ENV}${m_SUFFIX} -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/lib${PY_ENV}${m_SUFFIX}.so + - cmake --build ./build From 079cca1a5125df89a88920ae2078eb9615f442f3 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 17 Feb 2017 17:07:47 -0800 Subject: [PATCH 17/52] Travis build status to readme. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ce66561..b29f84c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.org/greatwolf/lunatic-python.svg?branch=master)](https://travis-ci.org/greatwolf/lunatic-python) + Details ======= From a9a7a1429dcad5de3afb0ecd0a1f9086ac1eafb8 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sun, 19 Feb 2017 00:59:27 -0800 Subject: [PATCH 18/52] Fixed string conversion. All unicode strings can go in a byte object but not all byte objects are unicode strings. Going from Python -> Lua always turns a unicode str into a byte object. Going from Lua -> Python, lunatic will try to decode as utf-8 first. Failing that it falls back to a byte object. Use 'PyUnicode_AsEncodedString' since it exists in both Py 2.7 and 3.3+. --- src/luainpython.c | 5 +++++ src/pythoninlua.c | 14 ++++++-------- src/pythoninlua.h | 5 +++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/luainpython.c b/src/luainpython.c index abb0b5f..8208f23 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -63,6 +63,11 @@ PyObject *LuaConvert(lua_State *L, int n) size_t len; const char *s = lua_tolstring(L, n, &len); ret = PyUnicode_FromStringAndSize(s, len); + if (!ret) + { + PyErr_Clear(); + ret = PyBytes_FromStringAndSize(s, len); + } break; } diff --git a/src/pythoninlua.c b/src/pythoninlua.c index ad84d7e..5be0e11 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -74,17 +74,15 @@ int py_convert(lua_State *L, PyObject *o, int withnone) } else if (o == Py_False) { lua_pushboolean(L, 0); ret = 1; -#if PY_MAJOR_VERSION >= 3 - } else if (PyUnicode_Check(o)) { - Py_ssize_t len; - char *s = PyUnicode_AsUTF8AndSize(o, &len); -#else - } else if (PyString_Check(o)) { + } else if (PyUnicode_Check(o) || PyBytes_Check(o)) { + PyObject *bstr = PyUnicode_AsEncodedString(o, "utf-8", NULL); Py_ssize_t len; char *s; - PyString_AsStringAndSize(o, &s, &len); -#endif + + PyErr_Clear(); + PyBytes_AsStringAndSize(bstr ? bstr : o, &s, &len); lua_pushlstring(L, s, len); + if (bstr) Py_DECREF(bstr); ret = 1; #if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(o)) { diff --git a/src/pythoninlua.h b/src/pythoninlua.h index 61171ca..533709a 100644 --- a/src/pythoninlua.h +++ b/src/pythoninlua.h @@ -25,6 +25,11 @@ #define POBJECT "POBJECT" +#if PY_MAJOR_VERSION < 3 + #define PyBytes_Check PyString_Check + #define PyBytes_AsStringAndSize PyString_AsStringAndSize +#endif + int py_convert(lua_State *L, PyObject *o, int withnone); typedef struct { From f2088483ea9644618a19d1ac206ffb079865b10f Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Wed, 22 Feb 2017 14:17:28 -0800 Subject: [PATCH 19/52] Just have 'Py_None' convert to 'nil'. Keeping as udata doesn't seem to serve any useful purpose. --- src/luainpython.c | 8 ++++---- src/pythoninlua.c | 32 ++++++++++++-------------------- src/pythoninlua.h | 2 +- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/luainpython.c b/src/luainpython.c index 8208f23..2aae6a9 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -127,7 +127,7 @@ static PyObject *LuaCall(lua_State *L, PyObject *args) lua_settop(L, 0); return NULL; } - rc = py_convert(L, arg, 0); + rc = py_convert(L, arg); if (!rc) { PyErr_Format(PyExc_TypeError, "failed to convert argument #%d", i); @@ -208,7 +208,7 @@ static PyObject *LuaObject_getattr(PyObject *obj, PyObject *attr) } PyObject *ret = NULL; - int rc = py_convert(LuaState, attr, 0); + int rc = py_convert(LuaState, attr); if (rc) { lua_gettable(LuaState, -2); ret = LuaConvert(LuaState, -1); @@ -234,13 +234,13 @@ static int LuaObject_setattr(PyObject *obj, PyObject *attr, PyObject *value) PyErr_SetString(PyExc_TypeError, "Lua object is not a table"); return -1; } - rc = py_convert(LuaState, attr, 0); + rc = py_convert(LuaState, attr); if (rc) { if (NULL == value) { lua_pushnil(LuaState); rc = 1; } else { - rc = py_convert(LuaState, value, 0); + rc = py_convert(LuaState, value); } if (rc) { diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 5be0e11..cf965bf 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -51,23 +51,15 @@ static int py_convert_custom(lua_State *L, PyObject *o, int asindx) return ret; } -int py_convert(lua_State *L, PyObject *o, int withnone) +int py_convert(lua_State *L, PyObject *o) { int ret = 0; - if (o == Py_None) { - if (withnone) { - lua_pushliteral(L, "Py_None"); - lua_rawget(L, LUA_REGISTRYINDEX); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - luaL_error(L, "lost none from registry"); - } - } else { - /* Not really needed, but this way we may check - * for errors with ret == 0. */ - lua_pushnil(L); - ret = 1; - } + if (o == Py_None) + { + /* Not really needed, but this way we may check + * for errors with ret == 0. */ + lua_pushnil(L); + ret = 1; } else if (o == Py_True) { lua_pushboolean(L, 1); ret = 1; @@ -191,7 +183,7 @@ static int py_object_call(lua_State *L) if (pKywdArgs) Py_DECREF(pKywdArgs); if (value) { - ret = py_convert(L, value, 0); + ret = py_convert(L, value); Py_DECREF(value); } else { PyErr_Print(); @@ -293,7 +285,7 @@ static int _p_object_index_get(lua_State *L, py_object *obj, int keyn) Py_DECREF(key); if (item) { - ret = py_convert(L, item, 0); + ret = py_convert(L, item); Py_DECREF(item); } else { PyErr_Clear(); @@ -349,7 +341,7 @@ static int py_object_index(lua_State *L) value = PyObject_GetAttrString(obj->o, (char*)attr); if (value) { - ret = py_convert(L, value, 0); + ret = py_convert(L, value); Py_DECREF(value); } else { PyErr_Clear(); @@ -379,7 +371,7 @@ static int py_object_tostring(lua_State *L) lua_pushstring(L, buf); PyErr_Clear(); } else { - py_convert(L, repr, 0); + py_convert(L, repr); assert(lua_type(L, -1) == LUA_TSTRING); Py_DECREF(repr); } @@ -504,7 +496,7 @@ static int py_run(lua_State *L, int eval) return 0; } - if (py_convert(L, o, 0)) + if (py_convert(L, o)) ret = 1; Py_DECREF(o); diff --git a/src/pythoninlua.h b/src/pythoninlua.h index 533709a..ee97f49 100644 --- a/src/pythoninlua.h +++ b/src/pythoninlua.h @@ -30,7 +30,7 @@ #define PyBytes_AsStringAndSize PyString_AsStringAndSize #endif -int py_convert(lua_State *L, PyObject *o, int withnone); +int py_convert(lua_State *L, PyObject *o); typedef struct { PyObject *o; From 1195d77713904bcdf0d7bf60ad80d8c696bda437 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Wed, 22 Feb 2017 14:41:26 -0800 Subject: [PATCH 20/52] Rely more on lua's API instead of manual allocation. Fixed Bracing. --- src/pythoninlua.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index cf965bf..4462668 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -457,41 +457,30 @@ static const luaL_Reg py_object_lib[] = { static int py_run(lua_State *L, int eval) { - const char *s; - char *buffer = NULL; + const char *s = luaL_checkstring(L, 1); PyObject *m, *d, *o; int ret = 0; - int len; - s = luaL_checkstring(L, 1); - if (!s) - return 0; + lua_settop(L, 1); - if (!eval) { - len = strlen(s)+1; - buffer = (char *) malloc(len+1); - if (!buffer) { - return luaL_error(L, "Failed allocating buffer for execution"); - } - strcpy(buffer, s); - buffer[len-1] = '\n'; - buffer[len] = '\0'; - s = buffer; + if (!eval) + { + lua_pushliteral(L, "\n"); + lua_concat(L, 2); + + s = luaL_checkstring(L, 1); } m = PyImport_AddModule("__main__"); - if (!m) { - free(buffer); + if (!m) return luaL_error(L, "Can't get __main__ module"); - } + d = PyModule_GetDict(m); o = PyRun_StringFlags(s, eval ? Py_eval_input : Py_single_input, d, d, NULL); - - free(buffer); - - if (!o) { + if (!o) + { PyErr_Print(); return 0; } From 746a71e1f910d3ec67cedb76086c1ded3a49a40d Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 24 Feb 2017 19:43:36 -0800 Subject: [PATCH 21/52] Switched to 'PyRun_String' since no flags used here. --- src/pythoninlua.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 4462668..966bcbd 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -477,8 +477,8 @@ static int py_run(lua_State *L, int eval) d = PyModule_GetDict(m); - o = PyRun_StringFlags(s, eval ? Py_eval_input : Py_single_input, - d, d, NULL); + o = PyRun_String(s, eval ? Py_eval_input : Py_single_input, + d, d); if (!o) { PyErr_Print(); From b50fcc7da5c54ac979794ac90f44adc9409fec82 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 24 Feb 2017 19:50:56 -0800 Subject: [PATCH 22/52] Added some tests from dmcooke/Lunatic-Python repo. --- tests/test_lua.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_py.lua | 15 +++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/test_lua.py create mode 100644 tests/test_py.lua diff --git a/tests/test_lua.py b/tests/test_lua.py new file mode 100644 index 0000000..ec92f5a --- /dev/null +++ b/tests/test_lua.py @@ -0,0 +1,65 @@ +""" +>>> lg = lua.globals() +>>> lg.string + +>>> lg.string.lower + +>>> lg.string.lower("Hello world!") == u'hello world!' +True + +>>> d = {} +>>> lg.d = d +>>> lua.execute("d['key'] = 'value'") +>>> d +{'key': 'value'} + +>>> d2 = lua.eval("d") +>>> d is d2 +True + +>>> lua.execute("python = require 'python'") +>>> lua.eval("python") + + +>>> obj + + +>>> lua.eval("python.eval 'obj'") + + +>>> lua.eval(\"\"\"python.eval([[lua.eval('python.eval("obj")')]])\"\"\") + + +>>> lua.execute("pg = python.globals()") +>>> lua.eval("pg.obj") + + +>>> def show(key, value): +... print("key is %s and value is %s" % (repr(key), repr(value))) +... +>>> asfunc = lua.eval("python.asfunc") +>>> asfunc + + +>>> l = ['a', 'b', 'c'] +>>> t = lua.eval("{a=1, b=2, c=3}") +>>> for k in l: +... show(k, t[k]) +key is 'a' and value is 1 +key is 'b' and value is 2 +key is 'c' and value is 3 + +""" + +import sys +import lua + +class MyClass: + def __repr__(self): return '' + +obj = MyClass() + +if __name__ == '__main__': + import doctest + sys.path.append("../../build/bin") + doctest.testmod(optionflags=doctest.ELLIPSIS) diff --git a/tests/test_py.lua b/tests/test_py.lua new file mode 100644 index 0000000..c3b135d --- /dev/null +++ b/tests/test_py.lua @@ -0,0 +1,15 @@ +python = require 'python' + +assert(nil == python.eval "None") +assert(true == python.eval "True") +assert(false == python.eval "False") + +assert(1 == python.eval "1") +assert(1.5 == python.eval "1.5") + +pyglob = python.globals() +d = {} +pyglob.d = d +-- This crashes if you've compiled the python.so to include another +-- Lua interpreter, i.e., with -llua. +python.execute "d['key'] = 'value'" From dd6c1534dae08ef5835db6e419ac0ac30eff2f29 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 24 Feb 2017 22:48:07 -0800 Subject: [PATCH 23/52] Run test scripts in travis.yml. --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index fd11441..a59d666 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,9 +19,16 @@ before_install: - sudo apt-get update -qq install: + - sudo apt-get install -qq --force-yes ${LUA_ENV} + - sudo apt-get install -qq --force-yes ${PY_ENV} - sudo apt-get install -qq --force-yes lib${LUA_ENV}-dev - sudo apt-get install -qq --force-yes lib${PY_ENV}-dev + - ${LUA_ENV} -v + - ${PY_ENV} --version script: - cmake -B./build -H. -DPYTHON_INCLUDE_DIR=/usr/include/${PY_ENV}${m_SUFFIX} -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/lib${PY_ENV}${m_SUFFIX}.so - cmake --build ./build + - cd ./build/bin + - ${PY_ENV} ../../tests/test_lua.py + - ${LUA_ENV} ../../tests/test_py.lua From dd67b4221a201ef9c4b02b4de434fa6fb98d5773 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 24 Feb 2017 22:48:48 -0800 Subject: [PATCH 24/52] Fixed up py test for 2.7 and 3.3. --- tests/test_lua.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/test_lua.py b/tests/test_lua.py index ec92f5a..cc5ad58 100644 --- a/tests/test_lua.py +++ b/tests/test_lua.py @@ -11,7 +11,7 @@ >>> lg.d = d >>> lua.execute("d['key'] = 'value'") >>> d -{'key': 'value'} +{...'key': ...'value'} >>> d2 = lua.eval("d") >>> d is d2 @@ -45,21 +45,23 @@ >>> t = lua.eval("{a=1, b=2, c=3}") >>> for k in l: ... show(k, t[k]) -key is 'a' and value is 1 -key is 'b' and value is 2 -key is 'c' and value is 3 +key is 'a' and value is 1... +key is 'b' and value is 2... +key is 'c' and value is 3... """ -import sys -import lua +import sys, os +sys.path.append(os.getcwd()) + class MyClass: def __repr__(self): return '' obj = MyClass() + if __name__ == '__main__': + import lua import doctest - sys.path.append("../../build/bin") doctest.testmod(optionflags=doctest.ELLIPSIS) From 28b221983d1bc2ff5bb3c827c4b9ab512c243cda Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 24 Feb 2017 23:03:06 -0800 Subject: [PATCH 25/52] Formatting. --- src/luainpython.h | 5 +++-- src/pythoninlua.h | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/luainpython.h b/src/luainpython.h index 8ea33cf..73ea65c 100644 --- a/src/luainpython.h +++ b/src/luainpython.h @@ -29,7 +29,8 @@ #define luaL_newlib(L, l) (lua_newtable(L), luaL_register(L, NULL, (l))) #endif -typedef struct { +typedef struct +{ PyObject_HEAD int ref; int refiter; @@ -39,7 +40,7 @@ extern PyTypeObject LuaObject_Type; #define LuaObject_Check(op) PyObject_TypeCheck(op, &LuaObject_Type) -PyObject *LuaConvert(lua_State *L, int n); +PyObject* LuaConvert(lua_State *L, int n); extern lua_State *LuaState; diff --git a/src/pythoninlua.h b/src/pythoninlua.h index ee97f49..dada102 100644 --- a/src/pythoninlua.h +++ b/src/pythoninlua.h @@ -32,12 +32,13 @@ int py_convert(lua_State *L, PyObject *o); -typedef struct { +typedef struct +{ PyObject *o; int asindx; } py_object; -py_object* luaPy_to_pobject(lua_State *L, int n); -LUA_API int luaopen_python(lua_State *L); +py_object* luaPy_to_pobject(lua_State *L, int n); +LUA_API int luaopen_python(lua_State *L); #endif From 973bff77ca285b5da83b0e3548c3e398f00800ec Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Fri, 24 Feb 2017 23:46:40 -0800 Subject: [PATCH 26/52] Reduce indent level. --- src/pythoninlua.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 966bcbd..9ee4cae 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -36,19 +36,17 @@ static int py_eval(lua_State *); static int py_convert_custom(lua_State *L, PyObject *o, int asindx) { - int ret = 0; py_object *obj = (py_object*) lua_newuserdata(L, sizeof(py_object)); - if (obj) { - Py_INCREF(o); - obj->o = o; - obj->asindx = asindx; - luaL_getmetatable(L, POBJECT); - lua_setmetatable(L, -2); - ret = 1; - } else { + if (!obj) luaL_error(L, "failed to allocate userdata object"); - } - return ret; + + Py_INCREF(o); + obj->o = o; + obj->asindx = asindx; + luaL_getmetatable(L, POBJECT); + lua_setmetatable(L, -2); + + return 1; } int py_convert(lua_State *L, PyObject *o) From f4110cf50cbb32adb42b2ca2c5f5ab35ab601602 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sat, 25 Feb 2017 00:04:23 -0800 Subject: [PATCH 27/52] More formatting and bracing. Removed unnecessary object checks; 'luaL_check*' has it covered. --- src/pythoninlua.c | 124 +++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 73 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 9ee4cae..9197be4 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -99,20 +99,17 @@ int py_convert(lua_State *L, PyObject *o) static int py_object_call(lua_State *L) { - py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); PyObject *args; PyObject *value; - PyObject* pKywdArgs = NULL; + PyObject *pKywdArgs = NULL; int nargs = lua_gettop(L)-1; int ret = 0; int i; + py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); + assert(obj); - if (!obj) { - return luaL_argerror(L, 1, "not a python object"); - } - if (!PyCallable_Check(obj->o)) { + if (!PyCallable_Check(obj->o)) return luaL_error(L, "object is not callable"); - } // passing a single table forces named keyword call style, e.g. plt.plot{x, y, c='red'} if (nargs==1 && lua_istable(L, 2)) { @@ -227,31 +224,25 @@ static int _p_object_newindex_set(lua_State *L, py_object *obj, static int py_object_newindex_set(lua_State *L) { - py_object *obj = (py_object*) luaL_checkudata(L, lua_upvalueindex(1), - POBJECT); - if (lua_gettop(L) != 2) { + py_object *obj = (py_object*) luaL_checkudata(L, lua_upvalueindex(1), POBJECT); + if (lua_gettop(L) != 2) return luaL_error(L, "invalid arguments"); - } + return _p_object_newindex_set(L, obj, 1, 2); } static int py_object_newindex(lua_State *L) { - py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - const char *attr; PyObject *value; + const char *attr; + py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); + assert(obj); - if (!obj) { - return luaL_argerror(L, 1, "not a python object"); - } - - if (obj->asindx || lua_type(L, 2)!=LUA_TSTRING) + if (obj->asindx || lua_type(L, 2) != LUA_TSTRING) return _p_object_newindex_set(L, obj, 2, 3); attr = luaL_checkstring(L, 2); - if (!attr) { - return luaL_argerror(L, 2, "string needed"); - } + assert(attr); value = LuaConvert(L, 3); if (!value) { @@ -298,33 +289,27 @@ static int _p_object_index_get(lua_State *L, py_object *obj, int keyn) static int py_object_index_get(lua_State *L) { - py_object *obj = (py_object*) luaL_checkudata(L, lua_upvalueindex(1), - POBJECT); + py_object *obj = (py_object*) luaL_checkudata(L, lua_upvalueindex(1), POBJECT); int top = lua_gettop(L); - if (top < 1 || top > 2) { + if (top < 1 || top > 2) return luaL_error(L, "invalid arguments"); - } + return _p_object_index_get(L, obj, 1); } static int py_object_index(lua_State *L) { - py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - const char *attr; - PyObject *value; int ret = 0; + PyObject *value; + const char *attr; + py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); + assert(obj); - if (!obj) { - return luaL_argerror(L, 1, "not a python object"); - } - - if (obj->asindx || lua_type(L, 2)!=LUA_TSTRING) + if (obj->asindx || lua_type(L, 2) != LUA_TSTRING) return _p_object_index_get(L, obj, 2); attr = luaL_checkstring(L, 2); - if (!attr) { - return luaL_argerror(L, 2, "string needed"); - } + assert(attr); if (attr[0] == '_' && strcmp(attr, "__get") == 0) { lua_pushvalue(L, 1); @@ -352,27 +337,30 @@ static int py_object_index(lua_State *L) static int py_object_gc(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - if (obj) { - Py_DECREF(obj->o); - } + assert(obj); + + Py_DECREF(obj->o); return 0; } static int py_object_tostring(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - if (obj) { - PyObject *repr = PyObject_Str(obj->o); - if (!repr) { - char buf[256]; - snprintf(buf, 256, "python object: %p", obj->o); - lua_pushstring(L, buf); - PyErr_Clear(); - } else { - py_convert(L, repr); - assert(lua_type(L, -1) == LUA_TSTRING); - Py_DECREF(repr); - } + assert(obj); + + PyObject *repr = PyObject_Str(obj->o); + if (!repr) + { + char buf[256]; + snprintf(buf, 256, "python object: %p", obj->o); + lua_pushstring(L, buf); + PyErr_Clear(); + } + else + { + py_convert(L, repr); + assert(lua_type(L, -1) == LUA_TSTRING); + Py_DECREF(repr); } return 1; } @@ -439,7 +427,8 @@ static int py_object_pow(lua_State *L) return py_object_call(L); } -static const luaL_Reg py_object_lib[] = { +static const luaL_Reg py_object_lib[] = +{ {"__call", py_object_call}, {"__index", py_object_index}, {"__newindex", py_object_newindex}, @@ -509,8 +498,7 @@ static int py_eval(lua_State *L) static int py_asindx(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - if (!obj) - return luaL_argerror(L, 1, "not a python object"); + assert(obj); return py_convert_custom(L, obj->o, 1); } @@ -518,8 +506,7 @@ static int py_asindx(lua_State *L) static int py_asattr(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); - if (!obj) - return luaL_argerror(L, 1, "not a python object"); + assert(obj); return py_convert_custom(L, obj->o, 0); } @@ -533,15 +520,10 @@ static int py_asfunc_call(lua_State *L) static int py_asfunc(lua_State *L) { - int ret = 0; - if (luaL_checkudata(L, 1, POBJECT)) { - lua_pushcclosure(L, py_asfunc_call, 1); - ret = 1; - } else { - luaL_argerror(L, 1, "not a python object"); - } + luaL_checkudata(L, 1, POBJECT); + lua_pushcclosure(L, py_asfunc_call, 1); - return ret; + return 1; } static int py_globals(lua_State *L) @@ -604,16 +586,11 @@ static int py_builtins(lua_State *L) static int py_import(lua_State *L) { const char *name = luaL_checkstring(L, 1); - PyObject *module; + PyObject *module = PyImport_ImportModule((char*)name); int ret; - if (!name) { - return luaL_argerror(L, 1, "module name expected"); - } - - module = PyImport_ImportModule((char*)name); - - if (!module) { + if (!module) + { PyErr_Print(); return luaL_error(L, "failed importing '%s'", name); } @@ -633,7 +610,8 @@ py_object* luaPy_to_pobject(lua_State *L, int n) return is_pobject ? (py_object *) lua_touserdata(L, n) : NULL; } -static const luaL_Reg py_lib[] = { +static const luaL_Reg py_lib[] = +{ {"execute", py_execute}, {"eval", py_eval}, {"asindx", py_asindx}, From 33a8bdf81e6f1bf07e72eee69b521d208479394d Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sat, 25 Feb 2017 00:18:43 -0800 Subject: [PATCH 28/52] Fixed bug where 'asfunc' sets wrong upvalue if given multiple args. Disallow non-callable PyObjects from being wrapped since it doesn't make sense. --- src/pythoninlua.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 9197be4..e2dc889 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -520,7 +520,11 @@ static int py_asfunc_call(lua_State *L) static int py_asfunc(lua_State *L) { - luaL_checkudata(L, 1, POBJECT); + py_object *obj = luaL_checkudata(L, 1, POBJECT); + if (!PyCallable_Check(obj->o)) + return luaL_error(L, "object is not callable"); + + lua_settop(L, 1); lua_pushcclosure(L, py_asfunc_call, 1); return 1; From dc61478591c8d03fc679be29fcf7dd22d80db224 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sat, 25 Feb 2017 23:00:02 -0800 Subject: [PATCH 29/52] Comparison support of lua values in py. --- src/luainpython.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/luainpython.c b/src/luainpython.c index 2aae6a9..8ed887d 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -301,6 +301,47 @@ static PyObject *LuaObject_str(PyObject *obj) return ret; } +static int LuaObject_pcmp(lua_State *L) +{ + int op = lua_tointeger(L, -3); + switch(op) + { + case Py_EQ: + lua_pushboolean(L, lua_compare(L, -2, -1, LUA_OPEQ)); + break; + case Py_NE: + lua_pushboolean(L, !lua_compare(L, -2, -1, LUA_OPEQ)); + break; + case Py_GT: + lua_insert(LuaState, -2); + case Py_LT: + lua_pushboolean(L, lua_compare(L, -2, -1, LUA_OPLT)); + break; + case Py_GE: + lua_insert(LuaState, -2); + case Py_LE: + lua_pushboolean(L, lua_compare(L, -2, -1, LUA_OPLE)); + } + + return 1; +} + +static PyObject* LuaObject_richcmp(PyObject *lhs, PyObject *rhs, int op) +{ + if (!LuaObject_Check(rhs)) return Py_False; + + lua_pushcfunction(LuaState, LuaObject_pcmp); + lua_pushinteger(LuaState, op); + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, ((LuaObject *)lhs)->ref); + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, ((LuaObject *)rhs)->ref); + if (lua_pcall(LuaState, 3, 1, 0) != LUA_OK) + { + PyErr_SetString(PyExc_RuntimeError, lua_tostring(LuaState, -1)); + return NULL; + } + return lua_toboolean(LuaState, -1) ? Py_True : Py_False; +} + static PyObject *LuaObject_call(PyObject *obj, PyObject *args) { lua_settop(LuaState, 0); @@ -390,7 +431,7 @@ PyTypeObject LuaObject_Type = { "custom lua object", /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ - 0, /*tp_richcompare*/ + LuaObject_richcmp, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ PyObject_SelfIter, /*tp_iter*/ (iternextfunc)LuaObject_iternext, /*tp_iternext*/ From 1d41f31eb520e9f7b9a47e81d16f01212b43402f Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sat, 25 Feb 2017 23:00:47 -0800 Subject: [PATCH 30/52] Consolidated tests. --- test.py | 29 ----------------------------- tests/test_lua.py | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 29 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index 354b010..0000000 --- a/test.py +++ /dev/null @@ -1,29 +0,0 @@ -print "----- import lua -----" -import lua -print "----- lg = lua.globals() -----" -lg = lua.globals() -print "lg:", lg -print "lg._G:", lg._G -print "lg['_G']:", lg['_G'] -print "----- lg.foo = \"bar\" -----" -lg.foo = 'bar' -print "----- lg.tmp = [] -----" -lg.tmp = [] -print "----- print lg.tmp -----" -print lg.tmp -print "----- lua.execute(\"xxx = {1,2,3,foo={4,5}}\") -----" -lua.execute("xxx = {1,2,3,foo={4,5}}") -print "----- print lg.xxx[1] -----" -print lg.xxx[1] -print "----- print lg.xxx[2] -----" -print lg.xxx[2] -print "----- print lg.xxx[3] -----" -print lg.xxx[3] -print "----- print lg.xxx['foo'][1] -----" -print lg.xxx['foo'][1] -print "lua.require =", lua.require -try: - lua.require("foo") -except: - print "lua.require('foo') raised an exception" - diff --git a/tests/test_lua.py b/tests/test_lua.py index cc5ad58..310d55f 100644 --- a/tests/test_lua.py +++ b/tests/test_lua.py @@ -1,5 +1,29 @@ """ >>> lg = lua.globals() +>>> lg == lg._G +True +>>> lg._G == lg._G +True +>>> lg._G == lg['_G'] +True + +>>> lg.foo = 'bar' +>>> lg.foo == u'bar' +True + +>>> lg.tmp = [] +>>> lg.tmp +[] + +>>> lua.execute("x = {1, 2, 3, foo = {4, 5}}") +>>> lg.x[1], lg.x[2], lg.x[3] +(1, 2, 3) +>>> lg.x['foo'][1], lg.x['foo'][2] +(4, 5) + +>>> lua.require + + >>> lg.string >>> lg.string.lower From 27b75207894c4c5bdd666941459ed54348d2148b Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sat, 25 Feb 2017 23:23:14 -0800 Subject: [PATCH 31/52] Fixed api changes between lua 5.1 and 5.2+. --- src/luainpython.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/luainpython.c b/src/luainpython.c index 8ed887d..9016baa 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -301,6 +301,25 @@ static PyObject *LuaObject_str(PyObject *obj) return ret; } +#if LUA_VERSION_NUM == 501 +enum +{ + LUA_OK, LUA_OPEQ, LUA_OPLT, LUA_OPLE, +}; +static int lua_compare(lua_State *L, int lhs, int rhs, int op) +{ + switch(op) + { + case LUA_OPEQ: + return lua_equal(L, lhs, rhs); + case LUA_OPLT: + return lua_lessthan(L, lhs, rhs); + case LUA_OPLE: + return lua_lessthan(L, lhs, rhs) || lua_equal(L, lhs, rhs); + } + return 0; +} +#endif static int LuaObject_pcmp(lua_State *L) { int op = lua_tointeger(L, -3); From 057b2da5b54a67d3ea3ca472b774ea907ac98c35 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sat, 25 Feb 2017 23:26:40 -0800 Subject: [PATCH 32/52] Minor test fixup. --- tests/test_lua.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_lua.py b/tests/test_lua.py index 310d55f..a8eb916 100644 --- a/tests/test_lua.py +++ b/tests/test_lua.py @@ -17,9 +17,9 @@ >>> lua.execute("x = {1, 2, 3, foo = {4, 5}}") >>> lg.x[1], lg.x[2], lg.x[3] -(1, 2, 3) +(1..., 2..., 3...) >>> lg.x['foo'][1], lg.x['foo'][2] -(4, 5) +(4..., 5...) >>> lua.require From 24347a8ee022836ed08c040fd2b3363433724018 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sat, 25 Feb 2017 23:36:16 -0800 Subject: [PATCH 33/52] Simplified statement. --- src/pythoninlua.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index e2dc889..e6998ed 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -89,9 +89,7 @@ int py_convert(lua_State *L, PyObject *o) lua_rawgeti(L, LUA_REGISTRYINDEX, ((LuaObject*)o)->ref); ret = 1; } else { - int asindx = 0; - if (PyDict_Check(o) || PyList_Check(o) || PyTuple_Check(o)) - asindx = 1; + int asindx = PyDict_Check(o) || PyList_Check(o) || PyTuple_Check(o); ret = py_convert_custom(L, o, asindx); } return ret; From 5fb9b4933a1ab9502991ca66c14214b834c9395d Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Thu, 2 Mar 2017 03:39:10 -0800 Subject: [PATCH 34/52] Added string test. --- tests/test_py.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_py.lua b/tests/test_py.lua index c3b135d..5ccf7d8 100644 --- a/tests/test_py.lua +++ b/tests/test_py.lua @@ -7,9 +7,13 @@ assert(false == python.eval "False") assert(1 == python.eval "1") assert(1.5 == python.eval "1.5") +assert("foo" == python.eval "b'foo'") +assert("bar" == python.eval "u'bar'") + pyglob = python.globals() d = {} pyglob.d = d -- This crashes if you've compiled the python.so to include another -- Lua interpreter, i.e., with -llua. python.execute "d['key'] = 'value'" +assert(d.key == 'value') From da9314401a5ae9bac304b1df607dacde21d4cfc3 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Thu, 2 Mar 2017 13:56:56 -0800 Subject: [PATCH 35/52] Renamed to something more appropriate. --- src/pythoninlua.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index e6998ed..52edb77 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -425,7 +425,7 @@ static int py_object_pow(lua_State *L) return py_object_call(L); } -static const luaL_Reg py_object_lib[] = +static const luaL_Reg py_object_mt[] = { {"__call", py_object_call}, {"__index", py_object_index}, @@ -635,7 +635,7 @@ LUA_API int luaopen_python(lua_State *L) /* Register python object metatable */ luaL_newmetatable(L, POBJECT); - luaL_setfuncs(L, py_object_lib, 0); + luaL_setfuncs(L, py_object_mt, 0); lua_pop(L, 1); /* Initialize Lua state in Python territory */ From 438ac2601e98d225d5ba8f636d0104a9039f76f8 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Thu, 2 Mar 2017 14:18:15 -0800 Subject: [PATCH 36/52] Fixed whitespace alignment. --- src/luainpython.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/luainpython.c b/src/luainpython.c index 9016baa..fb8b8a7 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -532,7 +532,7 @@ PyObject *Lua_globals(PyObject *self, PyObject *args) ret = LuaConvert(LuaState, -1); if (!ret) PyErr_Format(PyExc_TypeError, - "failed to convert globals table"); + "failed to convert globals table"); lua_settop(LuaState, 0); return ret; } From e7bddb0937ad437e2d4ff6ddb57830e3992e7fe5 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Thu, 2 Mar 2017 14:19:06 -0800 Subject: [PATCH 37/52] Added test for attribute assignment. Added some test for py operators on py container. --- tests/test_py.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_py.lua b/tests/test_py.lua index 5ccf7d8..e08f885 100644 --- a/tests/test_py.lua +++ b/tests/test_py.lua @@ -16,4 +16,12 @@ pyglob.d = d -- This crashes if you've compiled the python.so to include another -- Lua interpreter, i.e., with -llua. python.execute "d['key'] = 'value'" -assert(d.key == 'value') +assert(d.key == 'value', d.key) + +python.execute "d.key = 'newvalue'" +assert(d.key == 'newvalue', d.key) + +-- Test operators on py containers +l = python.eval "['hello']" +assert(tostring(l * 3) == "['hello', 'hello', 'hello']") +assert(tostring(l + python.eval "['bye']") == "['hello', 'bye']") From 4d031942e3e635a93a03eac15474d940e15022f5 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Thu, 2 Mar 2017 14:35:25 -0800 Subject: [PATCH 38/52] DRY'ed up py operators with macro. --- src/pythoninlua.c | 76 ++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 54 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 52edb77..3ea0ed9 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -375,55 +375,23 @@ static int py_operator_lambda(lua_State *L, const char *op) return luaL_ref(L, LUA_REGISTRYINDEX); } -static int py_object_mul(lua_State *L) -{ - static int op_ref = LUA_REFNIL; - if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "*"); - - lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); - lua_insert(L, 1); - return py_object_call(L); -} - -static int py_object_div(lua_State *L) -{ - static int op_ref = LUA_REFNIL; - if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "/"); - - lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); - lua_insert(L, 1); - return py_object_call(L); -} - -static int py_object_add(lua_State *L) -{ - static int op_ref = LUA_REFNIL; - if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "+"); - - lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); - lua_insert(L, 1); - return py_object_call(L); -} - -static int py_object_sub(lua_State *L) -{ - static int op_ref = LUA_REFNIL; - if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "-"); - - lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); - lua_insert(L, 1); - return py_object_call(L); -} - -static int py_object_pow(lua_State *L) -{ - static int op_ref = LUA_REFNIL; - if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, "**"); - - lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); - lua_insert(L, 1); - return py_object_call(L); -} +#define make_pyoperator(opname, opliteral) \ + static int py_object_ ## opname(lua_State *L) \ + { \ + static int op_ref = LUA_REFNIL; \ + if (op_ref == LUA_REFNIL) op_ref = py_operator_lambda(L, opliteral); \ + \ + lua_rawgeti(L, LUA_REGISTRYINDEX, op_ref); \ + lua_insert(L, 1); \ + return py_object_call(L); \ + } \ + struct opname ## __LINE__ // force semi + +make_pyoperator(_pow, "**"); +make_pyoperator(_mul, "*"); +make_pyoperator(_div, "/"); +make_pyoperator(_add, "+"); +make_pyoperator(_sub, "-"); static const luaL_Reg py_object_mt[] = { @@ -432,11 +400,11 @@ static const luaL_Reg py_object_mt[] = {"__newindex", py_object_newindex}, {"__gc", py_object_gc}, {"__tostring", py_object_tostring}, - {"__mul", py_object_mul}, - {"__div", py_object_div}, - {"__add", py_object_add}, - {"__sub", py_object_sub}, - {"__pow", py_object_pow}, + {"__pow", py_object__pow}, + {"__mul", py_object__mul}, + {"__div", py_object__div}, + {"__add", py_object__add}, + {"__sub", py_object__sub}, {NULL, NULL} }; From d1ff70d4479b04d61024d4f63543445659a23520 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 6 Mar 2017 22:25:58 -0800 Subject: [PATCH 39/52] Refactored python library name into compile-time string literal. Undefined symbols only happen on linux because of 'RTLD_LOCAL' by default; Other platforms don't have this issue so remove those cases. --- src/pythoninlua.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index cfa761d..7e954ae 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -21,7 +21,9 @@ */ #include -#include +#if defined(__linux__) +# include +#endif /* need this to build with Lua 5.2: defines luaL_register() macro */ #define LUA_COMPAT_MODULE @@ -625,15 +627,15 @@ LUA_API int luaopen_python(lua_State *L) /* Loading python library symbols so that dynamic extensions don't throw symbol not found error. Ref Link: http://stackoverflow.com/questions/29880931/importerror-and-pyexc-systemerror-while-embedding-python-script-within-c-for-pam */ - char str_python_lib[20]; -#ifdef _WIN32 - sprintf(str_python_lib, "libpython%d.%d.dll", PY_MAJOR_VERSION, PY_MINOR_VERSION); -#elif defined __unix__ - sprintf(str_python_lib, "libpython%d.%d.so", PY_MAJOR_VERSION, PY_MINOR_VERSION); -#elif defined __APPLE__ - sprintf(str_python_lib, "libpython%d.%d.dylib", PY_MAJOR_VERSION, PY_MINOR_VERSION); +#if defined(__linux__) +# define STR(s) #s +#if PY_MAJOR_VERSION < 3 +# define PYLIB_STR(major, minor) "libpython" STR(major) "." STR(minor) ".so" +#else +# define PYLIB_STR(major, minor) "libpython" STR(major) "." STR(minor) "m.so" +#endif + dlopen(PYLIB_STR(PY_MAJOR_VERSION, PY_MINOR_VERSION), RTLD_NOW | RTLD_GLOBAL); #endif - dlopen(str_python_lib, RTLD_NOW | RTLD_GLOBAL); Py_Initialize(); PySys_SetArgv(1, argv); From 1084df697767ca589a7b36e49be3b0a850172427 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 6 Mar 2017 22:34:22 -0800 Subject: [PATCH 40/52] Have Test try to load dynamic py extensions that needs py runtime symbols. --- tests/test_py.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_py.lua b/tests/test_py.lua index e08f885..4a6551e 100644 --- a/tests/test_py.lua +++ b/tests/test_py.lua @@ -25,3 +25,7 @@ assert(d.key == 'newvalue', d.key) l = python.eval "['hello']" assert(tostring(l * 3) == "['hello', 'hello', 'hello']") assert(tostring(l + python.eval "['bye']") == "['hello', 'bye']") + +-- Test that Python C module can access Py Runtime symbols +ctypes = python.import 'ctypes' +assert(tostring(ctypes):match "module 'ctypes'") From e4a19ef827699eb64a35d8f49117fdc9b75fd4b6 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sun, 12 Mar 2017 21:02:16 -0700 Subject: [PATCH 41/52] Test multiple statements in one execution. --- tests/test_py.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_py.lua b/tests/test_py.lua index 4a6551e..a5f4d28 100644 --- a/tests/test_py.lua +++ b/tests/test_py.lua @@ -29,3 +29,14 @@ assert(tostring(l + python.eval "['bye']") == "['hello', 'bye']") -- Test that Python C module can access Py Runtime symbols ctypes = python.import 'ctypes' assert(tostring(ctypes):match "module 'ctypes'") + +-- Test multiple Python statement execution +pytype = python.eval "type" +python.execute +[[ +foo = 1 +bar = 2 +]] + +assert(python.globals().foo == 1) +assert(python.globals().bar == 2) From 3156c37ee0b497f242475d6423f2f35a7c6f4fc9 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Sun, 12 Mar 2017 21:02:57 -0700 Subject: [PATCH 42/52] Changed to allow multiline source execution. --- src/pythoninlua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 7e954ae..386278a 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -433,7 +433,7 @@ static int py_run(lua_State *L, int eval) d = PyModule_GetDict(m); - o = PyRun_String(s, eval ? Py_eval_input : Py_single_input, + o = PyRun_String(s, eval ? Py_eval_input : Py_file_input, d, d); if (!o) { From 09d56fdf2c16a6b153d9c81fe09ecec59e6f5153 Mon Sep 17 00:00:00 2001 From: jayatubi Date: Thu, 11 May 2017 16:11:36 +0800 Subject: [PATCH 43/52] should not generate error if attribute not found on python object --- src/pythoninlua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 386278a..a58a4cc 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -329,7 +329,7 @@ static int py_object_index(lua_State *L) Py_DECREF(value); } else { PyErr_Clear(); - luaL_error(L, "unknown attribute in python object"); + // luaL_error(L, "unknown attribute in python object"); } return ret; From 4e70849bd6aada555b1eb98c78340b1149f5818c Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 14 May 2017 12:59:44 -0700 Subject: [PATCH 44/52] Update pythoninlua.c Actually push and return `nil`. --- src/pythoninlua.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index a58a4cc..98e8108 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -329,7 +329,8 @@ static int py_object_index(lua_State *L) Py_DECREF(value); } else { PyErr_Clear(); - // luaL_error(L, "unknown attribute in python object"); + lua_pushnil(L); + ret = 1; } return ret; From 987efa45d0f1321c727ad833338c705e8aaaf3cd Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 15 May 2017 15:28:01 -0700 Subject: [PATCH 45/52] Removed superfluous comparison. --- src/pythoninlua.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 98e8108..3f23972 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -312,11 +312,11 @@ static int py_object_index(lua_State *L) attr = luaL_checkstring(L, 2); assert(attr); - if (attr[0] == '_' && strcmp(attr, "__get") == 0) { + if (strcmp(attr, "__get") == 0) { lua_pushvalue(L, 1); lua_pushcclosure(L, py_object_index_get, 1); return 1; - } else if (attr[0] == '_' && strcmp(attr, "__set") == 0) { + } else if (strcmp(attr, "__set") == 0) { lua_pushvalue(L, 1); lua_pushcclosure(L, py_object_newindex_set, 1); return 1; From 5ed46cce32233b04b715721e4a7df1181c200d3e Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 15 May 2017 15:30:34 -0700 Subject: [PATCH 46/52] Updated working versions in readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b29f84c..bd6a1b4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This is a fork of Lunatic Python, which can be found on the 'net at http://labix Sadly, Lunatic Python is very much outdated and won't work with either a current Python or Lua. -This is an updated version of lunatic-python that works with Python 2.7 and Lua 5.1. +This is an updated version of lunatic-python that works with Python 2.7-3.x and Lua 5.1-5.3. I tried contacting the original author of Lunatic Python, but got no response. Installing From 280d5b1c6c01872fdfbcfb5951f9a5bb03f236f9 Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 15 May 2017 15:40:52 -0700 Subject: [PATCH 47/52] Unnecessary cast, 'const char *' is expected anyway. --- src/pythoninlua.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pythoninlua.c b/src/pythoninlua.c index 3f23972..f5b5bd5 100644 --- a/src/pythoninlua.c +++ b/src/pythoninlua.c @@ -250,7 +250,7 @@ static int py_object_newindex(lua_State *L) return luaL_argerror(L, 1, "failed to convert value"); } - if (PyObject_SetAttrString(obj->o, (char*)attr, value) == -1) { + if (PyObject_SetAttrString(obj->o, attr, value) == -1) { Py_DECREF(value); PyErr_Print(); return luaL_error(L, "failed to set value"); @@ -323,7 +323,7 @@ static int py_object_index(lua_State *L) } - value = PyObject_GetAttrString(obj->o, (char*)attr); + value = PyObject_GetAttrString(obj->o, attr); if (value) { ret = py_convert(L, value); Py_DECREF(value); From 6f25eb650e48e7926337f97f6b3566f9f86c9d0d Mon Sep 17 00:00:00 2001 From: Greatwolf Date: Mon, 15 May 2017 15:48:59 -0700 Subject: [PATCH 48/52] Updated travis build status to upstream. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd6a1b4..a525e2f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/greatwolf/lunatic-python.svg?branch=master)](https://travis-ci.org/greatwolf/lunatic-python) +[![Build Status](https://travis-ci.org/bastibe/lunatic-python.svg?branch=master)](https://travis-ci.org/bastibe/lunatic-python) Details ======= From f6caa00f77ffe20eedf913b212ef35292b61d1af Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 18 Sep 2017 11:02:58 -0700 Subject: [PATCH 49/52] Fixed potential leak in `lua_run` issue #61 --- src/luainpython.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/luainpython.c b/src/luainpython.c index fb8b8a7..c6db8be 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -492,6 +492,7 @@ PyObject *Lua_run(PyObject *args, int eval) PyErr_Format(PyExc_RuntimeError, "error loading code: %s", lua_tostring(LuaState, -1)); + free(buff); return NULL; } From 10db7744dd4b7a9e49ebecdb36108686246090aa Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 18 Sep 2017 11:31:16 -0700 Subject: [PATCH 50/52] Fixed variable name typo --- src/luainpython.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/luainpython.c b/src/luainpython.c index c6db8be..c55c6ab 100644 --- a/src/luainpython.c +++ b/src/luainpython.c @@ -492,7 +492,7 @@ PyObject *Lua_run(PyObject *args, int eval) PyErr_Format(PyExc_RuntimeError, "error loading code: %s", lua_tostring(LuaState, -1)); - free(buff); + free(buf); return NULL; } From b43f5daec0f1c223e04774ca87c2c1618025c98d Mon Sep 17 00:00:00 2001 From: Aaron Hosford Date: Thu, 5 Oct 2017 23:52:03 -0500 Subject: [PATCH 51/52] Bug fix: Combine pcoutput in pkgconfig The `for` loop that executes pkg-config was taking the libs & cflags from only the first package. --- setup.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 6501557..2fee368 100755 --- a/setup.py +++ b/setup.py @@ -30,18 +30,19 @@ def pkgconfig(*packages): # map pkg-config output to kwargs for distutils.core.Extension flag_map = {'-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} + combined_pcoutput = '' for package in packages: (pcstatus, pcoutput) = commands.getstatusoutput( "pkg-config --libs --cflags %s" % package) if pcstatus == 0: - break - else: - sys.exit("pkg-config failed for %s; " - "most recent output was:\n%s" % - (", ".join(packages), pcoutput)) + combined_pcoutput += ' ' + pcoutput + else: + sys.exit("pkg-config failed for %s; " + "most recent output was:\n%s" % + (", ".join(packages), pcoutput)) kwargs = {} - for token in pcoutput.split(): + for token in combined_pcoutput.split(): if token[:2] in flag_map: kwargs.setdefault(flag_map.get(token[:2]), []).append(token[2:]) else: # throw others to extra_link_args @@ -56,7 +57,7 @@ def pkgconfig(*packages): return kwargs -lua_pkgconfig = pkgconfig('lua' + LUAVERSION, 'lua' + LUAVERSION,'python-' + PYTHONVERSION) +lua_pkgconfig = pkgconfig('lua' + LUAVERSION, 'python-' + PYTHONVERSION) lua_pkgconfig['extra_compile_args'] = ['-I/usr/include/lua'+LUAVERSION] setup(name="lunatic-python", From 7bb5bb5103966e338a98f6ef2411f127bb7ba4f5 Mon Sep 17 00:00:00 2001 From: Danni Moiseyev Date: Sun, 23 Feb 2020 15:07:33 +0200 Subject: [PATCH 52/52] Use LUA 5.1 if 5.2 doesn't exists on the system --- setup.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2fee368..9f0496d 100755 --- a/setup.py +++ b/setup.py @@ -18,8 +18,15 @@ if os.path.isfile("MANIFEST"): os.unlink("MANIFEST") +presult, poutput = commands.getstatusoutput("pkg-config --exists lua5.2") +HAS_LUA5_2 = (presult == 0) + # You may have to change these -LUAVERSION = "5.2" +if HAS_LUA5_2: + LUAVERSION = "5.2" +else: + LUAVERSION = "5.1" + PYTHONVERSION = get_python_version() PYLIBS = ["python" + get_python_version(), "pthread", "util"] PYLIBDIR = [get_python_lib(standard_lib=True) + "/config"]