comparison src/if_lua.c @ 21006:ae185f35e256 v8.2.1054

patch 8.2.1054: not so easy to pass a lua function to Vim Commit: https://github.com/vim/vim/commit/801ab069341c8652680d63c174530fd4feb2911e Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jun 25 19:27:56 2020 +0200 patch 8.2.1054: not so easy to pass a lua function to Vim Problem: Not so easy to pass a lua function to Vim. Solution: Convert a Lua function and closure to a Vim funcref. (Prabir Shrestha, closes #6246)
author Bram Moolenaar <Bram@vim.org>
date Thu, 25 Jun 2020 19:30:21 +0200
parents 054ba681412d
children 380923b96878
comparison
equal deleted inserted replaced
21005:3f0abea9bed2 21006:ae185f35e256
33 char_u *name; // funcref 33 char_u *name; // funcref
34 dict_T *self; // selfdict 34 dict_T *self; // selfdict
35 } luaV_Funcref; 35 } luaV_Funcref;
36 typedef void (*msgfunc_T)(char_u *); 36 typedef void (*msgfunc_T)(char_u *);
37 37
38 typedef struct {
39 int lua_funcref; // ref to a lua func
40 int lua_tableref; // ref to a lua table if metatable else LUA_NOREF. used
41 // for __call
42 lua_State *L;
43 } luaV_CFuncState;
44
38 static const char LUAVIM_DICT[] = "dict"; 45 static const char LUAVIM_DICT[] = "dict";
39 static const char LUAVIM_LIST[] = "list"; 46 static const char LUAVIM_LIST[] = "list";
40 static const char LUAVIM_BLOB[] = "blob"; 47 static const char LUAVIM_BLOB[] = "blob";
41 static const char LUAVIM_FUNCREF[] = "funcref"; 48 static const char LUAVIM_FUNCREF[] = "funcref";
42 static const char LUAVIM_BUFFER[] = "buffer"; 49 static const char LUAVIM_BUFFER[] = "buffer";
43 static const char LUAVIM_WINDOW[] = "window"; 50 static const char LUAVIM_WINDOW[] = "window";
44 static const char LUAVIM_FREE[] = "luaV_free"; 51 static const char LUAVIM_FREE[] = "luaV_free";
45 static const char LUAVIM_LUAEVAL[] = "luaV_luaeval"; 52 static const char LUAVIM_LUAEVAL[] = "luaV_luaeval";
46 static const char LUAVIM_SETREF[] = "luaV_setref"; 53 static const char LUAVIM_SETREF[] = "luaV_setref";
54
55 static const char LUA___CALL[] = "__call";
47 56
48 // most functions are closures with a cache table as first upvalue; 57 // most functions are closures with a cache table as first upvalue;
49 // get/setudata manage references to vim userdata in cache table through 58 // get/setudata manage references to vim userdata in cache table through
50 // object pointers (light userdata) 59 // object pointers (light userdata)
51 #define luaV_getudata(L, v) \ 60 #define luaV_getudata(L, v) \
62 if (sandbox) luaL_error((L), "not allowed in sandbox") 71 if (sandbox) luaL_error((L), "not allowed in sandbox")
63 #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg) 72 #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg)
64 #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg) 73 #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg)
65 #define luaV_checktypval(L, a, v, msg) \ 74 #define luaV_checktypval(L, a, v, msg) \
66 do { \ 75 do { \
67 if (luaV_totypval(L, a, v) == FAIL) \ 76 if (luaV_totypval(L, a, v) == FAIL) \
68 luaL_error(L, msg ": cannot convert value"); \ 77 luaL_error(L, msg ": cannot convert value"); \
69 } while (0) 78 } while (0)
70 79
71 static luaV_List *luaV_pushlist(lua_State *L, list_T *lis); 80 static luaV_List *luaV_pushlist(lua_State *L, list_T *lis);
72 static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic); 81 static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic);
73 static luaV_Blob *luaV_pushblob(lua_State *L, blob_T *blo); 82 static luaV_Blob *luaV_pushblob(lua_State *L, blob_T *blo);
74 static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name); 83 static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name);
84 static int luaV_call_lua_func(int argcount, typval_T *argvars, typval_T *rettv, void *state);
85 static void luaV_call_lua_func_free(void *state);
75 86
76 #if LUA_VERSION_NUM <= 501 87 #if LUA_VERSION_NUM <= 501
77 #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n) 88 #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
78 #define luaL_typeerror luaL_typerror 89 #define luaL_typeerror luaL_typerror
79 #else 90 #else
589 #else 600 #else
590 tv->v_type = VAR_NUMBER; 601 tv->v_type = VAR_NUMBER;
591 tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos); 602 tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos);
592 #endif 603 #endif
593 break; 604 break;
605 case LUA_TFUNCTION:
606 {
607 char_u *name;
608 lua_pushvalue(L, pos);
609 luaV_CFuncState *state = ALLOC_CLEAR_ONE(luaV_CFuncState);
610 state->lua_funcref = luaL_ref(L, LUA_REGISTRYINDEX);
611 state->L = L;
612 state->lua_tableref = LUA_NOREF;
613 name = register_cfunc(&luaV_call_lua_func,
614 &luaV_call_lua_func_free, state);
615 tv->v_type = VAR_FUNC;
616 tv->vval.v_string = vim_strsave(name);
617 break;
618 }
619 case LUA_TTABLE:
620 {
621 lua_pushvalue(L, pos);
622 int lua_tableref = luaL_ref(L, LUA_REGISTRYINDEX);
623 if (lua_getmetatable(L, pos)) {
624 lua_getfield(L, -1, LUA___CALL);
625 if (lua_isfunction(L, -1)) {
626 char_u *name;
627 int lua_funcref = luaL_ref(L, LUA_REGISTRYINDEX);
628 luaV_CFuncState *state = ALLOC_CLEAR_ONE(luaV_CFuncState);
629 state->lua_funcref = lua_funcref;
630 state->L = L;
631 state->lua_tableref = lua_tableref;
632 name = register_cfunc(&luaV_call_lua_func,
633 &luaV_call_lua_func_free, state);
634 tv->v_type = VAR_FUNC;
635 tv->vval.v_string = vim_strsave(name);
636 break;
637 }
638 }
639 tv->v_type = VAR_NUMBER;
640 tv->vval.v_number = 0;
641 status = FAIL;
642 break;
643 }
594 case LUA_TUSERDATA: 644 case LUA_TUSERDATA:
595 { 645 {
596 void *p = lua_touserdata(L, pos); 646 void *p = lua_touserdata(L, pos);
597 647
598 if (lua_getmetatable(L, pos)) // has metatable? 648 if (lua_getmetatable(L, pos)) // has metatable?
2413 if (lua_pcall(L, 0, 0, 0)) 2463 if (lua_pcall(L, 0, 0, 0))
2414 luaV_emsg(L); 2464 luaV_emsg(L);
2415 } 2465 }
2416 } 2466 }
2417 2467
2418 #endif 2468 /*
2469 * Native C function callback
2470 */
2471 static int
2472 luaV_call_lua_func(
2473 int argcount,
2474 typval_T *argvars,
2475 typval_T *rettv,
2476 void *state)
2477 {
2478 int i;
2479 int luaargcount = argcount;
2480 luaV_CFuncState *funcstate = (luaV_CFuncState*)state;
2481 lua_rawgeti(funcstate->L, LUA_REGISTRYINDEX, funcstate->lua_funcref);
2482
2483 if (funcstate->lua_tableref != LUA_NOREF)
2484 {
2485 // First arg for metatable __call method is a table
2486 luaargcount += 1;
2487 lua_rawgeti(funcstate->L, LUA_REGISTRYINDEX, funcstate->lua_tableref);
2488 }
2489
2490 for (i = 0; i < argcount; ++i)
2491 luaV_pushtypval(funcstate->L, &argvars[i]);
2492
2493 if (lua_pcall(funcstate->L, luaargcount, 1, 0))
2494 {
2495 luaV_emsg(funcstate->L);
2496 return FCERR_OTHER;
2497 }
2498
2499 luaV_checktypval(funcstate->L, -1, rettv, "get return value");
2500 return FCERR_NONE;
2501 }
2502
2503 /*
2504 * Free up any lua references held by the func state.
2505 */
2506 static void
2507 luaV_call_lua_func_free(void *state)
2508 {
2509 luaV_CFuncState *funcstate = (luaV_CFuncState*)state;
2510 luaL_unref(L, LUA_REGISTRYINDEX, funcstate->lua_funcref);
2511 funcstate->L = NULL;
2512 if (funcstate->lua_tableref != LUA_NOREF)
2513 luaL_unref(L, LUA_REGISTRYINDEX, funcstate->lua_tableref);
2514 VIM_CLEAR(funcstate);
2515 }
2516
2517 #endif