⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 class_rep_scope.hpp

📁 魔兽世界的私服源程序
💻 HPP
📖 第 1 页 / 共 3 页
字号:
					std::string msg = "call of overloaded constructor '";
					msg += base->m_name;
					msg +=  "(";
					msg += stack_content_by_name(L, 2);
					msg += ")' is ambiguous";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

			// TODO: should this be a warning or something?
/*
			// since the derived class is a lua class
			// it may have reimplemented virtual functions
			// therefore, we have to instantiate the Basewrapper
			// if there is no basewrapper, throw a run-time error
			if (!rep->overloads[match_index].has_wrapped_construct())
			{
				{
					std::string msg = "Cannot derive from C++ class '";
					msg += base->name();
					msg += "'. It does not have a wrapped type";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}
*/
#endif

#ifndef LUABIND_NO_EXCEPTIONS

			try
			{

#endif

				if (!rep->overloads[match_index].has_wrapped_construct())
				{
					// if the type doesn't have a wrapped type, use the ordinary constructor
					obj->set_object(rep->overloads[match_index].construct(L));
				}
				else
				{
					// get reference to lua object
					lua_pushvalue(L, lua_upvalueindex(2));
					int ref = detail::ref(L);
					obj->set_object(rep->overloads[match_index].construct_wrapped(L, ref));
				}
				// TODO: is the wrapped type destructed correctly?
				// it should, since the destructor is either the wrapped type's
				// destructor or the base type's destructor, depending on wether
				// the type has a wrapped type or not.
				obj->set_destructor(base->destructor());
				return 0;

#ifndef LUABIND_NO_EXCEPTIONS

			}
			catch(const std::exception& e)
			{
				lua_pushstring(L, e.what());
			}
			catch(const char* s)
			{
				lua_pushstring(L, s);
			}
			catch(...)
			{
				std::string msg = base->m_name;
				msg += "() threw an exception";
				lua_pushstring(L, msg.c_str());
			}
			// can only be reached if an exception was thrown
			lua_error(L);
#endif
		}

		return 0;

	}

	static int lua_settable_dispatcher(lua_State* L)
	{
		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
		detail::getref(L, crep->m_table_ref);
		lua_replace(L, 1);
		lua_rawset(L, -3);
		return 0;
	}

	static int construct_lua_class_callback(lua_State* L)
	{
		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));

		int args = lua_gettop(L);

		// lua stack: crep <arguments>

		lua_newtable(L);
		int ref = detail::ref(L);

		bool has_bases = !crep->bases().empty();
		
		if (has_bases)
		{
			lua_pushstring(L, "super");
			lua_pushvalue(L, 1); // crep
		}

		// lua stack: crep <arguments> "super" crep
		// or
		// lua stack: crep <arguments>


		// if we have a baseclass we set the flag to say that the super has not yet been called
		// we will use this flag later to check that it actually was called from __init()
		int flags = object_rep::lua_class | object_rep::owner | (has_bases ? object_rep::call_super : 0);

		void* obj_ptr = lua_newuserdata(L, sizeof(object_rep));
		new(obj_ptr) object_rep(crep, flags, ref);

		detail::getref(L, crep->metatable_ref());
		lua_setmetatable(L, -2);

		// lua stack: crep <arguments> "super" crep obj_ptr
		// or
		// lua stack: crep <arguments> obj_ptr

		if (has_bases)	lua_pushvalue(L, -1); // obj_ptr
		lua_replace(L, 1); // obj_ptr

		// lua stack: obj_ptr <arguments> "super" crep obj_ptr
		// or
		// lua stack: obj_ptr <arguments>

		if (has_bases)
		{
			lua_pushcclosure(L, super_callback, 2);
			// lua stack: crep <arguments> "super" function
			lua_settable(L, LUA_GLOBALSINDEX);
		}

		// lua stack: crep <arguments>

		lua_pushvalue(L, 1);
		lua_insert(L, 1);

		detail::getref(L, crep->table_ref());
		lua_pushstring(L, "__init");
		lua_gettable(L, -2);

