|
staticint tolua_bnd_setpeer(lua_State *L) { // stack: userdata, tableif (!lua_isuserdata(L, -2)) { return luaL_error(L, "Invalid argument #1 to setpeer: userdata expected."); } if (lua_isnil(L, 2)) { lua_pop(L, 1); lua_pushvalue(L, TOLUA_NOPEER); lua_setfenv(L, -2); } else { lua_pushvalue(L, 2); //stack: u p p lua_setfenv(L, -3); //stack: u p lua_newtable(L); //stack: u p vt lua_pushlightuserdata(L, &vptr); //stack: u p vt lu lua_pushvalue(L, 1); //stack: u p vt lu u lua_rawset(L, -3); //stack: u p vt @vt[lu] = u //lua_pushvalue(L, 1); //lua_rawseti(L, -2, 1); lua_getref(L, LUA_RIDX_VPTR); //stack: u p vt mt lua_setmetatable(L, -2); //stack: u p vt lua_pushstring(L, "base"); //stack: u p vt "base" lua_pushvalue(L, -2); //stack: u p vt "base" vt lua_rawset(L, 2); //stack: u p vt lua_pop(L, 1); } return0;};
把C#对象在lua中对应的userdata(csobj)和一个lua table(peer)进行setpeer操作后:tolua.setpeer(csobj, peer)
1.把peer表设置为csobj的环境表,peer.base[&vptr] = csobj, setmetatable(peer.base, vptrtable)
2.在csobj访问一个元素,csobj[key],会进行以下步骤:
(1)在peer表直接查找,rawget(peer, key),如果不为nil, 则返回这个值。如果为nil,则进行第(2)不查找
如果userdata(u)和peer(p)表都不为空的话,会执行如下步骤:
1.lua_pushvalue(L, 2); 把peer表复制压进栈顶 此时虚拟栈:stack: u, p, p
2.lua_setfenv(L, -3); -3是u的位置,相当于把栈顶元素peer设置为u的环境表 此时虚拟栈:stack: u, p
3.lua_newtable(L); 创建一个空的table,压进栈顶 此时虚拟栈:stack: u, p,vt
4.lua_pushlightuserdata(L, &vptr); 把一个轻量级的userdata压进栈顶,vptr是一个值为1的static int类型 此时虚拟栈:stack: u, p,vt, lu
5.lua_pushvalue(L, 1); 把栈底元素u复制压进栈顶 此时虚拟栈:stack: u, p,vt, lu, u
6.lua_rawset(L, -3); 执行vt[lu] = u, 直接赋值,忽略元表 此时虚拟栈:stack: u, p,vt
7.lua_getref(L, LUA_RIDX_VPTR); 通过ref获取对应的一个table,压进栈顶 此时虚拟栈:stack: u, p,vt, mt
8.lua_setmetatable(L, -2); setmetatable(p, mt) 此时虚拟栈:stack: u, p,vt
9.lua_pushstring(L, "base"); 把"base"字符串压进栈顶 此时虚拟栈:stack: u, p,vt,"base"
10.lua_pushvalue(L, -2); 把vt表压进栈顶 此时虚拟栈:stack: u, p,vt,"base",vt
11.lua_rawset(L, 2); p.base = vt 此时虚拟栈:stack: u, p,vt
12.lua_pop(L, 1); 把vt弹出栈顶 此时虚拟栈:stack: u, p
转载于:https://www.cnblogs.com/xsxjin/p/6854584.html |
|