diff options
Diffstat (limited to 'contrib/package/ucode-mod-lua/src/lua.c')
-rw-r--r-- | contrib/package/ucode-mod-lua/src/lua.c | 177 |
1 files changed, 144 insertions, 33 deletions
diff --git a/contrib/package/ucode-mod-lua/src/lua.c b/contrib/package/ucode-mod-lua/src/lua.c index 679425fae5..d02c6dc867 100644 --- a/contrib/package/ucode-mod-lua/src/lua.c +++ b/contrib/package/ucode-mod-lua/src/lua.c @@ -155,30 +155,46 @@ ucv_to_lua(uc_vm_t *vm, uc_value_t *uv, lua_State *L, struct lh_table *visited) case UC_ARRAY: case UC_OBJECT: - if (!visited) { - freetbl = true; - visited = lh_kptr_table_new(16, NULL); + if (ucv_prototype_get(uv)) { + ud = lua_newuserdata(L, sizeof(*ud)); + + if (ud) { + ud->vm = vm; + ud->uv = ucv_get(uv); + + luaL_getmetatable(L, "ucode.value"); + lua_setmetatable(L, -2); + } + else { + lua_pushnil(L); + } } + else { + if (!visited) { + freetbl = true; + visited = lh_kptr_table_new(16, NULL); + } - if (visited) { - if (lua_table_new_or_ref(L, visited, uv)) { - if (ucv_type(uv) == UC_ARRAY) { - for (i = 0; i < ucv_array_length(uv); i++) { - e = ucv_array_get(uv, i); - ucv_to_lua(vm, e, L, visited); - lua_rawseti(L, -2, (int)i + 1); + if (visited) { + if (lua_table_new_or_ref(L, visited, uv)) { + if (ucv_type(uv) == UC_ARRAY) { + for (i = 0; i < ucv_array_length(uv); i++) { + e = ucv_array_get(uv, i); + ucv_to_lua(vm, e, L, visited); + lua_rawseti(L, -2, (int)i + 1); + } } - } - else { - ucv_object_foreach(uv, key, val) { - ucv_to_lua(vm, val, L, visited); - lua_setfield(L, -2, key); + else { + ucv_object_foreach(uv, key, val) { + ucv_to_lua(vm, val, L, visited); + lua_setfield(L, -2, key); + } } } } - } - else { - lua_pushnil(L); + else { + lua_pushnil(L); + } } break; @@ -401,17 +417,28 @@ lua_uv_call(lua_State *L) ucv_userdata_t *ud = luaL_checkudata(L, 1, "ucode.value"); int nargs = lua_gettop(L), i; uc_value_t *rv; + lua_Debug ar; + bool mcall; if (!ucv_is_callable(ud->uv)) return luaL_error(L, "%s: Invoked value is not a function", uc_exception_type_name(EXCEPTION_TYPE)); + if (!lua_getstack(L, 0, &ar) || !lua_getinfo(L, "n", &ar)) + return luaL_error(L, "%s: Unable to obtain stackframe information", + uc_exception_type_name(EXCEPTION_RUNTIME)); + + mcall = !strcmp(ar.namewhat, "method"); + + if (mcall) + uc_vm_stack_push(ud->vm, lua_to_ucv(L, 2, ud->vm, NULL)); + uc_vm_stack_push(ud->vm, ucv_get(ud->uv)); - for (i = 2; i <= nargs; i++) + for (i = 2 + mcall; i <= nargs; i++) uc_vm_stack_push(ud->vm, lua_to_ucv(L, i, ud->vm, NULL)); - if (uc_vm_call(ud->vm, false, nargs - 1)) { + if (uc_vm_call(ud->vm, mcall, nargs - 1 - mcall)) { rv = ucv_object_get(ucv_array_get(ud->vm->exception.stacktrace, 0), "context", NULL); return luaL_error(L, "%s: %s%s%s", @@ -429,6 +456,29 @@ lua_uv_call(lua_State *L) } static int +lua_uv_index(lua_State *L) +{ + ucv_userdata_t *ud = luaL_checkudata(L, 1, "ucode.value"); + const char *key = luaL_checkstring(L, 2); + long long idx; + char *e; + + if (ucv_type(ud->uv) == UC_ARRAY) { + idx = strtoll(key, &e, 10); + + if (e != key && *e == 0 && idx >= 1 && idx <= (long long)ucv_array_length(ud->uv)) { + ucv_to_lua(ud->vm, ucv_array_get(ud->uv, (size_t)(idx - 1)), L, NULL); + + return 1; + } + } + + ucv_to_lua(ud->vm, ucv_property_get(ud->uv, key), L, NULL); + + return 1; +} + +static int lua_uv_tostring(lua_State *L) { ucv_userdata_t *ud = luaL_checkudata(L, 1, "ucode.value"); @@ -443,6 +493,7 @@ lua_uv_tostring(lua_State *L) static const luaL_reg ucode_ud_methods[] = { { "__gc", lua_uv_gc }, { "__call", lua_uv_call }, + { "__index", lua_uv_index }, { "__tostring", lua_uv_tostring }, { } @@ -451,17 +502,17 @@ static const luaL_reg ucode_ud_methods[] = { static uc_value_t * uc_lua_vm_claim_result(uc_vm_t *vm, lua_State *L, int oldtop) { - int nargs = lua_gettop(L) - oldtop, i; + int nargs = lua_gettop(L) - oldtop - 1, i; uc_value_t *uv; if (nargs > 1) { uv = ucv_array_new_length(vm, nargs); - for (i = 1; i <= nargs; i++) + for (i = 2; i <= nargs; i++) ucv_array_push(uv, lua_to_ucv(L, oldtop + i, vm, NULL)); } else if (nargs == 1) { - uv = lua_to_ucv(L, oldtop + 1, vm, NULL); + uv = lua_to_ucv(L, oldtop + 2, vm, NULL); } else { uv = NULL; @@ -470,18 +521,57 @@ uc_lua_vm_claim_result(uc_vm_t *vm, lua_State *L, int oldtop) return uv; } +static int +uc_lua_vm_pcall_error_cb(lua_State *L) +{ + const char *message = luaL_checkstring(L, 1); + uc_stringbuf_t *buf = xprintbuf_new(); + lua_Debug ar; + int level; + + ucv_stringbuf_printf(buf, "%s\n", message); + + for (level = 1; lua_getstack(L, level, &ar) == 1; level++) { + if (lua_getinfo(L, "Snl", &ar) == 0) + continue; + + if (level == 1) { + ucv_stringbuf_printf(buf, "\nIn %s(), file %s", + ar.name ? ar.name : "[anonymous function]", ar.short_src); + + if (ar.currentline > -1) + ucv_stringbuf_printf(buf, ", line %d", ar.currentline); + + ucv_stringbuf_append(buf, "\n"); + } + else { + ucv_stringbuf_printf(buf, " called from function %s (%s", + ar.name ? ar.name : "[anonymous function]", ar.short_src); + + if (ar.currentline > -1) + ucv_stringbuf_printf(buf, ":%d", ar.currentline); + + ucv_stringbuf_append(buf, ")\n"); + } + } + + lua_pushstring(L, buf->buf); + printbuf_free(buf); + + return 1; +} + static uc_value_t * uc_lua_vm_pcall(uc_vm_t *vm, lua_State *L, int oldtop) { uc_value_t *uv; - switch (lua_pcall(L, lua_gettop(L) - oldtop - 1, LUA_MULTRET, 0)) { + switch (lua_pcall(L, lua_gettop(L) - oldtop - 2, LUA_MULTRET, oldtop + 1)) { case LUA_ERRRUN: case LUA_ERRMEM: case LUA_ERRERR: uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, - "Lua raised runtime exception: %s", - lua_tostring(L, -1)); + "%s", lua_tostring(L, -1)); uv = NULL; break; @@ -508,6 +598,7 @@ uc_lua_vm_invoke(uc_vm_t *vm, size_t nargs) top = lua_gettop(*L); + lua_pushcfunction(*L, uc_lua_vm_pcall_error_cb); lua_getglobal(*L, ucv_string_get(name)); for (i = 1; i < nargs; i++) { @@ -535,11 +626,12 @@ uc_lua_vm_eval(uc_vm_t *vm, size_t nargs) top = lua_gettop(*L); + lua_pushcfunction(*L, uc_lua_vm_pcall_error_cb); + switch (luaL_loadstring(*L, ucv_string_get(source))) { case LUA_ERRSYNTAX: uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, - "Syntax error while compiling Lua code: %s", - lua_tostring(*L, -1)); + "%s", lua_tostring(*L, -1)); break; @@ -573,6 +665,8 @@ uc_lua_vm_include(uc_vm_t *vm, size_t nargs) top = lua_gettop(*L); + lua_pushcfunction(*L, uc_lua_vm_pcall_error_cb); + switch (luaL_loadfile(*L, ucv_string_get(path))) { case LUA_ERRSYNTAX: uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, @@ -639,13 +733,22 @@ uc_lua_vm_get(uc_vm_t *vm, size_t nargs) uc_value_t *key = uc_fn_arg(0); lua_resource_t *lv; size_t i; + int top; if (!L || !*L || ucv_type(key) != UC_STRING) return NULL; + top = lua_gettop(*L); + lua_getglobal(*L, ucv_string_get(key)); for (i = 1; i < nargs; i++) { + if (lua_type(*L, -1) != LUA_TTABLE) { + lua_settop(*L, top); + + return NULL; + } + ucv_to_lua(vm, uc_fn_arg(i), *L, NULL); lua_gettable(*L, -2); } @@ -654,8 +757,7 @@ uc_lua_vm_get(uc_vm_t *vm, size_t nargs) lv->ref = luaL_ref(*L, LUA_REGISTRYINDEX); lv->uvL = ucv_this_to_uvL(vm); - if (nargs > 1) - lua_pop(*L, nargs - 1); + lua_settop(*L, top); return uc_resource_new(lv_type, lv); } @@ -691,6 +793,7 @@ uc_lua_lv_call(uc_vm_t *vm, size_t nargs) oldtop = lua_gettop(L); + lua_pushcfunction(L, uc_lua_vm_pcall_error_cb); lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref); for (i = 0; i < nargs; i++) @@ -718,6 +821,7 @@ uc_lua_lv_invoke(uc_vm_t *vm, size_t nargs) oldtop = lua_gettop(L); + lua_pushcfunction(L, uc_lua_vm_pcall_error_cb); lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref); ucv_to_lua(vm, method, L, NULL); lua_gettable(L, -2); @@ -740,15 +844,24 @@ uc_lua_lv_get_common(uc_vm_t *vm, size_t nargs, bool raw) lua_State *L = uc_lua_lv_to_L(lv); uc_value_t *key; size_t i; + int top; if (!L) return NULL; + top = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref); for (i = 0; i < nargs; i++) { key = uc_fn_arg(i); + if (lua_type(L, -1) != LUA_TTABLE) { + lua_settop(L, top); + + return NULL; + } + if (raw) { if (ucv_type(key) == UC_INTEGER) { lua_rawgeti(L, -1, (int)ucv_int64_get(key)); @@ -768,7 +881,7 @@ uc_lua_lv_get_common(uc_vm_t *vm, size_t nargs, bool raw) ref->ref = luaL_ref(L, LUA_REGISTRYINDEX); ref->uvL = ucv_this_to_uvL(vm); - lua_pop(L, nargs); + lua_settop(L, top); return uc_resource_new(lv_type, ref); } @@ -899,8 +1012,6 @@ uc_lua_create(uc_vm_t *vm, size_t nargs) luaL_newmetatable(L, "ucode.value"); luaL_register(L, NULL, ucode_ud_methods); - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); lua_pop(L, 1); return uc_resource_new(vm_type, L); |