summaryrefslogtreecommitdiffhomepage
path: root/contrib/package/ucode-mod-lua
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/package/ucode-mod-lua')
-rw-r--r--contrib/package/ucode-mod-lua/src/lua.c177
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);