Mercurial > vim
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 |