#ifndef LUABIND_NO_ERROR_CHECKING

		// TODO: should this be a run-time error?
		// maybe the default behavior should be to just call
		// the base calss' constructor. We should register
		// the super callback funktion as __init
		if (!lua_isfunction(L, -1))
		{
			{
				std::string msg = crep->name();
				msg += ":__init is not defined";
				lua_pushstring(L, msg.c_str());
			}
			lua_error(L);
		}

#endif

		lua_insert(L, 2); // function first on stack
		lua_pop(L, 1);
		// TODO: lua_call may invoke longjump! make sure we don't have any memory leaks!
		// we don't have any stack objects here
		lua_call(L, args, 0);

#ifndef LUABIND_NO_ERROR_CHECKING

		object_rep* obj = static_cast<object_rep*>(obj_ptr);
		if (obj->flags() & object_rep::call_super)
		{
			lua_pushstring(L, "derived class must call super on base");
			lua_error(L);
		}

#endif

		return 1;
	}

	// called from the metamethod for __index
	// obj is the object pointer
	static int lua_class_gettable(lua_State* L)
	{
		object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
		class_rep* crep = obj->crep();

#ifndef LUABIND_NO_ERROR_CHECKING

		if (obj->flags() & object_rep::call_super)
		{
			lua_pushstring(L, "derived class must call super on base");
			lua_error(L);
		}

#endif

		detail::getref(L, obj->lua_table_ref());
		lua_pushvalue(L, 2);
		lua_gettable(L, -2);

		if (!lua_isnil(L, -1)) return 1;

		lua_pop(L, 2);

		detail::getref(L, crep->table_ref());
		lua_pushvalue(L, 2);
		lua_gettable(L, -2);

		if (!lua_isnil(L, -1)) return 1;

		lua_pop(L, 2);


		if (lua_isnil(L, 2))
		{
			lua_pushnil(L);
			return 1;
		}

		// we have to ignore the first argument since this may point to
		// a method that is not present in this class (but in a subclass)
		const char* key = lua_tostring(L, 2);

		std::map<const char*, method_rep, ltstr>::iterator i = crep->m_methods.find(key);
		if (i != crep->m_methods.end())
		{
			// the name is a method, return it
			lua_pushlightuserdata(L, &i->second);
			lua_pushcclosure(L, class_rep::function_dispatcher, 1);
			return 1;
		}

		std::map<const char*, class_rep::callback, ltstr>::iterator j = crep->m_getters.find(key);
		if (j != crep->m_getters.end())
		{
			// the name is a data member
			return j->second.func(L, j->second.pointer_offset);
		}

		lua_pushnil(L);
		return 1;
	}

	// called from the metamethod for __newindex
	// obj is the object pointer
	static int lua_class_settable(lua_State* L)
	{
		object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
		class_rep* crep = obj->crep();

#ifndef LUABIND_NO_ERROR_CHECKING

		if (obj->flags() & object_rep::call_super)
		{
			// this block makes sure the std::string is destructed
			// before lua_error is called
			{
				std::string msg = "derived class '";
				msg += crep->name();
				msg += "'must call super on base";
				lua_pushstring(L, msg.c_str());
			}
			lua_error(L);
		}

#endif

		// we have to ignore the first argument since this may point to
		// a method that is not present in this class (but in a subclass)
		const char* key = lua_tostring(L, 2);
		std::map<const char*, class_rep::callback, ltstr>::iterator j = crep->m_setters.find(key);

		if (j == crep->m_setters.end())
		{
			std::map<const char*, class_rep::callback, ltstr>::iterator k = crep->m_getters.find(key);

#ifndef LUABIND_NO_ERROR_CHECKING

			if (k != crep->m_getters.end())
			{
				{
					std::string msg = "cannot set property '";
					msg += crep->name();
					msg += ".";
					msg += key;
					msg += "', because it's read only";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}

#endif

			detail::getref(L, obj->lua_table_ref());
			lua_replace(L, 1);
			lua_settable(L, 1);
		}
		else
		{
			// the name is a data member
			j->second.func(L, j->second.pointer_offset);
		}

		return 0;
	}

	static int static_class_gettable(lua_State* L)
	{
		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));

		if (crep->get_class_type() == class_rep::lua_class)
		{
			detail::getref(L, crep->m_table_ref);
			lua_pushvalue(L, 2);
			lua_gettable(L, -2);
			if (!lua_isnil(L, -1)) return 1;
			else lua_pop(L, 2);
		}

		const char* key = lua_tostring(L, 2);

		std::map<const char*, method_rep, ltstr>::iterator i = crep->m_methods.find(key);
		if (i != crep->m_methods.end())
		{
			// the name is a method, return it
			lua_pushlightuserdata(L, &i->second);
			lua_pushcclosure(L, class_rep::function_dispatcher, 1);
			return 1;
		}

