Beispiel #1
0
	void HybridBase::setMethod(lua_State *L, ClassInfo *ci)
	{
		SLB_DEBUG_CALL;
		SLB_DEBUG_CLEAN_STACK(L,-2);
		// key
		// value [top]
		int top = lua_gettop(L);
		// checks key, value
		assert( "Invalid key for method" && lua_type(L,top-1) == LUA_TSTRING);
		assert( "Invalid type of method" && lua_type(L,top) == LUA_TFUNCTION);

		ci->push(L); // top +1
		lua_getmetatable(L,-1); // top +2
		lua_getfield(L,-1, "__hybrid"); // top +3
		// create if not exists
		if (lua_isnil(L,-1))
		{
			lua_pop(L,1); // remove nil
			lua_newtable(L); // top +3
			lua_pushstring(L, "__hybrid");
			lua_pushvalue(L,-2); // a copy for ClassInfo
			lua_rawset(L, top+2); // set to he metatable 
		}
		lua_insert(L,top-2); // put the __hybrid table below key,value
		lua_settop(L, top+1); // table, key, and value
		lua_rawset(L,top-2); // set elements
		lua_settop(L, top-2); // remove everything :)
	}
Beispiel #2
0
	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;
	}
Beispiel #3
0
	int HybridBase::class__newindex(lua_State *L)
	{
		SLB_DEBUG_CALL;
		SLB_DEBUG_CLEAN_STACK(L,-2);
		// 1 - obj (table with classInfo)
		ClassInfo *ci = Manager::getInstance().getClass(L,1);
		if (ci == 0) luaL_error(L, "Invalid Class at #1");

		// 2 - key (string)
		const int key = 2;

		// 3 - value (func)
		const int value = 3;

		if (lua_isstring(L,key) && lua_isfunction(L,value))
		{
			// create a closure with the function to call
			lua_pushcclosure(L, HybridBase::call_lua_method, 1); // replaces [value]
			setMethod(L, ci);	
		}
		else
		{
			luaL_error(L,
				"hybrid instances can only have new methods (functions) "
				"indexed by strings ( called with: class[ (%s) ] = (%s) )",
				lua_typename(L, lua_type(L,key)), lua_typename(L, lua_type(L,value))
				);
		}
		return 0;
	}
Beispiel #4
0
	int HybridBase::object__index(lua_State *L)
	{
		SLB_DEBUG_CALL;
		SLB_DEBUG_CLEAN_STACK(L,+1);
		SLB_DEBUG(4, "HybridBase::object__index");
		// 1 - obj (table with classInfo)
		HybridBase* obj = get<HybridBase*>(L,1);
		if (obj == 0) luaL_error(L, "Invalid instance at #1");
		if (!obj->_L) luaL_error(L, "Hybrid instance not attached or invalid method");
		if (obj->_L != L) luaL_error(L, "Can not use that object outside its lua_state(%p)", obj->_L);

		// 2 - key (string) (at top)
		const char *key = lua_tostring(L,2);
		// call getMethod of hybrid (basic)
		if(!obj->getMethod(key)) luaL_error(L, "Invalid method %s", key);
		assert("Invalid stored function" && (lua_type(L,-1) == LUA_TFUNCTION) );
		return 1;
	}
Beispiel #5
0
 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);
 }
Beispiel #6
0
		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;
		}
Beispiel #7
0
		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);
		}
Beispiel #8
0
 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);
 }
Beispiel #9
0
	void HybridBase::attach(lua_State *L)
	{
		SLB_DEBUG_CALL;
		//TODO allow reattaching...
		if (_L) throw std::runtime_error("Trying to reattach an Hybrid instance");

		if (L)
		{
			SLB_DEBUG_CLEAN_STACK(L,0);
			_L = L;
			lua_newtable(_L); // [+1]
			//TODO this can be improved a little bit... by storing this metatable
			//somewhere....
			lua_newtable(_L); // [+1] metatable 
			lua_pushvalue(_L, LUA_GLOBALSINDEX); // [+1] globals _G
			lua_setfield(_L, -2, "__index"); // [-1] metatable.__index = _G
			lua_setmetatable(L,-2); // [-1]
			// done

			_global_environment = luaL_ref(_L, LUA_REGISTRYINDEX); // [-1]
		}
	}