lua和C++交互的lua栈操作——以LuaTinker为例
一、
-- C++类注册函数(LuaTinker) 的lua栈操作:
-- lua栈内容(执行到pop语句) 栈地址 <--执行语句 space_name[name] = t1 -- (2b8) -- lua_rawset(L, -4); -- t1[__gc] = destroyer<T> -- (2d8) -- lua_rawset(L, -3); -- destroyer<T> -- (2f8) -- lua_pushcclosure(L, destroyer<T>, 0); -- __gc -- (2e8) -- lua_pushstring(L, "__gc"); -- t1[__newindex] = meta_set -- (2d8) -- lua_rawset(L, -3); -- meta_set -- (2f8) -- lua_pushcclosure(L, meta_set, 0); -- __newindex -- (2e8) -- lua_pushstring(L, "__newindex"); -- t1[__index] = meta_get -- (2d8) -- lua_rawset(L, -3); -- meta_get -- (2f8) -- lua_pushcclosure(L, meta_get, 0); -- __index -- (2e8) -- lua_pushstring(L, "__index"); -- t1[__name] = name -- (2d8) -- lua_rawset(L, -3); -- name -- (2f8) -- lua_pushstring(L, name); -- __name -- (2e8) -- lua_pushstring(L, "__name"); -- setmetatable(t1, t2) -- (2d8) -- lua_setmetatable(L, -2); -- t2[__index] = static_meta_get -- (2e8) -- lua_rawset(L, -3); -- static_meta_get -- (308) -- lua_pushcclosure(L, static_meta_get, 0); -- __index -- (2f8) -- lua_pushstring(L, "__index"); -- t2 -- (2e8) -- lua_newtable(L); -- t1 -- (2d8) -- lua_newtable(L); -- name -- (2c8) -- lua_pushstring(L, name); -- space_name[name] -- (2b8) -- lua_rawget(L, -2); -- name -- (2b8) -- lua_pushstring(L, name); space_name -- (2a8) -- push_meta(L, space_name::name); L -- (298) -- 初始状态
-- C++类注册函数(LuaTinker),支持注册到命名空间namespace
template<typename T> void class_addEx(lua_State* L, const char* name) { push_meta(L, space_name::name()); if(lua_istable(L, -1)) { class_name<T>::name(name); lua_pushstring(L, name); lua_rawget(L, -2); if (!lua_istable(L, -1)) { lua_pushstring(L, name); lua_newtable(L); lua_newtable(L); lua_pushstring(L, "__index"); lua_pushcclosure(L, static_meta_get, 0); lua_rawset(L, -3); lua_setmetatable(L, -2); lua_pushstring(L, "__name"); lua_pushstring(L, name); lua_rawset(L, -3); lua_pushstring(L, "__index"); lua_pushcclosure(L, meta_get, 0); lua_rawset(L, -3); lua_pushstring(L, "__newindex"); lua_pushcclosure(L, meta_set, 0); lua_rawset(L, -3); lua_pushstring(L, "__gc"); lua_pushcclosure(L, destroyer<T>, 0); lua_rawset(L, -3); lua_rawset(L, -4); } } lua_pop(L, 2); }
二、
-- meta_get栈操作如下: -- lua栈内容 栈地址 <--执行语句 t_meta[__index] -- (ed8) -- lua_rawget(L,-2); <-- 执行到此语句 -- __index -- (ed8) -- lua_pushvalue(L,2); t_meta -- (ec8) -- lua_getmetatable(L,1); __index -- (eb8) -- 初始 lua_pushstring(L, "__index"); t -- (ea8) -- 初始 L -- (e98) -- 初始状态
--// int lua_tinker::meta_get(lua_State *L) int lua_tinker::meta_get(lua_State *L) { lua_getmetatable(L,1); lua_pushvalue(L,2); lua_rawget(L,-2); bool is_dispatcher = false; const char* func_name = lua_tostring(L, 2); if(lua_isuserdata(L,-1)) { user2type<var_base*>::invoke(L,-1)->get(L); lua_remove(L, -2); } else if (lua_istable(L, -1)) { lua_remove(L, -1); is_dispatcher = true; } else if (lua_isnil(L, -1)) { lua_remove(L, -1); invoke_parent(L, func_name); if (lua_isnil(L, -1)) { lua_remove(L, -1); invoke_child(L, func_name); } if (lua_istable(L, -1)) { lua_remove(L, -1); is_dispatcher = true; } } //函数分发 if (is_dispatcher) { push_currfuncname(L, func_name); push_dispatcher(L); } lua_remove(L,-2); return 1; }
三、
--> 假设:meta_get函数执行到上面语句(栈内容如上) ——> t_meta[__index] == nil ——> 进入invoke_parent(L, func_name);
-- lua栈内容 栈地址 <--执行语句 tt[funcname] -- (e18) -- lua_remove(L, -2); -- tt[funcname] -- (e28) -- lua_rawget(L, -2); -->lua_istable(L, -1) || lua_isfunction(L, -1) -- funcname -- (e28) -- lua_pushstring(L, funcname); -- t_meta[__parent] = tt -- (e18) -- lua_rawget(L, -2); --> lua_istable(L,-1),重命名为tt -- __parent -- (e18) -- lua_pushstring(L, "__parent"); -- -- (e08) -- lua_remove(L, -1); -- t_meta[__index] -- (e18) -- lua_rawget(L,-2); t_meta -- (d08) -- lua_getmetatable(L,1); __index -- (cf8) -- 初始 lua_pushstring(L, "__index"); t -- (ce8) -- 初始 L -- (cd8) -- 初始状态(和上面的栈内容不匹配,因为是另一个过程,其满足t_meta[__index] == nil)
// static void invoke_parent(lua_State *L, const char* funcname) static void invoke_parent(lua_State *L, const char* funcname) { lua_pushstring(L, "__parent"); lua_rawget(L, -2); if(lua_istable(L,-1)) { lua_pushstring(L, funcname); lua_rawget(L, -2); if (lua_istable(L, -1) || lua_isfunction(L, -1)) { lua_remove(L, -2); } else { lua_remove(L, -1); invoke_parent(L, funcname); lua_remove(L, -2); } } }