#ifndef LUABIND_NO_ERROR_CHECKING

		std::map<const char*, int, ltstr>::const_iterator j = crep->m_static_constants.find(key);

		if (j != crep->m_static_constants.end())
		{
			lua_pushnumber(L, j->second);
			return 1;
		}

		{
			std::string msg = "no static '";
			msg += key;
			msg += "' in class '";
			msg += crep->name();
			msg += "'";
			lua_pushstring(L, msg.c_str());
		}
		lua_error(L);

#endif

		return 0;
	}

	private:

		// this is a pointer to the type_info structure for
		// this type
		// warning: this may be a problem when using dll:s, since
		// typeid() may actually return different pointers for the same
		// type.
		LUABIND_TYPE_INFO m_type;
		LUABIND_TYPE_INFO m_held_type;

		typedef void*(*extract_ptr_t)(void*);
		extract_ptr_t m_extract_underlying_fun;

		// a list of info for every class this class derives from
		// the information stored here is sufficient to do
		// type casts to the base classes
		std::vector<base_info> m_bases;

		// the class' name (as given when registered to lua with class_)
#ifdef LUABIND_DONT_COPY_STRINGS
		const char* m_name;
#else
		std::string m_name;
#endif

		// contains signatures for all constructors
		construct_rep m_constructor;
		construct_rep m_wrapped_constructor;

		// a reference to this structure itself. Since this struct
		// is kept inside lua (to let lua collect it when lua_close()
		// is called) we need to lock it to prevent collection.
		// the actual reference is not currently used.
		int m_self_ref;

		// a reference to the lua table that represents this class
		// (only used if it is a lua class)
		int m_table_ref;

		// the type of this class.. determines if it's written in c++ or lua
		class_type m_class_type;

		// this is a lua reference that points to the lua table
		// that is to be used as meta table for all instances
		// of this class.
		int m_instance_metatable;

		// ***** the maps below contains all members in this class *****

		// maps method names to a structure with more
		// information about that method.
		// that struct contains the function-signatures
		// for every overload
		std::map<const char*, method_rep, ltstr> m_methods;

#ifndef LUABIND_DONT_COPY_STRINGS
		// this is where the strings that the maps contains
		// pointer to are kept. To make sure they are destructed.
		std::vector<char*> m_strings;
#endif

		struct callback
		{
			boost::function2<int, lua_State*, int> func;
			int pointer_offset;
		};

		// datamembers, some members may be readonly, and
		// only have a getter function
		std::map<const char*, callback, ltstr> m_getters;
		std::map<const char*, callback, ltstr> m_setters;

		struct operator_callback: public overload_rep_base
		{
			inline void set_fun(int (*f)(lua_State*)) { func = f; }
			inline int call(lua_State* L) { return func(L); }
			inline void set_arity(int arity) { m_arity = arity; }

		private:

			int(*func)(lua_State*);
		};

		std::vector<operator_callback> m_operators[number_of_operators]; // the operators in lua

		void(*m_destructor)(void*);

		std::map<const char*, int, ltstr> m_static_constants;
	};


	inline bool is_class_rep(lua_State* L, int index)
	{
		if (lua_getmetatable(L, index) == 0) return false;

		lua_pushstring(L, "__luabind_classrep");
		lua_gettable(L, -2);
		if (lua_toboolean(L, -1))
		{
			lua_pop(L, 2);
			return true;
		}

		lua_pop(L, 2);
		return false;

	}

}}

#endif // LUABIND_CLASS_REP_HPP_INCLUDED

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -