Created
January 8, 2012 09:27
-
-
Save koron/1577830 to your computer and use it in GitHub Desktop.
Fix confused references related with an environment table
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # HG changeset patch | |
| # Parent 2e546d787ee8d12f7ea1b22172b9d491652c1ed7 | |
| Fix confused references related with an environment table | |
| diff -r 2e546d787ee8 src/if_lua.c | |
| --- a/src/if_lua.c Thu Jan 05 09:14:30 2012 +0900 | |
| +++ b/src/if_lua.c Sun Jan 08 19:19:42 2012 +0900 | |
| @@ -73,6 +73,7 @@ | |
| #define lua_gettop dll_lua_gettop | |
| #define lua_settop dll_lua_settop | |
| #define lua_pushvalue dll_lua_pushvalue | |
| +#define lua_insert dll_lua_insert | |
| #define lua_replace dll_lua_replace | |
| #define lua_isnumber dll_lua_isnumber | |
| #define lua_isstring dll_lua_isstring | |
| @@ -135,6 +136,7 @@ | |
| int (*dll_lua_gettop) (lua_State *L); | |
| void (*dll_lua_settop) (lua_State *L, int idx); | |
| void (*dll_lua_pushvalue) (lua_State *L, int idx); | |
| +void (*dll_lua_insert) (lua_State *L, int idx); | |
| void (*dll_lua_replace) (lua_State *L, int idx); | |
| int (*dll_lua_isnumber) (lua_State *L, int idx); | |
| int (*dll_lua_isstring) (lua_State *L, int idx); | |
| @@ -204,6 +206,7 @@ | |
| {"lua_gettop", (luaV_function) &dll_lua_gettop}, | |
| {"lua_settop", (luaV_function) &dll_lua_settop}, | |
| {"lua_pushvalue", (luaV_function) &dll_lua_pushvalue}, | |
| + {"lua_insert", (luaV_function) &dll_lua_insert}, | |
| {"lua_replace", (luaV_function) &dll_lua_replace}, | |
| {"lua_isnumber", (luaV_function) &dll_lua_isnumber}, | |
| {"lua_isstring", (luaV_function) &dll_lua_isstring}, | |
| @@ -297,6 +300,143 @@ | |
| /* ======= Internal ======= */ | |
| +/** | |
| + * Push a lua object which associated to the pointer to the stack, and return | |
| + * 1. If no objects associated, nil is pushed to the stack, and return 0. | |
| + * | |
| + * [+1, 0, -] | |
| + */ | |
| + static int | |
| +luaV_get_associated_luavalue(lua_State *L, void *rawptr) | |
| +{ | |
| + lua_pushlightuserdata(L, rawptr); | |
| + lua_rawget(L, LUA_REGISTRYINDEX); | |
| + return lua_isnil(L, -1) ? 0 : 1; | |
| +} | |
| + | |
| +/** | |
| + * A lua object is associated with a C native pointer return 1, otherwise 0. | |
| + * | |
| + * [0, 0, -] | |
| + */ | |
| + static int | |
| +luaV_is_associated_luavalue(lua_State *L, void *rawptr) | |
| +{ | |
| + int retval = luaV_get_associated_luavalue(L, rawptr); | |
| + lua_pop(L, 1); /* obj */ | |
| + return retval; | |
| +} | |
| + | |
| +/** | |
| + * Associate a lua object which specified by index with a C native pointer. | |
| + * | |
| + * [0, 0, -] | |
| + */ | |
| + static void | |
| +luaV_set_associated_luavalue(lua_State *L, void *rawptr, int idx) | |
| +{ | |
| + lua_pushvalue(L, idx); | |
| + lua_pushlightuserdata(L, rawptr); | |
| + lua_pushvalue(L, -2); | |
| + lua_rawset(L, LUA_REGISTRYINDEX); | |
| + lua_pop(L, 1); | |
| +} | |
| + | |
| +/** | |
| + * Reset any associated values to associated with a C native pointer. | |
| + * | |
| + * [0, 0, -] | |
| + */ | |
| + static void | |
| +luaV_reset_associated_luavalue(lua_State *L, void *rawptr) | |
| +{ | |
| + lua_pushnil(L); | |
| + luaV_set_associated_luavalue(L, rawptr, -1); | |
| + lua_pop(L, 1); | |
| +} | |
| + | |
| +/** | |
| + * Setup a cache table be identified by cacheKey. | |
| + * | |
| + * [0, 0, -] | |
| + */ | |
| + static void | |
| +luaV_open_cachetable(lua_State *L, void *cacheKey) | |
| +{ | |
| + lua_pushlightuserdata(L, cacheKey); | |
| + lua_newtable(L); | |
| + lua_rawset(L, LUA_REGISTRYINDEX); | |
| +} | |
| + | |
| +/** | |
| + * Dispose a cache table be identified by cacheKey. | |
| + * | |
| + * [0, 0, -] | |
| + */ | |
| + static void | |
| +luaV_close_cachetable(lua_State *L, void *cacheKey) | |
| +{ | |
| + lua_pushlightuserdata(L, cacheKey); | |
| + lua_pushnil(L); | |
| + lua_rawset(L, LUA_REGISTRYINDEX); | |
| +} | |
| + | |
| +/** | |
| + * Push a lua object associated with a pointer in the cachetable which | |
| + * associated with cacheKey to the stack, and return 1. If no objects | |
| + * associated, nil is pushed to the stack, and return 0. | |
| + * | |
| + * [+1, 0, -] | |
| + */ | |
| + static int | |
| +luaV_get_cachetable(lua_State *L, void *cacheKey, void *rawptr) | |
| +{ | |
| + lua_pushlightuserdata(L, cacheKey); | |
| + lua_rawget(L, LUA_REGISTRYINDEX); | |
| + if (!lua_istable(L, -1)) | |
| + { | |
| + /* | |
| + * FIXME: This will causes if luaV_open_cachetable() isn't called. It | |
| + * may be failed by assertion or so. | |
| + */ | |
| + lua_pop(L, 1); /* {not table} */ | |
| + lua_pushnil(L); | |
| + return 0; | |
| + } | |
| + else | |
| + { | |
| + lua_pushlightuserdata(L, rawptr); | |
| + lua_rawget(L, -2); | |
| + lua_insert(L, -2); /* (table, object) -> (object, table) */ | |
| + lua_pop(L, 1); /* table */ | |
| + return lua_isnil(L, -1) ? 0 : 1; | |
| + } | |
| +} | |
| + | |
| +/** | |
| + * [0, 0, -] | |
| + */ | |
| + static void | |
| +luaV_set_cachetable(lua_State *L, void *cacheKey, void *rawptr, int idx) | |
| +{ | |
| + lua_pushvalue(L, idx); | |
| + | |
| + /* Push a cacheable for cacheKey. */ | |
| + lua_pushlightuserdata(L, cacheKey); | |
| + lua_rawget(L, LUA_REGISTRYINDEX); | |
| + if (!lua_istable(L, -1)) | |
| + { | |
| + lua_pop(L, 2); /* idx, {not table} */ | |
| + } | |
| + else | |
| + { | |
| + lua_pushlightuserdata(L, rawptr); | |
| + lua_pushvalue(L, -3); | |
| + lua_rawset(L, -3); | |
| + lua_pop(L, 2); /* idx, table */ | |
| + } | |
| +} | |
| + | |
| static void | |
| luaV_newmetatable(lua_State *L, const char *tname) | |
| { | |
| @@ -335,7 +475,7 @@ | |
| } | |
| static void | |
| -luaV_pushtypval(lua_State *L, typval_T *tv) | |
| +luaV_pushtypval2(lua_State *L, void *cacheKey, typval_T *tv) | |
| { | |
| if (tv == NULL) luaL_error(L, "null type"); | |
| switch (tv->v_type) | |
| @@ -357,20 +497,17 @@ | |
| if (l != NULL) | |
| { | |
| /* check cache */ | |
| - lua_pushlightuserdata(L, (void *) l); | |
| - lua_rawget(L, LUA_ENVIRONINDEX); | |
| - if (lua_isnil(L, -1)) /* not interned? */ | |
| - { | |
| + if (!luaV_get_cachetable(L, cacheKey, (void *)l)) | |
| + { | |
| + /* Push a new table (array) to the stack. */ | |
| listitem_T *li; | |
| int n = 0; | |
| lua_pop(L, 1); /* nil */ | |
| lua_newtable(L); | |
| - lua_pushlightuserdata(L, (void *) l); | |
| - lua_pushvalue(L, -2); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); | |
| + luaV_set_cachetable(L, cacheKey, (void *)l, -1); | |
| for (li = l->lv_first; li != NULL; li = li->li_next) | |
| { | |
| - luaV_pushtypval(L, &li->li_tv); | |
| + luaV_pushtypval2(L, cacheKey, &li->li_tv); | |
| lua_rawseti(L, -2, ++n); | |
| } | |
| } | |
| @@ -384,24 +521,21 @@ | |
| if (d != NULL) | |
| { | |
| /* check cache */ | |
| - lua_pushlightuserdata(L, (void *) d); | |
| - lua_rawget(L, LUA_ENVIRONINDEX); | |
| - if (lua_isnil(L, -1)) /* not interned? */ | |
| - { | |
| + if (!luaV_get_cachetable(L, cacheKey, (void *)d)) | |
| + { | |
| + /* Push a new table (dict) to the stack. */ | |
| hashtab_T *ht = &d->dv_hashtab; | |
| hashitem_T *hi; | |
| int n = ht->ht_used; /* remaining items */ | |
| lua_pop(L, 1); /* nil */ | |
| lua_newtable(L); | |
| - lua_pushlightuserdata(L, (void *) d); | |
| - lua_pushvalue(L, -2); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); | |
| + luaV_set_cachetable(L, cacheKey, (void *)d, -1); | |
| for (hi = ht->ht_array; n > 0; hi++) | |
| { | |
| if (!HASHITEM_EMPTY(hi)) | |
| { | |
| dictitem_T *di = dict_lookup(hi); | |
| - luaV_pushtypval(L, &di->di_tv); | |
| + luaV_pushtypval2(L, cacheKey, &di->di_tv); | |
| lua_setfield(L, -2, (char *) hi->hi_key); | |
| n--; | |
| } | |
| @@ -416,6 +550,19 @@ | |
| } | |
| } | |
| +/** | |
| + * [+1, 0, -] | |
| + */ | |
| + static void | |
| +luaV_pushtypval(lua_State *L, typval_T *tv) | |
| +{ | |
| + void *cacheKey = (void *)tv; | |
| + | |
| + luaV_open_cachetable(L, cacheKey); | |
| + luaV_pushtypval2(L, cacheKey, tv); | |
| + luaV_close_cachetable(L, cacheKey); | |
| +} | |
| + | |
| /* similar to luaL_addlstring, but replaces \0 with \n if toline and | |
| * \n with \0 otherwise */ | |
| static void | |
| @@ -489,13 +636,9 @@ | |
| { | |
| luaV_Buffer *b = (luaV_Buffer *) lua_newuserdata(L, sizeof(luaV_Buffer)); | |
| *b = buf; | |
| - lua_pushlightuserdata(L, (void *) buf); | |
| - lua_pushvalue(L, -2); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); /* env[buf] = udata */ | |
| - /* to avoid GC, store as key in env */ | |
| - lua_pushvalue(L, -1); | |
| - lua_pushboolean(L, 1); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */ | |
| + | |
| + luaV_set_associated_luavalue(L, (void *)buf, -1); | |
| + | |
| /* set metatable */ | |
| luaV_getfield(L, LUAVIM_BUFFER); | |
| lua_setmetatable(L, -2); | |
| @@ -508,12 +651,11 @@ | |
| luaV_Buffer *b = NULL; | |
| if (buf == NULL) | |
| lua_pushnil(L); | |
| - else { | |
| - lua_pushlightuserdata(L, (void *) buf); | |
| - lua_rawget(L, LUA_ENVIRONINDEX); | |
| - if (lua_isnil(L, -1)) /* not interned? */ | |
| - { | |
| - lua_pop(L, 1); | |
| + else | |
| + { | |
| + if (!luaV_get_associated_luavalue(L, (void *)buf)) | |
| + { | |
| + lua_pop(L, 1); /* nil */ | |
| b = luaV_newbuffer(L, buf); | |
| } | |
| else | |
| @@ -553,6 +695,14 @@ | |
| { | |
| luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1); | |
| linenr_T n = (linenr_T) lua_tointeger(L, 2); | |
| + | |
| + /* Check validity of a buffer. */ | |
| + if (!luaV_is_associated_luavalue(L, (void *)(*b))) | |
| + { | |
| + lua_pushnil(L); | |
| + return 1; | |
| + } | |
| + | |
| if (n > 0 && n <= (*b)->b_ml.ml_line_count) | |
| luaV_pushline(L, *b, n); | |
| else if (lua_isstring(L, 2)) | |
| @@ -702,9 +852,8 @@ | |
| luaV_buffer_isvalid(lua_State *L) | |
| { | |
| luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER); | |
| - lua_pushlightuserdata(L, (void *) (*b)); | |
| - lua_rawget(L, LUA_ENVIRONINDEX); | |
| - lua_pushboolean(L, !lua_isnil(L, -1)); | |
| + lua_pushboolean(L, | |
| + luaV_get_associated_luavalue(L, (void *)(*b))); | |
| return 1; | |
| } | |
| @@ -729,13 +878,9 @@ | |
| { | |
| luaV_Window *w = (luaV_Window *) lua_newuserdata(L, sizeof(luaV_Window)); | |
| *w = win; | |
| - lua_pushlightuserdata(L, (void *) win); | |
| - lua_pushvalue(L, -2); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); /* env[win] = udata */ | |
| - /* to avoid GC, store as key in env */ | |
| - lua_pushvalue(L, -1); | |
| - lua_pushboolean(L, 1); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */ | |
| + | |
| + luaV_set_associated_luavalue(L, (void *)win, -1); | |
| + | |
| /* set metatable */ | |
| luaV_getfield(L, LUAVIM_WINDOW); | |
| lua_setmetatable(L, -2); | |
| @@ -748,15 +893,15 @@ | |
| luaV_Window *w = NULL; | |
| if (win == NULL) | |
| lua_pushnil(L); | |
| - else { | |
| - lua_pushlightuserdata(L, (void *) win); | |
| - lua_rawget(L, LUA_ENVIRONINDEX); | |
| - if (lua_isnil(L, -1)) /* not interned? */ | |
| - { | |
| - lua_pop(L, 1); | |
| + else | |
| + { | |
| + if (!luaV_get_associated_luavalue(L, (void *)win)) | |
| + { | |
| + lua_pop(L, 1); /* nil */ | |
| w = luaV_newwindow(L, win); | |
| } | |
| - else w = (luaV_Window *) lua_touserdata(L, -1); | |
| + else | |
| + w = (luaV_Window *) lua_touserdata(L, -1); | |
| } | |
| return w; | |
| } | |
| @@ -784,6 +929,14 @@ | |
| { | |
| luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1); | |
| const char *s = luaL_checkstring(L, 2); | |
| + | |
| + /* Check validity of a window. */ | |
| + if (!luaV_is_associated_luavalue(L, (void *)(*w))) | |
| + { | |
| + lua_pushnil(L); | |
| + return 1; | |
| + } | |
| + | |
| if (strncmp(s, "buffer", 6) == 0) | |
| luaV_pushbuffer(L, (*w)->w_buffer); | |
| else if (strncmp(s, "line", 4) == 0) | |
| @@ -880,9 +1033,8 @@ | |
| luaV_window_isvalid(lua_State *L) | |
| { | |
| luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW); | |
| - lua_pushlightuserdata(L, (void *) (*w)); | |
| - lua_rawget(L, LUA_ENVIRONINDEX); | |
| - lua_pushboolean(L, !lua_isnil(L, -1)); | |
| + lua_pushboolean(L, | |
| + luaV_get_associated_luavalue(L, (void *)(*w))); | |
| return 1; | |
| } | |
| @@ -1071,15 +1223,7 @@ | |
| static int | |
| luaV_free(lua_State *L) | |
| { | |
| - lua_pushvalue(L, 1); /* lightudata */ | |
| - lua_rawget(L, LUA_ENVIRONINDEX); | |
| - if (!lua_isnil(L, -1)) | |
| - { | |
| - lua_pushnil(L); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = nil */ | |
| - lua_pushnil(L); | |
| - lua_rawset(L, LUA_ENVIRONINDEX); /* env[lightudata] = nil */ | |
| - } | |
| + luaV_reset_associated_luavalue(L, lua_touserdata(L, 1)); | |
| return 0; | |
| } | |
| @@ -1099,13 +1243,6 @@ | |
| static int | |
| luaopen_vim(lua_State *L) | |
| { | |
| - /* set environment */ | |
| - lua_newtable(L); | |
| - lua_newtable(L); | |
| - lua_pushliteral(L, "v"); | |
| - lua_setfield(L, -2, "__mode"); | |
| - lua_setmetatable(L, -2); | |
| - lua_replace(L, LUA_ENVIRONINDEX); | |
| /* print */ | |
| lua_pushcfunction(L, luaV_print); | |
| lua_setglobal(L, "print"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment