Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/openwrt/luci.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2022-08-21 02:32:12 +0300
committerJo-Philipp Wich <jo@mein.io>2022-08-26 11:11:17 +0300
commit42201e336d53412c63dbfde934786841d7bf29d2 (patch)
treedecaa3ac1a471acaaea6cea8b67ffa38bb6a6dae /contrib
parent7e4c087f868935d1ee42ca515f3be40f91474848 (diff)
ucode-mod-lua: support prototype lookups and method calls on ucode values
Expose ucode arrays and objects with prototypes as userdata proxy objects to Lua and extend the userdata metadatable with an __index metamethod to lookup not found properties in the ucode values prototype chain. Also extend the __call metamethod implementation to infer method call status from the activation record in order to invoke ucode functions with the correct `this` context when called as method from Lua. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'contrib')
-rw-r--r--contrib/package/ucode-mod-lua/src/lua.c90
1 files changed, 68 insertions, 22 deletions
diff --git a/contrib/package/ucode-mod-lua/src/lua.c b/contrib/package/ucode-mod-lua/src/lua.c
index 679425fae5..241f4a92ff 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,26 @@ 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);
+ uc_value_t *proto, *rv;
+ bool found;
+
+ proto = ucv_prototype_get(ud->uv);
+ rv = ucv_object_get(proto, key, &found);
+
+ if (!found)
+ return 0;
+
+ ucv_to_lua(ud->vm, rv, L, NULL);
+ ucv_put(rv);
+
+ return 1;
+}
+
+static int
lua_uv_tostring(lua_State *L)
{
ucv_userdata_t *ud = luaL_checkudata(L, 1, "ucode.value");
@@ -443,6 +490,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 },
{ }
@@ -899,8 +947,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);