lua5.2模块注册

lua 5.2不鼓励使用luaL_register把模块注册到全局域,而是使用luaL_newlib。
我们首先看下luaL_newlib,它是一个宏,代码如下:

#define luaL_newlib(L,l)    (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

luaL_newlibtable创建一个表放到栈顶,然后luaL_setfuncs把列表参数l中的函数名作为key,函数地址用来创建的闭包作为value插入到新建的table中,代码如下:

LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
    for (; l->name != NULL; l++) {  /* fill the table with given functions */
        int i;
        for (i = 0; i < nup; i++)  /* copy upvalues to the top */
            lua_pushvalue(L, -nup);
        lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
        lua_setfield(L, -(nup + 2), l->name);
    }
    lua_pop(L, nup);  /* remove upvalues */
}

luaL_setfuncs 函数在压入C闭包之前,把位于栈顶的nup个upvalue(外层函数局部变量)重新压栈,在创建C闭包的时候,存到C闭包的upvalue链表中。lua模块注册的时候,nup是0,故不用考虑upvalue入栈。C闭包入栈函数如下:

LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
  lua_lock(L);
  if (n == 0) {
    setfvalue(L->top, fn);
  }
  else {
    Closure *cl;
    api_checknelems(L, n);
    api_check(L, n <= MAXUPVAL, "upvalue index too large");
    luaC_checkGC(L);
    cl = luaF_newCclosure(L, n);
    cl->c.f = fn;
    L->top -= n;
    while (n--)
      setobj2n(L, &cl->c.upvalue[n], L->top + n);
    setclCvalue(L, L->top, cl);
  }
  api_incr_top(L);
  lua_unlock(L);
}

如果没有upvalue,此时压入的是light C function,否则压入的是C closure。回到luaL_setfuncs函数,压栈闭包后,设置函数名和闭包(或者light C function)的键值对,最后删除栈顶的upvalue。

此时,模块注册完毕。

阅读更多

没有更多推荐了,返回首页