int HybridBase::class__index(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_CLEAN_STACK(L,+1); SLB_DEBUG_STACK(6, L, "Call class__index"); // trying to traverse the class... create a new InternalHybridSubclass ClassInfo *ci = Manager::getInstance().getClass(L,1); if (ci == 0) luaL_error(L, "Expected a valid class."); luaL_checkstring(L,2); // only valid with strings if (!ci->hasConstructor()) { luaL_error(L, "Hybrid Class(%s) doesn't have constructor." " You can not subclass(%s) from it", ci->getName().c_str(), lua_tostring(L,2)); } ref_ptr<InternalHybridSubclass> subc = new InternalHybridSubclass(ci); subc->push(L); // -- set cache... lua_pushvalue(L,2); // [+1] key lua_pushvalue(L,-2); // [+1] copy of new InternalHybrid... ci->setCache(L); // [-2] keep a copy in the cache // -- set cache done return 1; }
int Table::__eq(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_STACK(10,L,"Table::__eq (%p)",this); luaL_error(L, "__eq metamethod called but no implementation was given"); return 0; }
int Table::__garbageCollector(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_STACK(10,L,"Table::__GC (%p)",this); luaL_error(L, "(%p) __gc metamethod not implemented", (void*)this); return 0; }
int Table::__call(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_STACK(10,L,"Table::__call (%p)",this); luaL_error(L, "(%p)__call metamethod not implemented", (void*)this); return 0; }
bool HybridBase::getMethod(const char *name) const { SLB_DEBUG_CALL; if (_L == 0) throw std::runtime_error("Hybrid instance not attached");\ SLB_DEBUG_STACK(5,_L, "HybridBase(%p)::getMethod '%s' (_L = %p)", this, name, _L); int top = lua_gettop(_L); // first try to find in _subclassMethods if (_subclassMethods.valid()) { //TODO: NEED DEBUG... // ---- why not: // Object *m = obj->_subclassMethods->get(key); // if (m) // { // SLB_DEBUG(5, "Hybrid subclassed instance, looking for '%s' method [OK]", key); // m->push(L); // return 1; // } // else SLB_DEBUG(5, "Hybrid subclassed instance, looking for '%s' method [FAIL!]", key); // ---- instead of: (even though this is quicker) but code above should work lua_pushstring(_L,name); // [+1] _subclassMethods->getCache(_L); // [-1, +1] will pop key's copy and return the cache if (!lua_isnil(_L,-1)) { assert("Invalid Stack" && (lua_gettop(_L) == top+1)); return true; } lua_pop(_L,1); // [-1] remove nil assert("Invalid Stack" && (lua_gettop(_L) == top)); //end TODO------------------------------------------------------------------------------- } ClassInfo *ci = getClassInfo(); ci->push(_L); lua_getmetatable(_L,-1); lua_getfield(_L,-1, "__hybrid"); if (!lua_isnil(_L,-1)) { lua_pushstring(_L,name); lua_rawget(_L,-2); if (!lua_isnil(_L,-1)) { lua_replace(_L,top+1); lua_settop(_L,top+1); SLB_DEBUG(6, "HybridBase(%p-%s)::getMethod '%s' (_L = %p) -> FOUND", this, ci->getName().c_str(),name, _L); assert("Invalid Stack" && (lua_gettop(_L) == top+1)); return true; } else SLB_DEBUG(6, "HybridBase(%p-%s)::getMethod '%s' (_L = %p) -> *NOT* FOUND", this,ci->getName().c_str(), name, _L); } else SLB_DEBUG(4, "HybridBase(%p-%s) do not have any hybrid methods", this, ci->getName().c_str()); // anyway... if not found: lua_settop(_L,top); return false; }
void Table::getCache(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_CLEAN_STACK(L,0); SLB_DEBUG_STACK(8, L, "Table(%p) :: getCache BEGIN ", this); int top = lua_gettop(L); if (top < 1 ) luaL_error(L, "Not enough elements to perform Table::getCache"); push(L); // [+1] push ::Table if (!luaL_getmetafield(L,-1, "__indexCache")) // [+1] { luaL_error(L, "Invalid setCache; %s:%d", __FILE__, __LINE__ ); } lua_pushvalue(L, top); // [+1] copy value lua_rawget(L, -2); // [-2] SLB_DEBUG_STACK(8, L, "Table(%p) :: getCache END (result is at top) top was = %d", this, top); lua_replace(L, top); // [-1,+1] as result lua_settop(L, top); }
void Table::setCache(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_CLEAN_STACK(L,-2); SLB_DEBUG_STACK(8, L, "Table(%p) :: setCache BEGIN ", this); int top = lua_gettop(L); if (top < 2 ) luaL_error(L, "Not enough elements to perform Table::setCache"); push(L); // push ::Table if (luaL_getmetafield(L,-1, "__indexCache")) { lua_insert(L, top - 1); // move the metatable above key,value lua_settop(L, top + 1); // remove everything else lua_rawset(L,-3); } else { luaL_error(L, "Invalid setCache; %s:%d", __FILE__, __LINE__ ); } SLB_DEBUG_STACK(8, L, "Table(%p) :: setCache END original top = %d", this, top); lua_settop(L, top - 2); }
int Table::__meta(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_STACK(10,L,"Table::__meta (static method)"); // upvalue(1) is the cache table... void *table_raw = lua_touserdata(L, lua_upvalueindex(2)); void *table_member_raw = lua_touserdata(L, lua_upvalueindex(3)); Table *table = reinterpret_cast<Table*>(table_raw); TableMember member = *reinterpret_cast<TableMember*>(table_member_raw); return (table->*member)(L); }
int Table::__tostring(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_STACK(10,L,"Table::__tostring (%p)",this); int top = lua_gettop(L); lua_pushfstring(L, "Table(%p) [%s] with keys:", this, typeInfo().name()); for(Elements::iterator i = _elements.begin(); i != _elements.end(); ++i) { lua_pushfstring(L, "\n\t%s -> %p [%s]",i->first.c_str(), i->second.get(), i->second->typeInfo().name()); } lua_concat(L, lua_gettop(L) - top); return 1; }
int HybridBase::call_lua_method(lua_State *L) { SLB_DEBUG_CALL; const HybridBase *hb = get_hybrid( L, 1 ); if (hb->_L == 0) luaL_error(L, "Instance(%p) not attached to any lua_State...", hb); if (hb->_L != L) luaL_error(L, "This instance(%p) is attached to another lua_State(%p)", hb, hb->_L); // get the real function to call lua_pushvalue(L, lua_upvalueindex(1)); // get the environment (from object) and set it lua_rawgeti(L, LUA_REGISTRYINDEX, hb->_global_environment); lua_setfenv(L,-2); lua_insert(L,1); //put the target function at 1 SLB_DEBUG_STACK(10, L, "Hybrid(%p)::call_lua_method ...", hb); lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); return lua_gettop(L); }
int __newindex(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_CLEAN_STACK(L,-2); SLB_DEBUG_STACK(6,L, "Call InternalHybridSubclass(%p)::__nexindex", this); //1 = table //2 = string //3 = function luaL_checkstring(L,2); if (lua_type(L,3) != LUA_TFUNCTION) { luaL_error(L, "Only functions can be added to hybrid classes" " (invalid %s of type %s)", lua_tostring(L,2), lua_typename(L, 3)); } SLB_DEBUG(4, "Added method to an hybrid-subclass:%s", lua_tostring(L,2)); lua_pushcclosure(L, HybridBase::call_lua_method, 1); // replaces setCache(L); return 0; }
int Table::__indexProxy(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG(9, "---> __index search"); SLB_DEBUG_STACK(10,L,"Table::__indexProxy (%p)",this); int result = __index(L); if (result < 0) { SLB_DEBUG(9, "Nothing found...."); /* TODO Change the result behaviour, resturn 0 when nothing is found * and quit using result = -1 */ lua_pushnil(L); result = 1; } SLB_DEBUG(9, "<--- __index result = %d", result); assert(result == 1 && "Result must be 1 when it gets here"); return result; }
int __call(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_STACK(6,L, "Call InternalHybridSubclass(%p)::__call", this); // create new instance: ref_ptr<FuncCall> fc = _CI->getConstructor(); assert("Invalid Constructor!" && fc.valid()); fc->push(L); lua_replace(L,1); // table of metamethod __call lua_call(L, lua_gettop(L) -1 , LUA_MULTRET); { SLB_DEBUG_CLEAN_STACK(L,0); // at 1 we should have an HybridBase instance... HybridBase *obj = SLB::get<HybridBase*>(L,1); if (obj == 0) luaL_error(L, "Output(1) of constructor should be an HybridBase instance"); // now our table... to find methods obj->_subclassMethods = this; } return lua_gettop(L); }
int Table::__index(lua_State *L) { SLB_DEBUG_CALL; SLB_DEBUG_STACK(10,L,"Table::__index (%p)",this); int result = -1; { // Always tries to look in the cache first lua_pushvalue(L,2); lua_rawget(L, cacheTableIndex()); if (lua_isnil(L,-1)) lua_pop(L,1); // remove nil else { SLB_DEBUG(10, "Access Table(%p) (In CACHE)", this); result = 1; // we found it } } if (result < 0) { if (lua_type(L, 2) == LUA_TSTRING) { Object *obj = get(lua_tostring(L,2)); if (obj) { result = 1; obj->push(L); if (_cacheable) { // store in the cache... SLB_DEBUG(10, "L(%p) table(%p) key %s (->to cache)", L, this, lua_tostring(L,2)); lua_pushvalue(L,2); // key lua_pushvalue(L,-2); // returned value lua_rawset(L, cacheTableIndex() ); // table } } } } return result; }