Skip to content

Instantly share code, notes, and snippets.

@koron
Created January 8, 2012 09:27
Show Gist options
  • Save koron/1577830 to your computer and use it in GitHub Desktop.
Save koron/1577830 to your computer and use it in GitHub Desktop.
Fix confused references related with an environment table
# 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