See More

/* Lunatic Python -------------- Copyright (c) 2002-2005 Gustavo Niemeyer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #if defined(__linux__) # include #endif /* need this to build with Lua 5.2: defines luaL_register() macro */ #define LUA_COMPAT_MODULE #include #include #include "pythoninlua.h" #include "luainpython.h" 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) { py_object *obj = (py_object*) lua_newuserdata(L, sizeof(py_object)); if (!obj) luaL_error(L, "failed to allocate userdata object"); 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) { int ret = 0; 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; } else if (o == Py_False) { lua_pushboolean(L, 0); ret = 1; } else if (PyUnicode_Check(o) || PyBytes_Check(o)) { PyObject *bstr = PyUnicode_AsEncodedString(o, "utf-8", NULL); Py_ssize_t len; char *s; 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)) { lua_pushnumber(L, (lua_Number)PyInt_AsLong(o)); ret = 1; #endif } else if (PyLong_Check(o)) { lua_pushnumber(L, (lua_Number)PyLong_AsLong(o)); ret = 1; } else if (PyFloat_Check(o)) { lua_pushnumber(L, (lua_Number)PyFloat_AsDouble(o)); ret = 1; } else if (LuaObject_Check(o)) { lua_rawgeti(L, LUA_REGISTRYINDEX, ((LuaObject*)o)->ref); ret = 1; } else { int asindx = PyDict_Check(o) || PyList_Check(o) || PyTuple_Check(o); ret = py_convert_custom(L, o, asindx); } return ret; } static int py_object_call(lua_State *L) { PyObject *args; PyObject *value; 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 (!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)) { lua_pushnil(L); /* first key */ nargs=0; while (lua_next(L, 2) != 0) { if (lua_isnumber(L, -2)) { int i = lua_tointeger(L, -2); nargs = i < nargs ? nargs : i; } lua_pop(L, 1); } args = PyTuple_New(nargs); if (!args) { PyErr_Print(); return luaL_error(L, "failed to create arguments tuple"); } pKywdArgs = PyDict_New(); if (!pKywdArgs) { Py_DECREF(args); PyErr_Print(); return luaL_error(L, "failed to create arguments dictionary"); } lua_pushnil(L); /* first key */ while (lua_next(L, 2) != 0) { if (lua_isnumber(L, -2)) { PyObject *arg = LuaConvert(L, -1); if (!arg) { Py_DECREF(args); Py_DECREF(pKywdArgs); return luaL_error(L, "failed to convert argument #%d", lua_tointeger(L, -2)); } PyTuple_SetItem(args, lua_tointeger(L, -2)-1, arg); } else if (lua_isstring(L, -2)) { PyObject *arg = LuaConvert(L, -1); if (!arg) { Py_DECREF(args); Py_DECREF(pKywdArgs); return luaL_error(L, "failed to convert argument '%s'", lua_tostring(L, -2)); } PyDict_SetItemString(pKywdArgs, lua_tostring(L, -2), arg); Py_DECREF(arg); } lua_pop(L, 1); } } // regular call style e.g. plt.plot(x, y) else { 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+2); 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->o, args, pKywdArgs); Py_DECREF(args); if (pKywdArgs) Py_DECREF(pKywdArgs); if (value) { ret = py_convert(L, value); Py_DECREF(value); } else { char s_exc[1024] = {0}; char s_traceback[1024] = {0}; PyObject *exc_type, *exc_value, *exc_traceback; PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback); PyObject *exc_str = PyObject_Str(exc_value); // Need not be garbage collected as per documentation of PyUnicode_AsUTF8 const char *exc_cstr = (exc_str)?PyUnicode_AsUTF8(exc_str):""; strncpy(s_exc, (!(exc_cstr)?"UNKNOWN ERROR\n":exc_cstr), 1023); if (exc_value != NULL && exc_traceback != NULL) { PyObject *traceback_module = PyImport_ImportModule("traceback"); if (traceback_module != NULL) { PyObject *traceback_list = PyObject_CallMethod(traceback_module, "format_exception", "OOO", exc_type, exc_value, exc_traceback); if (traceback_list != NULL) { PyObject *traceback_str = PyUnicode_Join(PyUnicode_FromString(""), traceback_list); if (traceback_str != NULL) { // Need not be garbage collected as per documentation of PyUnicode_AsUTF8 const char *traceback_cstr = PyUnicode_AsUTF8(traceback_str); if (traceback_cstr != NULL) { strncpy(s_traceback, traceback_cstr, 1023); } Py_XDECREF(traceback_str); } Py_XDECREF(traceback_list); } Py_XDECREF(traceback_module); } } Py_XDECREF(exc_type); Py_XDECREF(exc_value); Py_XDECREF(exc_traceback); Py_XDECREF(exc_str); if (*s_traceback == '\0') { luaL_error(L, "error calling python function:\nException: %s", s_exc); } else { luaL_error(L, "error calling python function:\nException: %s", s_traceback); } } return ret; } static int _p_object_newindex_set(lua_State *L, py_object *obj, int keyn, int valuen) { PyObject *value; PyObject *key = LuaConvert(L, keyn); if (!key) { return luaL_argerror(L, 1, "failed to convert key"); } if (!lua_isnil(L, valuen)) { value = LuaConvert(L, valuen); if (!value) { Py_DECREF(key); return luaL_argerror(L, 1, "failed to convert value"); } if (PyObject_SetItem(obj->o, key, value) == -1) { PyErr_Print(); luaL_error(L, "failed to set item"); } Py_DECREF(value); } else { if (PyObject_DelItem(obj->o, key) == -1) { PyErr_Print(); luaL_error(L, "failed to delete item"); } } Py_DECREF(key); return 0; } 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) return luaL_error(L, "invalid arguments"); return _p_object_newindex_set(L, obj, 1, 2); } static int py_object_newindex(lua_State *L) { PyObject *value; const char *attr; py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); assert(obj); if (obj->asindx || lua_type(L, 2) != LUA_TSTRING) return _p_object_newindex_set(L, obj, 2, 3); attr = luaL_checkstring(L, 2); assert(attr); value = LuaConvert(L, 3); if (!value) { return luaL_argerror(L, 1, "failed to convert value"); } if (PyObject_SetAttrString(obj->o, attr, value) == -1) { Py_DECREF(value); PyErr_Print(); return luaL_error(L, "failed to set value"); } Py_DECREF(value); return 0; } static int _p_object_index_get(lua_State *L, py_object *obj, int keyn) { PyObject *key = LuaConvert(L, keyn); PyObject *item; int ret = 0; if (!key) { return luaL_argerror(L, 1, "failed to convert key"); } item = PyObject_GetItem(obj->o, key); if (!item) { item = PyObject_GetAttr(obj->o, key); } Py_DECREF(key); if (item) { ret = py_convert(L, item); Py_DECREF(item); } else { PyErr_Clear(); if (lua_gettop(L) > keyn) { lua_pushvalue(L, keyn+1); ret = 1; } } return ret; } static int py_object_index_get(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, lua_upvalueindex(1), POBJECT); int top = lua_gettop(L); 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) { int ret = 0; PyObject *value; const char *attr; py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); assert(obj); if (obj->asindx || lua_type(L, 2) != LUA_TSTRING) return _p_object_index_get(L, obj, 2); attr = luaL_checkstring(L, 2); assert(attr); if (strcmp(attr, "__get") == 0) { lua_pushvalue(L, 1); lua_pushcclosure(L, py_object_index_get, 1); return 1; } else if (strcmp(attr, "__set") == 0) { lua_pushvalue(L, 1); lua_pushcclosure(L, py_object_newindex_set, 1); return 1; } value = PyObject_GetAttrString(obj->o, attr); if (value) { ret = py_convert(L, value); Py_DECREF(value); } else { PyErr_Clear(); lua_pushnil(L); ret = 1; } return ret; } static int py_object_gc(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); 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); assert(obj); PyObject *repr = PyObject_Str(obj->o); if (!repr) { char buf[256]; snprintf(buf, 256, "python object: %p", (void *)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; } 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); } #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[] = { {"__call", py_object_call}, {"__index", py_object_index}, {"__newindex", py_object_newindex}, {"__gc", py_object_gc}, {"__tostring", py_object_tostring}, {"__pow", py_object__pow}, {"__mul", py_object__mul}, {"__div", py_object__div}, {"__add", py_object__add}, {"__sub", py_object__sub}, {NULL, NULL} }; static int py_run(lua_State *L, int eval) { const char *s = luaL_checkstring(L, 1); PyObject *m, *d, *o; int ret = 0; lua_settop(L, 1); if (!eval) { lua_pushliteral(L, "\n"); lua_concat(L, 2); s = luaL_checkstring(L, 1); } m = PyImport_AddModule("__main__"); if (!m) return luaL_error(L, "Can't get __main__ module"); d = PyModule_GetDict(m); o = PyRun_String(s, eval ? Py_eval_input : Py_file_input, d, d); if (!o) { PyErr_Print(); return 0; } if (py_convert(L, o)) ret = 1; Py_DECREF(o); #if PY_MAJOR_VERSION < 3 if (Py_FlushLine()) #endif PyErr_Clear(); return ret; } static int py_execute(lua_State *L) { return py_run(L, 0); } static int py_eval(lua_State *L) { return py_run(L, 1); } static int py_asindx(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); assert(obj); return py_convert_custom(L, obj->o, 1); } static int py_asattr(lua_State *L) { py_object *obj = (py_object*) luaL_checkudata(L, 1, POBJECT); assert(obj); return py_convert_custom(L, obj->o, 0); } static int py_asfunc_call(lua_State *L) { lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1); return py_object_call(L); } static int py_asfunc(lua_State *L) { 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; } static int py_globals(lua_State *L) { PyObject *globals; if (lua_gettop(L) != 0) { return luaL_error(L, "invalid arguments"); } globals = PyEval_GetGlobals(); if (!globals) { PyObject *module = PyImport_AddModule("__main__"); if (!module) { return luaL_error(L, "Can't get __main__ module"); } globals = PyModule_GetDict(module); } if (!globals) { PyErr_Print(); return luaL_error(L, "can't get globals"); } return py_convert_custom(L, globals, 1); } static int py_locals(lua_State *L) { PyObject *locals; if (lua_gettop(L) != 0) { return luaL_error(L, "invalid arguments"); } locals = PyEval_GetLocals(); if (!locals) return py_globals(L); return py_convert_custom(L, locals, 1); } static int py_builtins(lua_State *L) { PyObject *builtins; if (lua_gettop(L) != 0) { return luaL_error(L, "invalid arguments"); } builtins = PyEval_GetBuiltins(); if (!builtins) { PyErr_Print(); return luaL_error(L, "failed to get builtins"); } return py_convert_custom(L, builtins, 1); } static int py_import(lua_State *L) { const char *name = luaL_checkstring(L, 1); PyObject *module = PyImport_ImportModule((char*)name); int ret; if (!module) { PyErr_Print(); return luaL_error(L, "failed importing '%s'", name); } ret = py_convert_custom(L, module, 0); Py_DECREF(module); return ret; } py_object* luaPy_to_pobject(lua_State *L, int n) { if(!lua_getmetatable(L, n)) return NULL; luaL_getmetatable(L, POBJECT); int is_pobject = lua_rawequal(L, -1, -2); lua_pop(L, 2); return is_pobject ? (py_object *) lua_touserdata(L, n) : NULL; } static const luaL_Reg py_lib[] = { {"execute", py_execute}, {"eval", py_eval}, {"asindx", py_asindx}, {"asattr", py_asattr}, {"asfunc", py_asfunc}, {"locals", py_locals}, {"globals", py_globals}, {"builtins", py_builtins}, {"import", py_import}, {NULL, NULL} }; LUA_API int luaopen_python(lua_State *L) { int rc; /* Register module */ luaL_newlib(L, py_lib); /* Register python object metatable */ luaL_newmetatable(L, POBJECT); luaL_setfuncs(L, py_object_mt, 0); lua_pop(L, 1); /* Initialize Lua state in Python territory */ if (!LuaState) LuaState = L; /* Initialize Python interpreter */ if (!Py_IsInitialized()) { PyObject *luam, *mainm, *maind; #if PY_MAJOR_VERSION >= 3 wchar_t *argv[] = {L"", 0}; #else char *argv[] = {"", 0}; #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 */ #if defined(__linux__) # define STR(s) #s # define PYLIB_STR(s) STR(s) #if !defined(PYTHON_LIBRT) # error PYTHON_LIBRT must be defined when building under Linux! #endif void *ok = dlopen(PYLIB_STR(PYTHON_LIBRT), RTLD_NOW | RTLD_GLOBAL); assert(ok); (void) ok; #endif Py_Initialize(); PySys_SetArgv(1, argv); /* Import 'lua' automatically. */ luam = PyImport_ImportModule("lua"); if (!luam) return luaL_error(L, "Can't import lua module"); 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); Py_DECREF(luam); } /* Register 'none' */ rc = py_convert_custom(L, Py_None, 0); if (!rc) return luaL_error(L, "failed to convert none object"); lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, "Py_None"); /* registry.Py_None */ lua_setfield(L, -2, "none"); /* python.none */ return 1; }