mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	ratunku... :/
tak czy siak lua/src jest wykorzystywane w include :( nie umiem zmusić mojego programu svn do współpracy, zwłaszcz z VC
This commit is contained in:
		
							
								
								
									
										421
									
								
								lua/luabind/class.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								lua/luabind/class.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,421 @@ | ||||
| // Copyright (c) 2004 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/config.hpp> | ||||
| #include <luabind/class.hpp> | ||||
|  | ||||
| #include <cstring> | ||||
| #include <iostream> | ||||
|  | ||||
| namespace luabind { namespace detail { | ||||
|      | ||||
| 	struct method_name | ||||
| 	{ | ||||
| 		method_name(char const* n): name(n) {} | ||||
| 		bool operator()(method_rep const& o) const | ||||
| 		{ return std::strcmp(o.name, name) == 0; } | ||||
| 		char const* name; | ||||
| 	}; | ||||
|  | ||||
|     struct class_registration : registration | ||||
|     {    | ||||
|         class_registration(char const* name); | ||||
|  | ||||
|         void register_(lua_State* L) const; | ||||
|  | ||||
|         const char* m_name; | ||||
|  | ||||
|         mutable std::list<detail::method_rep> m_methods; | ||||
|  | ||||
|         // datamembers, some members may be readonly, and | ||||
|         // only have a getter function | ||||
|         mutable std::map<const char*, detail::class_rep::callback, detail::ltstr> m_getters; | ||||
|         mutable std::map<const char*, detail::class_rep::callback, detail::ltstr> m_setters; | ||||
|  | ||||
|         // the operators in lua | ||||
|         mutable std::vector<detail::class_rep::operator_callback> m_operators[detail::number_of_operators];  | ||||
|         mutable std::map<const char*, int, detail::ltstr> m_static_constants; | ||||
|  | ||||
|         mutable std::vector<class_base::base_desc> m_bases; | ||||
|         mutable detail::construct_rep m_constructor; | ||||
|  | ||||
|         void(*m_destructor)(void*); | ||||
|         void(*m_const_holder_destructor)(void*); | ||||
|  | ||||
|         void*(*m_extractor)(void*); | ||||
|         const void*(*m_const_extractor)(void*); | ||||
|  | ||||
|         void(*m_const_converter)(void*,void*); | ||||
|  | ||||
|         void(*m_construct_holder)(void*, void*); | ||||
|         void(*m_construct_const_holder)(void*, void*); | ||||
|  | ||||
|         void(*m_default_construct_holder)(void*); | ||||
|         void(*m_default_construct_const_holder)(void*); | ||||
|  | ||||
| 		void(*m_adopt_fun)(void*); | ||||
|  | ||||
|         int m_holder_size; | ||||
|         int m_holder_alignment; | ||||
|  | ||||
|         LUABIND_TYPE_INFO m_type; | ||||
|         LUABIND_TYPE_INFO m_holder_type; | ||||
|         LUABIND_TYPE_INFO m_const_holder_type; | ||||
|  | ||||
|         scope m_scope; | ||||
|     }; | ||||
|  | ||||
|     class_registration::class_registration(char const* name) | ||||
|     { | ||||
|         m_name = name; | ||||
|     } | ||||
|  | ||||
|     void class_registration::register_(lua_State* L) const | ||||
|     { | ||||
|         LUABIND_CHECK_STACK(L); | ||||
|  | ||||
|         assert(lua_type(L, -1) == LUA_TTABLE); | ||||
|  | ||||
|         lua_pushstring(L, m_name); | ||||
|  | ||||
|         detail::class_rep* crep; | ||||
|  | ||||
|         detail::class_registry* r = detail::class_registry::get_registry(L); | ||||
|         // create a class_rep structure for this class. | ||||
|         // allocate it within lua to let lua collect it on | ||||
|         // lua_close(). This is better than allocating it | ||||
|         // as a static, since it will then be destructed | ||||
|         // when the program exits instead. | ||||
|         // warning: we assume that lua will not | ||||
|         // move the userdata memory. | ||||
|         lua_newuserdata(L, sizeof(detail::class_rep)); | ||||
|         crep = reinterpret_cast<detail::class_rep*>(lua_touserdata(L, -1)); | ||||
|  | ||||
|         new(crep) detail::class_rep( | ||||
|             m_type | ||||
|             , m_name | ||||
|             , L | ||||
|             , m_destructor | ||||
|             , m_const_holder_destructor | ||||
|             , m_holder_type | ||||
|             , m_const_holder_type | ||||
|             , m_extractor | ||||
|             , m_const_extractor | ||||
|             , m_const_converter | ||||
|             , m_construct_holder | ||||
|             , m_construct_const_holder | ||||
|             , m_default_construct_holder | ||||
|             , m_default_construct_const_holder | ||||
| 			, m_adopt_fun | ||||
|             , m_holder_size | ||||
|             , m_holder_alignment); | ||||
|  | ||||
|         // register this new type in the class registry | ||||
|         r->add_class(m_type, crep); | ||||
|         if (!(LUABIND_TYPE_INFO_EQUAL(m_holder_type, LUABIND_INVALID_TYPE_INFO))) | ||||
|         { | ||||
|             // if we have a held type | ||||
|             // we have to register it in the class-table | ||||
|             // but only for the base class, if it already | ||||
|             // exists, we don't have to register it | ||||
|             detail::class_rep* c = r->find_class(m_holder_type); | ||||
|             if (c == 0) | ||||
|             { | ||||
|                 r->add_class(m_holder_type, crep); | ||||
|                 r->add_class(m_const_holder_type, crep); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // constructors | ||||
|         m_constructor.swap(crep->m_constructor); | ||||
|  | ||||
|         crep->m_getters.swap(m_getters); | ||||
|         crep->m_setters.swap(m_setters); | ||||
|  | ||||
|         for (int i = 0; i < detail::number_of_operators; ++i) | ||||
|             crep->m_operators[i].swap(m_operators[i]); | ||||
|  | ||||
|         crep->m_static_constants.swap(m_static_constants); | ||||
|  | ||||
| 		typedef std::list<detail::method_rep> methods_t; | ||||
|  | ||||
| 		detail::class_registry* registry = detail::class_registry::get_registry(L); | ||||
|  | ||||
|         for (std::vector<class_base::base_desc>::iterator i = m_bases.begin(); | ||||
|             i != m_bases.end(); ++i) | ||||
|         { | ||||
|             LUABIND_CHECK_STACK(L); | ||||
|  | ||||
|             // the baseclass' class_rep structure | ||||
|             detail::class_rep* bcrep = registry->find_class(i->type); | ||||
|  | ||||
|             detail::class_rep::base_info base; | ||||
|             base.pointer_offset = i->ptr_offset; | ||||
|             base.base = bcrep; | ||||
|  | ||||
|             crep->add_base_class(base); | ||||
|  | ||||
|             // copy base class table | ||||
| 			crep->get_table(L); | ||||
| 			bcrep->get_table(L); | ||||
|             lua_pushnil(L); | ||||
|  | ||||
|             while (lua_next(L, -2)) | ||||
|             { | ||||
|                 lua_pushvalue(L, -2); // copy key | ||||
|                 lua_insert(L, -2); | ||||
|                 lua_settable(L, -5); | ||||
|             } | ||||
|             lua_pop(L, 2); | ||||
|  | ||||
|             // copy base class detaults table | ||||
| 			crep->get_default_table(L); | ||||
| 			bcrep->get_default_table(L); | ||||
|             lua_pushnil(L); | ||||
|  | ||||
|             while (lua_next(L, -2)) | ||||
|             { | ||||
|                 lua_pushvalue(L, -2); // copy key | ||||
|                 lua_insert(L, -2); | ||||
|                 lua_settable(L, -5); | ||||
|             } | ||||
|             lua_pop(L, 2); | ||||
|  | ||||
| 		} | ||||
|  | ||||
|         // add methods | ||||
|         for (std::list<detail::method_rep>::iterator i  | ||||
|             = m_methods.begin(); i != m_methods.end(); ++i) | ||||
|         { | ||||
|             LUABIND_CHECK_STACK(L); | ||||
| 			crep->add_method(*i); | ||||
| 		} | ||||
|  | ||||
| 		crep->register_methods(L); | ||||
|  | ||||
|         m_methods.clear(); | ||||
|  | ||||
|         crep->get_default_table(L); | ||||
|         m_scope.register_(L); | ||||
|         lua_pop(L, 1); | ||||
|  | ||||
|         lua_settable(L, -3); | ||||
|     } | ||||
|      | ||||
|     // -- interface --------------------------------------------------------- | ||||
|  | ||||
|     class_base::class_base(char const* name) | ||||
|         : scope(std::auto_ptr<registration>( | ||||
|                 m_registration = new class_registration(name)) | ||||
|           ) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void class_base::init( | ||||
|         LUABIND_TYPE_INFO type_id | ||||
|         , LUABIND_TYPE_INFO holder_type | ||||
|         , LUABIND_TYPE_INFO const_holder_type | ||||
|         , void*(*extractor)(void*) | ||||
|         , const void*(*const_extractor)(void*) | ||||
|         , void(*const_converter_)(void*,void*) | ||||
|         , void(*holder_constructor_)(void*,void*) | ||||
|         , void(*const_holder_constructor_)(void*,void*) | ||||
|         , void(*holder_default_constructor_)(void*) | ||||
|         , void(*const_holder_default_constructor_)(void*) | ||||
| 		, void(*adopt_fun)(void*) | ||||
|         , void(*destructor)(void*) | ||||
|         , void(*const_holder_destructor)(void*) | ||||
|         , int holder_size | ||||
|         , int holder_alignment) | ||||
|     { | ||||
|         m_registration->m_type = type_id; | ||||
|         m_registration->m_holder_type = holder_type; | ||||
|         m_registration->m_const_holder_type = const_holder_type; | ||||
|         m_registration->m_extractor = extractor; | ||||
|         m_registration->m_const_extractor = const_extractor; | ||||
|         m_registration->m_const_converter = const_converter_; | ||||
|         m_registration->m_construct_holder = holder_constructor_; | ||||
|         m_registration->m_construct_const_holder = const_holder_constructor_; | ||||
|         m_registration->m_default_construct_holder = holder_default_constructor_; | ||||
|         m_registration->m_default_construct_const_holder = const_holder_default_constructor_; | ||||
|         m_registration->m_destructor = destructor; | ||||
|         m_registration->m_const_holder_destructor = const_holder_destructor; | ||||
| 		m_registration->m_adopt_fun = adopt_fun; | ||||
|         m_registration->m_holder_size = holder_size; | ||||
|         m_registration->m_holder_alignment = holder_alignment; | ||||
|     } | ||||
|  | ||||
|     void class_base::add_getter( | ||||
|         const char* name, const boost::function2<int, lua_State*, int>& g) | ||||
|     { | ||||
|         detail::class_rep::callback c; | ||||
|         c.func = g; | ||||
|         c.pointer_offset = 0; | ||||
|  | ||||
|         const char* key = name; | ||||
|         m_registration->m_getters[key] = c; | ||||
|     } | ||||
|  | ||||
| #ifdef LUABIND_NO_ERROR_CHECKING | ||||
|     void class_base::add_setter( | ||||
|         const char* name | ||||
|         , const boost::function2<int, lua_State*, int>& s) | ||||
| #else | ||||
|     void class_base::add_setter( | ||||
|         const char* name | ||||
|         , const boost::function2<int, lua_State*, int>& s | ||||
|         , int (*match)(lua_State*, int) | ||||
|         , void (*get_sig_ptr)(lua_State*, std::string&)) | ||||
| #endif | ||||
|     { | ||||
|         detail::class_rep::callback c; | ||||
|         c.func = s; | ||||
|         c.pointer_offset = 0; | ||||
|  | ||||
| #ifndef LUABIND_NO_ERROR_CHECKING | ||||
|         c.match = match; | ||||
|         c.sig = get_sig_ptr; | ||||
| #endif | ||||
|  | ||||
|  | ||||
|         const char* key = name; | ||||
|         m_registration->m_setters[key] = c; | ||||
|     } | ||||
|  | ||||
|     void class_base::add_base(const base_desc& b) | ||||
|     { | ||||
|         m_registration->m_bases.push_back(b); | ||||
|     } | ||||
|  | ||||
|     void class_base::add_constructor(const detail::construct_rep::overload_t& o) | ||||
|     { | ||||
|         m_registration->m_constructor.overloads.push_back(o); | ||||
|     } | ||||
|  | ||||
|     void class_base::add_method(const char* name, const detail::overload_rep& o) | ||||
|     { | ||||
| 		typedef std::list<detail::method_rep> methods_t; | ||||
|  | ||||
| 		methods_t::iterator m = std::find_if( | ||||
| 			m_registration->m_methods.begin() | ||||
| 			, m_registration->m_methods.end() | ||||
| 			, method_name(name)); | ||||
| 		if (m == m_registration->m_methods.end()) | ||||
| 		{ | ||||
| 			m_registration->m_methods.push_back(method_rep()); | ||||
| 			m = m_registration->m_methods.end(); | ||||
| 			std::advance(m, -1); | ||||
| 			m->name = name; | ||||
| 		} | ||||
| 		 | ||||
|         m->add_overload(o); | ||||
|         m->crep = 0; | ||||
|     } | ||||
|  | ||||
| #ifndef LUABIND_NO_ERROR_CHECKING | ||||
|     void class_base::add_operator( | ||||
|         int op_id,  int(*func)(lua_State*), int(*matcher)(lua_State*) | ||||
|         , void(*sig)(lua_State*, std::string&), int arity) | ||||
| #else | ||||
|     void class_base::add_operator( | ||||
|         int op_id,  int(*func)(lua_State*) | ||||
|         , int(*matcher)(lua_State*), int arity) | ||||
| #endif | ||||
|     { | ||||
|         detail::class_rep::operator_callback o; | ||||
|         o.set_fun(func); | ||||
|         o.set_match_fun(matcher); | ||||
|         o.set_arity(arity); | ||||
|  | ||||
| #ifndef LUABIND_NO_ERROR_CHECKING | ||||
|  | ||||
|         o.set_sig_fun(sig); | ||||
|  | ||||
| #endif | ||||
|         m_registration->m_operators[op_id].push_back(o); | ||||
|     } | ||||
|  | ||||
|     const char* class_base::name() const  | ||||
|     {  | ||||
|         return m_registration->m_name;  | ||||
|     } | ||||
|  | ||||
|     void class_base::add_static_constant(const char* name, int val) | ||||
|     { | ||||
|         m_registration->m_static_constants[name] = val; | ||||
|     } | ||||
|  | ||||
|     void class_base::add_inner_scope(scope& s) | ||||
|     { | ||||
|         m_registration->m_scope.operator,(s); | ||||
|     } | ||||
|  | ||||
| 	template<class T> | ||||
| 	void add_custom_name(T i, std::string& s) {} | ||||
|  | ||||
| 	void add_custom_name(std::type_info const* i, std::string& s) | ||||
| 	{ | ||||
| 		s += " ["; | ||||
| 		s += i->name(); | ||||
| 		s += "]"; | ||||
| 	} | ||||
|  | ||||
|     std::string get_class_name(lua_State* L, LUABIND_TYPE_INFO i) | ||||
|     { | ||||
|         std::string ret; | ||||
|  | ||||
| 		assert(L); | ||||
|  | ||||
| 		class_registry* r = class_registry::get_registry(L); | ||||
|         class_rep* crep = r->find_class(i); | ||||
|  | ||||
|         if (crep == 0) | ||||
|         { | ||||
|             ret = "custom"; | ||||
| 			add_custom_name(i, ret); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (LUABIND_TYPE_INFO_EQUAL(i, crep->holder_type())) | ||||
|             { | ||||
|                 ret += "smart_ptr<"; | ||||
|                 ret += crep->name(); | ||||
|                 ret += ">"; | ||||
|             } | ||||
|             else if (LUABIND_TYPE_INFO_EQUAL(i, crep->const_holder_type())) | ||||
|             { | ||||
|                 ret += "smart_ptr<const "; | ||||
|                 ret += crep->name(); | ||||
|                 ret += ">"; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 ret += crep->name(); | ||||
|             } | ||||
|         } | ||||
|         return ret; | ||||
|     }; | ||||
|  | ||||
| }} // namespace luabind::detail | ||||
|  | ||||
							
								
								
									
										76
									
								
								lua/luabind/class_info.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								lua/luabind/class_info.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/luabind.hpp> | ||||
| #include <luabind/class_info.hpp> | ||||
|  | ||||
| namespace luabind | ||||
| { | ||||
| 	class_info get_class_info(const object& o) | ||||
| 	{ | ||||
| 		lua_State* L = o.interpreter(); | ||||
| 	 | ||||
| 		class_info result; | ||||
| 	 | ||||
| 		o.push(L); | ||||
| 		detail::object_rep* obj = static_cast<detail::object_rep*>(lua_touserdata(L, -1)); | ||||
| 		lua_pop(L, 1); | ||||
|  | ||||
| 		result.name = obj->crep()->name(); | ||||
| 		obj->crep()->get_table(L); | ||||
|  | ||||
| 		object methods(from_stack(L, -1)); | ||||
| 		 | ||||
| 		methods.swap(result.methods); | ||||
| 		lua_pop(L, 1); | ||||
| 		 | ||||
| 		result.attributes = newtable(L); | ||||
|  | ||||
| 		typedef detail::class_rep::property_map map_type; | ||||
| 		 | ||||
| 		std::size_t index = 1; | ||||
| 		 | ||||
| 		for (map_type::const_iterator i = obj->crep()->properties().begin(); | ||||
| 				i != obj->crep()->properties().end(); ++i) | ||||
| 		{ | ||||
| 			result.attributes[index] = i->first; | ||||
| 		} | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	void bind_class_info(lua_State* L) | ||||
| 	{ | ||||
| 		module(L) | ||||
| 		[ | ||||
| 			class_<class_info>("class_info_data") | ||||
| 				.def_readonly("name", &class_info::name) | ||||
| 				.def_readonly("methods", &class_info::methods) | ||||
| 				.def_readonly("attributes", &class_info::attributes), | ||||
| 		 | ||||
| 			def("class_info", &get_class_info) | ||||
| 		]; | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										258
									
								
								lua/luabind/class_registry.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								lua/luabind/class_registry.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,258 @@ | ||||
| // Copyright (c) 2004 Daniel Wallin | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/luabind.hpp> | ||||
| #include <luabind/detail/class_registry.hpp> | ||||
| #include <luabind/detail/class_rep.hpp> | ||||
| #include <luabind/detail/operator_id.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail { | ||||
|  | ||||
|     namespace { | ||||
|  | ||||
|         void add_operator_to_metatable(lua_State* L, int op_index) | ||||
|         { | ||||
|             lua_pushstring(L, get_operator_name(op_index)); | ||||
|             lua_pushstring(L, get_operator_name(op_index)); | ||||
|             lua_pushboolean(L, op_index == op_unm); | ||||
|             lua_pushcclosure(L, &class_rep::operator_dispatcher, 2); | ||||
|             lua_settable(L, -3); | ||||
|         } | ||||
|  | ||||
|         int create_cpp_class_metatable(lua_State* L) | ||||
|         { | ||||
|             lua_newtable(L); | ||||
|  | ||||
|             // mark the table with our (hopefully) unique tag | ||||
|             // that says that the user data that has this | ||||
|             // metatable is a class_rep | ||||
|             lua_pushstring(L, "__luabind_classrep"); | ||||
|             lua_pushboolean(L, 1); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__gc"); | ||||
|             lua_pushcclosure( | ||||
|                 L | ||||
|               , &garbage_collector_s< | ||||
|                     detail::class_rep | ||||
|                 >::apply | ||||
|                 , 0); | ||||
|  | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__call"); | ||||
|             lua_pushcclosure(L, &class_rep::constructor_dispatcher, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__index"); | ||||
|             lua_pushcclosure(L, &class_rep::static_class_gettable, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__newindex"); | ||||
|             lua_pushcclosure(L, &class_rep::lua_settable_dispatcher, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             return detail::ref(L); | ||||
|         } | ||||
|  | ||||
|         int create_cpp_instance_metatable(lua_State* L) | ||||
|         { | ||||
|             lua_newtable(L); | ||||
|  | ||||
|             // just indicate that this really is a class and not just  | ||||
|             // any user data | ||||
|             lua_pushstring(L, "__luabind_class"); | ||||
|             lua_pushboolean(L, 1); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             // __index and __newindex will simply be references to the  | ||||
|             // class_rep which in turn has it's own metamethods for __index | ||||
|             // and __newindex | ||||
|             lua_pushstring(L, "__index"); | ||||
|             lua_pushcclosure(L, &class_rep::gettable_dispatcher, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__newindex"); | ||||
|             lua_pushcclosure(L, &class_rep::settable_dispatcher, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__gc"); | ||||
|  | ||||
|             lua_pushcclosure(L, detail::object_rep::garbage_collector, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__gettable"); | ||||
|             lua_pushcclosure(L, &class_rep::static_class_gettable, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             for (int i = 0; i < number_of_operators; ++i)  | ||||
|                 add_operator_to_metatable(L, i); | ||||
|  | ||||
|             // store a reference to the instance-metatable in our class_rep | ||||
|             assert((lua_type(L, -1) == LUA_TTABLE)  | ||||
|                 && "internal error, please report"); | ||||
|  | ||||
|             return detail::ref(L); | ||||
|         } | ||||
|  | ||||
|         int create_lua_class_metatable(lua_State* L) | ||||
|         { | ||||
|             lua_newtable(L); | ||||
|  | ||||
|             lua_pushstring(L, "__luabind_classrep"); | ||||
|             lua_pushboolean(L, 1); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__gc"); | ||||
|             lua_pushcclosure( | ||||
|                 L | ||||
|               , &detail::garbage_collector_s< | ||||
|                     detail::class_rep | ||||
|                 >::apply | ||||
|                 , 0); | ||||
|  | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__newindex"); | ||||
|             lua_pushcclosure(L, &class_rep::lua_settable_dispatcher, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__call"); | ||||
|             lua_pushcclosure(L, &class_rep::construct_lua_class_callback, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__index"); | ||||
|             lua_pushcclosure(L, &class_rep::static_class_gettable, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             return detail::ref(L); | ||||
|         } | ||||
|  | ||||
|         int create_lua_instance_metatable(lua_State* L) | ||||
|         { | ||||
|             lua_newtable(L); | ||||
|  | ||||
|             // just indicate that this really is a class and not just  | ||||
|             // any user data | ||||
|             lua_pushstring(L, "__luabind_class"); | ||||
|             lua_pushboolean(L, 1); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__index"); | ||||
|             lua_pushcclosure(L, &class_rep::lua_class_gettable, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__newindex"); | ||||
|             lua_pushcclosure(L, &class_rep::lua_class_settable, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             lua_pushstring(L, "__gc"); | ||||
|             lua_pushcclosure(L, detail::object_rep::garbage_collector, 0); | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             for (int i = 0; i < number_of_operators; ++i)  | ||||
|                 add_operator_to_metatable(L, i); | ||||
|  | ||||
|             // store a reference to the instance-metatable in our class_rep | ||||
|             return detail::ref(L); | ||||
|         } | ||||
|  | ||||
|         int create_lua_function_metatable(lua_State* L) | ||||
|         { | ||||
|             lua_newtable(L); | ||||
|  | ||||
|             lua_pushstring(L, "__gc"); | ||||
|             lua_pushcclosure( | ||||
|                 L  | ||||
|               , detail::garbage_collector_s< | ||||
|                     detail::free_functions::function_rep | ||||
|                 >::apply | ||||
|               , 0); | ||||
|  | ||||
|             lua_rawset(L, -3); | ||||
|  | ||||
|             return detail::ref(L); | ||||
|         } | ||||
|  | ||||
|     } // namespace unnamed | ||||
|  | ||||
|     class class_rep; | ||||
|  | ||||
|     class_registry::class_registry(lua_State* L) | ||||
|         : m_cpp_instance_metatable(create_cpp_instance_metatable(L)) | ||||
|         , m_cpp_class_metatable(create_cpp_class_metatable(L)) | ||||
|         , m_lua_instance_metatable(create_lua_instance_metatable(L)) | ||||
|         , m_lua_class_metatable(create_lua_class_metatable(L)) | ||||
|         , m_lua_function_metatable(create_lua_function_metatable(L)) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     class_registry* class_registry::get_registry(lua_State* L) | ||||
|     { | ||||
|  | ||||
| #ifdef LUABIND_NOT_THREADSAFE | ||||
|  | ||||
|         // if we don't have to be thread safe, we can keep a | ||||
|         // chache of the class_registry pointer without the | ||||
|         // need of a mutex | ||||
|         static lua_State* cache_key = 0; | ||||
|         static class_registry* registry_cache = 0; | ||||
|         if (cache_key == L) return registry_cache; | ||||
|  | ||||
| #endif | ||||
|  | ||||
|         lua_pushstring(L, "__luabind_classes"); | ||||
|         lua_gettable(L, LUA_REGISTRYINDEX); | ||||
|         class_registry* p = static_cast<class_registry*>(lua_touserdata(L, -1)); | ||||
|         lua_pop(L, 1); | ||||
|  | ||||
| #ifdef LUABIND_NOT_THREADSAFE | ||||
|  | ||||
|         cache_key = L; | ||||
|         registry_cache = p; | ||||
|  | ||||
| #endif | ||||
|  | ||||
|         return p; | ||||
|     } | ||||
|  | ||||
|     void class_registry::add_class(LUABIND_TYPE_INFO info, class_rep* crep) | ||||
|     { | ||||
|         // class is already registered | ||||
|         assert((m_classes.find(info) == m_classes.end())  | ||||
|             && "you are trying to register a class twice"); | ||||
|         m_classes[info] = crep; | ||||
|     } | ||||
|  | ||||
|     class_rep* class_registry::find_class(LUABIND_TYPE_INFO info) const | ||||
|     { | ||||
|         std::map<LUABIND_TYPE_INFO, class_rep*, cmp>::const_iterator i( | ||||
|             m_classes.find(info)); | ||||
|  | ||||
|         if (i == m_classes.end()) return 0; // the type is not registered | ||||
|         return i->second; | ||||
|     } | ||||
|  | ||||
| }} // namespace luabind::detail | ||||
|  | ||||
							
								
								
									
										1675
									
								
								lua/luabind/class_rep.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1675
									
								
								lua/luabind/class_rep.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										142
									
								
								lua/luabind/create_class.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								lua/luabind/create_class.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/luabind.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail | ||||
| { | ||||
| 	namespace | ||||
| 	{ | ||||
| 		// expects two tables on the lua stack: | ||||
| 		// 1: destination | ||||
| 		// 2: source | ||||
| 		void copy_member_table(lua_State* L) | ||||
| 		{ | ||||
| 			lua_pushnil(L); | ||||
|  | ||||
| 			while (lua_next(L, -2)) | ||||
| 			{ | ||||
| 				lua_pushstring(L, "__init"); | ||||
| 				if (lua_equal(L, -1, -3)) | ||||
| 				{ | ||||
| 					lua_pop(L, 2); | ||||
| 					continue; | ||||
| 				} | ||||
| 				else lua_pop(L, 1); // __init string | ||||
|  | ||||
| 				lua_pushstring(L, "__finalize"); | ||||
| 				if (lua_equal(L, -1, -3)) | ||||
| 				{ | ||||
| 					lua_pop(L, 2); | ||||
| 					continue; | ||||
| 				} | ||||
| 				else lua_pop(L, 1); // __finalize string | ||||
|  | ||||
| 				lua_pushvalue(L, -2); // copy key | ||||
| 				lua_insert(L, -2); | ||||
| 				lua_settable(L, -5); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	int create_class::stage2(lua_State* L) | ||||
| 	{ | ||||
| 		class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, lua_upvalueindex(1))); | ||||
| 		assert((crep != 0) && "internal error, please report"); | ||||
| 		assert((is_class_rep(L, lua_upvalueindex(1))) && "internal error, please report"); | ||||
|  | ||||
| 	#ifndef LUABIND_NO_ERROR_CHECKING | ||||
|  | ||||
| 		if (!is_class_rep(L, 1)) | ||||
| 		{ | ||||
| 			lua_pushstring(L, "expected class to derive from or a newline"); | ||||
| 			lua_error(L); | ||||
| 		} | ||||
|  | ||||
| 	#endif | ||||
|  | ||||
| 		class_rep* base = static_cast<class_rep*>(lua_touserdata(L, 1)); | ||||
| 		class_rep::base_info binfo; | ||||
|  | ||||
| 		binfo.pointer_offset = 0; | ||||
| 		binfo.base = base; | ||||
| 		crep->add_base_class(binfo); | ||||
|  | ||||
| 		// set holder size and alignment so that we can class_rep::allocate | ||||
| 		// can return the correctly sized buffers | ||||
| 		crep->derived_from(base); | ||||
| 		 | ||||
| 		// copy base class members | ||||
|  | ||||
| 		crep->get_table(L); | ||||
| 		base->get_table(L); | ||||
| 		copy_member_table(L); | ||||
|  | ||||
| 		crep->get_default_table(L); | ||||
| 		base->get_default_table(L); | ||||
| 		copy_member_table(L); | ||||
|  | ||||
| 		crep->set_type(base->type()); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	int create_class::stage1(lua_State* L) | ||||
| 	{ | ||||
|  | ||||
| 	#ifndef LUABIND_NO_ERROR_CHECKING | ||||
|  | ||||
| 		if (lua_gettop(L) != 1 || lua_type(L, 1) != LUA_TSTRING || lua_isnumber(L, 1)) | ||||
| 		{ | ||||
| 			lua_pushstring(L, "invalid construct, expected class name"); | ||||
| 			lua_error(L); | ||||
| 		} | ||||
|  | ||||
| 		if (std::strlen(lua_tostring(L, 1)) != lua_strlen(L, 1)) | ||||
| 		{ | ||||
| 			lua_pushstring(L, "luabind does not support class names with extra nulls"); | ||||
| 			lua_error(L); | ||||
| 		} | ||||
|  | ||||
| 	#endif | ||||
|  | ||||
| 		const char* name = lua_tostring(L, 1); | ||||
|  | ||||
| 		void* c = lua_newuserdata(L, sizeof(class_rep)); | ||||
| 		new(c) class_rep(L, name); | ||||
|  | ||||
| 		// make the class globally available | ||||
| 		lua_pushstring(L, name); | ||||
| 		lua_pushvalue(L, -2); | ||||
| 		lua_settable(L, LUA_GLOBALSINDEX); | ||||
|  | ||||
| 		// also add it to the closure as return value | ||||
| 		lua_pushcclosure(L, &stage2, 1); | ||||
|  | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| }} | ||||
|  | ||||
							
								
								
									
										76
									
								
								lua/luabind/error.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								lua/luabind/error.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/error.hpp> | ||||
|  | ||||
|  | ||||
| namespace luabind | ||||
| { | ||||
|  | ||||
| 	namespace | ||||
| 	{ | ||||
| 		pcall_callback_fun pcall_callback = 0; | ||||
| #ifdef LUABIND_NO_EXCEPTIONS | ||||
| 		error_callback_fun error_callback = 0; | ||||
| 		cast_failed_callback_fun cast_failed_callback = 0; | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
|  | ||||
| #ifdef LUABIND_NO_EXCEPTIONS | ||||
|  | ||||
| 	typedef void(*error_callback_fun)(lua_State*); | ||||
| 	typedef void(*cast_failed_callback_fun)(lua_State*, LUABIND_TYPE_INFO); | ||||
|  | ||||
| 	void set_error_callback(error_callback_fun e) | ||||
| 	{ | ||||
| 		error_callback = e; | ||||
| 	} | ||||
|  | ||||
| 	void set_cast_failed_callback(cast_failed_callback_fun c) | ||||
| 	{ | ||||
| 		cast_failed_callback = c; | ||||
| 	} | ||||
|  | ||||
| 	error_callback_fun get_error_callback() | ||||
| 	{ | ||||
| 		return error_callback; | ||||
| 	} | ||||
|  | ||||
| 	cast_failed_callback_fun get_cast_failed_callback() | ||||
| 	{ | ||||
| 		return cast_failed_callback; | ||||
| 	} | ||||
|  | ||||
| #endif | ||||
|  | ||||
| 	void set_pcall_callback(pcall_callback_fun e) | ||||
| 	{ | ||||
| 		pcall_callback = e; | ||||
| 	} | ||||
|  | ||||
| 	pcall_callback_fun get_pcall_callback() | ||||
| 	{ | ||||
| 		return pcall_callback; | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										83
									
								
								lua/luabind/find_best_match.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								lua/luabind/find_best_match.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/luabind.hpp> | ||||
|  | ||||
| using namespace luabind::detail; | ||||
|  | ||||
| bool luabind::detail::find_best_match( | ||||
|     lua_State* L | ||||
|   , overload_rep_base const* start | ||||
|   , int num_overloads | ||||
|   , size_t orep_size | ||||
|   , bool& ambiguous | ||||
|   , int& min_match | ||||
|   , int& match_index | ||||
|   , int num_params) | ||||
| { | ||||
|     int min_but_one_match = std::numeric_limits<int>::max(); | ||||
|     bool found = false; | ||||
|  | ||||
|     for (int index = 0; index < num_overloads; ++index) | ||||
|     { | ||||
|         int match_value = start->match(L, num_params); | ||||
|  | ||||
|         reinterpret_cast<const char*&>(start) += orep_size; | ||||
|  | ||||
|         if (match_value < 0) continue; | ||||
|         if (match_value < min_match) | ||||
|         { | ||||
|             found = true; | ||||
|             match_index = index; | ||||
|             min_but_one_match = min_match; | ||||
|             min_match = match_value; | ||||
|         } | ||||
|         else if (match_value < min_but_one_match) | ||||
|         { | ||||
|             min_but_one_match = match_value; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     ambiguous = min_match == min_but_one_match | ||||
|         && min_match < std::numeric_limits<int>::max(); | ||||
|     return found; | ||||
| } | ||||
|  | ||||
| void luabind::detail::find_exact_match( | ||||
|     lua_State* L | ||||
|   , overload_rep_base const* start | ||||
|   , int num_overloads | ||||
|   , size_t orep_size | ||||
|   , int cmp_match | ||||
|   , int num_params | ||||
|   , std::vector<const overload_rep_base*>& dest) | ||||
| { | ||||
|     for (int i = 0; i < num_overloads; ++i) | ||||
|     { | ||||
|         int match_value = start->match(L, num_params); | ||||
|         if (match_value == cmp_match) dest.push_back(start); | ||||
|         reinterpret_cast<const char*&>(start) += orep_size; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										294
									
								
								lua/luabind/function.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								lua/luabind/function.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,294 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/config.hpp> | ||||
| #include <luabind/luabind.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail { namespace free_functions { | ||||
|  | ||||
|     void function_rep::add_overload(overload_rep const& o) | ||||
|     { | ||||
|         std::vector<overload_rep>::iterator i = std::find( | ||||
|             m_overloads.begin(), m_overloads.end(), o); | ||||
|  | ||||
|         // if the overload already exists, overwrite the existing function | ||||
|         if (i != m_overloads.end()) | ||||
|         { | ||||
|             *i = o; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             m_overloads.push_back(o); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     int function_dispatcher(lua_State* L) | ||||
|     { | ||||
|         function_rep* rep = static_cast<function_rep*>( | ||||
|             lua_touserdata(L, lua_upvalueindex(1)) | ||||
|         ); | ||||
|  | ||||
|         bool ambiguous = false; | ||||
|         int min_match = std::numeric_limits<int>::max(); | ||||
|         int match_index = -1; | ||||
|         bool ret; | ||||
|  | ||||
| #ifdef LUABIND_NO_ERROR_CHECKING | ||||
|         if (rep->overloads().size() == 1) | ||||
|         { | ||||
|             match_index = 0; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| #endif | ||||
|             int num_params = lua_gettop(L); | ||||
|             ret = find_best_match( | ||||
|                 L | ||||
|               , &rep->overloads().front() | ||||
|               , (int)rep->overloads().size() | ||||
|               , sizeof(overload_rep) | ||||
|               , ambiguous | ||||
|               , min_match | ||||
|               , match_index | ||||
|               , num_params | ||||
|             ); | ||||
| #ifdef LUABIND_NO_ERROR_CHECKING | ||||
|         } | ||||
| #else | ||||
|         if (!ret) | ||||
|         { | ||||
|             // this bock is needed to make sure the std::string is destructed | ||||
|             { | ||||
|                 std::string msg = "no match for function call '"; | ||||
|                 msg += rep->name(); | ||||
|                 msg += "' with the parameters ("; | ||||
|                 msg += stack_content_by_name(L, 1); | ||||
|                 msg += ")\ncandidates are:\n"; | ||||
|  | ||||
|                 msg += get_overload_signatures( | ||||
|                     L | ||||
|                   , rep->overloads().begin() | ||||
|                   , rep->overloads().end() | ||||
|                   , rep->name() | ||||
|                 ); | ||||
|  | ||||
|                 lua_pushstring(L, msg.c_str()); | ||||
|             } | ||||
|  | ||||
|             lua_error(L); | ||||
|         } | ||||
|  | ||||
|         if (ambiguous) | ||||
|         { | ||||
|             // this bock is needed to make sure the std::string is destructed | ||||
|             { | ||||
|                 std::string msg = "call of overloaded function '"; | ||||
|                 msg += rep->name(); | ||||
|                 msg += "("; | ||||
|                 msg += stack_content_by_name(L, 1); | ||||
|                 msg += ") is ambiguous\nnone of the overloads " | ||||
|                        "have a best conversion:"; | ||||
|  | ||||
|                 std::vector<overload_rep_base const*> candidates; | ||||
|                 find_exact_match( | ||||
|                     L | ||||
|                   , &rep->overloads().front() | ||||
|                   , (int)rep->overloads().size() | ||||
|                   , sizeof(overload_rep) | ||||
|                   , min_match | ||||
|                   , num_params | ||||
|                   , candidates | ||||
|                 ); | ||||
|  | ||||
|                 msg += get_overload_signatures_candidates( | ||||
|                     L | ||||
|                   , candidates.begin() | ||||
|                   , candidates.end() | ||||
|                   , rep->name() | ||||
|                 ); | ||||
|  | ||||
|                 lua_pushstring(L, msg.c_str()); | ||||
|             } | ||||
|             lua_error(L); | ||||
|         } | ||||
| #endif | ||||
|         overload_rep const& ov_rep = rep->overloads()[match_index]; | ||||
|  | ||||
| #ifndef LUABIND_NO_EXCEPTIONS | ||||
|         try | ||||
|         { | ||||
| #endif | ||||
|             return ov_rep.call(L, ov_rep.fun); | ||||
| #ifndef LUABIND_NO_EXCEPTIONS | ||||
|         } | ||||
|         catch(const luabind::error&) | ||||
|         { | ||||
|         } | ||||
|         catch(const std::exception& e) | ||||
|         { | ||||
|             lua_pushstring(L, e.what()); | ||||
|         } | ||||
|         catch (const char* s) | ||||
|         { | ||||
|             lua_pushstring(L, s); | ||||
|         } | ||||
|         catch(...) | ||||
|         { | ||||
|             std::string msg = rep->name(); | ||||
|             msg += "() threw an exception"; | ||||
|             lua_pushstring(L, msg.c_str()); | ||||
|         } | ||||
|         // we can only reach this line if an exception was thrown | ||||
|         lua_error(L); | ||||
|         return 0; // will never be reached | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|      | ||||
| }}} // namespace luabind::detail::free_functions | ||||
|  | ||||
| #if 0 | ||||
|  | ||||
| void luabind::detail::free_functions::function_rep::add_overload( | ||||
|     luabind::detail::free_functions::overload_rep const& o) | ||||
| { | ||||
|     std::vector<luabind::detail::free_functions::overload_rep>::iterator i  | ||||
|         = std::find(m_overloads.begin(), m_overloads.end(), o); | ||||
|  | ||||
|     // if the overload already exists, overwrite the existing function | ||||
|     if (i != m_overloads.end()) | ||||
|     { | ||||
|         *i = o; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         m_overloads.push_back(o); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int luabind::detail::free_functions::function_dispatcher(lua_State* L) | ||||
| { | ||||
|     function_rep* rep = static_cast<function_rep*>(lua_touserdata(L, lua_upvalueindex(1))); | ||||
|  | ||||
|     bool ambiguous = false; | ||||
|     int min_match = std::numeric_limits<int>::max(); | ||||
|     int match_index = -1; | ||||
|     bool ret; | ||||
|  | ||||
| #ifdef LUABIND_NO_ERROR_CHECKING | ||||
|                  | ||||
|     if (rep->overloads().size() == 1) | ||||
|     { | ||||
|         match_index = 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|  | ||||
| #endif | ||||
|         int num_params = lua_gettop(L); | ||||
|         ret = find_best_match( | ||||
|             L, &rep->overloads().front(), (int)rep->overloads().size() | ||||
|           , sizeof(free_functions::overload_rep), ambiguous, min_match | ||||
|           , match_index, num_params); | ||||
|  | ||||
| #ifdef LUABIND_NO_ERROR_CHECKING | ||||
|     } | ||||
|  | ||||
| #else | ||||
|  | ||||
|     if (!ret) | ||||
|     { | ||||
|         // this bock is needed to make sure the std::string is destructed | ||||
|         { | ||||
|             std::string msg = "no match for function call '"; | ||||
|             msg += rep->name(); | ||||
|             msg += "' with the parameters ("; | ||||
|             msg += stack_content_by_name(L, 1); | ||||
|             msg += ")\ncandidates are:\n"; | ||||
|  | ||||
|             msg += get_overload_signatures(L, rep->overloads().begin(), rep->overloads().end(), rep->name()); | ||||
|  | ||||
|             lua_pushstring(L, msg.c_str()); | ||||
|         } | ||||
|  | ||||
|         lua_error(L); | ||||
|     } | ||||
|  | ||||
|     if (ambiguous) | ||||
|     { | ||||
|         // this bock is needed to make sure the std::string is destructed | ||||
|         { | ||||
|             std::string msg = "call of overloaded function '"; | ||||
|             msg += rep->name(); | ||||
|             msg += "("; | ||||
|             msg += stack_content_by_name(L, 1); | ||||
|             msg += ") is ambiguous\nnone of the overloads have a best conversion:"; | ||||
|  | ||||
|             std::vector<const overload_rep_base*> candidates; | ||||
|             find_exact_match( | ||||
|                 L, &rep->overloads().front(), (int)rep->overloads().size() | ||||
|               , sizeof(free_functions::overload_rep), min_match | ||||
|               , num_params, candidates); | ||||
|  | ||||
|             msg += get_overload_signatures_candidates(L, candidates.begin(), candidates.end(), rep->name()); | ||||
|  | ||||
|             lua_pushstring(L, msg.c_str()); | ||||
|         } | ||||
|         lua_error(L); | ||||
|     } | ||||
| #endif | ||||
|     const overload_rep& ov_rep = rep->overloads()[match_index]; | ||||
|  | ||||
| #ifndef LUABIND_NO_EXCEPTIONS | ||||
|     try | ||||
|     { | ||||
| #endif | ||||
|         return ov_rep.call(L, ov_rep.fun); | ||||
| #ifndef LUABIND_NO_EXCEPTIONS | ||||
|     } | ||||
|     catch(const luabind::error& e) | ||||
|     { | ||||
|     } | ||||
|     catch(const std::exception& e) | ||||
|     { | ||||
|         lua_pushstring(L, e.what()); | ||||
|     } | ||||
|     catch (const char* s) | ||||
|     { | ||||
|         lua_pushstring(L, s); | ||||
|     } | ||||
|     catch(...) | ||||
|     { | ||||
|         std::string msg = rep->name(); | ||||
|         msg += "() threw an exception"; | ||||
|         lua_pushstring(L, msg.c_str()); | ||||
|     } | ||||
|     // we can only reach this line if an exception was thrown | ||||
|     lua_error(L); | ||||
|     return 0; // will never be reached | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										62
									
								
								lua/luabind/implicit_cast.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								lua/luabind/implicit_cast.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/luabind.hpp> | ||||
| #include <luabind/detail/implicit_cast.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail { | ||||
|  | ||||
|     // returns -1 if there exists no implicit cast from the given class_rep | ||||
|     // to T. If there exists an implicit cast to T, the number of steps times | ||||
|     // 2 is returned and pointer_offset is filled with the number of bytes  | ||||
|     // the pointer have to be offseted to perform the cast the reason why we | ||||
|     // return the number of cast-steps times two, instead of just the number  | ||||
|     // of steps is to be consistent with the function matchers. They have to  | ||||
|     // give one matching-point extra to match const functions. There may be | ||||
|     // two functions that match their parameters exactly, but there is one  | ||||
|     // const function and one non-const function, then (if the this-pointer | ||||
|     // is non-const) both functions will match. To avoid amiguaties, the const | ||||
|     // version will get one penalty point to make the match-selector select | ||||
|     // the non-const version. If the this-pointer is const, there's no  | ||||
|     // problem, since the non-const function will not match at all. | ||||
|      | ||||
|     int implicit_cast( | ||||
|         class_rep const* crep | ||||
|       , LUABIND_TYPE_INFO const& type_id | ||||
|       , int& pointer_offset) | ||||
|     { | ||||
|         int offset = 0; | ||||
|         if (LUABIND_TYPE_INFO_EQUAL(crep->type(), type_id)) return 0; | ||||
|  | ||||
|         for (std::vector<class_rep::base_info>::const_iterator i =  | ||||
|             crep->bases().begin(); i != crep->bases().end(); ++i) | ||||
|         { | ||||
|             int steps = implicit_cast(i->base, type_id, offset); | ||||
|             pointer_offset = offset + i->pointer_offset; | ||||
|             if (steps >= 0) return steps + 2; | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
| }} | ||||
|  | ||||
							
								
								
									
										41
									
								
								lua/luabind/link_compatibility.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								lua/luabind/link_compatibility.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/detail/link_compatibility.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail | ||||
| { | ||||
|  | ||||
| #ifdef LUABIND_NOT_THREADSAFE | ||||
| 	void not_threadsafe_defined_conflict() {} | ||||
| #else | ||||
| 	void not_threadsafe_not_defined_conflict() {} | ||||
| #endif | ||||
|  | ||||
| #ifdef LUABIND_NO_ERROR_CHECKING | ||||
| 	void no_error_checking_defined_conflict() {} | ||||
| #else | ||||
| 	void no_error_checking_not_defined_conflict() {} | ||||
| #endif | ||||
|  | ||||
| }} | ||||
|  | ||||
							
								
								
									
										112
									
								
								lua/luabind/object_rep.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lua/luabind/object_rep.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/detail/object_rep.hpp> | ||||
| #include <luabind/detail/class_rep.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail | ||||
| { | ||||
|  | ||||
| 	// dest is a function that is called to delete the c++ object this struct holds | ||||
| 	object_rep::object_rep(void* obj, class_rep* crep, int flags, void(*dest)(void*)) | ||||
| 		: m_object(obj) | ||||
| 		, m_classrep(crep) | ||||
| 		, m_flags(flags) | ||||
| 		, m_destructor(dest) | ||||
| 		, m_dependency_cnt(1) | ||||
| 	{ | ||||
| 		// if the object is owned by lua, a valid destructor must be given | ||||
| 		assert((((m_flags & owner) && dest) || !(m_flags & owner)) && "internal error, please report"); | ||||
| 	} | ||||
|  | ||||
| 	object_rep::object_rep(class_rep* crep, int flags, detail::lua_reference const& table_ref) | ||||
| 		: m_object(0) | ||||
| 		, m_classrep(crep) | ||||
| 		, m_flags(flags) | ||||
| 		, m_lua_table_ref(table_ref) | ||||
| 		, m_destructor(0) | ||||
| 		, m_dependency_cnt(1) | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	object_rep::~object_rep()  | ||||
| 	{ | ||||
| 		if (m_flags & owner && m_destructor) m_destructor(m_object); | ||||
| 	} | ||||
|  | ||||
| 	void object_rep::remove_ownership() | ||||
| 	{ | ||||
| 		assert((m_flags & owner) && "cannot remove ownership of object that's not owned"); | ||||
| 		assert(m_classrep->get_class_type() == class_rep::cpp_class | ||||
| 			|| m_classrep->bases().size() == 1 && "can only adopt c++ types or lua classes that derives from a c++ class"); | ||||
|  | ||||
|         // daniel040727 Bogus assert above? C++ types can be adopted just fine | ||||
|         // without a hierarchy? | ||||
|  | ||||
| 		m_flags &= ~owner; | ||||
| 		// if this is a type with a wrapper we also have to | ||||
| 		// transform the wrappers weak_ref into a strong | ||||
| 		// reference, to make sure the lua part | ||||
| 		// stays alive as long as the c++ part stays | ||||
| 		// alive. | ||||
| /*		if (m_classrep->get_class_type() == class_rep::cpp_class) | ||||
| 			m_classrep->adopt(m_flags & constant, m_object); | ||||
| 		else*/ | ||||
|  | ||||
|         // daniel040727 I changed the above. It just seems wrong. adopt() | ||||
|         // should only be called on the wrapper type. | ||||
|         if (m_classrep->get_class_type() == class_rep::lua_class) | ||||
| 			m_classrep->bases().front().base->adopt(m_flags & constant, m_object); | ||||
| 	} | ||||
|  | ||||
| 	void object_rep::set_destructor(void(*ptr)(void*)) | ||||
| 	{ | ||||
| 		m_destructor = ptr; | ||||
| 	} | ||||
|  | ||||
| 	void object_rep::add_dependency(lua_State* L, int index) | ||||
| 	{ | ||||
| 		if (!m_dependency_ref.is_valid()) | ||||
| 		{ | ||||
| 			lua_newtable(L); | ||||
| 			m_dependency_ref.set(L); | ||||
| 		} | ||||
|  | ||||
| 		m_dependency_ref.get(L); | ||||
| 		lua_pushvalue(L, index); | ||||
| 		lua_rawseti(L, -2, m_dependency_cnt); | ||||
| 		lua_pop(L, 1); | ||||
| 		++m_dependency_cnt; | ||||
| 	} | ||||
|  | ||||
| 	int object_rep::garbage_collector(lua_State* L) | ||||
| 	{ | ||||
| 		object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, -1)); | ||||
|  | ||||
| 		finalize(L, obj->crep()); | ||||
|  | ||||
| 		obj->~object_rep(); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| }} | ||||
|  | ||||
							
								
								
									
										68
									
								
								lua/luabind/open.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lua/luabind/open.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/luabind.hpp> | ||||
| #include <luabind/function.hpp> | ||||
|  | ||||
| namespace luabind { | ||||
|  | ||||
|     void open(lua_State* L) | ||||
|     { | ||||
|         // get the global class registry, or create one if it doesn't exist | ||||
|         // (it's global within a lua state) | ||||
|         detail::class_registry* r = 0; | ||||
|  | ||||
|         // If you hit this assert it's because you have called luabind::open() | ||||
|         // twice on the same lua_State. | ||||
|         assert((detail::class_registry::get_registry(L) == 0)  | ||||
|             && "you cannot call luabind::open() twice"); | ||||
|  | ||||
|         lua_pushstring(L, "__luabind_classes"); | ||||
|         r = static_cast<detail::class_registry*>( | ||||
|             lua_newuserdata(L, sizeof(detail::class_registry))); | ||||
|  | ||||
|         // set gc metatable | ||||
|         lua_newtable(L); | ||||
|         lua_pushstring(L, "__gc"); | ||||
|         lua_pushcclosure( | ||||
|             L | ||||
|           , detail::garbage_collector_s< | ||||
|                 detail::class_registry | ||||
|             >::apply | ||||
|           , 0); | ||||
|  | ||||
|         lua_settable(L, -3); | ||||
|         lua_setmetatable(L, -2); | ||||
|  | ||||
|         new(r) detail::class_registry(L); | ||||
|         lua_settable(L, LUA_REGISTRYINDEX); | ||||
|  | ||||
|         // add functions (class, cast etc...) | ||||
|         lua_pushstring(L, "class"); | ||||
|         lua_pushcclosure(L, detail::create_class::stage1, 0); | ||||
|         lua_settable(L, LUA_GLOBALSINDEX); | ||||
|     } | ||||
|  | ||||
| } // namespace luabind | ||||
|  | ||||
							
								
								
									
										37
									
								
								lua/luabind/overload_rep.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lua/luabind/overload_rep.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| // Copyright (c) 2005 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/detail/overload_rep.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail | ||||
| { | ||||
| 	int overload_rep::call(lua_State* L, bool force_static_call) const  | ||||
| 	{  | ||||
| 		if (force_static_call) | ||||
| 			return call_fun_static(L); | ||||
| 		else | ||||
| 			return call_fun(L); | ||||
| 	} | ||||
|  | ||||
| }} // namespace luabind::detail | ||||
|  | ||||
|  | ||||
							
								
								
									
										51
									
								
								lua/luabind/pcall.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								lua/luabind/pcall.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/detail/pcall.hpp> | ||||
| #include <luabind/error.hpp> | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail | ||||
| { | ||||
| 	int pcall(lua_State *L, int nargs, int nresults) | ||||
| 	{ | ||||
| 		pcall_callback_fun e = get_pcall_callback(); | ||||
| 		int en = 0; | ||||
| 		if ( e ) | ||||
| 		{ | ||||
| 			int base = lua_gettop(L) - nargs; | ||||
| 			lua_pushcfunction(L, e); | ||||
| 			lua_insert(L, base);  // push pcall_callback under chunk and args | ||||
| 			en = base; | ||||
|   		} | ||||
| 		int result = lua_pcall(L, nargs, nresults, en); | ||||
| 		if ( en ) | ||||
| 			lua_remove(L, en);  // remove pcall_callback | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	int resume_impl(lua_State *L, int nargs, int) | ||||
| 	{ | ||||
| 		return lua_resume(L, nargs); | ||||
| 	} | ||||
|  | ||||
| }} | ||||
							
								
								
									
										176
									
								
								lua/luabind/ref.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								lua/luabind/ref.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,176 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <algorithm> | ||||
| #include <luabind/config.hpp> | ||||
| #include <luabind/detail/ref.hpp> | ||||
| #include <luabind/lua_include.hpp> | ||||
| #include <luabind/detail/debug.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail | ||||
| { | ||||
|  | ||||
| // most of the code in this file comes from | ||||
| // lauxlib.c in lua distribution | ||||
|  | ||||
| /****************************************************************************** | ||||
| * Copyright (C) 1994-2003 Tecgraf, PUC-Rio.  All rights reserved. | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining | ||||
| * a copy of this software and associated documentation files (the | ||||
| * "Software"), to deal in the Software without restriction, including | ||||
| * without limitation the rights to use, copy, modify, merge, publish, | ||||
| * distribute, sublicense, and/or sell copies of the Software, and to | ||||
| * permit persons to whom the Software is furnished to do so, subject to | ||||
| * the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be | ||||
| * included in all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| ******************************************************************************/ | ||||
|  | ||||
| 	enum | ||||
| 	{ | ||||
| 		// the number of reserved references | ||||
| 		RESERVED_REFS = 2, | ||||
|  | ||||
| 		// free list of references | ||||
| 		FREELIST_REF = 1, | ||||
|  | ||||
| 		// array sizes (not used here) | ||||
| 		ARRAYSIZE_REF = 2 | ||||
| 	}; | ||||
|  | ||||
| 	int checkint (lua_State *L, int topop) | ||||
| 	{ | ||||
| 		int n = (int)lua_tonumber(L, -1); | ||||
| 		if (n == 0 && !lua_isnumber(L, -1)) n = -1; | ||||
| 		lua_pop(L, topop); | ||||
| 		return n; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	void getsizes (lua_State *L) | ||||
| 	{ | ||||
| 		lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); | ||||
| 		if (lua_isnil(L, -1)) {  /* no `size' table? */ | ||||
| 			lua_pop(L, 1);  /* remove nil */ | ||||
| 			lua_newtable(L);  /* create it */ | ||||
| 			lua_pushvalue(L, -1);  /* `size' will be its own metatable */ | ||||
| 			lua_setmetatable(L, -2); | ||||
| 			lua_pushliteral(L, "__mode"); | ||||
| 			lua_pushliteral(L, "k"); | ||||
| 			lua_rawset(L, -3);  /* metatable(N).__mode = "k" */ | ||||
| 			lua_pushvalue(L, -1); | ||||
| 			lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF);  /* store in register */ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void luaL_setn (lua_State *L, int t, int n) | ||||
| 	{ | ||||
| 		lua_pushliteral(L, "n"); | ||||
| 		lua_rawget(L, t); | ||||
| 		if (checkint(L, 1) >= 0) {  /* is there a numeric field `n'? */ | ||||
| 			lua_pushliteral(L, "n");  /* use it */ | ||||
| 			lua_pushnumber(L, n); | ||||
| 			lua_rawset(L, t); | ||||
| 		} | ||||
| 		else {  /* use `sizes' */ | ||||
| 			getsizes(L); | ||||
| 			lua_pushvalue(L, t); | ||||
| 			lua_pushnumber(L, n); | ||||
| 			lua_rawset(L, -3);  /* sizes[t] = n */ | ||||
| 			lua_pop(L, 1);  /* remove `sizes' */ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	int luaL_getn (lua_State *L, int t) | ||||
| 	{ | ||||
| 		int n; | ||||
| 		lua_pushliteral(L, "n");  /* try t.n */ | ||||
| 		lua_rawget(L, t); | ||||
| 		if ((n = checkint(L, 1)) >= 0) return n; | ||||
| 		getsizes(L);  /* else try sizes[t] */ | ||||
| 		lua_pushvalue(L, t); | ||||
| 		lua_rawget(L, -2); | ||||
| 		if ((n = checkint(L, 2)) >= 0) return n; | ||||
| 		for (n = 1; ; n++) {  /* else must count elements */ | ||||
| 			lua_rawgeti(L, t, n); | ||||
| 			if (lua_isnil(L, -1)) break; | ||||
| 			lua_pop(L, 1); | ||||
| 		} | ||||
| 		lua_pop(L, 1); | ||||
| 		return n - 1; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	// based on luaL_ref | ||||
| 	int LUABIND_API ref(lua_State *L) | ||||
| 	{ | ||||
| 		int t = LUA_REGISTRYINDEX; | ||||
|  | ||||
| 		int ref; | ||||
| 		if (lua_isnil(L, -1)) | ||||
| 		{ | ||||
| 			lua_pop(L, 1);  /* remove from stack */ | ||||
| 			return LUA_REFNIL;  /* `nil' has a unique fixed reference */ | ||||
| 		} | ||||
|  | ||||
| 		lua_rawgeti(L, t, FREELIST_REF);  /* get first free element */ | ||||
| 		ref = (int)lua_tonumber(L, -1);  /* ref = t[FREELIST_REF] */ | ||||
| 		lua_pop(L, 1);  /* remove it from stack */ | ||||
| 		if (ref != 0) {  /* any free element? */ | ||||
| 			lua_rawgeti(L, t, ref);  /* remove it from list */ | ||||
| 			lua_rawseti(L, t, FREELIST_REF);  /* (t[FREELIST_REF] = t[ref]) */ | ||||
| 		} | ||||
| 		else {  /* no free elements */ | ||||
| 			ref = ::luabind::detail::luaL_getn(L, t); | ||||
| 			if (ref < RESERVED_REFS) | ||||
| 			ref = RESERVED_REFS;  /* skip reserved references */ | ||||
| 			ref++;  /* create new reference */ | ||||
| 			::luabind::detail::luaL_setn(L, t, ref); | ||||
| 		} | ||||
| 		lua_rawseti(L, t, ref); | ||||
| 		return ref; | ||||
| 	} | ||||
|  | ||||
| 	void LUABIND_API unref(lua_State *L, int ref) | ||||
| 	{ | ||||
| 		LUABIND_CHECK_STACK(L); | ||||
|  | ||||
| 		int t = LUA_REGISTRYINDEX; | ||||
| 		if (ref >= 0) { | ||||
| 			lua_rawgeti(L, t, FREELIST_REF); | ||||
| 			lua_rawseti(L, t, ref);  /* t[ref] = t[FREELIST_REF] */ | ||||
| 			lua_pushnumber(L, ref); | ||||
| 			lua_rawseti(L, t, FREELIST_REF);  /* t[FREELIST_REF] = ref */ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| }} | ||||
							
								
								
									
										199
									
								
								lua/luabind/scope.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								lua/luabind/scope.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| // Copyright (c) 2004 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/scope.hpp> | ||||
| #include <luabind/detail/debug.hpp> | ||||
| #include <luabind/detail/stack_utils.hpp> | ||||
| #include <cassert> | ||||
|  | ||||
| namespace luabind { namespace detail { | ||||
|  | ||||
|     registration::registration() | ||||
|         : m_next(0) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     registration::~registration() | ||||
|     { | ||||
|         delete m_next; | ||||
|     } | ||||
|  | ||||
|     } // namespace detail | ||||
|      | ||||
|     scope::scope() | ||||
|         : m_chain(0) | ||||
|     { | ||||
|     } | ||||
|      | ||||
|     scope::scope(std::auto_ptr<detail::registration> reg) | ||||
|         : m_chain(reg.release()) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     scope::scope(scope const& other) | ||||
|         : m_chain(other.m_chain) | ||||
|     { | ||||
|         const_cast<scope&>(other).m_chain = 0; | ||||
|     } | ||||
|  | ||||
|     scope::~scope() | ||||
|     { | ||||
|         delete m_chain; | ||||
|     } | ||||
|      | ||||
|     scope& scope::operator,(scope s) | ||||
|     { | ||||
|         if (!m_chain)  | ||||
|         { | ||||
|             m_chain = s.m_chain; | ||||
|             s.m_chain = 0; | ||||
|             return *this; | ||||
|         } | ||||
|          | ||||
|         for (detail::registration* c = m_chain;; c = c->m_next) | ||||
|         { | ||||
|             if (!c->m_next) | ||||
|             { | ||||
|                 c->m_next = s.m_chain; | ||||
|                 s.m_chain = 0; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     void scope::register_(lua_State* L) const | ||||
|     { | ||||
|         for (detail::registration* r = m_chain; r != 0; r = r->m_next) | ||||
|         { | ||||
| 			LUABIND_CHECK_STACK(L); | ||||
|             r->register_(L); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } // namespace luabind | ||||
|  | ||||
| namespace luabind { | ||||
|  | ||||
|     namespace { | ||||
|  | ||||
|         struct lua_pop_stack | ||||
|         { | ||||
|             lua_pop_stack(lua_State* L) | ||||
|                 : m_state(L) | ||||
|             { | ||||
|             } | ||||
|  | ||||
|             ~lua_pop_stack() | ||||
|             { | ||||
|                 lua_pop(m_state, 1); | ||||
|             } | ||||
|  | ||||
|             lua_State* m_state; | ||||
|         }; | ||||
|  | ||||
|     } // namespace unnamed | ||||
|      | ||||
|     module_::module_(lua_State* L, char const* name = 0) | ||||
|         : m_state(L) | ||||
|         , m_name(name) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void module_::operator[](scope s) | ||||
|     { | ||||
|         if (m_name) | ||||
|         { | ||||
|             lua_pushstring(m_state, m_name); | ||||
|             lua_gettable(m_state, LUA_GLOBALSINDEX); | ||||
|  | ||||
|             if (!lua_istable(m_state, -1)) | ||||
|             { | ||||
|                 lua_pop(m_state, 1); | ||||
|  | ||||
|                 lua_newtable(m_state); | ||||
|                 lua_pushstring(m_state, m_name); | ||||
|                 lua_pushvalue(m_state, -2); | ||||
|                 lua_settable(m_state, LUA_GLOBALSINDEX); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             lua_pushvalue(m_state, LUA_GLOBALSINDEX); | ||||
|         } | ||||
|  | ||||
|         lua_pop_stack guard(m_state); | ||||
|  | ||||
|         s.register_(m_state); | ||||
|     } | ||||
|  | ||||
|     struct namespace_::registration_ : detail::registration | ||||
|     { | ||||
|         registration_(char const* name) | ||||
|             : m_name(name) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         void register_(lua_State* L) const | ||||
|         { | ||||
| 			LUABIND_CHECK_STACK(L); | ||||
|             assert(lua_gettop(L) >= 1); | ||||
|  | ||||
|             lua_pushstring(L, m_name); | ||||
|             lua_gettable(L, -2); | ||||
|  | ||||
| 			detail::stack_pop p(L, 1); // pops the table on exit | ||||
|  | ||||
|             if (!lua_istable(L, -1)) | ||||
|             { | ||||
|                 lua_pop(L, 1); | ||||
|  | ||||
|                 lua_newtable(L); | ||||
|                 lua_pushstring(L, m_name); | ||||
|                 lua_pushvalue(L, -2); | ||||
|                 lua_settable(L, -4); | ||||
|             } | ||||
|  | ||||
|             m_scope.register_(L); | ||||
|         } | ||||
|  | ||||
|         char const* m_name; | ||||
|         scope m_scope; | ||||
|     }; | ||||
|  | ||||
|     namespace_::namespace_(char const* name) | ||||
|         : scope(std::auto_ptr<detail::registration>( | ||||
|               m_registration = new registration_(name))) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     namespace_& namespace_::operator[](scope s) | ||||
|     { | ||||
|         m_registration->m_scope.operator,(s);         | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
| } // namespace luabind | ||||
|  | ||||
							
								
								
									
										57
									
								
								lua/luabind/stack_content_by_name.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lua/luabind/stack_content_by_name.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/luabind.hpp> | ||||
|  | ||||
| using namespace luabind::detail; | ||||
|  | ||||
| std::string luabind::detail::stack_content_by_name(lua_State* L, int start_index) | ||||
| { | ||||
| 	std::string ret; | ||||
| 	int top = lua_gettop(L); | ||||
| 	for (int i = start_index; i <= top; ++i) | ||||
| 	{ | ||||
| 		object_rep* obj = is_class_object(L, i); | ||||
| 		class_rep* crep = is_class_rep(L, i)?(class_rep*)lua_touserdata(L, i):0; | ||||
| 		if (obj == 0 && crep == 0) | ||||
| 		{ | ||||
| 			int type = lua_type(L, i); | ||||
| 			ret += lua_typename(L, type); | ||||
| 		} | ||||
| 		else if (obj) | ||||
| 		{ | ||||
| 			if (obj->flags() & object_rep::constant) ret += "const "; | ||||
| 			ret += obj->crep()->name(); | ||||
| 		} | ||||
| 		else if (crep) | ||||
| 		{ | ||||
| 			ret += "<"; | ||||
| 			ret += crep->name(); | ||||
| 			ret += ">"; | ||||
| 		} | ||||
| 		if (i < top) ret += ", "; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
							
								
								
									
										203
									
								
								lua/luabind/weak_ref.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								lua/luabind/weak_ref.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | ||||
| // Copyright (c) 2004 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <algorithm> | ||||
|  | ||||
| #include <luabind/lua_include.hpp> | ||||
|  | ||||
| #include <luabind/config.hpp> | ||||
| #include <luabind/weak_ref.hpp> | ||||
| #include <cassert> | ||||
|  | ||||
| namespace luabind { | ||||
|  | ||||
| // allocation code from lauxlib.c | ||||
| /****************************************************************************** | ||||
| * Copyright (C) 1994-2003 Tecgraf, PUC-Rio.  All rights reserved. | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining | ||||
| * a copy of this software and associated documentation files (the | ||||
| * "Software"), to deal in the Software without restriction, including | ||||
| * without limitation the rights to use, copy, modify, merge, publish, | ||||
| * distribute, sublicense, and/or sell copies of the Software, and to | ||||
| * permit persons to whom the Software is furnished to do so, subject to | ||||
| * the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be | ||||
| * included in all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| ******************************************************************************/ | ||||
|      | ||||
|     namespace { | ||||
|  | ||||
|         enum | ||||
|         { | ||||
|             freelist_ref = 1, count_ref = 2 | ||||
|         }; | ||||
|          | ||||
|         void get_weak_table(lua_State* L) | ||||
|         { | ||||
|             lua_pushliteral(L, "__luabind_weak_refs"); | ||||
|             lua_gettable(L, LUA_REGISTRYINDEX); | ||||
|  | ||||
|             if (lua_isnil(L, -1)) | ||||
|             { | ||||
|                 lua_pop(L, 1); | ||||
|                 lua_newtable(L); | ||||
|                 // metatable | ||||
|                 lua_newtable(L); | ||||
|                 lua_pushliteral(L, "__mode"); | ||||
|                 lua_pushliteral(L, "v"); | ||||
|                 lua_rawset(L, -3); | ||||
|                 // set metatable | ||||
|                 lua_setmetatable(L, -2); | ||||
|                 lua_pushnumber(L, 0); | ||||
|                 lua_rawseti(L, -2, freelist_ref); | ||||
|                 lua_pushnumber(L, 2); | ||||
|                 lua_rawseti(L, -2, count_ref); | ||||
|  | ||||
|                 lua_pushliteral(L, "__luabind_weak_refs"); | ||||
|                 lua_pushvalue(L, -2); | ||||
|                 lua_settable(L, LUA_REGISTRYINDEX); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } // namespace unnamed | ||||
|  | ||||
|     struct weak_ref::impl | ||||
|     { | ||||
|         impl(lua_State* s, int index) | ||||
|             : count(0) | ||||
|             , state(s) | ||||
|             , ref(0) | ||||
|         { | ||||
|             lua_pushvalue(s, index); | ||||
|             get_weak_table(s); | ||||
|  | ||||
|             lua_rawgeti(s, -1, freelist_ref); | ||||
|             ref = (int)lua_tonumber(s, -1); | ||||
|             lua_pop(s, 1); | ||||
|  | ||||
|             if (ref == 0) | ||||
|             { | ||||
|                 lua_rawgeti(s, -1, count_ref); | ||||
|                 ref = (int)lua_tonumber(s, -1) + 1; | ||||
|                 lua_pop(s, 1); | ||||
|                 lua_pushnumber(s, ref); | ||||
|                 lua_rawseti(s, -2, count_ref); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 lua_rawgeti(s, -1, ref); | ||||
|                 lua_rawseti(s, -2, freelist_ref); | ||||
|             } | ||||
|  | ||||
|             lua_pushvalue(s, -2); // duplicate value | ||||
|             lua_rawseti(s, -2, ref); | ||||
|             lua_pop(s, 2); // pop weakref table and value | ||||
|         } | ||||
|  | ||||
|         ~impl() | ||||
|         { | ||||
|             get_weak_table(state); | ||||
|             lua_rawgeti(state, -1, freelist_ref); | ||||
|             lua_rawseti(state, -2, ref); | ||||
|             lua_pushnumber(state, ref); | ||||
|             lua_rawseti(state, -2, freelist_ref); | ||||
|             lua_pop(state, 1); | ||||
|         } | ||||
|  | ||||
|         int count; | ||||
|         lua_State* state; | ||||
|         int ref; | ||||
|     }; | ||||
|  | ||||
|     weak_ref::weak_ref() | ||||
|         : m_impl(0) | ||||
|     { | ||||
|     } | ||||
|      | ||||
|     weak_ref::weak_ref(lua_State* L, int index) | ||||
|         : m_impl(new impl(L, index)) | ||||
|     { | ||||
|         m_impl->count = 1; | ||||
|     } | ||||
|  | ||||
|     weak_ref::weak_ref(weak_ref const& other) | ||||
|         : m_impl(other.m_impl) | ||||
|     { | ||||
|         if (m_impl) ++m_impl->count; | ||||
|     } | ||||
|  | ||||
|     weak_ref::~weak_ref() | ||||
|     { | ||||
|         if (m_impl && --m_impl->count == 0) | ||||
|         { | ||||
|             delete m_impl; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     weak_ref& weak_ref::operator=(weak_ref const& other) | ||||
|     { | ||||
|         weak_ref(other).swap(*this); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     void weak_ref::swap(weak_ref& other) | ||||
|     { | ||||
|         std::swap(m_impl, other.m_impl); | ||||
|     } | ||||
|  | ||||
|     int weak_ref::id() const | ||||
|     { | ||||
|         assert(m_impl); | ||||
| 		return m_impl->ref; | ||||
|     } | ||||
|  | ||||
| 	// L may not be the same pointer as | ||||
| 	// was used when creating this reference | ||||
| 	// since it may be a thread that shares | ||||
| 	// the same globals table. | ||||
|     void weak_ref::get(lua_State* L) const | ||||
|     { | ||||
|         assert(m_impl); | ||||
| 		assert(L); | ||||
|         get_weak_table(L); | ||||
|         lua_rawgeti(L, -1, m_impl->ref); | ||||
|         lua_remove(L, -2); | ||||
|     } | ||||
|  | ||||
|     lua_State* weak_ref::state() const | ||||
|     { | ||||
|         assert(m_impl); | ||||
|         return m_impl->state; | ||||
|     } | ||||
|      | ||||
| } // namespace luabind | ||||
|  | ||||
							
								
								
									
										57
									
								
								lua/luabind/wrapper_base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lua/luabind/wrapper_base.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| // Copyright (c) 2003 Daniel Wallin and Arvid Norberg | ||||
|  | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a | ||||
| // copy of this software and associated documentation files (the "Software"), | ||||
| // to deal in the Software without restriction, including without limitation | ||||
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
| // and/or sell copies of the Software, and to permit persons to whom the | ||||
| // Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| // The above copyright notice and this permission notice shall be included | ||||
| // in all copies or substantial portions of the Software. | ||||
|  | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | ||||
| // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||||
| // OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include "stdafx.h" | ||||
| #include <luabind/config.hpp> | ||||
| #include <luabind/lua_include.hpp> | ||||
| #include <luabind/detail/object_rep.hpp> | ||||
| #include <luabind/detail/class_rep.hpp> | ||||
| #include <luabind/detail/stack_utils.hpp> | ||||
|  | ||||
| namespace luabind { namespace detail | ||||
| { | ||||
| 	void do_call_member_selection(lua_State* L, char const* name) | ||||
| 	{ | ||||
| 		object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, -1)); | ||||
| 		lua_pop(L, 1); // pop self | ||||
|  | ||||
| 		obj->crep()->get_table(L); // push the crep table | ||||
| 		lua_pushstring(L, name); | ||||
| 		lua_gettable(L, -2); | ||||
| 		lua_remove(L, -2); // remove the crep table | ||||
|  | ||||
| 		{ | ||||
| 			if (!lua_iscfunction(L, -1)) return; | ||||
| 			if (lua_getupvalue(L, -1, 3) == 0) return; | ||||
| 			detail::stack_pop p(L, 1); | ||||
| 			if (lua_touserdata(L, -1) != reinterpret_cast<void*>(0x1337)) return; | ||||
| 		} | ||||
|  | ||||
| 		// this (usually) means the function has not been | ||||
| 		// overridden by lua, call the default implementation | ||||
| 		lua_pop(L, 1); | ||||
| 		obj->crep()->get_default_table(L); // push the crep table | ||||
| 		lua_pushstring(L, name); | ||||
| 		lua_gettable(L, -2); | ||||
| 		assert(!lua_isnil(L, -1)); | ||||
| 		lua_remove(L, -2); // remove the crep table | ||||
| 	} | ||||
| }} | ||||
							
								
								
									
										183
									
								
								lua/src/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								lua/src/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | ||||
| # makefile for building Lua | ||||
| # see ../INSTALL for installation instructions | ||||
| # see ../Makefile and luaconf.h for further customization | ||||
|  | ||||
| # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= | ||||
|  | ||||
| # Your platform. See PLATS for possible values. | ||||
| PLAT= none | ||||
|  | ||||
| CC= gcc | ||||
| CFLAGS= -O2 -Wall $(MYCFLAGS) | ||||
| AR= ar rcu | ||||
| RANLIB= ranlib | ||||
| RM= rm -f | ||||
| LIBS= -lm $(MYLIBS) | ||||
|  | ||||
| MYCFLAGS= | ||||
| MYLDFLAGS= | ||||
| MYLIBS= | ||||
|  | ||||
| # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= | ||||
|  | ||||
| PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris | ||||
|  | ||||
| LUA_A=	liblua.a | ||||
| CORE_O=	lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ | ||||
| 	lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o  \ | ||||
| 	lundump.o lvm.o lzio.o | ||||
| LIB_O=	lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ | ||||
| 	lstrlib.o loadlib.o linit.o | ||||
|  | ||||
| LUA_T=	lua | ||||
| LUA_O=	lua.o | ||||
|  | ||||
| LUAC_T=	luac | ||||
| LUAC_O=	luac.o print.o | ||||
|  | ||||
| ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) | ||||
| ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) | ||||
| ALL_A= $(LUA_A) | ||||
|  | ||||
| default: $(PLAT) | ||||
|  | ||||
| all:	$(ALL_T) | ||||
|  | ||||
| o:	$(ALL_O) | ||||
|  | ||||
| a:	$(ALL_A) | ||||
|  | ||||
| $(LUA_A): $(CORE_O) $(LIB_O) | ||||
| 	$(AR) $@ $? | ||||
| 	$(RANLIB) $@ | ||||
|  | ||||
| $(LUA_T): $(LUA_O) $(LUA_A) | ||||
| 	$(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) | ||||
|  | ||||
| $(LUAC_T): $(LUAC_O) $(LUA_A) | ||||
| 	$(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) | ||||
|  | ||||
| clean: | ||||
| 	$(RM) $(ALL_T) $(ALL_O) | ||||
|  | ||||
| depend: | ||||
| 	@$(CC) $(CFLAGS) -MM l*.c print.c | ||||
|  | ||||
| echo: | ||||
| 	@echo "PLAT = $(PLAT)" | ||||
| 	@echo "CC = $(CC)" | ||||
| 	@echo "CFLAGS = $(CFLAGS)" | ||||
| 	@echo "AR = $(AR)" | ||||
| 	@echo "RANLIB = $(RANLIB)" | ||||
| 	@echo "RM = $(RM)" | ||||
| 	@echo "MYCFLAGS = $(MYCFLAGS)" | ||||
| 	@echo "MYLDFLAGS = $(MYLDFLAGS)" | ||||
| 	@echo "MYLIBS = $(MYLIBS)" | ||||
|  | ||||
| # convenience targets for popular platforms | ||||
|  | ||||
| none: | ||||
| 	@echo "Please choose a platform:" | ||||
| 	@echo "   $(PLATS)" | ||||
|  | ||||
| aix: | ||||
| 	$(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" | ||||
|  | ||||
| ansi: | ||||
| 	$(MAKE) all MYCFLAGS=-DLUA_ANSI | ||||
|  | ||||
| bsd: | ||||
| 	$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" | ||||
|  | ||||
| freebsd: | ||||
| 	$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" | ||||
|  | ||||
| generic: | ||||
| 	$(MAKE) all MYCFLAGS= | ||||
|  | ||||
| linux: | ||||
| 	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" | ||||
|  | ||||
| macosx: | ||||
| 	$(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX | ||||
| # use this on Mac OS X 10.4 | ||||
| #	$(MAKE) all MYCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" MYLIBS="-lreadline" | ||||
|  | ||||
| mingw: | ||||
| 	$(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ | ||||
| 	"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ | ||||
| 	"MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe | ||||
| 	$(MAKE) "LUAC_T=luac.exe" luac.exe | ||||
|  | ||||
| posix: | ||||
| 	$(MAKE) all MYCFLAGS=-DLUA_USE_POSIX | ||||
|  | ||||
| solaris: | ||||
| 	$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" | ||||
|  | ||||
| # list targets that do not create files (but not all makes understand .PHONY) | ||||
| .PHONY: all $(PLATS) default o a clean depend echo none | ||||
|  | ||||
| # DO NOT DELETE | ||||
|  | ||||
| lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ | ||||
|   lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ | ||||
|   lundump.h lvm.h | ||||
| lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h | ||||
| lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ | ||||
|   lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ | ||||
|   ltable.h | ||||
| ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ | ||||
|   llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ | ||||
|   lfunc.h lstring.h lgc.h ltable.h lvm.h | ||||
| ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ | ||||
|   lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ | ||||
|   ltable.h lundump.h lvm.h | ||||
| ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ | ||||
|   lzio.h lmem.h lundump.h | ||||
| lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ | ||||
|   lstate.h ltm.h lzio.h | ||||
| lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ | ||||
|   lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h | ||||
| linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h | ||||
| liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ | ||||
|   lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h | ||||
| lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ | ||||
|   ltm.h lzio.h lmem.h ldo.h | ||||
| loadlib.o: loadlib.c lauxlib.h lua.h luaconf.h lobject.h llimits.h \ | ||||
|   lualib.h | ||||
| lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ | ||||
|   ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h | ||||
| lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h | ||||
| loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ | ||||
|   lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ | ||||
|   lfunc.h lstring.h lgc.h ltable.h | ||||
| lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ | ||||
|   ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h | ||||
| lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ | ||||
|   ltm.h lzio.h lstring.h lgc.h | ||||
| lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ | ||||
|   ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h | ||||
| ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ | ||||
|   lmem.h lstring.h lgc.h ltable.h | ||||
| lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h | ||||
| luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ | ||||
|   lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ | ||||
|   lundump.h | ||||
| lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ | ||||
|   llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h | ||||
| lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ | ||||
|   lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h | ||||
| lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ | ||||
|   lzio.h | ||||
| print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ | ||||
|   ltm.h lzio.h lmem.h lopcodes.h lundump.h | ||||
|  | ||||
| # (end of Makefile) | ||||
							
								
								
									
										1089
									
								
								lua/src/lapi.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1089
									
								
								lua/src/lapi.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										653
									
								
								lua/src/lauxlib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										653
									
								
								lua/src/lauxlib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,653 @@ | ||||
| /* | ||||
| ** $Id: lauxlib.c,v 1.159 2006/03/21 19:31:09 roberto Exp $ | ||||
| ** Auxiliary functions for building Lua libraries | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <ctype.h> | ||||
| #include <errno.h> | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
|  | ||||
| /* This file uses only the official API of Lua. | ||||
| ** Any function declared here could be written as an application function. | ||||
| */ | ||||
|  | ||||
| #define lauxlib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
|  | ||||
|  | ||||
| #define FREELIST_REF	0	/* free list of references */ | ||||
|  | ||||
|  | ||||
| /* convert a stack index to positive */ | ||||
| #define abs_index(L, i)		((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ | ||||
| 					lua_gettop(L) + (i) + 1) | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Error-report functions | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { | ||||
|   lua_Debug ar; | ||||
|   if (!lua_getstack(L, 0, &ar))  /* no stack frame? */ | ||||
|     return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); | ||||
|   lua_getinfo(L, "n", &ar); | ||||
|   if (strcmp(ar.namewhat, "method") == 0) { | ||||
|     narg--;  /* do not count `self' */ | ||||
|     if (narg == 0)  /* error is in the self argument itself? */ | ||||
|       return luaL_error(L, "calling " LUA_QS " on bad self (%s)", | ||||
|                            ar.name, extramsg); | ||||
|   } | ||||
|   if (ar.name == NULL) | ||||
|     ar.name = "?"; | ||||
|   return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", | ||||
|                         narg, ar.name, extramsg); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { | ||||
|   const char *msg = lua_pushfstring(L, "%s expected, got %s", | ||||
|                                     tname, luaL_typename(L, narg)); | ||||
|   return luaL_argerror(L, narg, msg); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void tag_error (lua_State *L, int narg, int tag) { | ||||
|   luaL_typerror(L, narg, lua_typename(L, tag)); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_where (lua_State *L, int level) { | ||||
|   lua_Debug ar; | ||||
|   if (lua_getstack(L, level, &ar)) {  /* check function at level */ | ||||
|     lua_getinfo(L, "Sl", &ar);  /* get info about it */ | ||||
|     if (ar.currentline > 0) {  /* is there info? */ | ||||
|       lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   lua_pushliteral(L, "");  /* else, no information available... */ | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { | ||||
|   va_list argp; | ||||
|   va_start(argp, fmt); | ||||
|   luaL_where(L, 1); | ||||
|   lua_pushvfstring(L, fmt, argp); | ||||
|   va_end(argp); | ||||
|   lua_concat(L, 2); | ||||
|   return lua_error(L); | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, | ||||
|                                  const char *const lst[]) { | ||||
|   const char *name = (def) ? luaL_optstring(L, narg, def) : | ||||
|                              luaL_checkstring(L, narg); | ||||
|   int i; | ||||
|   for (i=0; lst[i]; i++) | ||||
|     if (strcmp(lst[i], name) == 0) | ||||
|       return i; | ||||
|   return luaL_argerror(L, narg, | ||||
|                        lua_pushfstring(L, "invalid option " LUA_QS, name)); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { | ||||
|   lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get registry.name */ | ||||
|   if (!lua_isnil(L, -1))  /* name already in use? */ | ||||
|     return 0;  /* leave previous value on top, but return 0 */ | ||||
|   lua_pop(L, 1); | ||||
|   lua_newtable(L);  /* create metatable */ | ||||
|   lua_pushvalue(L, -1); | ||||
|   lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { | ||||
|   void *p = lua_touserdata(L, ud); | ||||
|   if (p != NULL) {  /* value is a userdata? */ | ||||
|     if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */ | ||||
|       lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get correct metatable */ | ||||
|       if (lua_rawequal(L, -1, -2)) {  /* does it have the correct mt? */ | ||||
|         lua_pop(L, 2);  /* remove both metatables */ | ||||
|         return p; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   luaL_typerror(L, ud, tname);  /* else error */ | ||||
|   return NULL;  /* to avoid warnings */ | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { | ||||
|   if (!lua_checkstack(L, space)) | ||||
|     luaL_error(L, "stack overflow (%s)", mes); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { | ||||
|   if (lua_type(L, narg) != t) | ||||
|     tag_error(L, narg, t); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_checkany (lua_State *L, int narg) { | ||||
|   if (lua_type(L, narg) == LUA_TNONE) | ||||
|     luaL_argerror(L, narg, "value expected"); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { | ||||
|   const char *s = lua_tolstring(L, narg, len); | ||||
|   if (!s) tag_error(L, narg, LUA_TSTRING); | ||||
|   return s; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, | ||||
|                                         const char *def, size_t *len) { | ||||
|   if (lua_isnoneornil(L, narg)) { | ||||
|     if (len) | ||||
|       *len = (def ? strlen(def) : 0); | ||||
|     return def; | ||||
|   } | ||||
|   else return luaL_checklstring(L, narg, len); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { | ||||
|   lua_Number d = lua_tonumber(L, narg); | ||||
|   if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */ | ||||
|     tag_error(L, narg, LUA_TNUMBER); | ||||
|   return d; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { | ||||
|   return luaL_opt(L, luaL_checknumber, narg, def); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { | ||||
|   lua_Integer d = lua_tointeger(L, narg); | ||||
|   if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */ | ||||
|     tag_error(L, narg, LUA_TNUMBER); | ||||
|   return d; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, | ||||
|                                                       lua_Integer def) { | ||||
|   return luaL_opt(L, luaL_checkinteger, narg, def); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { | ||||
|   if (!lua_getmetatable(L, obj))  /* no metatable? */ | ||||
|     return 0; | ||||
|   lua_pushstring(L, event); | ||||
|   lua_rawget(L, -2); | ||||
|   if (lua_isnil(L, -1)) { | ||||
|     lua_pop(L, 2);  /* remove metatable and metafield */ | ||||
|     return 0; | ||||
|   } | ||||
|   else { | ||||
|     lua_remove(L, -2);  /* remove only metatable */ | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { | ||||
|   obj = abs_index(L, obj); | ||||
|   if (!luaL_getmetafield(L, obj, event))  /* no metafield? */ | ||||
|     return 0; | ||||
|   lua_pushvalue(L, obj); | ||||
|   lua_call(L, 1, 1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void (luaL_register) (lua_State *L, const char *libname, | ||||
|                                 const luaL_Reg *l) { | ||||
|   luaI_openlib(L, libname, l, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int libsize (const luaL_Reg *l) { | ||||
|   int size = 0; | ||||
|   for (; l->name; l++) size++; | ||||
|   return size; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaI_openlib (lua_State *L, const char *libname, | ||||
|                               const luaL_Reg *l, int nup) { | ||||
|   if (libname) { | ||||
|     int size = libsize(l); | ||||
|     /* check whether lib already exists */ | ||||
|     luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); | ||||
|     lua_getfield(L, -1, libname);  /* get _LOADED[libname] */ | ||||
|     if (!lua_istable(L, -1)) {  /* not found? */ | ||||
|       lua_pop(L, 1);  /* remove previous result */ | ||||
|       /* try global variable (and create one if it does not exist) */ | ||||
|       if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) | ||||
|         luaL_error(L, "name conflict for module " LUA_QS, libname); | ||||
|       lua_pushvalue(L, -1); | ||||
|       lua_setfield(L, -3, libname);  /* _LOADED[libname] = new table */ | ||||
|     } | ||||
|     lua_remove(L, -2);  /* remove _LOADED table */ | ||||
|     lua_insert(L, -(nup+1));  /* move library table to below upvalues */ | ||||
|   } | ||||
|   for (; l->name; l++) { | ||||
|     int i; | ||||
|     for (i=0; i<nup; i++)  /* copy upvalues to the top */ | ||||
|       lua_pushvalue(L, -nup); | ||||
|     lua_pushcclosure(L, l->func, nup); | ||||
|     lua_setfield(L, -(nup+2), l->name); | ||||
|   } | ||||
|   lua_pop(L, nup);  /* remove upvalues */ | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** getn-setn: size for arrays | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
| #if defined(LUA_COMPAT_GETN) | ||||
|  | ||||
| static int checkint (lua_State *L, int topop) { | ||||
|   int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; | ||||
|   lua_pop(L, topop); | ||||
|   return n; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void getsizes (lua_State *L) { | ||||
|   lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); | ||||
|   if (lua_isnil(L, -1)) {  /* no `size' table? */ | ||||
|     lua_pop(L, 1);  /* remove nil */ | ||||
|     lua_newtable(L);  /* create it */ | ||||
|     lua_pushvalue(L, -1);  /* `size' will be its own metatable */ | ||||
|     lua_setmetatable(L, -2); | ||||
|     lua_pushliteral(L, "kv"); | ||||
|     lua_setfield(L, -2, "__mode");  /* metatable(N).__mode = "kv" */ | ||||
|     lua_pushvalue(L, -1); | ||||
|     lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");  /* store in register */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_setn (lua_State *L, int t, int n) { | ||||
|   t = abs_index(L, t); | ||||
|   lua_pushliteral(L, "n"); | ||||
|   lua_rawget(L, t); | ||||
|   if (checkint(L, 1) >= 0) {  /* is there a numeric field `n'? */ | ||||
|     lua_pushliteral(L, "n");  /* use it */ | ||||
|     lua_pushinteger(L, n); | ||||
|     lua_rawset(L, t); | ||||
|   } | ||||
|   else {  /* use `sizes' */ | ||||
|     getsizes(L); | ||||
|     lua_pushvalue(L, t); | ||||
|     lua_pushinteger(L, n); | ||||
|     lua_rawset(L, -3);  /* sizes[t] = n */ | ||||
|     lua_pop(L, 1);  /* remove `sizes' */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_getn (lua_State *L, int t) { | ||||
|   int n; | ||||
|   t = abs_index(L, t); | ||||
|   lua_pushliteral(L, "n");  /* try t.n */ | ||||
|   lua_rawget(L, t); | ||||
|   if ((n = checkint(L, 1)) >= 0) return n; | ||||
|   getsizes(L);  /* else try sizes[t] */ | ||||
|   lua_pushvalue(L, t); | ||||
|   lua_rawget(L, -2); | ||||
|   if ((n = checkint(L, 2)) >= 0) return n; | ||||
|   return (int)lua_objlen(L, t); | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
|  | ||||
| LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, | ||||
|                                                                const char *r) { | ||||
|   const char *wild; | ||||
|   size_t l = strlen(p); | ||||
|   luaL_Buffer b; | ||||
|   luaL_buffinit(L, &b); | ||||
|   while ((wild = strstr(s, p)) != NULL) { | ||||
|     luaL_addlstring(&b, s, wild - s);  /* push prefix */ | ||||
|     luaL_addstring(&b, r);  /* push replacement in place of pattern */ | ||||
|     s = wild + l;  /* continue after `p' */ | ||||
|   } | ||||
|   luaL_addstring(&b, s);  /* push last suffix */ | ||||
|   luaL_pushresult(&b); | ||||
|   return lua_tostring(L, -1); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API const char *luaL_findtable (lua_State *L, int idx, | ||||
|                                        const char *fname, int szhint) { | ||||
|   const char *e; | ||||
|   lua_pushvalue(L, idx); | ||||
|   do { | ||||
|     e = strchr(fname, '.'); | ||||
|     if (e == NULL) e = fname + strlen(fname); | ||||
|     lua_pushlstring(L, fname, e - fname); | ||||
|     lua_rawget(L, -2); | ||||
|     if (lua_isnil(L, -1)) {  /* no such field? */ | ||||
|       lua_pop(L, 1);  /* remove this nil */ | ||||
|       lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ | ||||
|       lua_pushlstring(L, fname, e - fname); | ||||
|       lua_pushvalue(L, -2); | ||||
|       lua_settable(L, -4);  /* set new table into field */ | ||||
|     } | ||||
|     else if (!lua_istable(L, -1)) {  /* field has a non-table value? */ | ||||
|       lua_pop(L, 2);  /* remove table and value */ | ||||
|       return fname;  /* return problematic part of the name */ | ||||
|     } | ||||
|     lua_remove(L, -2);  /* remove previous table */ | ||||
|     fname = e + 1; | ||||
|   } while (*e == '.'); | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Generic Buffer manipulation | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
| #define bufflen(B)	((B)->p - (B)->buffer) | ||||
| #define bufffree(B)	((size_t)(LUAL_BUFFERSIZE - bufflen(B))) | ||||
|  | ||||
| #define LIMIT	(LUA_MINSTACK/2) | ||||
|  | ||||
|  | ||||
| static int emptybuffer (luaL_Buffer *B) { | ||||
|   size_t l = bufflen(B); | ||||
|   if (l == 0) return 0;  /* put nothing on stack */ | ||||
|   else { | ||||
|     lua_pushlstring(B->L, B->buffer, l); | ||||
|     B->p = B->buffer; | ||||
|     B->lvl++; | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void adjuststack (luaL_Buffer *B) { | ||||
|   if (B->lvl > 1) { | ||||
|     lua_State *L = B->L; | ||||
|     int toget = 1;  /* number of levels to concat */ | ||||
|     size_t toplen = lua_strlen(L, -1); | ||||
|     do { | ||||
|       size_t l = lua_strlen(L, -(toget+1)); | ||||
|       if (B->lvl - toget + 1 >= LIMIT || toplen > l) { | ||||
|         toplen += l; | ||||
|         toget++; | ||||
|       } | ||||
|       else break; | ||||
|     } while (toget < B->lvl); | ||||
|     lua_concat(L, toget); | ||||
|     B->lvl = B->lvl - toget + 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { | ||||
|   if (emptybuffer(B)) | ||||
|     adjuststack(B); | ||||
|   return B->buffer; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { | ||||
|   while (l--) | ||||
|     luaL_addchar(B, *s++); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { | ||||
|   luaL_addlstring(B, s, strlen(s)); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_pushresult (luaL_Buffer *B) { | ||||
|   emptybuffer(B); | ||||
|   lua_concat(B->L, B->lvl); | ||||
|   B->lvl = 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_addvalue (luaL_Buffer *B) { | ||||
|   lua_State *L = B->L; | ||||
|   size_t vl; | ||||
|   const char *s = lua_tolstring(L, -1, &vl); | ||||
|   if (vl <= bufffree(B)) {  /* fit into buffer? */ | ||||
|     memcpy(B->p, s, vl);  /* put it there */ | ||||
|     B->p += vl; | ||||
|     lua_pop(L, 1);  /* remove from stack */ | ||||
|   } | ||||
|   else { | ||||
|     if (emptybuffer(B)) | ||||
|       lua_insert(L, -2);  /* put buffer before new value */ | ||||
|     B->lvl++;  /* add new value into B stack */ | ||||
|     adjuststack(B); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { | ||||
|   B->L = L; | ||||
|   B->p = B->buffer; | ||||
|   B->lvl = 0; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_ref (lua_State *L, int t) { | ||||
|   int ref; | ||||
|   t = abs_index(L, t); | ||||
|   if (lua_isnil(L, -1)) { | ||||
|     lua_pop(L, 1);  /* remove from stack */ | ||||
|     return LUA_REFNIL;  /* `nil' has a unique fixed reference */ | ||||
|   } | ||||
|   lua_rawgeti(L, t, FREELIST_REF);  /* get first free element */ | ||||
|   ref = (int)lua_tointeger(L, -1);  /* ref = t[FREELIST_REF] */ | ||||
|   lua_pop(L, 1);  /* remove it from stack */ | ||||
|   if (ref != 0) {  /* any free element? */ | ||||
|     lua_rawgeti(L, t, ref);  /* remove it from list */ | ||||
|     lua_rawseti(L, t, FREELIST_REF);  /* (t[FREELIST_REF] = t[ref]) */ | ||||
|   } | ||||
|   else {  /* no free elements */ | ||||
|     ref = (int)lua_objlen(L, t); | ||||
|     ref++;  /* create new reference */ | ||||
|   } | ||||
|   lua_rawseti(L, t, ref); | ||||
|   return ref; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { | ||||
|   if (ref >= 0) { | ||||
|     t = abs_index(L, t); | ||||
|     lua_rawgeti(L, t, FREELIST_REF); | ||||
|     lua_rawseti(L, t, ref);  /* t[ref] = t[FREELIST_REF] */ | ||||
|     lua_pushinteger(L, ref); | ||||
|     lua_rawseti(L, t, FREELIST_REF);  /* t[FREELIST_REF] = ref */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Load functions | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
| typedef struct LoadF { | ||||
|   int extraline; | ||||
|   FILE *f; | ||||
|   char buff[LUAL_BUFFERSIZE]; | ||||
| } LoadF; | ||||
|  | ||||
|  | ||||
| static const char *getF (lua_State *L, void *ud, size_t *size) { | ||||
|   LoadF *lf = (LoadF *)ud; | ||||
|   (void)L; | ||||
|   if (lf->extraline) { | ||||
|     lf->extraline = 0; | ||||
|     *size = 1; | ||||
|     return "\n"; | ||||
|   } | ||||
|   if (feof(lf->f)) return NULL; | ||||
|   *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); | ||||
|   return (*size > 0) ? lf->buff : NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int errfile (lua_State *L, const char *what, int fnameindex) { | ||||
|   const char *serr = strerror(errno); | ||||
|   const char *filename = lua_tostring(L, fnameindex) + 1; | ||||
|   lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); | ||||
|   lua_remove(L, fnameindex); | ||||
|   return LUA_ERRFILE; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { | ||||
|   LoadF lf; | ||||
|   int status, readstatus; | ||||
|   int c; | ||||
|   int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */ | ||||
|   lf.extraline = 0; | ||||
|   if (filename == NULL) { | ||||
|     lua_pushliteral(L, "=stdin"); | ||||
|     lf.f = stdin; | ||||
|   } | ||||
|   else { | ||||
|     lua_pushfstring(L, "@%s", filename); | ||||
|     lf.f = fopen(filename, "r"); | ||||
|     if (lf.f == NULL) return errfile(L, "open", fnameindex); | ||||
|   } | ||||
|   c = getc(lf.f); | ||||
|   if (c == '#') {  /* Unix exec. file? */ | ||||
|     lf.extraline = 1; | ||||
|     while ((c = getc(lf.f)) != EOF && c != '\n') ;  /* skip first line */ | ||||
|     if (c == '\n') c = getc(lf.f); | ||||
|   } | ||||
|   if (c == LUA_SIGNATURE[0] && lf.f != stdin) {  /* binary file? */ | ||||
|     fclose(lf.f); | ||||
|     lf.f = fopen(filename, "rb");  /* reopen in binary mode */ | ||||
|     if (lf.f == NULL) return errfile(L, "reopen", fnameindex); | ||||
|     /* skip eventual `#!...' */ | ||||
|    while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; | ||||
|     lf.extraline = 0; | ||||
|   } | ||||
|   ungetc(c, lf.f); | ||||
|   status = lua_load(L, getF, &lf, lua_tostring(L, -1)); | ||||
|   readstatus = ferror(lf.f); | ||||
|   if (lf.f != stdin) fclose(lf.f);  /* close file (even in case of errors) */ | ||||
|   if (readstatus) { | ||||
|     lua_settop(L, fnameindex);  /* ignore results from `lua_load' */ | ||||
|     return errfile(L, "read", fnameindex); | ||||
|   } | ||||
|   lua_remove(L, fnameindex); | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| typedef struct LoadS { | ||||
|   const char *s; | ||||
|   size_t size; | ||||
| } LoadS; | ||||
|  | ||||
|  | ||||
| static const char *getS (lua_State *L, void *ud, size_t *size) { | ||||
|   LoadS *ls = (LoadS *)ud; | ||||
|   (void)L; | ||||
|   if (ls->size == 0) return NULL; | ||||
|   *size = ls->size; | ||||
|   ls->size = 0; | ||||
|   return ls->s; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, | ||||
|                                 const char *name) { | ||||
|   LoadS ls; | ||||
|   ls.s = buff; | ||||
|   ls.size = size; | ||||
|   return lua_load(L, getS, &ls, name); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { | ||||
|   return luaL_loadbuffer(L, s, strlen(s), s); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { | ||||
|   (void)ud; | ||||
|   (void)osize; | ||||
|   if (nsize == 0) { | ||||
|     free(ptr); | ||||
|     return NULL; | ||||
|   } | ||||
|   else | ||||
|     return realloc(ptr, nsize); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int panic (lua_State *L) { | ||||
|   (void)L;  /* to avoid warnings */ | ||||
|   fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", | ||||
|                    lua_tostring(L, -1)); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API lua_State *luaL_newstate (void) { | ||||
|   lua_State *L = lua_newstate(l_alloc, NULL); | ||||
|   if (L) lua_atpanic(L, &panic); | ||||
|   return L; | ||||
| } | ||||
|  | ||||
							
								
								
									
										643
									
								
								lua/src/lbaselib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										643
									
								
								lua/src/lbaselib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,643 @@ | ||||
| /* | ||||
| ** $Id: lbaselib.c,v 1.191a 2006/06/02 15:34:00 roberto Exp $ | ||||
| ** Basic library | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <ctype.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define lbaselib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** If your system does not support `stdout', you can just remove this function. | ||||
| ** If you need, you can define your own `print' function, following this | ||||
| ** model but changing `fputs' to put the strings at a proper place | ||||
| ** (a console window or a log file, for instance). | ||||
| */ | ||||
| static int luaB_print (lua_State *L) { | ||||
|   int n = lua_gettop(L);  /* number of arguments */ | ||||
|   int i; | ||||
|   lua_getglobal(L, "tostring"); | ||||
|   for (i=1; i<=n; i++) { | ||||
|     const char *s; | ||||
|     lua_pushvalue(L, -1);  /* function to be called */ | ||||
|     lua_pushvalue(L, i);   /* value to print */ | ||||
|     lua_call(L, 1, 1); | ||||
|     s = lua_tostring(L, -1);  /* get result */ | ||||
|     if (s == NULL) | ||||
|       return luaL_error(L, LUA_QL("tostring") " must return a string to " | ||||
|                            LUA_QL("print")); | ||||
|     if (i>1) fputs("\t", stdout); | ||||
|     fputs(s, stdout); | ||||
|     lua_pop(L, 1);  /* pop result */ | ||||
|   } | ||||
|   fputs("\n", stdout); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_tonumber (lua_State *L) { | ||||
|   int base = luaL_optint(L, 2, 10); | ||||
|   if (base == 10) {  /* standard conversion */ | ||||
|     luaL_checkany(L, 1); | ||||
|     if (lua_isnumber(L, 1)) { | ||||
|       lua_pushnumber(L, lua_tonumber(L, 1)); | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     const char *s1 = luaL_checkstring(L, 1); | ||||
|     char *s2; | ||||
|     unsigned long n; | ||||
|     luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); | ||||
|     n = strtoul(s1, &s2, base); | ||||
|     if (s1 != s2) {  /* at least one valid digit? */ | ||||
|       while (isspace((unsigned char)(*s2))) s2++;  /* skip trailing spaces */ | ||||
|       if (*s2 == '\0') {  /* no invalid trailing characters? */ | ||||
|         lua_pushnumber(L, (lua_Number)n); | ||||
|         return 1; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   lua_pushnil(L);  /* else not a number */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_error (lua_State *L) { | ||||
|   int level = luaL_optint(L, 2, 1); | ||||
|   lua_settop(L, 1); | ||||
|   if (lua_isstring(L, 1) && level > 0) {  /* add extra information? */ | ||||
|     luaL_where(L, level); | ||||
|     lua_pushvalue(L, 1); | ||||
|     lua_concat(L, 2); | ||||
|   } | ||||
|   return lua_error(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_getmetatable (lua_State *L) { | ||||
|   luaL_checkany(L, 1); | ||||
|   if (!lua_getmetatable(L, 1)) { | ||||
|     lua_pushnil(L); | ||||
|     return 1;  /* no metatable */ | ||||
|   } | ||||
|   luaL_getmetafield(L, 1, "__metatable"); | ||||
|   return 1;  /* returns either __metatable field (if present) or metatable */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_setmetatable (lua_State *L) { | ||||
|   int t = lua_type(L, 2); | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, | ||||
|                     "nil or table expected"); | ||||
|   if (luaL_getmetafield(L, 1, "__metatable")) | ||||
|     luaL_error(L, "cannot change a protected metatable"); | ||||
|   lua_settop(L, 2); | ||||
|   lua_setmetatable(L, 1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void getfunc (lua_State *L, int opt) { | ||||
|   if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); | ||||
|   else { | ||||
|     lua_Debug ar; | ||||
|     int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); | ||||
|     luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); | ||||
|     if (lua_getstack(L, level, &ar) == 0) | ||||
|       luaL_argerror(L, 1, "invalid level"); | ||||
|     lua_getinfo(L, "f", &ar); | ||||
|     if (lua_isnil(L, -1)) | ||||
|       luaL_error(L, "no function environment for tail call at level %d", | ||||
|                     level); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_getfenv (lua_State *L) { | ||||
|   getfunc(L, 1); | ||||
|   if (lua_iscfunction(L, -1))  /* is a C function? */ | ||||
|     lua_pushvalue(L, LUA_GLOBALSINDEX);  /* return the thread's global env. */ | ||||
|   else | ||||
|     lua_getfenv(L, -1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_setfenv (lua_State *L) { | ||||
|   luaL_checktype(L, 2, LUA_TTABLE); | ||||
|   getfunc(L, 0); | ||||
|   lua_pushvalue(L, 2); | ||||
|   if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { | ||||
|     /* change environment of current thread */ | ||||
|     lua_pushthread(L); | ||||
|     lua_insert(L, -2); | ||||
|     lua_setfenv(L, -2); | ||||
|     return 0; | ||||
|   } | ||||
|   else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) | ||||
|     luaL_error(L, | ||||
|           LUA_QL("setfenv") " cannot change environment of given object"); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_rawequal (lua_State *L) { | ||||
|   luaL_checkany(L, 1); | ||||
|   luaL_checkany(L, 2); | ||||
|   lua_pushboolean(L, lua_rawequal(L, 1, 2)); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_rawget (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   luaL_checkany(L, 2); | ||||
|   lua_settop(L, 2); | ||||
|   lua_rawget(L, 1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int luaB_rawset (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   luaL_checkany(L, 2); | ||||
|   luaL_checkany(L, 3); | ||||
|   lua_settop(L, 3); | ||||
|   lua_rawset(L, 1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_gcinfo (lua_State *L) { | ||||
|   lua_pushinteger(L, lua_getgccount(L)); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_collectgarbage (lua_State *L) { | ||||
|   static const char *const opts[] = {"stop", "restart", "collect", | ||||
|     "count", "step", "setpause", "setstepmul", NULL}; | ||||
|   static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, | ||||
|     LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; | ||||
|   int o = luaL_checkoption(L, 1, "collect", opts); | ||||
|   int ex = luaL_optint(L, 2, 0); | ||||
|   int res = lua_gc(L, optsnum[o], ex); | ||||
|   switch (optsnum[o]) { | ||||
|     case LUA_GCCOUNT: { | ||||
|       int b = lua_gc(L, LUA_GCCOUNTB, 0); | ||||
|       lua_pushnumber(L, res + ((lua_Number)b/1024)); | ||||
|       return 1; | ||||
|     } | ||||
|     case LUA_GCSTEP: { | ||||
|       lua_pushboolean(L, res); | ||||
|       return 1; | ||||
|     } | ||||
|     default: { | ||||
|       lua_pushnumber(L, res); | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_type (lua_State *L) { | ||||
|   luaL_checkany(L, 1); | ||||
|   lua_pushstring(L, luaL_typename(L, 1)); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_next (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   lua_settop(L, 2);  /* create a 2nd argument if there isn't one */ | ||||
|   if (lua_next(L, 1)) | ||||
|     return 2; | ||||
|   else { | ||||
|     lua_pushnil(L); | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_pairs (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */ | ||||
|   lua_pushvalue(L, 1);  /* state, */ | ||||
|   lua_pushnil(L);  /* and initial value */ | ||||
|   return 3; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int ipairsaux (lua_State *L) { | ||||
|   int i = luaL_checkint(L, 2); | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   i++;  /* next value */ | ||||
|   lua_pushinteger(L, i); | ||||
|   lua_rawgeti(L, 1, i); | ||||
|   return (lua_isnil(L, -1)) ? 0 : 2; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_ipairs (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */ | ||||
|   lua_pushvalue(L, 1);  /* state, */ | ||||
|   lua_pushinteger(L, 0);  /* and initial value */ | ||||
|   return 3; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int load_aux (lua_State *L, int status) { | ||||
|   if (status == 0)  /* OK? */ | ||||
|     return 1; | ||||
|   else { | ||||
|     lua_pushnil(L); | ||||
|     lua_insert(L, -2);  /* put before error message */ | ||||
|     return 2;  /* return nil plus error message */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_loadstring (lua_State *L) { | ||||
|   size_t l; | ||||
|   const char *s = luaL_checklstring(L, 1, &l); | ||||
|   const char *chunkname = luaL_optstring(L, 2, s); | ||||
|   return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_loadfile (lua_State *L) { | ||||
|   const char *fname = luaL_optstring(L, 1, NULL); | ||||
|   return load_aux(L, luaL_loadfile(L, fname)); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Reader for generic `load' function: `lua_load' uses the | ||||
| ** stack for internal stuff, so the reader cannot change the | ||||
| ** stack top. Instead, it keeps its resulting string in a | ||||
| ** reserved slot inside the stack. | ||||
| */ | ||||
| static const char *generic_reader (lua_State *L, void *ud, size_t *size) { | ||||
|   (void)ud;  /* to avoid warnings */ | ||||
|   luaL_checkstack(L, 2, "too many nested functions"); | ||||
|   lua_pushvalue(L, 1);  /* get function */ | ||||
|   lua_call(L, 0, 1);  /* call it */ | ||||
|   if (lua_isnil(L, -1)) { | ||||
|     *size = 0; | ||||
|     return NULL; | ||||
|   } | ||||
|   else if (lua_isstring(L, -1)) { | ||||
|     lua_replace(L, 3);  /* save string in a reserved stack slot */ | ||||
|     return lua_tolstring(L, 3, size); | ||||
|   } | ||||
|   else luaL_error(L, "reader function must return a string"); | ||||
|   return NULL;  /* to avoid warnings */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_load (lua_State *L) { | ||||
|   int status; | ||||
|   const char *cname = luaL_optstring(L, 2, "=(load)"); | ||||
|   luaL_checktype(L, 1, LUA_TFUNCTION); | ||||
|   lua_settop(L, 3);  /* function, eventual name, plus one reserved slot */ | ||||
|   status = lua_load(L, generic_reader, NULL, cname); | ||||
|   return load_aux(L, status); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_dofile (lua_State *L) { | ||||
|   const char *fname = luaL_optstring(L, 1, NULL); | ||||
|   int n = lua_gettop(L); | ||||
|   if (luaL_loadfile(L, fname) != 0) lua_error(L); | ||||
|   lua_call(L, 0, LUA_MULTRET); | ||||
|   return lua_gettop(L) - n; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_assert (lua_State *L) { | ||||
|   luaL_checkany(L, 1); | ||||
|   if (!lua_toboolean(L, 1)) | ||||
|     return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); | ||||
|   return lua_gettop(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_unpack (lua_State *L) { | ||||
|   int i, e, n; | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   i = luaL_optint(L, 2, 1); | ||||
|   e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); | ||||
|   n = e - i + 1;  /* number of elements */ | ||||
|   if (n <= 0) return 0;  /* empty range */ | ||||
|   luaL_checkstack(L, n, "table too big to unpack"); | ||||
|   for (; i<=e; i++)  /* push arg[i...e] */ | ||||
|     lua_rawgeti(L, 1, i); | ||||
|   return n; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_select (lua_State *L) { | ||||
|   int n = lua_gettop(L); | ||||
|   if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { | ||||
|     lua_pushinteger(L, n-1); | ||||
|     return 1; | ||||
|   } | ||||
|   else { | ||||
|     int i = luaL_checkint(L, 1); | ||||
|     if (i < 0) i = n + i; | ||||
|     else if (i > n) i = n; | ||||
|     luaL_argcheck(L, 1 <= i, 1, "index out of range"); | ||||
|     return n - i; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_pcall (lua_State *L) { | ||||
|   int status; | ||||
|   luaL_checkany(L, 1); | ||||
|   status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); | ||||
|   lua_pushboolean(L, (status == 0)); | ||||
|   lua_insert(L, 1); | ||||
|   return lua_gettop(L);  /* return status + all results */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_xpcall (lua_State *L) { | ||||
|   int status; | ||||
|   luaL_checkany(L, 2); | ||||
|   lua_settop(L, 2); | ||||
|   lua_insert(L, 1);  /* put error function under function to be called */ | ||||
|   status = lua_pcall(L, 0, LUA_MULTRET, 1); | ||||
|   lua_pushboolean(L, (status == 0)); | ||||
|   lua_replace(L, 1); | ||||
|   return lua_gettop(L);  /* return status + all results */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_tostring (lua_State *L) { | ||||
|   luaL_checkany(L, 1); | ||||
|   if (luaL_callmeta(L, 1, "__tostring"))  /* is there a metafield? */ | ||||
|     return 1;  /* use its value */ | ||||
|   switch (lua_type(L, 1)) { | ||||
|     case LUA_TNUMBER: | ||||
|       lua_pushstring(L, lua_tostring(L, 1)); | ||||
|       break; | ||||
|     case LUA_TSTRING: | ||||
|       lua_pushvalue(L, 1); | ||||
|       break; | ||||
|     case LUA_TBOOLEAN: | ||||
|       lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); | ||||
|       break; | ||||
|     case LUA_TNIL: | ||||
|       lua_pushliteral(L, "nil"); | ||||
|       break; | ||||
|     default: | ||||
|       lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); | ||||
|       break; | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_newproxy (lua_State *L) { | ||||
|   lua_settop(L, 1); | ||||
|   lua_newuserdata(L, 0);  /* create proxy */ | ||||
|   if (lua_toboolean(L, 1) == 0) | ||||
|     return 1;  /* no metatable */ | ||||
|   else if (lua_isboolean(L, 1)) { | ||||
|     lua_newtable(L);  /* create a new metatable `m' ... */ | ||||
|     lua_pushvalue(L, -1);  /* ... and mark `m' as a valid metatable */ | ||||
|     lua_pushboolean(L, 1); | ||||
|     lua_rawset(L, lua_upvalueindex(1));  /* weaktable[m] = true */ | ||||
|   } | ||||
|   else { | ||||
|     int validproxy = 0;  /* to check if weaktable[metatable(u)] == true */ | ||||
|     if (lua_getmetatable(L, 1)) { | ||||
|       lua_rawget(L, lua_upvalueindex(1)); | ||||
|       validproxy = lua_toboolean(L, -1); | ||||
|       lua_pop(L, 1);  /* remove value */ | ||||
|     } | ||||
|     luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); | ||||
|     lua_getmetatable(L, 1);  /* metatable is valid; get it */ | ||||
|   } | ||||
|   lua_setmetatable(L, 2); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const luaL_Reg base_funcs[] = { | ||||
|   {"assert", luaB_assert}, | ||||
|   {"collectgarbage", luaB_collectgarbage}, | ||||
|   {"dofile", luaB_dofile}, | ||||
|   {"error", luaB_error}, | ||||
|   {"gcinfo", luaB_gcinfo}, | ||||
|   {"getfenv", luaB_getfenv}, | ||||
|   {"getmetatable", luaB_getmetatable}, | ||||
|   {"loadfile", luaB_loadfile}, | ||||
|   {"load", luaB_load}, | ||||
|   {"loadstring", luaB_loadstring}, | ||||
|   {"next", luaB_next}, | ||||
|   {"pcall", luaB_pcall}, | ||||
|   {"print", luaB_print}, | ||||
|   {"rawequal", luaB_rawequal}, | ||||
|   {"rawget", luaB_rawget}, | ||||
|   {"rawset", luaB_rawset}, | ||||
|   {"select", luaB_select}, | ||||
|   {"setfenv", luaB_setfenv}, | ||||
|   {"setmetatable", luaB_setmetatable}, | ||||
|   {"tonumber", luaB_tonumber}, | ||||
|   {"tostring", luaB_tostring}, | ||||
|   {"type", luaB_type}, | ||||
|   {"unpack", luaB_unpack}, | ||||
|   {"xpcall", luaB_xpcall}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Coroutine library | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
| static int auxresume (lua_State *L, lua_State *co, int narg) { | ||||
|   int status; | ||||
|   if (!lua_checkstack(co, narg)) | ||||
|     luaL_error(L, "too many arguments to resume"); | ||||
|   if (lua_status(co) == 0 && lua_gettop(co) == 0) { | ||||
|     lua_pushliteral(L, "cannot resume dead coroutine"); | ||||
|     return -1;  /* error flag */ | ||||
|   } | ||||
|   lua_xmove(L, co, narg); | ||||
|   status = lua_resume(co, narg); | ||||
|   if (status == 0 || status == LUA_YIELD) { | ||||
|     int nres = lua_gettop(co); | ||||
|     if (!lua_checkstack(L, nres)) | ||||
|       luaL_error(L, "too many results to resume"); | ||||
|     lua_xmove(co, L, nres);  /* move yielded values */ | ||||
|     return nres; | ||||
|   } | ||||
|   else { | ||||
|     lua_xmove(co, L, 1);  /* move error message */ | ||||
|     return -1;  /* error flag */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_coresume (lua_State *L) { | ||||
|   lua_State *co = lua_tothread(L, 1); | ||||
|   int r; | ||||
|   luaL_argcheck(L, co, 1, "coroutine expected"); | ||||
|   r = auxresume(L, co, lua_gettop(L) - 1); | ||||
|   if (r < 0) { | ||||
|     lua_pushboolean(L, 0); | ||||
|     lua_insert(L, -2); | ||||
|     return 2;  /* return false + error message */ | ||||
|   } | ||||
|   else { | ||||
|     lua_pushboolean(L, 1); | ||||
|     lua_insert(L, -(r + 1)); | ||||
|     return r + 1;  /* return true + `resume' returns */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_auxwrap (lua_State *L) { | ||||
|   lua_State *co = lua_tothread(L, lua_upvalueindex(1)); | ||||
|   int r = auxresume(L, co, lua_gettop(L)); | ||||
|   if (r < 0) { | ||||
|     if (lua_isstring(L, -1)) {  /* error object is a string? */ | ||||
|       luaL_where(L, 1);  /* add extra info */ | ||||
|       lua_insert(L, -2); | ||||
|       lua_concat(L, 2); | ||||
|     } | ||||
|     lua_error(L);  /* propagate error */ | ||||
|   } | ||||
|   return r; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_cocreate (lua_State *L) { | ||||
|   lua_State *NL = lua_newthread(L); | ||||
|   luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, | ||||
|     "Lua function expected"); | ||||
|   lua_pushvalue(L, 1);  /* move function to top */ | ||||
|   lua_xmove(L, NL, 1);  /* move function from L to NL */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_cowrap (lua_State *L) { | ||||
|   luaB_cocreate(L); | ||||
|   lua_pushcclosure(L, luaB_auxwrap, 1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_yield (lua_State *L) { | ||||
|   return lua_yield(L, lua_gettop(L)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_costatus (lua_State *L) { | ||||
|   lua_State *co = lua_tothread(L, 1); | ||||
|   luaL_argcheck(L, co, 1, "coroutine expected"); | ||||
|   if (L == co) lua_pushliteral(L, "running"); | ||||
|   else { | ||||
|     switch (lua_status(co)) { | ||||
|       case LUA_YIELD: | ||||
|         lua_pushliteral(L, "suspended"); | ||||
|         break; | ||||
|       case 0: { | ||||
|         lua_Debug ar; | ||||
|         if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */ | ||||
|           lua_pushliteral(L, "normal");  /* it is running */ | ||||
|         else if (lua_gettop(co) == 0) | ||||
|             lua_pushliteral(L, "dead"); | ||||
|         else | ||||
|           lua_pushliteral(L, "suspended");  /* initial state */ | ||||
|         break; | ||||
|       } | ||||
|       default:  /* some error occured */ | ||||
|         lua_pushliteral(L, "dead"); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaB_corunning (lua_State *L) { | ||||
|   if (lua_pushthread(L)) | ||||
|     return 0;  /* main thread is not a coroutine */ | ||||
|   else | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const luaL_Reg co_funcs[] = { | ||||
|   {"create", luaB_cocreate}, | ||||
|   {"resume", luaB_coresume}, | ||||
|   {"running", luaB_corunning}, | ||||
|   {"status", luaB_costatus}, | ||||
|   {"wrap", luaB_cowrap}, | ||||
|   {"yield", luaB_yield}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| static void auxopen (lua_State *L, const char *name, | ||||
|                      lua_CFunction f, lua_CFunction u) { | ||||
|   lua_pushcfunction(L, u); | ||||
|   lua_pushcclosure(L, f, 1); | ||||
|   lua_setfield(L, -2, name); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void base_open (lua_State *L) { | ||||
|   /* set global _G */ | ||||
|   lua_pushvalue(L, LUA_GLOBALSINDEX); | ||||
|   lua_setglobal(L, "_G"); | ||||
|   /* open lib into global table */ | ||||
|   luaL_register(L, "_G", base_funcs); | ||||
|   lua_pushliteral(L, LUA_VERSION); | ||||
|   lua_setglobal(L, "_VERSION");  /* set global _VERSION */ | ||||
|   /* `ipairs' and `pairs' need auxliliary functions as upvalues */ | ||||
|   auxopen(L, "ipairs", luaB_ipairs, ipairsaux); | ||||
|   auxopen(L, "pairs", luaB_pairs, luaB_next); | ||||
|   /* `newproxy' needs a weaktable as upvalue */ | ||||
|   lua_createtable(L, 0, 1);  /* new table `w' */ | ||||
|   lua_pushvalue(L, -1);  /* `w' will be its own metatable */ | ||||
|   lua_setmetatable(L, -2); | ||||
|   lua_pushliteral(L, "kv"); | ||||
|   lua_setfield(L, -2, "__mode");  /* metatable(w).__mode = "kv" */ | ||||
|   lua_pushcclosure(L, luaB_newproxy, 1); | ||||
|   lua_setglobal(L, "newproxy");  /* set global `newproxy' */ | ||||
| } | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaopen_base (lua_State *L) { | ||||
|   base_open(L); | ||||
|   luaL_register(L, LUA_COLIBNAME, co_funcs); | ||||
|   return 2; | ||||
| } | ||||
|  | ||||
							
								
								
									
										839
									
								
								lua/src/lcode.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										839
									
								
								lua/src/lcode.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,839 @@ | ||||
| /* | ||||
| ** $Id: lcode.c,v 2.25a 2006/03/21 19:28:49 roberto Exp $ | ||||
| ** Code generator for Lua | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #define lcode_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lcode.h" | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lgc.h" | ||||
| #include "llex.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lopcodes.h" | ||||
| #include "lparser.h" | ||||
| #include "ltable.h" | ||||
|  | ||||
|  | ||||
| #define hasjumps(e)	((e)->t != (e)->f) | ||||
|  | ||||
|  | ||||
| static int isnumeral(expdesc *e) { | ||||
|   return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_nil (FuncState *fs, int from, int n) { | ||||
|   Instruction *previous; | ||||
|   if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */ | ||||
|     if (fs->pc == 0) {  /* function start? */ | ||||
|       if (from >= fs->nactvar) | ||||
|         return;  /* positions are already clean */ | ||||
|     } | ||||
|     else { | ||||
|       previous = &fs->f->code[fs->pc-1]; | ||||
|       if (GET_OPCODE(*previous) == OP_LOADNIL) { | ||||
|         int pfrom = GETARG_A(*previous); | ||||
|         int pto = GETARG_B(*previous); | ||||
|         if (pfrom <= from && from <= pto+1) {  /* can connect both? */ | ||||
|           if (from+n-1 > pto) | ||||
|             SETARG_B(*previous, from+n-1); | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0);  /* else no optimization */ | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaK_jump (FuncState *fs) { | ||||
|   int jpc = fs->jpc;  /* save list of jumps to here */ | ||||
|   int j; | ||||
|   fs->jpc = NO_JUMP; | ||||
|   j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); | ||||
|   luaK_concat(fs, &j, jpc);  /* keep them on hold */ | ||||
|   return j; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_ret (FuncState *fs, int first, int nret) { | ||||
|   luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { | ||||
|   luaK_codeABC(fs, op, A, B, C); | ||||
|   return luaK_jump(fs); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void fixjump (FuncState *fs, int pc, int dest) { | ||||
|   Instruction *jmp = &fs->f->code[pc]; | ||||
|   int offset = dest-(pc+1); | ||||
|   lua_assert(dest != NO_JUMP); | ||||
|   if (abs(offset) > MAXARG_sBx) | ||||
|     luaX_syntaxerror(fs->ls, "control structure too long"); | ||||
|   SETARG_sBx(*jmp, offset); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** returns current `pc' and marks it as a jump target (to avoid wrong | ||||
| ** optimizations with consecutive instructions not in the same basic block). | ||||
| */ | ||||
| int luaK_getlabel (FuncState *fs) { | ||||
|   fs->lasttarget = fs->pc; | ||||
|   return fs->pc; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int getjump (FuncState *fs, int pc) { | ||||
|   int offset = GETARG_sBx(fs->f->code[pc]); | ||||
|   if (offset == NO_JUMP)  /* point to itself represents end of list */ | ||||
|     return NO_JUMP;  /* end of list */ | ||||
|   else | ||||
|     return (pc+1)+offset;  /* turn offset into absolute position */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static Instruction *getjumpcontrol (FuncState *fs, int pc) { | ||||
|   Instruction *pi = &fs->f->code[pc]; | ||||
|   if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) | ||||
|     return pi-1; | ||||
|   else | ||||
|     return pi; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** check whether list has any jump that do not produce a value | ||||
| ** (or produce an inverted value) | ||||
| */ | ||||
| static int need_value (FuncState *fs, int list) { | ||||
|   for (; list != NO_JUMP; list = getjump(fs, list)) { | ||||
|     Instruction i = *getjumpcontrol(fs, list); | ||||
|     if (GET_OPCODE(i) != OP_TESTSET) return 1; | ||||
|   } | ||||
|   return 0;  /* not found */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int patchtestreg (FuncState *fs, int node, int reg) { | ||||
|   Instruction *i = getjumpcontrol(fs, node); | ||||
|   if (GET_OPCODE(*i) != OP_TESTSET) | ||||
|     return 0;  /* cannot patch other instructions */ | ||||
|   if (reg != NO_REG && reg != GETARG_B(*i)) | ||||
|     SETARG_A(*i, reg); | ||||
|   else  /* no register to put value or register already has the value */ | ||||
|     *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void removevalues (FuncState *fs, int list) { | ||||
|   for (; list != NO_JUMP; list = getjump(fs, list)) | ||||
|       patchtestreg(fs, list, NO_REG); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, | ||||
|                           int dtarget) { | ||||
|   while (list != NO_JUMP) { | ||||
|     int next = getjump(fs, list); | ||||
|     if (patchtestreg(fs, list, reg)) | ||||
|       fixjump(fs, list, vtarget); | ||||
|     else | ||||
|       fixjump(fs, list, dtarget);  /* jump to default target */ | ||||
|     list = next; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void dischargejpc (FuncState *fs) { | ||||
|   patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); | ||||
|   fs->jpc = NO_JUMP; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_patchlist (FuncState *fs, int list, int target) { | ||||
|   if (target == fs->pc) | ||||
|     luaK_patchtohere(fs, list); | ||||
|   else { | ||||
|     lua_assert(target < fs->pc); | ||||
|     patchlistaux(fs, list, target, NO_REG, target); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_patchtohere (FuncState *fs, int list) { | ||||
|   luaK_getlabel(fs); | ||||
|   luaK_concat(fs, &fs->jpc, list); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_concat (FuncState *fs, int *l1, int l2) { | ||||
|   if (l2 == NO_JUMP) return; | ||||
|   else if (*l1 == NO_JUMP) | ||||
|     *l1 = l2; | ||||
|   else { | ||||
|     int list = *l1; | ||||
|     int next; | ||||
|     while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */ | ||||
|       list = next; | ||||
|     fixjump(fs, list, l2); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_checkstack (FuncState *fs, int n) { | ||||
|   int newstack = fs->freereg + n; | ||||
|   if (newstack > fs->f->maxstacksize) { | ||||
|     if (newstack >= MAXSTACK) | ||||
|       luaX_syntaxerror(fs->ls, "function or expression too complex"); | ||||
|     fs->f->maxstacksize = cast_byte(newstack); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_reserveregs (FuncState *fs, int n) { | ||||
|   luaK_checkstack(fs, n); | ||||
|   fs->freereg += n; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void freereg (FuncState *fs, int reg) { | ||||
|   if (!ISK(reg) && reg >= fs->nactvar) { | ||||
|     fs->freereg--; | ||||
|     lua_assert(reg == fs->freereg); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void freeexp (FuncState *fs, expdesc *e) { | ||||
|   if (e->k == VNONRELOC) | ||||
|     freereg(fs, e->u.s.info); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int addk (FuncState *fs, TValue *k, TValue *v) { | ||||
|   lua_State *L = fs->L; | ||||
|   TValue *idx = luaH_set(L, fs->h, k); | ||||
|   Proto *f = fs->f; | ||||
|   int oldsize = f->sizek; | ||||
|   if (ttisnumber(idx)) { | ||||
|     lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); | ||||
|     return cast_int(nvalue(idx)); | ||||
|   } | ||||
|   else {  /* constant not found; create a new entry */ | ||||
|     setnvalue(idx, cast_num(fs->nk)); | ||||
|     luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, | ||||
|                     MAXARG_Bx, "constant table overflow"); | ||||
|     while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); | ||||
|     setobj(L, &f->k[fs->nk], v); | ||||
|     luaC_barrier(L, f, v); | ||||
|     return fs->nk++; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaK_stringK (FuncState *fs, TString *s) { | ||||
|   TValue o; | ||||
|   setsvalue(fs->L, &o, s); | ||||
|   return addk(fs, &o, &o); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaK_numberK (FuncState *fs, lua_Number r) { | ||||
|   TValue o; | ||||
|   setnvalue(&o, r); | ||||
|   return addk(fs, &o, &o); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int boolK (FuncState *fs, int b) { | ||||
|   TValue o; | ||||
|   setbvalue(&o, b); | ||||
|   return addk(fs, &o, &o); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int nilK (FuncState *fs) { | ||||
|   TValue k, v; | ||||
|   setnilvalue(&v); | ||||
|   /* cannot use nil as key; instead use table itself to represent nil */ | ||||
|   sethvalue(fs->L, &k, fs->h); | ||||
|   return addk(fs, &k, &v); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { | ||||
|   if (e->k == VCALL) {  /* expression is an open function call? */ | ||||
|     SETARG_C(getcode(fs, e), nresults+1); | ||||
|   } | ||||
|   else if (e->k == VVARARG) { | ||||
|     SETARG_B(getcode(fs, e), nresults+1); | ||||
|     SETARG_A(getcode(fs, e), fs->freereg); | ||||
|     luaK_reserveregs(fs, 1); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_setoneret (FuncState *fs, expdesc *e) { | ||||
|   if (e->k == VCALL) {  /* expression is an open function call? */ | ||||
|     e->k = VNONRELOC; | ||||
|     e->u.s.info = GETARG_A(getcode(fs, e)); | ||||
|   } | ||||
|   else if (e->k == VVARARG) { | ||||
|     SETARG_B(getcode(fs, e), 2); | ||||
|     e->k = VRELOCABLE;  /* can relocate its simple result */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_dischargevars (FuncState *fs, expdesc *e) { | ||||
|   switch (e->k) { | ||||
|     case VLOCAL: { | ||||
|       e->k = VNONRELOC; | ||||
|       break; | ||||
|     } | ||||
|     case VUPVAL: { | ||||
|       e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); | ||||
|       e->k = VRELOCABLE; | ||||
|       break; | ||||
|     } | ||||
|     case VGLOBAL: { | ||||
|       e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); | ||||
|       e->k = VRELOCABLE; | ||||
|       break; | ||||
|     } | ||||
|     case VINDEXED: { | ||||
|       freereg(fs, e->u.s.aux); | ||||
|       freereg(fs, e->u.s.info); | ||||
|       e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); | ||||
|       e->k = VRELOCABLE; | ||||
|       break; | ||||
|     } | ||||
|     case VVARARG: | ||||
|     case VCALL: { | ||||
|       luaK_setoneret(fs, e); | ||||
|       break; | ||||
|     } | ||||
|     default: break;  /* there is one value available (somewhere) */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int code_label (FuncState *fs, int A, int b, int jump) { | ||||
|   luaK_getlabel(fs);  /* those instructions may be jump targets */ | ||||
|   return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void discharge2reg (FuncState *fs, expdesc *e, int reg) { | ||||
|   luaK_dischargevars(fs, e); | ||||
|   switch (e->k) { | ||||
|     case VNIL: { | ||||
|       luaK_nil(fs, reg, 1); | ||||
|       break; | ||||
|     } | ||||
|     case VFALSE:  case VTRUE: { | ||||
|       luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); | ||||
|       break; | ||||
|     } | ||||
|     case VK: { | ||||
|       luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); | ||||
|       break; | ||||
|     } | ||||
|     case VKNUM: { | ||||
|       luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); | ||||
|       break; | ||||
|     } | ||||
|     case VRELOCABLE: { | ||||
|       Instruction *pc = &getcode(fs, e); | ||||
|       SETARG_A(*pc, reg); | ||||
|       break; | ||||
|     } | ||||
|     case VNONRELOC: { | ||||
|       if (reg != e->u.s.info) | ||||
|         luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       lua_assert(e->k == VVOID || e->k == VJMP); | ||||
|       return;  /* nothing to do... */ | ||||
|     } | ||||
|   } | ||||
|   e->u.s.info = reg; | ||||
|   e->k = VNONRELOC; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void discharge2anyreg (FuncState *fs, expdesc *e) { | ||||
|   if (e->k != VNONRELOC) { | ||||
|     luaK_reserveregs(fs, 1); | ||||
|     discharge2reg(fs, e, fs->freereg-1); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void exp2reg (FuncState *fs, expdesc *e, int reg) { | ||||
|   discharge2reg(fs, e, reg); | ||||
|   if (e->k == VJMP) | ||||
|     luaK_concat(fs, &e->t, e->u.s.info);  /* put this jump in `t' list */ | ||||
|   if (hasjumps(e)) { | ||||
|     int final;  /* position after whole expression */ | ||||
|     int p_f = NO_JUMP;  /* position of an eventual LOAD false */ | ||||
|     int p_t = NO_JUMP;  /* position of an eventual LOAD true */ | ||||
|     if (need_value(fs, e->t) || need_value(fs, e->f)) { | ||||
|       int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); | ||||
|       p_f = code_label(fs, reg, 0, 1); | ||||
|       p_t = code_label(fs, reg, 1, 0); | ||||
|       luaK_patchtohere(fs, fj); | ||||
|     } | ||||
|     final = luaK_getlabel(fs); | ||||
|     patchlistaux(fs, e->f, final, reg, p_f); | ||||
|     patchlistaux(fs, e->t, final, reg, p_t); | ||||
|   } | ||||
|   e->f = e->t = NO_JUMP; | ||||
|   e->u.s.info = reg; | ||||
|   e->k = VNONRELOC; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_exp2nextreg (FuncState *fs, expdesc *e) { | ||||
|   luaK_dischargevars(fs, e); | ||||
|   freeexp(fs, e); | ||||
|   luaK_reserveregs(fs, 1); | ||||
|   exp2reg(fs, e, fs->freereg - 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaK_exp2anyreg (FuncState *fs, expdesc *e) { | ||||
|   luaK_dischargevars(fs, e); | ||||
|   if (e->k == VNONRELOC) { | ||||
|     if (!hasjumps(e)) return e->u.s.info;  /* exp is already in a register */ | ||||
|     if (e->u.s.info >= fs->nactvar) {  /* reg. is not a local? */ | ||||
|       exp2reg(fs, e, e->u.s.info);  /* put value on it */ | ||||
|       return e->u.s.info; | ||||
|     } | ||||
|   } | ||||
|   luaK_exp2nextreg(fs, e);  /* default */ | ||||
|   return e->u.s.info; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_exp2val (FuncState *fs, expdesc *e) { | ||||
|   if (hasjumps(e)) | ||||
|     luaK_exp2anyreg(fs, e); | ||||
|   else | ||||
|     luaK_dischargevars(fs, e); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaK_exp2RK (FuncState *fs, expdesc *e) { | ||||
|   luaK_exp2val(fs, e); | ||||
|   switch (e->k) { | ||||
|     case VKNUM: | ||||
|     case VTRUE: | ||||
|     case VFALSE: | ||||
|     case VNIL: { | ||||
|       if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */ | ||||
|         e->u.s.info = (e->k == VNIL)  ? nilK(fs) : | ||||
|                       (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : | ||||
|                                         boolK(fs, (e->k == VTRUE)); | ||||
|         e->k = VK; | ||||
|         return RKASK(e->u.s.info); | ||||
|       } | ||||
|       else break; | ||||
|     } | ||||
|     case VK: { | ||||
|       if (e->u.s.info <= MAXINDEXRK)  /* constant fit in argC? */ | ||||
|         return RKASK(e->u.s.info); | ||||
|       else break; | ||||
|     } | ||||
|     default: break; | ||||
|   } | ||||
|   /* not a constant in the right range: put it in a register */ | ||||
|   return luaK_exp2anyreg(fs, e); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { | ||||
|   switch (var->k) { | ||||
|     case VLOCAL: { | ||||
|       freeexp(fs, ex); | ||||
|       exp2reg(fs, ex, var->u.s.info); | ||||
|       return; | ||||
|     } | ||||
|     case VUPVAL: { | ||||
|       int e = luaK_exp2anyreg(fs, ex); | ||||
|       luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); | ||||
|       break; | ||||
|     } | ||||
|     case VGLOBAL: { | ||||
|       int e = luaK_exp2anyreg(fs, ex); | ||||
|       luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); | ||||
|       break; | ||||
|     } | ||||
|     case VINDEXED: { | ||||
|       int e = luaK_exp2RK(fs, ex); | ||||
|       luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       lua_assert(0);  /* invalid var kind to store */ | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   freeexp(fs, ex); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { | ||||
|   int func; | ||||
|   luaK_exp2anyreg(fs, e); | ||||
|   freeexp(fs, e); | ||||
|   func = fs->freereg; | ||||
|   luaK_reserveregs(fs, 2); | ||||
|   luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); | ||||
|   freeexp(fs, key); | ||||
|   e->u.s.info = func; | ||||
|   e->k = VNONRELOC; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void invertjump (FuncState *fs, expdesc *e) { | ||||
|   Instruction *pc = getjumpcontrol(fs, e->u.s.info); | ||||
|   lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && | ||||
|                                            GET_OPCODE(*pc) != OP_TEST); | ||||
|   SETARG_A(*pc, !(GETARG_A(*pc))); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int jumponcond (FuncState *fs, expdesc *e, int cond) { | ||||
|   if (e->k == VRELOCABLE) { | ||||
|     Instruction ie = getcode(fs, e); | ||||
|     if (GET_OPCODE(ie) == OP_NOT) { | ||||
|       fs->pc--;  /* remove previous OP_NOT */ | ||||
|       return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); | ||||
|     } | ||||
|     /* else go through */ | ||||
|   } | ||||
|   discharge2anyreg(fs, e); | ||||
|   freeexp(fs, e); | ||||
|   return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_goiftrue (FuncState *fs, expdesc *e) { | ||||
|   int pc;  /* pc of last jump */ | ||||
|   luaK_dischargevars(fs, e); | ||||
|   switch (e->k) { | ||||
|     case VK: case VKNUM: case VTRUE: { | ||||
|       pc = NO_JUMP;  /* always true; do nothing */ | ||||
|       break; | ||||
|     } | ||||
|     case VFALSE: { | ||||
|       pc = luaK_jump(fs);  /* always jump */ | ||||
|       break; | ||||
|     } | ||||
|     case VJMP: { | ||||
|       invertjump(fs, e); | ||||
|       pc = e->u.s.info; | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       pc = jumponcond(fs, e, 0); | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */ | ||||
|   luaK_patchtohere(fs, e->t); | ||||
|   e->t = NO_JUMP; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void luaK_goiffalse (FuncState *fs, expdesc *e) { | ||||
|   int pc;  /* pc of last jump */ | ||||
|   luaK_dischargevars(fs, e); | ||||
|   switch (e->k) { | ||||
|     case VNIL: case VFALSE: { | ||||
|       pc = NO_JUMP;  /* always false; do nothing */ | ||||
|       break; | ||||
|     } | ||||
|     case VTRUE: { | ||||
|       pc = luaK_jump(fs);  /* always jump */ | ||||
|       break; | ||||
|     } | ||||
|     case VJMP: { | ||||
|       pc = e->u.s.info; | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       pc = jumponcond(fs, e, 1); | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */ | ||||
|   luaK_patchtohere(fs, e->f); | ||||
|   e->f = NO_JUMP; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void codenot (FuncState *fs, expdesc *e) { | ||||
|   luaK_dischargevars(fs, e); | ||||
|   switch (e->k) { | ||||
|     case VNIL: case VFALSE: { | ||||
|       e->k = VTRUE; | ||||
|       break; | ||||
|     } | ||||
|     case VK: case VKNUM: case VTRUE: { | ||||
|       e->k = VFALSE; | ||||
|       break; | ||||
|     } | ||||
|     case VJMP: { | ||||
|       invertjump(fs, e); | ||||
|       break; | ||||
|     } | ||||
|     case VRELOCABLE: | ||||
|     case VNONRELOC: { | ||||
|       discharge2anyreg(fs, e); | ||||
|       freeexp(fs, e); | ||||
|       e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); | ||||
|       e->k = VRELOCABLE; | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       lua_assert(0);  /* cannot happen */ | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   /* interchange true and false lists */ | ||||
|   { int temp = e->f; e->f = e->t; e->t = temp; } | ||||
|   removevalues(fs, e->f); | ||||
|   removevalues(fs, e->t); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { | ||||
|   t->u.s.aux = luaK_exp2RK(fs, k); | ||||
|   t->k = VINDEXED; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { | ||||
|   lua_Number v1, v2, r; | ||||
|   if (!isnumeral(e1) || !isnumeral(e2)) return 0; | ||||
|   v1 = e1->u.nval; | ||||
|   v2 = e2->u.nval; | ||||
|   switch (op) { | ||||
|     case OP_ADD: r = luai_numadd(v1, v2); break; | ||||
|     case OP_SUB: r = luai_numsub(v1, v2); break; | ||||
|     case OP_MUL: r = luai_nummul(v1, v2); break; | ||||
|     case OP_DIV: | ||||
|       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */ | ||||
|       r = luai_numdiv(v1, v2); break; | ||||
|     case OP_MOD: | ||||
|       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */ | ||||
|       r = luai_nummod(v1, v2); break; | ||||
|     case OP_POW: r = luai_numpow(v1, v2); break; | ||||
|     case OP_UNM: r = luai_numunm(v1); break; | ||||
|     case OP_LEN: return 0;  /* no constant folding for 'len' */ | ||||
|     default: lua_assert(0); r = 0; break; | ||||
|   } | ||||
|   if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */ | ||||
|   e1->u.nval = r; | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { | ||||
|   if (constfolding(op, e1, e2)) | ||||
|     return; | ||||
|   else { | ||||
|     int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; | ||||
|     int o1 = luaK_exp2RK(fs, e1); | ||||
|     if (o1 > o2) { | ||||
|       freeexp(fs, e1); | ||||
|       freeexp(fs, e2); | ||||
|     } | ||||
|     else { | ||||
|       freeexp(fs, e2); | ||||
|       freeexp(fs, e1); | ||||
|     } | ||||
|     e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); | ||||
|     e1->k = VRELOCABLE; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, | ||||
|                                                           expdesc *e2) { | ||||
|   int o1 = luaK_exp2RK(fs, e1); | ||||
|   int o2 = luaK_exp2RK(fs, e2); | ||||
|   freeexp(fs, e2); | ||||
|   freeexp(fs, e1); | ||||
|   if (cond == 0 && op != OP_EQ) { | ||||
|     int temp;  /* exchange args to replace by `<' or `<=' */ | ||||
|     temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */ | ||||
|     cond = 1; | ||||
|   } | ||||
|   e1->u.s.info = condjump(fs, op, cond, o1, o2); | ||||
|   e1->k = VJMP; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { | ||||
|   expdesc e2; | ||||
|   e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; | ||||
|   switch (op) { | ||||
|     case OPR_MINUS: { | ||||
|       if (e->k == VK) | ||||
|         luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */ | ||||
|       codearith(fs, OP_UNM, e, &e2); | ||||
|       break; | ||||
|     } | ||||
|     case OPR_NOT: codenot(fs, e); break; | ||||
|     case OPR_LEN: { | ||||
|       luaK_exp2anyreg(fs, e);  /* cannot operate on constants */ | ||||
|       codearith(fs, OP_LEN, e, &e2); | ||||
|       break; | ||||
|     } | ||||
|     default: lua_assert(0); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { | ||||
|   switch (op) { | ||||
|     case OPR_AND: { | ||||
|       luaK_goiftrue(fs, v); | ||||
|       break; | ||||
|     } | ||||
|     case OPR_OR: { | ||||
|       luaK_goiffalse(fs, v); | ||||
|       break; | ||||
|     } | ||||
|     case OPR_CONCAT: { | ||||
|       luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */ | ||||
|       break; | ||||
|     } | ||||
|     case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: | ||||
|     case OPR_MOD: case OPR_POW: { | ||||
|       if (!isnumeral(v)) luaK_exp2RK(fs, v); | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       luaK_exp2RK(fs, v); | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { | ||||
|   switch (op) { | ||||
|     case OPR_AND: { | ||||
|       lua_assert(e1->t == NO_JUMP);  /* list must be closed */ | ||||
|       luaK_dischargevars(fs, e2); | ||||
|       luaK_concat(fs, &e2->f, e1->f); | ||||
|       *e1 = *e2; | ||||
|       break; | ||||
|     } | ||||
|     case OPR_OR: { | ||||
|       lua_assert(e1->f == NO_JUMP);  /* list must be closed */ | ||||
|       luaK_dischargevars(fs, e2); | ||||
|       luaK_concat(fs, &e2->t, e1->t); | ||||
|       *e1 = *e2; | ||||
|       break; | ||||
|     } | ||||
|     case OPR_CONCAT: { | ||||
|       luaK_exp2val(fs, e2); | ||||
|       if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { | ||||
|         lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); | ||||
|         freeexp(fs, e1); | ||||
|         SETARG_B(getcode(fs, e2), e1->u.s.info); | ||||
|         e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; | ||||
|       } | ||||
|       else { | ||||
|         luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */ | ||||
|         codearith(fs, OP_CONCAT, e1, e2); | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; | ||||
|     case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; | ||||
|     case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; | ||||
|     case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; | ||||
|     case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; | ||||
|     case OPR_POW: codearith(fs, OP_POW, e1, e2); break; | ||||
|     case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; | ||||
|     case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; | ||||
|     case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; | ||||
|     case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; | ||||
|     case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; | ||||
|     case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; | ||||
|     default: lua_assert(0); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_fixline (FuncState *fs, int line) { | ||||
|   fs->f->lineinfo[fs->pc - 1] = line; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int luaK_code (FuncState *fs, Instruction i, int line) { | ||||
|   Proto *f = fs->f; | ||||
|   dischargejpc(fs);  /* `pc' will change */ | ||||
|   /* put new instruction in code array */ | ||||
|   luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, | ||||
|                   MAX_INT, "code size overflow"); | ||||
|   f->code[fs->pc] = i; | ||||
|   /* save corresponding line information */ | ||||
|   luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, | ||||
|                   MAX_INT, "code size overflow"); | ||||
|   f->lineinfo[fs->pc] = line; | ||||
|   return fs->pc++; | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { | ||||
|   lua_assert(getOpMode(o) == iABC); | ||||
|   lua_assert(getBMode(o) != OpArgN || b == 0); | ||||
|   lua_assert(getCMode(o) != OpArgN || c == 0); | ||||
|   return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { | ||||
|   lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); | ||||
|   lua_assert(getCMode(o) == OpArgN); | ||||
|   return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { | ||||
|   int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1; | ||||
|   int b = (tostore == LUA_MULTRET) ? 0 : tostore; | ||||
|   lua_assert(tostore != 0); | ||||
|   if (c <= MAXARG_C) | ||||
|     luaK_codeABC(fs, OP_SETLIST, base, b, c); | ||||
|   else { | ||||
|     luaK_codeABC(fs, OP_SETLIST, base, b, 0); | ||||
|     luaK_code(fs, cast(Instruction, c), fs->ls->lastline); | ||||
|   } | ||||
|   fs->freereg = base + 1;  /* free registers with list values */ | ||||
| } | ||||
|  | ||||
							
								
								
									
										397
									
								
								lua/src/ldblib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								lua/src/ldblib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,397 @@ | ||||
| /* | ||||
| ** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $ | ||||
| ** Interface from Lua to its debug API | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define ldblib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| static int db_getregistry (lua_State *L) { | ||||
|   lua_pushvalue(L, LUA_REGISTRYINDEX); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_getmetatable (lua_State *L) { | ||||
|   luaL_checkany(L, 1); | ||||
|   if (!lua_getmetatable(L, 1)) { | ||||
|     lua_pushnil(L);  /* no metatable */ | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_setmetatable (lua_State *L) { | ||||
|   int t = lua_type(L, 2); | ||||
|   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, | ||||
|                     "nil or table expected"); | ||||
|   lua_settop(L, 2); | ||||
|   lua_pushboolean(L, lua_setmetatable(L, 1)); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_getfenv (lua_State *L) { | ||||
|   lua_getfenv(L, 1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_setfenv (lua_State *L) { | ||||
|   luaL_checktype(L, 2, LUA_TTABLE); | ||||
|   lua_settop(L, 2); | ||||
|   if (lua_setfenv(L, 1) == 0) | ||||
|     luaL_error(L, LUA_QL("setfenv") | ||||
|                   " cannot change environment of given object"); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void settabss (lua_State *L, const char *i, const char *v) { | ||||
|   lua_pushstring(L, v); | ||||
|   lua_setfield(L, -2, i); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void settabsi (lua_State *L, const char *i, int v) { | ||||
|   lua_pushinteger(L, v); | ||||
|   lua_setfield(L, -2, i); | ||||
| } | ||||
|  | ||||
|  | ||||
| static lua_State *getthread (lua_State *L, int *arg) { | ||||
|   if (lua_isthread(L, 1)) { | ||||
|     *arg = 1; | ||||
|     return lua_tothread(L, 1); | ||||
|   } | ||||
|   else { | ||||
|     *arg = 0; | ||||
|     return L; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { | ||||
|   if (L == L1) { | ||||
|     lua_pushvalue(L, -2); | ||||
|     lua_remove(L, -3); | ||||
|   } | ||||
|   else | ||||
|     lua_xmove(L1, L, 1); | ||||
|   lua_setfield(L, -2, fname); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_getinfo (lua_State *L) { | ||||
|   lua_Debug ar; | ||||
|   int arg; | ||||
|   lua_State *L1 = getthread(L, &arg); | ||||
|   const char *options = luaL_optstring(L, arg+2, "flnSu"); | ||||
|   if (lua_isnumber(L, arg+1)) { | ||||
|     if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { | ||||
|       lua_pushnil(L);  /* level out of range */ | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
|   else if (lua_isfunction(L, arg+1)) { | ||||
|     lua_pushfstring(L, ">%s", options); | ||||
|     options = lua_tostring(L, -1); | ||||
|     lua_pushvalue(L, arg+1); | ||||
|     lua_xmove(L, L1, 1); | ||||
|   } | ||||
|   else | ||||
|     return luaL_argerror(L, arg+1, "function or level expected"); | ||||
|   if (!lua_getinfo(L1, options, &ar)) | ||||
|     return luaL_argerror(L, arg+2, "invalid option"); | ||||
|   lua_createtable(L, 0, 2); | ||||
|   if (strchr(options, 'S')) { | ||||
|     settabss(L, "source", ar.source); | ||||
|     settabss(L, "short_src", ar.short_src); | ||||
|     settabsi(L, "linedefined", ar.linedefined); | ||||
|     settabsi(L, "lastlinedefined", ar.lastlinedefined); | ||||
|     settabss(L, "what", ar.what); | ||||
|   } | ||||
|   if (strchr(options, 'l')) | ||||
|     settabsi(L, "currentline", ar.currentline); | ||||
|   if (strchr(options, 'u')) | ||||
|     settabsi(L, "nups", ar.nups); | ||||
|   if (strchr(options, 'n')) { | ||||
|     settabss(L, "name", ar.name); | ||||
|     settabss(L, "namewhat", ar.namewhat); | ||||
|   } | ||||
|   if (strchr(options, 'L')) | ||||
|     treatstackoption(L, L1, "activelines"); | ||||
|   if (strchr(options, 'f')) | ||||
|     treatstackoption(L, L1, "func"); | ||||
|   return 1;  /* return table */ | ||||
| } | ||||
|      | ||||
|  | ||||
| static int db_getlocal (lua_State *L) { | ||||
|   int arg; | ||||
|   lua_State *L1 = getthread(L, &arg); | ||||
|   lua_Debug ar; | ||||
|   const char *name; | ||||
|   if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */ | ||||
|     return luaL_argerror(L, arg+1, "level out of range"); | ||||
|   name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); | ||||
|   if (name) { | ||||
|     lua_xmove(L1, L, 1); | ||||
|     lua_pushstring(L, name); | ||||
|     lua_pushvalue(L, -2); | ||||
|     return 2; | ||||
|   } | ||||
|   else { | ||||
|     lua_pushnil(L); | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_setlocal (lua_State *L) { | ||||
|   int arg; | ||||
|   lua_State *L1 = getthread(L, &arg); | ||||
|   lua_Debug ar; | ||||
|   if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */ | ||||
|     return luaL_argerror(L, arg+1, "level out of range"); | ||||
|   luaL_checkany(L, arg+3); | ||||
|   lua_settop(L, arg+3); | ||||
|   lua_xmove(L, L1, 1); | ||||
|   lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int auxupvalue (lua_State *L, int get) { | ||||
|   const char *name; | ||||
|   int n = luaL_checkint(L, 2); | ||||
|   luaL_checktype(L, 1, LUA_TFUNCTION); | ||||
|   if (lua_iscfunction(L, 1)) return 0;  /* cannot touch C upvalues from Lua */ | ||||
|   name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); | ||||
|   if (name == NULL) return 0; | ||||
|   lua_pushstring(L, name); | ||||
|   lua_insert(L, -(get+1)); | ||||
|   return get + 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_getupvalue (lua_State *L) { | ||||
|   return auxupvalue(L, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_setupvalue (lua_State *L) { | ||||
|   luaL_checkany(L, 3); | ||||
|   return auxupvalue(L, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static const char KEY_HOOK = 'h'; | ||||
|  | ||||
|  | ||||
| static void hookf (lua_State *L, lua_Debug *ar) { | ||||
|   static const char *const hooknames[] = | ||||
|     {"call", "return", "line", "count", "tail return"}; | ||||
|   lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||||
|   lua_rawget(L, LUA_REGISTRYINDEX); | ||||
|   lua_pushlightuserdata(L, L); | ||||
|   lua_rawget(L, -2); | ||||
|   if (lua_isfunction(L, -1)) { | ||||
|     lua_pushstring(L, hooknames[(int)ar->event]); | ||||
|     if (ar->currentline >= 0) | ||||
|       lua_pushinteger(L, ar->currentline); | ||||
|     else lua_pushnil(L); | ||||
|     lua_assert(lua_getinfo(L, "lS", ar)); | ||||
|     lua_call(L, 2, 0); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int makemask (const char *smask, int count) { | ||||
|   int mask = 0; | ||||
|   if (strchr(smask, 'c')) mask |= LUA_MASKCALL; | ||||
|   if (strchr(smask, 'r')) mask |= LUA_MASKRET; | ||||
|   if (strchr(smask, 'l')) mask |= LUA_MASKLINE; | ||||
|   if (count > 0) mask |= LUA_MASKCOUNT; | ||||
|   return mask; | ||||
| } | ||||
|  | ||||
|  | ||||
| static char *unmakemask (int mask, char *smask) { | ||||
|   int i = 0; | ||||
|   if (mask & LUA_MASKCALL) smask[i++] = 'c'; | ||||
|   if (mask & LUA_MASKRET) smask[i++] = 'r'; | ||||
|   if (mask & LUA_MASKLINE) smask[i++] = 'l'; | ||||
|   smask[i] = '\0'; | ||||
|   return smask; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void gethooktable (lua_State *L) { | ||||
|   lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||||
|   lua_rawget(L, LUA_REGISTRYINDEX); | ||||
|   if (!lua_istable(L, -1)) { | ||||
|     lua_pop(L, 1); | ||||
|     lua_createtable(L, 0, 1); | ||||
|     lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||||
|     lua_pushvalue(L, -2); | ||||
|     lua_rawset(L, LUA_REGISTRYINDEX); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_sethook (lua_State *L) { | ||||
|   int arg; | ||||
|   lua_State *L1 = getthread(L, &arg); | ||||
|   if (lua_isnoneornil(L, arg+1)) { | ||||
|     lua_settop(L, arg+1); | ||||
|     lua_sethook(L1, NULL, 0, 0);  /* turn off hooks */ | ||||
|   } | ||||
|   else { | ||||
|     const char *smask = luaL_checkstring(L, arg+2); | ||||
|     int count = luaL_optint(L, arg+3, 0); | ||||
|     luaL_checktype(L, arg+1, LUA_TFUNCTION); | ||||
|     lua_sethook(L1, hookf, makemask(smask, count), count); | ||||
|   } | ||||
|   gethooktable(L1); | ||||
|   lua_pushlightuserdata(L1, L1); | ||||
|   lua_pushvalue(L, arg+1); | ||||
|   lua_xmove(L, L1, 1); | ||||
|   lua_rawset(L1, -3);  /* set new hook */ | ||||
|   lua_pop(L1, 1);  /* remove hook table */ | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_gethook (lua_State *L) { | ||||
|   int arg; | ||||
|   lua_State *L1 = getthread(L, &arg); | ||||
|   char buff[5]; | ||||
|   int mask = lua_gethookmask(L1); | ||||
|   lua_Hook hook = lua_gethook(L1); | ||||
|   if (hook != NULL && hook != hookf)  /* external hook? */ | ||||
|     lua_pushliteral(L, "external hook"); | ||||
|   else { | ||||
|     gethooktable(L1); | ||||
|     lua_pushlightuserdata(L1, L1); | ||||
|     lua_rawget(L1, -2);   /* get hook */ | ||||
|     lua_remove(L1, -2);  /* remove hook table */ | ||||
|     lua_xmove(L1, L, 1); | ||||
|   } | ||||
|   lua_pushstring(L, unmakemask(mask, buff)); | ||||
|   lua_pushinteger(L, lua_gethookcount(L1)); | ||||
|   return 3; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int db_debug (lua_State *L) { | ||||
|   for (;;) { | ||||
|     char buffer[250]; | ||||
|     fputs("lua_debug> ", stderr); | ||||
|     if (fgets(buffer, sizeof(buffer), stdin) == 0 || | ||||
|         strcmp(buffer, "cont\n") == 0) | ||||
|       return 0; | ||||
|     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || | ||||
|         lua_pcall(L, 0, 0, 0)) { | ||||
|       fputs(lua_tostring(L, -1), stderr); | ||||
|       fputs("\n", stderr); | ||||
|     } | ||||
|     lua_settop(L, 0);  /* remove eventual returns */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| #define LEVELS1	12	/* size of the first part of the stack */ | ||||
| #define LEVELS2	10	/* size of the second part of the stack */ | ||||
|  | ||||
| static int db_errorfb (lua_State *L) { | ||||
|   int level; | ||||
|   int firstpart = 1;  /* still before eventual `...' */ | ||||
|   int arg; | ||||
|   lua_State *L1 = getthread(L, &arg); | ||||
|   lua_Debug ar; | ||||
|   if (lua_isnumber(L, arg+2)) { | ||||
|     level = (int)lua_tointeger(L, arg+2); | ||||
|     lua_pop(L, 1); | ||||
|   } | ||||
|   else | ||||
|     level = (L == L1) ? 1 : 0;  /* level 0 may be this own function */ | ||||
|   if (lua_gettop(L) == arg) | ||||
|     lua_pushliteral(L, ""); | ||||
|   else if (!lua_isstring(L, arg+1)) return 1;  /* message is not a string */ | ||||
|   else lua_pushliteral(L, "\n"); | ||||
|   lua_pushliteral(L, "stack traceback:"); | ||||
|   while (lua_getstack(L1, level++, &ar)) { | ||||
|     if (level > LEVELS1 && firstpart) { | ||||
|       /* no more than `LEVELS2' more levels? */ | ||||
|       if (!lua_getstack(L1, level+LEVELS2, &ar)) | ||||
|         level--;  /* keep going */ | ||||
|       else { | ||||
|         lua_pushliteral(L, "\n\t...");  /* too many levels */ | ||||
|         while (lua_getstack(L1, level+LEVELS2, &ar))  /* find last levels */ | ||||
|           level++; | ||||
|       } | ||||
|       firstpart = 0; | ||||
|       continue; | ||||
|     } | ||||
|     lua_pushliteral(L, "\n\t"); | ||||
|     lua_getinfo(L1, "Snl", &ar); | ||||
|     lua_pushfstring(L, "%s:", ar.short_src); | ||||
|     if (ar.currentline > 0) | ||||
|       lua_pushfstring(L, "%d:", ar.currentline); | ||||
|     if (*ar.namewhat != '\0')  /* is there a name? */ | ||||
|         lua_pushfstring(L, " in function " LUA_QS, ar.name); | ||||
|     else { | ||||
|       if (*ar.what == 'm')  /* main? */ | ||||
|         lua_pushfstring(L, " in main chunk"); | ||||
|       else if (*ar.what == 'C' || *ar.what == 't') | ||||
|         lua_pushliteral(L, " ?");  /* C function or tail call */ | ||||
|       else | ||||
|         lua_pushfstring(L, " in function <%s:%d>", | ||||
|                            ar.short_src, ar.linedefined); | ||||
|     } | ||||
|     lua_concat(L, lua_gettop(L) - arg); | ||||
|   } | ||||
|   lua_concat(L, lua_gettop(L) - arg); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const luaL_Reg dblib[] = { | ||||
|   {"debug", db_debug}, | ||||
|   {"getfenv", db_getfenv}, | ||||
|   {"gethook", db_gethook}, | ||||
|   {"getinfo", db_getinfo}, | ||||
|   {"getlocal", db_getlocal}, | ||||
|   {"getregistry", db_getregistry}, | ||||
|   {"getmetatable", db_getmetatable}, | ||||
|   {"getupvalue", db_getupvalue}, | ||||
|   {"setfenv", db_setfenv}, | ||||
|   {"sethook", db_sethook}, | ||||
|   {"setlocal", db_setlocal}, | ||||
|   {"setmetatable", db_setmetatable}, | ||||
|   {"setupvalue", db_setupvalue}, | ||||
|   {"traceback", db_errorfb}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaopen_debug (lua_State *L) { | ||||
|   luaL_register(L, LUA_DBLIBNAME, dblib); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
							
								
								
									
										622
									
								
								lua/src/ldebug.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										622
									
								
								lua/src/ldebug.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,622 @@ | ||||
| /* | ||||
| ** $Id: ldebug.c,v 2.29a 2005/12/22 16:19:56 roberto Exp $ | ||||
| ** Debug Interface | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stdarg.h> | ||||
| #include <stddef.h> | ||||
| #include <string.h> | ||||
|  | ||||
|  | ||||
| #define ldebug_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lapi.h" | ||||
| #include "lcode.h" | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lfunc.h" | ||||
| #include "lobject.h" | ||||
| #include "lopcodes.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "ltable.h" | ||||
| #include "ltm.h" | ||||
| #include "lvm.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); | ||||
|  | ||||
|  | ||||
| static int currentpc (lua_State *L, CallInfo *ci) { | ||||
|   if (!isLua(ci)) return -1;  /* function is not a Lua function? */ | ||||
|   if (ci == L->ci) | ||||
|     ci->savedpc = L->savedpc; | ||||
|   return pcRel(ci->savedpc, ci_func(ci)->l.p); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int currentline (lua_State *L, CallInfo *ci) { | ||||
|   int pc = currentpc(L, ci); | ||||
|   if (pc < 0) | ||||
|     return -1;  /* only active lua functions have current-line information */ | ||||
|   else | ||||
|     return getline(ci_func(ci)->l.p, pc); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** this function can be called asynchronous (e.g. during a signal) | ||||
| */ | ||||
| LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { | ||||
|   if (func == NULL || mask == 0) {  /* turn off hooks? */ | ||||
|     mask = 0; | ||||
|     func = NULL; | ||||
|   } | ||||
|   L->hook = func; | ||||
|   L->basehookcount = count; | ||||
|   resethookcount(L); | ||||
|   L->hookmask = cast_byte(mask); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API lua_Hook lua_gethook (lua_State *L) { | ||||
|   return L->hook; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API int lua_gethookmask (lua_State *L) { | ||||
|   return L->hookmask; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API int lua_gethookcount (lua_State *L) { | ||||
|   return L->basehookcount; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { | ||||
|   int status; | ||||
|   CallInfo *ci; | ||||
|   lua_lock(L); | ||||
|   for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { | ||||
|     level--; | ||||
|     if (f_isLua(ci))  /* Lua function? */ | ||||
|       level -= ci->tailcalls;  /* skip lost tail calls */ | ||||
|   } | ||||
|   if (level == 0 && ci > L->base_ci) {  /* level found? */ | ||||
|     status = 1; | ||||
|     ar->i_ci = cast_int(ci - L->base_ci); | ||||
|   } | ||||
|   else if (level < 0) {  /* level is of a lost tail call? */ | ||||
|     status = 1; | ||||
|     ar->i_ci = 0; | ||||
|   } | ||||
|   else status = 0;  /* no such level */ | ||||
|   lua_unlock(L); | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| static Proto *getluaproto (CallInfo *ci) { | ||||
|   return (isLua(ci) ? ci_func(ci)->l.p : NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *findlocal (lua_State *L, CallInfo *ci, int n) { | ||||
|   const char *name; | ||||
|   Proto *fp = getluaproto(ci); | ||||
|   if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) | ||||
|     return name;  /* is a local variable in a Lua function */ | ||||
|   else { | ||||
|     StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; | ||||
|     if (limit - ci->base >= n && n > 0)  /* is 'n' inside 'ci' stack? */ | ||||
|       return "(*temporary)"; | ||||
|     else | ||||
|       return NULL; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { | ||||
|   CallInfo *ci = L->base_ci + ar->i_ci; | ||||
|   const char *name = findlocal(L, ci, n); | ||||
|   lua_lock(L); | ||||
|   if (name) | ||||
|       luaA_pushobject(L, ci->base + (n - 1)); | ||||
|   lua_unlock(L); | ||||
|   return name; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { | ||||
|   CallInfo *ci = L->base_ci + ar->i_ci; | ||||
|   const char *name = findlocal(L, ci, n); | ||||
|   lua_lock(L); | ||||
|   if (name) | ||||
|       setobjs2s(L, ci->base + (n - 1), L->top - 1); | ||||
|   L->top--;  /* pop value */ | ||||
|   lua_unlock(L); | ||||
|   return name; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void funcinfo (lua_Debug *ar, Closure *cl) { | ||||
|   if (cl->c.isC) { | ||||
|     ar->source = "=[C]"; | ||||
|     ar->linedefined = -1; | ||||
|     ar->lastlinedefined = -1; | ||||
|     ar->what = "C"; | ||||
|   } | ||||
|   else { | ||||
|     ar->source = getstr(cl->l.p->source); | ||||
|     ar->linedefined = cl->l.p->linedefined; | ||||
|     ar->lastlinedefined = cl->l.p->lastlinedefined; | ||||
|     ar->what = (ar->linedefined == 0) ? "main" : "Lua"; | ||||
|   } | ||||
|   luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void info_tailcall (lua_Debug *ar) { | ||||
|   ar->name = ar->namewhat = ""; | ||||
|   ar->what = "tail"; | ||||
|   ar->lastlinedefined = ar->linedefined = ar->currentline = -1; | ||||
|   ar->source = "=(tail call)"; | ||||
|   luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); | ||||
|   ar->nups = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void collectvalidlines (lua_State *L, Closure *f) { | ||||
|   if (f == NULL || f->c.isC) { | ||||
|     setnilvalue(L->top); | ||||
|   } | ||||
|   else { | ||||
|     Table *t = luaH_new(L, 0, 0); | ||||
|     int *lineinfo = f->l.p->lineinfo; | ||||
|     int i; | ||||
|     for (i=0; i<f->l.p->sizelineinfo; i++) | ||||
|       setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); | ||||
|     sethvalue(L, L->top, t);  | ||||
|   } | ||||
|   incr_top(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, | ||||
|                     Closure *f, CallInfo *ci) { | ||||
|   int status = 1; | ||||
|   if (f == NULL) { | ||||
|     info_tailcall(ar); | ||||
|     return status; | ||||
|   } | ||||
|   for (; *what; what++) { | ||||
|     switch (*what) { | ||||
|       case 'S': { | ||||
|         funcinfo(ar, f); | ||||
|         break; | ||||
|       } | ||||
|       case 'l': { | ||||
|         ar->currentline = (ci) ? currentline(L, ci) : -1; | ||||
|         break; | ||||
|       } | ||||
|       case 'u': { | ||||
|         ar->nups = f->c.nupvalues; | ||||
|         break; | ||||
|       } | ||||
|       case 'n': { | ||||
|         ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; | ||||
|         if (ar->namewhat == NULL) { | ||||
|           ar->namewhat = "";  /* not found */ | ||||
|           ar->name = NULL; | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|       case 'L': | ||||
|       case 'f':  /* handled by lua_getinfo */ | ||||
|         break; | ||||
|       default: status = 0;  /* invalid option */ | ||||
|     } | ||||
|   } | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { | ||||
|   int status; | ||||
|   Closure *f = NULL; | ||||
|   CallInfo *ci = NULL; | ||||
|   lua_lock(L); | ||||
|   if (*what == '>') { | ||||
|     StkId func = L->top - 1; | ||||
|     luai_apicheck(L, ttisfunction(func)); | ||||
|     what++;  /* skip the '>' */ | ||||
|     f = clvalue(func); | ||||
|     L->top--;  /* pop function */ | ||||
|   } | ||||
|   else if (ar->i_ci != 0) {  /* no tail call? */ | ||||
|     ci = L->base_ci + ar->i_ci; | ||||
|     lua_assert(ttisfunction(ci->func)); | ||||
|     f = clvalue(ci->func); | ||||
|   } | ||||
|   status = auxgetinfo(L, what, ar, f, ci); | ||||
|   if (strchr(what, 'f')) { | ||||
|     if (f == NULL) setnilvalue(L->top); | ||||
|     else setclvalue(L, L->top, f); | ||||
|     incr_top(L); | ||||
|   } | ||||
|   if (strchr(what, 'L')) | ||||
|     collectvalidlines(L, f); | ||||
|   lua_unlock(L); | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Symbolic Execution and code checker | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
| #define check(x)		if (!(x)) return 0; | ||||
|  | ||||
| #define checkjump(pt,pc)	check(0 <= pc && pc < pt->sizecode) | ||||
|  | ||||
| #define checkreg(pt,reg)	check((reg) < (pt)->maxstacksize) | ||||
|  | ||||
|  | ||||
|  | ||||
| static int precheck (const Proto *pt) { | ||||
|   check(pt->maxstacksize <= MAXSTACK); | ||||
|   lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); | ||||
|   lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || | ||||
|               (pt->is_vararg & VARARG_HASARG)); | ||||
|   check(pt->sizeupvalues <= pt->nups); | ||||
|   check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); | ||||
|   check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| #define checkopenop(pt,pc)	luaG_checkopenop((pt)->code[(pc)+1]) | ||||
|  | ||||
| int luaG_checkopenop (Instruction i) { | ||||
|   switch (GET_OPCODE(i)) { | ||||
|     case OP_CALL: | ||||
|     case OP_TAILCALL: | ||||
|     case OP_RETURN: | ||||
|     case OP_SETLIST: { | ||||
|       check(GETARG_B(i) == 0); | ||||
|       return 1; | ||||
|     } | ||||
|     default: return 0;  /* invalid instruction after an open call */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { | ||||
|   switch (mode) { | ||||
|     case OpArgN: check(r == 0); break; | ||||
|     case OpArgU: break; | ||||
|     case OpArgR: checkreg(pt, r); break; | ||||
|     case OpArgK: | ||||
|       check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); | ||||
|       break; | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static Instruction symbexec (const Proto *pt, int lastpc, int reg) { | ||||
|   int pc; | ||||
|   int last;  /* stores position of last instruction that changed `reg' */ | ||||
|   last = pt->sizecode-1;  /* points to final return (a `neutral' instruction) */ | ||||
|   check(precheck(pt)); | ||||
|   for (pc = 0; pc < lastpc; pc++) { | ||||
|     Instruction i = pt->code[pc]; | ||||
|     OpCode op = GET_OPCODE(i); | ||||
|     int a = GETARG_A(i); | ||||
|     int b = 0; | ||||
|     int c = 0; | ||||
|     check(op < NUM_OPCODES); | ||||
|     checkreg(pt, a); | ||||
|     switch (getOpMode(op)) { | ||||
|       case iABC: { | ||||
|         b = GETARG_B(i); | ||||
|         c = GETARG_C(i); | ||||
|         check(checkArgMode(pt, b, getBMode(op))); | ||||
|         check(checkArgMode(pt, c, getCMode(op))); | ||||
|         break; | ||||
|       } | ||||
|       case iABx: { | ||||
|         b = GETARG_Bx(i); | ||||
|         if (getBMode(op) == OpArgK) check(b < pt->sizek); | ||||
|         break; | ||||
|       } | ||||
|       case iAsBx: { | ||||
|         b = GETARG_sBx(i); | ||||
|         if (getBMode(op) == OpArgR) { | ||||
|           int dest = pc+1+b; | ||||
|           check(0 <= dest && dest < pt->sizecode); | ||||
|           if (dest > 0) { | ||||
|             /* cannot jump to a setlist count */ | ||||
|             Instruction d = pt->code[dest-1]; | ||||
|             check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); | ||||
|           } | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     if (testAMode(op)) { | ||||
|       if (a == reg) last = pc;  /* change register `a' */ | ||||
|     } | ||||
|     if (testTMode(op)) { | ||||
|       check(pc+2 < pt->sizecode);  /* check skip */ | ||||
|       check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); | ||||
|     } | ||||
|     switch (op) { | ||||
|       case OP_LOADBOOL: { | ||||
|         check(c == 0 || pc+2 < pt->sizecode);  /* check its jump */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_LOADNIL: { | ||||
|         if (a <= reg && reg <= b) | ||||
|           last = pc;  /* set registers from `a' to `b' */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_GETUPVAL: | ||||
|       case OP_SETUPVAL: { | ||||
|         check(b < pt->nups); | ||||
|         break; | ||||
|       } | ||||
|       case OP_GETGLOBAL: | ||||
|       case OP_SETGLOBAL: { | ||||
|         check(ttisstring(&pt->k[b])); | ||||
|         break; | ||||
|       } | ||||
|       case OP_SELF: { | ||||
|         checkreg(pt, a+1); | ||||
|         if (reg == a+1) last = pc; | ||||
|         break; | ||||
|       } | ||||
|       case OP_CONCAT: { | ||||
|         check(b < c);  /* at least two operands */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_TFORLOOP: { | ||||
|         check(c >= 1);  /* at least one result (control variable) */ | ||||
|         checkreg(pt, a+2+c);  /* space for results */ | ||||
|         if (reg >= a+2) last = pc;  /* affect all regs above its base */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_FORLOOP: | ||||
|       case OP_FORPREP: | ||||
|         checkreg(pt, a+3); | ||||
|         /* go through */ | ||||
|       case OP_JMP: { | ||||
|         int dest = pc+1+b; | ||||
|         /* not full check and jump is forward and do not skip `lastpc'? */ | ||||
|         if (reg != NO_REG && pc < dest && dest <= lastpc) | ||||
|           pc += b;  /* do the jump */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_CALL: | ||||
|       case OP_TAILCALL: { | ||||
|         if (b != 0) { | ||||
|           checkreg(pt, a+b-1); | ||||
|         } | ||||
|         c--;  /* c = num. returns */ | ||||
|         if (c == LUA_MULTRET) { | ||||
|           check(checkopenop(pt, pc)); | ||||
|         } | ||||
|         else if (c != 0) | ||||
|           checkreg(pt, a+c-1); | ||||
|         if (reg >= a) last = pc;  /* affect all registers above base */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_RETURN: { | ||||
|         b--;  /* b = num. returns */ | ||||
|         if (b > 0) checkreg(pt, a+b-1); | ||||
|         break; | ||||
|       } | ||||
|       case OP_SETLIST: { | ||||
|         if (b > 0) checkreg(pt, a + b); | ||||
|         if (c == 0) pc++; | ||||
|         break; | ||||
|       } | ||||
|       case OP_CLOSURE: { | ||||
|         int nup, j; | ||||
|         check(b < pt->sizep); | ||||
|         nup = pt->p[b]->nups; | ||||
|         check(pc + nup < pt->sizecode); | ||||
|         for (j = 1; j <= nup; j++) { | ||||
|           OpCode op1 = GET_OPCODE(pt->code[pc + j]); | ||||
|           check(op1 == OP_GETUPVAL || op1 == OP_MOVE); | ||||
|         } | ||||
|         if (reg != NO_REG)  /* tracing? */ | ||||
|           pc += nup;  /* do not 'execute' these pseudo-instructions */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_VARARG: { | ||||
|         check((pt->is_vararg & VARARG_ISVARARG) && | ||||
|              !(pt->is_vararg & VARARG_NEEDSARG)); | ||||
|         b--; | ||||
|         if (b == LUA_MULTRET) check(checkopenop(pt, pc)); | ||||
|         checkreg(pt, a+b-1); | ||||
|         break; | ||||
|       } | ||||
|       default: break; | ||||
|     } | ||||
|   } | ||||
|   return pt->code[last]; | ||||
| } | ||||
|  | ||||
| #undef check | ||||
| #undef checkjump | ||||
| #undef checkreg | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| int luaG_checkcode (const Proto *pt) { | ||||
|   return (symbexec(pt, pt->sizecode, NO_REG) != 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *kname (Proto *p, int c) { | ||||
|   if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) | ||||
|     return svalue(&p->k[INDEXK(c)]); | ||||
|   else | ||||
|     return "?"; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, | ||||
|                                const char **name) { | ||||
|   if (isLua(ci)) {  /* a Lua function? */ | ||||
|     Proto *p = ci_func(ci)->l.p; | ||||
|     int pc = currentpc(L, ci); | ||||
|     Instruction i; | ||||
|     *name = luaF_getlocalname(p, stackpos+1, pc); | ||||
|     if (*name)  /* is a local? */ | ||||
|       return "local"; | ||||
|     i = symbexec(p, pc, stackpos);  /* try symbolic execution */ | ||||
|     lua_assert(pc != -1); | ||||
|     switch (GET_OPCODE(i)) { | ||||
|       case OP_GETGLOBAL: { | ||||
|         int g = GETARG_Bx(i);  /* global index */ | ||||
|         lua_assert(ttisstring(&p->k[g])); | ||||
|         *name = svalue(&p->k[g]); | ||||
|         return "global"; | ||||
|       } | ||||
|       case OP_MOVE: { | ||||
|         int a = GETARG_A(i); | ||||
|         int b = GETARG_B(i);  /* move from `b' to `a' */ | ||||
|         if (b < a) | ||||
|           return getobjname(L, ci, b, name);  /* get name for `b' */ | ||||
|         break; | ||||
|       } | ||||
|       case OP_GETTABLE: { | ||||
|         int k = GETARG_C(i);  /* key index */ | ||||
|         *name = kname(p, k); | ||||
|         return "field"; | ||||
|       } | ||||
|       case OP_GETUPVAL: { | ||||
|         int u = GETARG_B(i);  /* upvalue index */ | ||||
|         *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; | ||||
|         return "upvalue"; | ||||
|       } | ||||
|       case OP_SELF: { | ||||
|         int k = GETARG_C(i);  /* key index */ | ||||
|         *name = kname(p, k); | ||||
|         return "method"; | ||||
|       } | ||||
|       default: break; | ||||
|     } | ||||
|   } | ||||
|   return NULL;  /* no useful name found */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { | ||||
|   Instruction i; | ||||
|   if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) | ||||
|     return NULL;  /* calling function is not Lua (or is unknown) */ | ||||
|   ci--;  /* calling function */ | ||||
|   i = ci_func(ci)->l.p->code[currentpc(L, ci)]; | ||||
|   if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || | ||||
|       GET_OPCODE(i) == OP_TFORLOOP) | ||||
|     return getobjname(L, ci, GETARG_A(i), name); | ||||
|   else | ||||
|     return NULL;  /* no useful name can be found */ | ||||
| } | ||||
|  | ||||
|  | ||||
| /* only ANSI way to check whether a pointer points to an array */ | ||||
| static int isinstack (CallInfo *ci, const TValue *o) { | ||||
|   StkId p; | ||||
|   for (p = ci->base; p < ci->top; p++) | ||||
|     if (o == p) return 1; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { | ||||
|   const char *name = NULL; | ||||
|   const char *t = luaT_typenames[ttype(o)]; | ||||
|   const char *kind = (isinstack(L->ci, o)) ? | ||||
|                          getobjname(L, L->ci, cast_int(o - L->base), &name) : | ||||
|                          NULL; | ||||
|   if (kind) | ||||
|     luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", | ||||
|                 op, kind, name, t); | ||||
|   else | ||||
|     luaG_runerror(L, "attempt to %s a %s value", op, t); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { | ||||
|   if (ttisstring(p1)) p1 = p2; | ||||
|   lua_assert(!ttisstring(p1)); | ||||
|   luaG_typeerror(L, p1, "concatenate"); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { | ||||
|   TValue temp; | ||||
|   if (luaV_tonumber(p1, &temp) == NULL) | ||||
|     p2 = p1;  /* first operand is wrong */ | ||||
|   luaG_typeerror(L, p2, "perform arithmetic on"); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { | ||||
|   const char *t1 = luaT_typenames[ttype(p1)]; | ||||
|   const char *t2 = luaT_typenames[ttype(p2)]; | ||||
|   if (t1[2] == t2[2]) | ||||
|     luaG_runerror(L, "attempt to compare two %s values", t1); | ||||
|   else | ||||
|     luaG_runerror(L, "attempt to compare %s with %s", t1, t2); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void addinfo (lua_State *L, const char *msg) { | ||||
|   CallInfo *ci = L->ci; | ||||
|   if (isLua(ci)) {  /* is Lua code? */ | ||||
|     char buff[LUA_IDSIZE];  /* add file:line information */ | ||||
|     int line = currentline(L, ci); | ||||
|     luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); | ||||
|     luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaG_errormsg (lua_State *L) { | ||||
|   if (L->errfunc != 0) {  /* is there an error handling function? */ | ||||
|     StkId errfunc = restorestack(L, L->errfunc); | ||||
|     if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); | ||||
|     setobjs2s(L, L->top, L->top - 1);  /* move argument */ | ||||
|     setobjs2s(L, L->top - 1, errfunc);  /* push function */ | ||||
|     incr_top(L); | ||||
|     luaD_call(L, L->top - 2, 1);  /* call it */ | ||||
|   } | ||||
|   luaD_throw(L, LUA_ERRRUN); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaG_runerror (lua_State *L, const char *fmt, ...) { | ||||
|   va_list argp; | ||||
|   va_start(argp, fmt); | ||||
|   addinfo(L, luaO_pushvfstring(L, fmt, argp)); | ||||
|   va_end(argp); | ||||
|   luaG_errormsg(L); | ||||
| } | ||||
|  | ||||
							
								
								
									
										516
									
								
								lua/src/ldo.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										516
									
								
								lua/src/ldo.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,516 @@ | ||||
| /* | ||||
| ** $Id: ldo.c,v 2.38 2006/06/05 19:36:14 roberto Exp $ | ||||
| ** Stack and Call structure of Lua | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <setjmp.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define ldo_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lfunc.h" | ||||
| #include "lgc.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lopcodes.h" | ||||
| #include "lparser.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "ltable.h" | ||||
| #include "ltm.h" | ||||
| #include "lundump.h" | ||||
| #include "lvm.h" | ||||
| #include "lzio.h" | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Error-recovery functions | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
| /* chain list of long jump buffers */ | ||||
| struct lua_longjmp { | ||||
|   struct lua_longjmp *previous; | ||||
|   luai_jmpbuf b; | ||||
|   volatile int status;  /* error code */ | ||||
| }; | ||||
|  | ||||
|  | ||||
| void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { | ||||
|   switch (errcode) { | ||||
|     case LUA_ERRMEM: { | ||||
|       setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); | ||||
|       break; | ||||
|     } | ||||
|     case LUA_ERRERR: { | ||||
|       setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); | ||||
|       break; | ||||
|     } | ||||
|     case LUA_ERRSYNTAX: | ||||
|     case LUA_ERRRUN: { | ||||
|       setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */ | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   L->top = oldtop + 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void restore_stack_limit (lua_State *L) { | ||||
|   lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); | ||||
|   if (L->size_ci > LUAI_MAXCALLS) {  /* there was an overflow? */ | ||||
|     int inuse = cast_int(L->ci - L->base_ci); | ||||
|     if (inuse + 1 < LUAI_MAXCALLS)  /* can `undo' overflow? */ | ||||
|       luaD_reallocCI(L, LUAI_MAXCALLS); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void resetstack (lua_State *L, int status) { | ||||
|   L->ci = L->base_ci; | ||||
|   L->base = L->ci->base; | ||||
|   luaF_close(L, L->base);  /* close eventual pending closures */ | ||||
|   luaD_seterrorobj(L, status, L->base); | ||||
|   L->nCcalls = 0; | ||||
|   L->allowhook = 1; | ||||
|   restore_stack_limit(L); | ||||
|   L->errfunc = 0; | ||||
|   L->errorJmp = NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaD_throw (lua_State *L, int errcode) { | ||||
|   if (L->errorJmp) { | ||||
|     L->errorJmp->status = errcode; | ||||
|     LUAI_THROW(L, L->errorJmp); | ||||
|   } | ||||
|   else { | ||||
|     L->status = cast_byte(errcode); | ||||
|     if (G(L)->panic) { | ||||
|       resetstack(L, errcode); | ||||
|       lua_unlock(L); | ||||
|       G(L)->panic(L); | ||||
|     } | ||||
|     exit(EXIT_FAILURE); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | ||||
|   struct lua_longjmp lj; | ||||
|   lj.status = 0; | ||||
|   lj.previous = L->errorJmp;  /* chain new error handler */ | ||||
|   L->errorJmp = &lj; | ||||
|   LUAI_TRY(L, &lj, | ||||
|     (*f)(L, ud); | ||||
|   ); | ||||
|   L->errorJmp = lj.previous;  /* restore old error handler */ | ||||
|   return lj.status; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| static void correctstack (lua_State *L, TValue *oldstack) { | ||||
|   CallInfo *ci; | ||||
|   GCObject *up; | ||||
|   L->top = (L->top - oldstack) + L->stack; | ||||
|   for (up = L->openupval; up != NULL; up = up->gch.next) | ||||
|     gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; | ||||
|   for (ci = L->base_ci; ci <= L->ci; ci++) { | ||||
|     ci->top = (ci->top - oldstack) + L->stack; | ||||
|     ci->base = (ci->base - oldstack) + L->stack; | ||||
|     ci->func = (ci->func - oldstack) + L->stack; | ||||
|   } | ||||
|   L->base = (L->base - oldstack) + L->stack; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaD_reallocstack (lua_State *L, int newsize) { | ||||
|   TValue *oldstack = L->stack; | ||||
|   int realsize = newsize + 1 + EXTRA_STACK; | ||||
|   lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); | ||||
|   luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); | ||||
|   L->stacksize = realsize; | ||||
|   L->stack_last = L->stack+newsize; | ||||
|   correctstack(L, oldstack); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaD_reallocCI (lua_State *L, int newsize) { | ||||
|   CallInfo *oldci = L->base_ci; | ||||
|   luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); | ||||
|   L->size_ci = newsize; | ||||
|   L->ci = (L->ci - oldci) + L->base_ci; | ||||
|   L->end_ci = L->base_ci + L->size_ci - 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaD_growstack (lua_State *L, int n) { | ||||
|   if (n <= L->stacksize)  /* double size is enough? */ | ||||
|     luaD_reallocstack(L, 2*L->stacksize); | ||||
|   else | ||||
|     luaD_reallocstack(L, L->stacksize + n); | ||||
| } | ||||
|  | ||||
|  | ||||
| static CallInfo *growCI (lua_State *L) { | ||||
|   if (L->size_ci > LUAI_MAXCALLS)  /* overflow while handling overflow? */ | ||||
|     luaD_throw(L, LUA_ERRERR); | ||||
|   else { | ||||
|     luaD_reallocCI(L, 2*L->size_ci); | ||||
|     if (L->size_ci > LUAI_MAXCALLS) | ||||
|       luaG_runerror(L, "stack overflow"); | ||||
|   } | ||||
|   return ++L->ci; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaD_callhook (lua_State *L, int event, int line) { | ||||
|   lua_Hook hook = L->hook; | ||||
|   if (hook && L->allowhook) { | ||||
|     ptrdiff_t top = savestack(L, L->top); | ||||
|     ptrdiff_t ci_top = savestack(L, L->ci->top); | ||||
|     lua_Debug ar; | ||||
|     ar.event = event; | ||||
|     ar.currentline = line; | ||||
|     if (event == LUA_HOOKTAILRET) | ||||
|       ar.i_ci = 0;  /* tail call; no debug information about it */ | ||||
|     else | ||||
|       ar.i_ci = cast_int(L->ci - L->base_ci); | ||||
|     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */ | ||||
|     L->ci->top = L->top + LUA_MINSTACK; | ||||
|     lua_assert(L->ci->top <= L->stack_last); | ||||
|     L->allowhook = 0;  /* cannot call hooks inside a hook */ | ||||
|     lua_unlock(L); | ||||
|     (*hook)(L, &ar); | ||||
|     lua_lock(L); | ||||
|     lua_assert(!L->allowhook); | ||||
|     L->allowhook = 1; | ||||
|     L->ci->top = restorestack(L, ci_top); | ||||
|     L->top = restorestack(L, top); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { | ||||
|   int i; | ||||
|   int nfixargs = p->numparams; | ||||
|   Table *htab = NULL; | ||||
|   StkId base, fixed; | ||||
|   for (; actual < nfixargs; ++actual) | ||||
|     setnilvalue(L->top++); | ||||
| #if defined(LUA_COMPAT_VARARG) | ||||
|   if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ | ||||
|     int nvar = actual - nfixargs;  /* number of extra arguments */ | ||||
|     lua_assert(p->is_vararg & VARARG_HASARG); | ||||
|     luaC_checkGC(L); | ||||
|     htab = luaH_new(L, nvar, 1);  /* create `arg' table */ | ||||
|     for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */ | ||||
|       setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i); | ||||
|     /* store counter in field `n' */ | ||||
|     setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); | ||||
|   } | ||||
| #endif | ||||
|   /* move fixed parameters to final position */ | ||||
|   fixed = L->top - actual;  /* first fixed argument */ | ||||
|   base = L->top;  /* final position of first argument */ | ||||
|   for (i=0; i<nfixargs; i++) { | ||||
|     setobjs2s(L, L->top++, fixed+i); | ||||
|     setnilvalue(fixed+i); | ||||
|   } | ||||
|   /* add `arg' parameter */ | ||||
|   if (htab) { | ||||
|     sethvalue(L, L->top++, htab); | ||||
|     lua_assert(iswhite(obj2gco(htab))); | ||||
|   } | ||||
|   return base; | ||||
| } | ||||
|  | ||||
|  | ||||
| static StkId tryfuncTM (lua_State *L, StkId func) { | ||||
|   const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); | ||||
|   StkId p; | ||||
|   ptrdiff_t funcr = savestack(L, func); | ||||
|   if (!ttisfunction(tm)) | ||||
|     luaG_typeerror(L, func, "call"); | ||||
|   /* Open a hole inside the stack at `func' */ | ||||
|   for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); | ||||
|   incr_top(L); | ||||
|   func = restorestack(L, funcr);  /* previous call may change stack */ | ||||
|   setobj2s(L, func, tm);  /* tag method is the new function to be called */ | ||||
|   return func; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| #define inc_ci(L) \ | ||||
|   ((L->ci == L->end_ci) ? growCI(L) : \ | ||||
|    (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) | ||||
|  | ||||
|  | ||||
| int luaD_precall (lua_State *L, StkId func, int nresults) { | ||||
|   LClosure *cl; | ||||
|   ptrdiff_t funcr; | ||||
|   if (!ttisfunction(func)) /* `func' is not a function? */ | ||||
|     func = tryfuncTM(L, func);  /* check the `function' tag method */ | ||||
|   funcr = savestack(L, func); | ||||
|   cl = &clvalue(func)->l; | ||||
|   L->ci->savedpc = L->savedpc; | ||||
|   if (!cl->isC) {  /* Lua function? prepare its call */ | ||||
|     CallInfo *ci; | ||||
|     StkId st, base; | ||||
|     Proto *p = cl->p; | ||||
|     luaD_checkstack(L, p->maxstacksize); | ||||
|     func = restorestack(L, funcr); | ||||
|     if (!p->is_vararg) {  /* no varargs? */ | ||||
|       base = func + 1; | ||||
|       if (L->top > base + p->numparams) | ||||
|         L->top = base + p->numparams; | ||||
|     } | ||||
|     else {  /* vararg function */ | ||||
|       int nargs = cast_int(L->top - func) - 1; | ||||
|       base = adjust_varargs(L, p, nargs); | ||||
|       func = restorestack(L, funcr);  /* previous call may change the stack */ | ||||
|     } | ||||
|     ci = inc_ci(L);  /* now `enter' new function */ | ||||
|     ci->func = func; | ||||
|     L->base = ci->base = base; | ||||
|     ci->top = L->base + p->maxstacksize; | ||||
|     lua_assert(ci->top <= L->stack_last); | ||||
|     L->savedpc = p->code;  /* starting point */ | ||||
|     ci->tailcalls = 0; | ||||
|     ci->nresults = nresults; | ||||
|     for (st = L->top; st < ci->top; st++) | ||||
|       setnilvalue(st); | ||||
|     L->top = ci->top; | ||||
|     if (L->hookmask & LUA_MASKCALL) { | ||||
|       L->savedpc++;  /* hooks assume 'pc' is already incremented */ | ||||
|       luaD_callhook(L, LUA_HOOKCALL, -1); | ||||
|       L->savedpc--;  /* correct 'pc' */ | ||||
|     } | ||||
|     return PCRLUA; | ||||
|   } | ||||
|   else {  /* if is a C function, call it */ | ||||
|     CallInfo *ci; | ||||
|     int n; | ||||
|     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */ | ||||
|     ci = inc_ci(L);  /* now `enter' new function */ | ||||
|     ci->func = restorestack(L, funcr); | ||||
|     L->base = ci->base = ci->func + 1; | ||||
|     ci->top = L->top + LUA_MINSTACK; | ||||
|     lua_assert(ci->top <= L->stack_last); | ||||
|     ci->nresults = nresults; | ||||
|     if (L->hookmask & LUA_MASKCALL) | ||||
|       luaD_callhook(L, LUA_HOOKCALL, -1); | ||||
|     lua_unlock(L); | ||||
|     n = (*curr_func(L)->c.f)(L);  /* do the actual call */ | ||||
|     lua_lock(L); | ||||
|     if (n < 0)  /* yielding? */ | ||||
|       return PCRYIELD; | ||||
|     else { | ||||
|       luaD_poscall(L, L->top - n); | ||||
|       return PCRC; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static StkId callrethooks (lua_State *L, StkId firstResult) { | ||||
|   ptrdiff_t fr = savestack(L, firstResult);  /* next call may change stack */ | ||||
|   luaD_callhook(L, LUA_HOOKRET, -1); | ||||
|   if (f_isLua(L->ci)) {  /* Lua function? */ | ||||
|     while (L->ci->tailcalls--)  /* call hook for eventual tail calls */ | ||||
|       luaD_callhook(L, LUA_HOOKTAILRET, -1); | ||||
|   } | ||||
|   return restorestack(L, fr); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaD_poscall (lua_State *L, StkId firstResult) { | ||||
|   StkId res; | ||||
|   int wanted, i; | ||||
|   CallInfo *ci; | ||||
|   if (L->hookmask & LUA_MASKRET) | ||||
|     firstResult = callrethooks(L, firstResult); | ||||
|   ci = L->ci--; | ||||
|   res = ci->func;  /* res == final position of 1st result */ | ||||
|   wanted = ci->nresults; | ||||
|   L->base = (ci - 1)->base;  /* restore base */ | ||||
|   L->savedpc = (ci - 1)->savedpc;  /* restore savedpc */ | ||||
|   /* move results to correct place */ | ||||
|   for (i = wanted; i != 0 && firstResult < L->top; i--) | ||||
|     setobjs2s(L, res++, firstResult++); | ||||
|   while (i-- > 0) | ||||
|     setnilvalue(res++); | ||||
|   L->top = res; | ||||
|   return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */ | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Call a function (C or Lua). The function to be called is at *func. | ||||
| ** The arguments are on the stack, right after the function. | ||||
| ** When returns, all the results are on the stack, starting at the original | ||||
| ** function position. | ||||
| */  | ||||
| void luaD_call (lua_State *L, StkId func, int nResults) { | ||||
|   if (++L->nCcalls >= LUAI_MAXCCALLS) { | ||||
|     if (L->nCcalls == LUAI_MAXCCALLS) | ||||
|       luaG_runerror(L, "C stack overflow"); | ||||
|     else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) | ||||
|       luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */ | ||||
|   } | ||||
|   if (luaD_precall(L, func, nResults) == PCRLUA)  /* is a Lua function? */ | ||||
|     luaV_execute(L, 1);  /* call it */ | ||||
|   L->nCcalls--; | ||||
|   luaC_checkGC(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void resume (lua_State *L, void *ud) { | ||||
|   StkId firstArg = cast(StkId, ud); | ||||
|   CallInfo *ci = L->ci; | ||||
|   if (L->status == 0) {  /* start coroutine? */ | ||||
|     lua_assert(ci == L->base_ci && firstArg > L->base); | ||||
|     if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) | ||||
|       return; | ||||
|   } | ||||
|   else {  /* resuming from previous yield */ | ||||
|     lua_assert(L->status == LUA_YIELD); | ||||
|     L->status = 0; | ||||
|     if (!f_isLua(ci)) {  /* `common' yield? */ | ||||
|       /* finish interrupted execution of `OP_CALL' */ | ||||
|       lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || | ||||
|                  GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); | ||||
|       if (luaD_poscall(L, firstArg))  /* complete it... */ | ||||
|         L->top = L->ci->top;  /* and correct top if not multiple results */ | ||||
|     } | ||||
|     else  /* yielded inside a hook: just continue its execution */ | ||||
|       L->base = L->ci->base; | ||||
|   } | ||||
|   luaV_execute(L, cast_int(L->ci - L->base_ci)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int resume_error (lua_State *L, const char *msg) { | ||||
|   L->top = L->ci->base; | ||||
|   setsvalue2s(L, L->top, luaS_new(L, msg)); | ||||
|   incr_top(L); | ||||
|   lua_unlock(L); | ||||
|   return LUA_ERRRUN; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API int lua_resume (lua_State *L, int nargs) { | ||||
|   int status; | ||||
|   lua_lock(L); | ||||
|   if (L->status != LUA_YIELD) { | ||||
|     if (L->status != 0) | ||||
|       return resume_error(L, "cannot resume dead coroutine"); | ||||
|     else if (L->ci != L->base_ci) | ||||
|       return resume_error(L, "cannot resume non-suspended coroutine"); | ||||
|   } | ||||
|   luai_userstateresume(L, nargs); | ||||
|   lua_assert(L->errfunc == 0 && L->nCcalls == 0); | ||||
|   status = luaD_rawrunprotected(L, resume, L->top - nargs); | ||||
|   if (status != 0) {  /* error? */ | ||||
|     L->status = cast_byte(status);  /* mark thread as `dead' */ | ||||
|     luaD_seterrorobj(L, status, L->top); | ||||
|     L->ci->top = L->top; | ||||
|   } | ||||
|   else | ||||
|     status = L->status; | ||||
|   lua_unlock(L); | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API int lua_yield (lua_State *L, int nresults) { | ||||
|   luai_userstateyield(L, nresults); | ||||
|   lua_lock(L); | ||||
|   if (L->nCcalls > 0) | ||||
|     luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); | ||||
|   L->base = L->top - nresults;  /* protect stack slots below */ | ||||
|   L->status = LUA_YIELD; | ||||
|   lua_unlock(L); | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaD_pcall (lua_State *L, Pfunc func, void *u, | ||||
|                 ptrdiff_t old_top, ptrdiff_t ef) { | ||||
|   int status; | ||||
|   unsigned short oldnCcalls = L->nCcalls; | ||||
|   ptrdiff_t old_ci = saveci(L, L->ci); | ||||
|   lu_byte old_allowhooks = L->allowhook; | ||||
|   ptrdiff_t old_errfunc = L->errfunc; | ||||
|   L->errfunc = ef; | ||||
|   status = luaD_rawrunprotected(L, func, u); | ||||
|   if (status != 0) {  /* an error occurred? */ | ||||
|     StkId oldtop = restorestack(L, old_top); | ||||
|     luaF_close(L, oldtop);  /* close eventual pending closures */ | ||||
|     luaD_seterrorobj(L, status, oldtop); | ||||
|     L->nCcalls = oldnCcalls; | ||||
|     L->ci = restoreci(L, old_ci); | ||||
|     L->base = L->ci->base; | ||||
|     L->savedpc = L->ci->savedpc; | ||||
|     L->allowhook = old_allowhooks; | ||||
|     restore_stack_limit(L); | ||||
|   } | ||||
|   L->errfunc = old_errfunc; | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Execute a protected parser. | ||||
| */ | ||||
| struct SParser {  /* data to `f_parser' */ | ||||
|   ZIO *z; | ||||
|   Mbuffer buff;  /* buffer to be used by the scanner */ | ||||
|   const char *name; | ||||
| }; | ||||
|  | ||||
| static void f_parser (lua_State *L, void *ud) { | ||||
|   int i; | ||||
|   Proto *tf; | ||||
|   Closure *cl; | ||||
|   struct SParser *p = cast(struct SParser *, ud); | ||||
|   int c = luaZ_lookahead(p->z); | ||||
|   luaC_checkGC(L); | ||||
|   tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, | ||||
|                                                              &p->buff, p->name); | ||||
|   cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); | ||||
|   cl->l.p = tf; | ||||
|   for (i = 0; i < tf->nups; i++)  /* initialize eventual upvalues */ | ||||
|     cl->l.upvals[i] = luaF_newupval(L); | ||||
|   setclvalue(L, L->top, cl); | ||||
|   incr_top(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { | ||||
|   struct SParser p; | ||||
|   int status; | ||||
|   p.z = z; p.name = name; | ||||
|   luaZ_initbuffer(L, &p.buff); | ||||
|   status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); | ||||
|   luaZ_freebuffer(L, &p.buff); | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										164
									
								
								lua/src/ldump.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								lua/src/ldump.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| /* | ||||
| ** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $ | ||||
| ** save precompiled Lua chunks | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
| #include <stddef.h> | ||||
|  | ||||
| #define ldump_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
| #include "lundump.h" | ||||
|  | ||||
| typedef struct { | ||||
|  lua_State* L; | ||||
|  lua_Writer writer; | ||||
|  void* data; | ||||
|  int strip; | ||||
|  int status; | ||||
| } DumpState; | ||||
|  | ||||
| #define DumpMem(b,n,size,D)	DumpBlock(b,(n)*(size),D) | ||||
| #define DumpVar(x,D)	 	DumpMem(&x,1,sizeof(x),D) | ||||
|  | ||||
| static void DumpBlock(const void* b, size_t size, DumpState* D) | ||||
| { | ||||
|  if (D->status==0) | ||||
|  { | ||||
|   lua_unlock(D->L); | ||||
|   D->status=(*D->writer)(D->L,b,size,D->data); | ||||
|   lua_lock(D->L); | ||||
|  } | ||||
| } | ||||
|  | ||||
| static void DumpChar(int y, DumpState* D) | ||||
| { | ||||
|  char x=(char)y; | ||||
|  DumpVar(x,D); | ||||
| } | ||||
|  | ||||
| static void DumpInt(int x, DumpState* D) | ||||
| { | ||||
|  DumpVar(x,D); | ||||
| } | ||||
|  | ||||
| static void DumpNumber(lua_Number x, DumpState* D) | ||||
| { | ||||
|  DumpVar(x,D); | ||||
| } | ||||
|  | ||||
| static void DumpVector(const void* b, int n, size_t size, DumpState* D) | ||||
| { | ||||
|  DumpInt(n,D); | ||||
|  DumpMem(b,n,size,D); | ||||
| } | ||||
|  | ||||
| static void DumpString(const TString* s, DumpState* D) | ||||
| { | ||||
|  if (s==NULL || getstr(s)==NULL) | ||||
|  { | ||||
|   size_t size=0; | ||||
|   DumpVar(size,D); | ||||
|  } | ||||
|  else | ||||
|  { | ||||
|   size_t size=s->tsv.len+1;		/* include trailing '\0' */ | ||||
|   DumpVar(size,D); | ||||
|   DumpBlock(getstr(s),size,D); | ||||
|  } | ||||
| } | ||||
|  | ||||
| #define DumpCode(f,D)	 DumpVector(f->code,f->sizecode,sizeof(Instruction),D) | ||||
|  | ||||
| static void DumpFunction(const Proto* f, const TString* p, DumpState* D); | ||||
|  | ||||
| static void DumpConstants(const Proto* f, DumpState* D) | ||||
| { | ||||
|  int i,n=f->sizek; | ||||
|  DumpInt(n,D); | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   const TValue* o=&f->k[i]; | ||||
|   DumpChar(ttype(o),D); | ||||
|   switch (ttype(o)) | ||||
|   { | ||||
|    case LUA_TNIL: | ||||
| 	break; | ||||
|    case LUA_TBOOLEAN: | ||||
| 	DumpChar(bvalue(o),D); | ||||
| 	break; | ||||
|    case LUA_TNUMBER: | ||||
| 	DumpNumber(nvalue(o),D); | ||||
| 	break; | ||||
|    case LUA_TSTRING: | ||||
| 	DumpString(rawtsvalue(o),D); | ||||
| 	break; | ||||
|    default: | ||||
| 	lua_assert(0);			/* cannot happen */ | ||||
| 	break; | ||||
|   } | ||||
|  } | ||||
|  n=f->sizep; | ||||
|  DumpInt(n,D); | ||||
|  for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D); | ||||
| } | ||||
|  | ||||
| static void DumpDebug(const Proto* f, DumpState* D) | ||||
| { | ||||
|  int i,n; | ||||
|  n= (D->strip) ? 0 : f->sizelineinfo; | ||||
|  DumpVector(f->lineinfo,n,sizeof(int),D); | ||||
|  n= (D->strip) ? 0 : f->sizelocvars; | ||||
|  DumpInt(n,D); | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   DumpString(f->locvars[i].varname,D); | ||||
|   DumpInt(f->locvars[i].startpc,D); | ||||
|   DumpInt(f->locvars[i].endpc,D); | ||||
|  } | ||||
|  n= (D->strip) ? 0 : f->sizeupvalues; | ||||
|  DumpInt(n,D); | ||||
|  for (i=0; i<n; i++) DumpString(f->upvalues[i],D); | ||||
| } | ||||
|  | ||||
| static void DumpFunction(const Proto* f, const TString* p, DumpState* D) | ||||
| { | ||||
|  DumpString((f->source==p || D->strip) ? NULL : f->source,D); | ||||
|  DumpInt(f->linedefined,D); | ||||
|  DumpInt(f->lastlinedefined,D); | ||||
|  DumpChar(f->nups,D); | ||||
|  DumpChar(f->numparams,D); | ||||
|  DumpChar(f->is_vararg,D); | ||||
|  DumpChar(f->maxstacksize,D); | ||||
|  DumpCode(f,D); | ||||
|  DumpConstants(f,D); | ||||
|  DumpDebug(f,D); | ||||
| } | ||||
|  | ||||
| static void DumpHeader(DumpState* D) | ||||
| { | ||||
|  char h[LUAC_HEADERSIZE]; | ||||
|  luaU_header(h); | ||||
|  DumpBlock(h,LUAC_HEADERSIZE,D); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ** dump Lua function as precompiled chunk | ||||
| */ | ||||
| int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) | ||||
| { | ||||
|  DumpState D; | ||||
|  D.L=L; | ||||
|  D.writer=w; | ||||
|  D.data=data; | ||||
|  D.strip=strip; | ||||
|  D.status=0; | ||||
|  DumpHeader(&D); | ||||
|  DumpFunction(f,NULL,&D); | ||||
|  return D.status; | ||||
| } | ||||
							
								
								
									
										174
									
								
								lua/src/lfunc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								lua/src/lfunc.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| /* | ||||
| ** $Id: lfunc.c,v 2.12a 2005/12/22 16:19:56 roberto Exp $ | ||||
| ** Auxiliary functions to manipulate prototypes and closures | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stddef.h> | ||||
|  | ||||
| #define lfunc_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lfunc.h" | ||||
| #include "lgc.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { | ||||
|   Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); | ||||
|   luaC_link(L, obj2gco(c), LUA_TFUNCTION); | ||||
|   c->c.isC = 1; | ||||
|   c->c.env = e; | ||||
|   c->c.nupvalues = cast_byte(nelems); | ||||
|   return c; | ||||
| } | ||||
|  | ||||
|  | ||||
| Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { | ||||
|   Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); | ||||
|   luaC_link(L, obj2gco(c), LUA_TFUNCTION); | ||||
|   c->l.isC = 0; | ||||
|   c->l.env = e; | ||||
|   c->l.nupvalues = cast_byte(nelems); | ||||
|   while (nelems--) c->l.upvals[nelems] = NULL; | ||||
|   return c; | ||||
| } | ||||
|  | ||||
|  | ||||
| UpVal *luaF_newupval (lua_State *L) { | ||||
|   UpVal *uv = luaM_new(L, UpVal); | ||||
|   luaC_link(L, obj2gco(uv), LUA_TUPVAL); | ||||
|   uv->v = &uv->u.value; | ||||
|   setnilvalue(uv->v); | ||||
|   return uv; | ||||
| } | ||||
|  | ||||
|  | ||||
| UpVal *luaF_findupval (lua_State *L, StkId level) { | ||||
|   global_State *g = G(L); | ||||
|   GCObject **pp = &L->openupval; | ||||
|   UpVal *p; | ||||
|   UpVal *uv; | ||||
|   while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { | ||||
|     lua_assert(p->v != &p->u.value); | ||||
|     if (p->v == level) {  /* found a corresponding upvalue? */ | ||||
|       if (isdead(g, obj2gco(p)))  /* is it dead? */ | ||||
|         changewhite(obj2gco(p));  /* ressurect it */ | ||||
|       return p; | ||||
|     } | ||||
|     pp = &p->next; | ||||
|   } | ||||
|   uv = luaM_new(L, UpVal);  /* not found: create a new one */ | ||||
|   uv->tt = LUA_TUPVAL; | ||||
|   uv->marked = luaC_white(g); | ||||
|   uv->v = level;  /* current value lives in the stack */ | ||||
|   uv->next = *pp;  /* chain it in the proper position */ | ||||
|   *pp = obj2gco(uv); | ||||
|   uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */ | ||||
|   uv->u.l.next = g->uvhead.u.l.next; | ||||
|   uv->u.l.next->u.l.prev = uv; | ||||
|   g->uvhead.u.l.next = uv; | ||||
|   lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||||
|   return uv; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void unlinkupval (UpVal *uv) { | ||||
|   lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||||
|   uv->u.l.next->u.l.prev = uv->u.l.prev;  /* remove from `uvhead' list */ | ||||
|   uv->u.l.prev->u.l.next = uv->u.l.next; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaF_freeupval (lua_State *L, UpVal *uv) { | ||||
|   if (uv->v != &uv->u.value)  /* is it open? */ | ||||
|     unlinkupval(uv);  /* remove from open list */ | ||||
|   luaM_free(L, uv);  /* free upvalue */ | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaF_close (lua_State *L, StkId level) { | ||||
|   UpVal *uv; | ||||
|   global_State *g = G(L); | ||||
|   while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { | ||||
|     GCObject *o = obj2gco(uv); | ||||
|     lua_assert(!isblack(o) && uv->v != &uv->u.value); | ||||
|     L->openupval = uv->next;  /* remove from `open' list */ | ||||
|     if (isdead(g, o)) | ||||
|       luaF_freeupval(L, uv);  /* free upvalue */ | ||||
|     else { | ||||
|       unlinkupval(uv); | ||||
|       setobj(L, &uv->u.value, uv->v); | ||||
|       uv->v = &uv->u.value;  /* now current value lives here */ | ||||
|       luaC_linkupval(L, uv);  /* link upvalue into `gcroot' list */ | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| Proto *luaF_newproto (lua_State *L) { | ||||
|   Proto *f = luaM_new(L, Proto); | ||||
|   luaC_link(L, obj2gco(f), LUA_TPROTO); | ||||
|   f->k = NULL; | ||||
|   f->sizek = 0; | ||||
|   f->p = NULL; | ||||
|   f->sizep = 0; | ||||
|   f->code = NULL; | ||||
|   f->sizecode = 0; | ||||
|   f->sizelineinfo = 0; | ||||
|   f->sizeupvalues = 0; | ||||
|   f->nups = 0; | ||||
|   f->upvalues = NULL; | ||||
|   f->numparams = 0; | ||||
|   f->is_vararg = 0; | ||||
|   f->maxstacksize = 0; | ||||
|   f->lineinfo = NULL; | ||||
|   f->sizelocvars = 0; | ||||
|   f->locvars = NULL; | ||||
|   f->linedefined = 0; | ||||
|   f->lastlinedefined = 0; | ||||
|   f->source = NULL; | ||||
|   return f; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaF_freeproto (lua_State *L, Proto *f) { | ||||
|   luaM_freearray(L, f->code, f->sizecode, Instruction); | ||||
|   luaM_freearray(L, f->p, f->sizep, Proto *); | ||||
|   luaM_freearray(L, f->k, f->sizek, TValue); | ||||
|   luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); | ||||
|   luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); | ||||
|   luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); | ||||
|   luaM_free(L, f); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaF_freeclosure (lua_State *L, Closure *c) { | ||||
|   int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : | ||||
|                           sizeLclosure(c->l.nupvalues); | ||||
|   luaM_freemem(L, c, size); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Look for n-th local variable at line `line' in function `func'. | ||||
| ** Returns NULL if not found. | ||||
| */ | ||||
| const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { | ||||
|   int i; | ||||
|   for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) { | ||||
|     if (pc < f->locvars[i].endpc) {  /* is variable active? */ | ||||
|       local_number--; | ||||
|       if (local_number == 0) | ||||
|         return getstr(f->locvars[i].varname); | ||||
|     } | ||||
|   } | ||||
|   return NULL;  /* not found */ | ||||
| } | ||||
|  | ||||
							
								
								
									
										711
									
								
								lua/src/lgc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										711
									
								
								lua/src/lgc.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,711 @@ | ||||
| /* | ||||
| ** $Id: lgc.c,v 2.38 2006/05/24 14:34:06 roberto Exp $ | ||||
| ** Garbage Collector | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
| #include <string.h> | ||||
|  | ||||
| #define lgc_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lfunc.h" | ||||
| #include "lgc.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "ltable.h" | ||||
| #include "ltm.h" | ||||
|  | ||||
|  | ||||
| #define GCSTEPSIZE	1024u | ||||
| #define GCSWEEPMAX	40 | ||||
| #define GCSWEEPCOST	10 | ||||
| #define GCFINALIZECOST	100 | ||||
|  | ||||
|  | ||||
| #define maskmarks	cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) | ||||
|  | ||||
| #define makewhite(g,x)	\ | ||||
|    ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) | ||||
|  | ||||
| #define white2gray(x)	reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) | ||||
| #define black2gray(x)	resetbit((x)->gch.marked, BLACKBIT) | ||||
|  | ||||
| #define stringmark(s)	reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) | ||||
|  | ||||
|  | ||||
| #define isfinalized(u)		testbit((u)->marked, FINALIZEDBIT) | ||||
| #define markfinalized(u)	l_setbit((u)->marked, FINALIZEDBIT) | ||||
|  | ||||
|  | ||||
| #define KEYWEAK         bitmask(KEYWEAKBIT) | ||||
| #define VALUEWEAK       bitmask(VALUEWEAKBIT) | ||||
|  | ||||
|  | ||||
|  | ||||
| #define markvalue(g,o) { checkconsistency(o); \ | ||||
|   if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } | ||||
|  | ||||
| #define markobject(g,t) { if (iswhite(obj2gco(t))) \ | ||||
| 		reallymarkobject(g, obj2gco(t)); } | ||||
|  | ||||
|  | ||||
| #define setthreshold(g)  (g->GCthreshold = (g->estimate/100) * g->gcpause) | ||||
|  | ||||
|  | ||||
| static void removeentry (Node *n) { | ||||
|   lua_assert(ttisnil(gval(n))); | ||||
|   if (iscollectable(gkey(n))) | ||||
|     setttype(gkey(n), LUA_TDEADKEY);  /* dead key; remove it */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static void reallymarkobject (global_State *g, GCObject *o) { | ||||
|   lua_assert(iswhite(o) && !isdead(g, o)); | ||||
|   white2gray(o); | ||||
|   switch (o->gch.tt) { | ||||
|     case LUA_TSTRING: { | ||||
|       return; | ||||
|     } | ||||
|     case LUA_TUSERDATA: { | ||||
|       Table *mt = gco2u(o)->metatable; | ||||
|       gray2black(o);  /* udata are never gray */ | ||||
|       if (mt) markobject(g, mt); | ||||
|       markobject(g, gco2u(o)->env); | ||||
|       return; | ||||
|     } | ||||
|     case LUA_TUPVAL: { | ||||
|       UpVal *uv = gco2uv(o); | ||||
|       markvalue(g, uv->v); | ||||
|       if (uv->v == &uv->u.value)  /* closed? */ | ||||
|         gray2black(o);  /* open upvalues are never black */ | ||||
|       return; | ||||
|     } | ||||
|     case LUA_TFUNCTION: { | ||||
|       gco2cl(o)->c.gclist = g->gray; | ||||
|       g->gray = o; | ||||
|       break; | ||||
|     } | ||||
|     case LUA_TTABLE: { | ||||
|       gco2h(o)->gclist = g->gray; | ||||
|       g->gray = o; | ||||
|       break; | ||||
|     } | ||||
|     case LUA_TTHREAD: { | ||||
|       gco2th(o)->gclist = g->gray; | ||||
|       g->gray = o; | ||||
|       break; | ||||
|     } | ||||
|     case LUA_TPROTO: { | ||||
|       gco2p(o)->gclist = g->gray; | ||||
|       g->gray = o; | ||||
|       break; | ||||
|     } | ||||
|     default: lua_assert(0); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void marktmu (global_State *g) { | ||||
|   GCObject *u = g->tmudata; | ||||
|   if (u) { | ||||
|     do { | ||||
|       u = u->gch.next; | ||||
|       makewhite(g, u);  /* may be marked, if left from previous GC */ | ||||
|       reallymarkobject(g, u); | ||||
|     } while (u != g->tmudata); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* move `dead' udata that need finalization to list `tmudata' */ | ||||
| size_t luaC_separateudata (lua_State *L, int all) { | ||||
|   global_State *g = G(L); | ||||
|   size_t deadmem = 0; | ||||
|   GCObject **p = &g->mainthread->next; | ||||
|   GCObject *curr; | ||||
|   while ((curr = *p) != NULL) { | ||||
|     if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) | ||||
|       p = &curr->gch.next;  /* don't bother with them */ | ||||
|     else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { | ||||
|       markfinalized(gco2u(curr));  /* don't need finalization */ | ||||
|       p = &curr->gch.next; | ||||
|     } | ||||
|     else {  /* must call its gc method */ | ||||
|       deadmem += sizeudata(gco2u(curr)); | ||||
|       markfinalized(gco2u(curr)); | ||||
|       *p = curr->gch.next; | ||||
|       /* link `curr' at the end of `tmudata' list */ | ||||
|       if (g->tmudata == NULL)  /* list is empty? */ | ||||
|         g->tmudata = curr->gch.next = curr;  /* creates a circular list */ | ||||
|       else { | ||||
|         curr->gch.next = g->tmudata->gch.next; | ||||
|         g->tmudata->gch.next = curr; | ||||
|         g->tmudata = curr; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return deadmem; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int traversetable (global_State *g, Table *h) { | ||||
|   int i; | ||||
|   int weakkey = 0; | ||||
|   int weakvalue = 0; | ||||
|   const TValue *mode; | ||||
|   if (h->metatable) | ||||
|     markobject(g, h->metatable); | ||||
|   mode = gfasttm(g, h->metatable, TM_MODE); | ||||
|   if (mode && ttisstring(mode)) {  /* is there a weak mode? */ | ||||
|     weakkey = (strchr(svalue(mode), 'k') != NULL); | ||||
|     weakvalue = (strchr(svalue(mode), 'v') != NULL); | ||||
|     if (weakkey || weakvalue) {  /* is really weak? */ | ||||
|       h->marked &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */ | ||||
|       h->marked |= cast_byte((weakkey << KEYWEAKBIT) | | ||||
|                              (weakvalue << VALUEWEAKBIT)); | ||||
|       h->gclist = g->weak;  /* must be cleared after GC, ... */ | ||||
|       g->weak = obj2gco(h);  /* ... so put in the appropriate list */ | ||||
|     } | ||||
|   } | ||||
|   if (weakkey && weakvalue) return 1; | ||||
|   if (!weakvalue) { | ||||
|     i = h->sizearray; | ||||
|     while (i--) | ||||
|       markvalue(g, &h->array[i]); | ||||
|   } | ||||
|   i = sizenode(h); | ||||
|   while (i--) { | ||||
|     Node *n = gnode(h, i); | ||||
|     lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); | ||||
|     if (ttisnil(gval(n))) | ||||
|       removeentry(n);  /* remove empty entries */ | ||||
|     else { | ||||
|       lua_assert(!ttisnil(gkey(n))); | ||||
|       if (!weakkey) markvalue(g, gkey(n)); | ||||
|       if (!weakvalue) markvalue(g, gval(n)); | ||||
|     } | ||||
|   } | ||||
|   return weakkey || weakvalue; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** All marks are conditional because a GC may happen while the | ||||
| ** prototype is still being created | ||||
| */ | ||||
| static void traverseproto (global_State *g, Proto *f) { | ||||
|   int i; | ||||
|   if (f->source) stringmark(f->source); | ||||
|   for (i=0; i<f->sizek; i++)  /* mark literals */ | ||||
|     markvalue(g, &f->k[i]); | ||||
|   for (i=0; i<f->sizeupvalues; i++) {  /* mark upvalue names */ | ||||
|     if (f->upvalues[i]) | ||||
|       stringmark(f->upvalues[i]); | ||||
|   } | ||||
|   for (i=0; i<f->sizep; i++) {  /* mark nested protos */ | ||||
|     if (f->p[i]) | ||||
|       markobject(g, f->p[i]); | ||||
|   } | ||||
|   for (i=0; i<f->sizelocvars; i++) {  /* mark local-variable names */ | ||||
|     if (f->locvars[i].varname) | ||||
|       stringmark(f->locvars[i].varname); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static void traverseclosure (global_State *g, Closure *cl) { | ||||
|   markobject(g, cl->c.env); | ||||
|   if (cl->c.isC) { | ||||
|     int i; | ||||
|     for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */ | ||||
|       markvalue(g, &cl->c.upvalue[i]); | ||||
|   } | ||||
|   else { | ||||
|     int i; | ||||
|     lua_assert(cl->l.nupvalues == cl->l.p->nups); | ||||
|     markobject(g, cl->l.p); | ||||
|     for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */ | ||||
|       markobject(g, cl->l.upvals[i]); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void checkstacksizes (lua_State *L, StkId max) { | ||||
|   int ci_used = cast_int(L->ci - L->base_ci);  /* number of `ci' in use */ | ||||
|   int s_used = cast_int(max - L->stack);  /* part of stack in use */ | ||||
|   if (L->size_ci > LUAI_MAXCALLS)  /* handling overflow? */ | ||||
|     return;  /* do not touch the stacks */ | ||||
|   if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) | ||||
|     luaD_reallocCI(L, L->size_ci/2);  /* still big enough... */ | ||||
|   condhardstacktests(luaD_reallocCI(L, ci_used + 1)); | ||||
|   if (4*s_used < L->stacksize && | ||||
|       2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) | ||||
|     luaD_reallocstack(L, L->stacksize/2);  /* still big enough... */ | ||||
|   condhardstacktests(luaD_reallocstack(L, s_used)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void traversestack (global_State *g, lua_State *l) { | ||||
|   StkId o, lim; | ||||
|   CallInfo *ci; | ||||
|   markvalue(g, gt(l)); | ||||
|   lim = l->top; | ||||
|   for (ci = l->base_ci; ci <= l->ci; ci++) { | ||||
|     lua_assert(ci->top <= l->stack_last); | ||||
|     if (lim < ci->top) lim = ci->top; | ||||
|   } | ||||
|   for (o = l->stack; o < l->top; o++) | ||||
|     markvalue(g, o); | ||||
|   for (; o <= lim; o++) | ||||
|     setnilvalue(o); | ||||
|   checkstacksizes(l, lim); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** traverse one gray object, turning it to black. | ||||
| ** Returns `quantity' traversed. | ||||
| */ | ||||
| static l_mem propagatemark (global_State *g) { | ||||
|   GCObject *o = g->gray; | ||||
|   lua_assert(isgray(o)); | ||||
|   gray2black(o); | ||||
|   switch (o->gch.tt) { | ||||
|     case LUA_TTABLE: { | ||||
|       Table *h = gco2h(o); | ||||
|       g->gray = h->gclist; | ||||
|       if (traversetable(g, h))  /* table is weak? */ | ||||
|         black2gray(o);  /* keep it gray */ | ||||
|       return sizeof(Table) + sizeof(TValue) * h->sizearray + | ||||
|                              sizeof(Node) * sizenode(h); | ||||
|     } | ||||
|     case LUA_TFUNCTION: { | ||||
|       Closure *cl = gco2cl(o); | ||||
|       g->gray = cl->c.gclist; | ||||
|       traverseclosure(g, cl); | ||||
|       return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : | ||||
|                            sizeLclosure(cl->l.nupvalues); | ||||
|     } | ||||
|     case LUA_TTHREAD: { | ||||
|       lua_State *th = gco2th(o); | ||||
|       g->gray = th->gclist; | ||||
|       th->gclist = g->grayagain; | ||||
|       g->grayagain = o; | ||||
|       black2gray(o); | ||||
|       traversestack(g, th); | ||||
|       return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||||
|                                  sizeof(CallInfo) * th->size_ci; | ||||
|     } | ||||
|     case LUA_TPROTO: { | ||||
|       Proto *p = gco2p(o); | ||||
|       g->gray = p->gclist; | ||||
|       traverseproto(g, p); | ||||
|       return sizeof(Proto) + sizeof(Instruction) * p->sizecode + | ||||
|                              sizeof(Proto *) * p->sizep + | ||||
|                              sizeof(TValue) * p->sizek +  | ||||
|                              sizeof(int) * p->sizelineinfo + | ||||
|                              sizeof(LocVar) * p->sizelocvars + | ||||
|                              sizeof(TString *) * p->sizeupvalues; | ||||
|     } | ||||
|     default: lua_assert(0); return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static size_t propagateall (global_State *g) { | ||||
|   size_t m = 0; | ||||
|   while (g->gray) m += propagatemark(g); | ||||
|   return m; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** The next function tells whether a key or value can be cleared from | ||||
| ** a weak table. Non-collectable objects are never removed from weak | ||||
| ** tables. Strings behave as `values', so are never removed too. for | ||||
| ** other objects: if really collected, cannot keep them; for userdata | ||||
| ** being finalized, keep them in keys, but not in values | ||||
| */ | ||||
| static int iscleared (const TValue *o, int iskey) { | ||||
|   if (!iscollectable(o)) return 0; | ||||
|   if (ttisstring(o)) { | ||||
|     stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */ | ||||
|     return 0; | ||||
|   } | ||||
|   return iswhite(gcvalue(o)) || | ||||
|     (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** clear collected entries from weaktables | ||||
| */ | ||||
| static void cleartable (GCObject *l) { | ||||
|   while (l) { | ||||
|     Table *h = gco2h(l); | ||||
|     int i = h->sizearray; | ||||
|     lua_assert(testbit(h->marked, VALUEWEAKBIT) || | ||||
|                testbit(h->marked, KEYWEAKBIT)); | ||||
|     if (testbit(h->marked, VALUEWEAKBIT)) { | ||||
|       while (i--) { | ||||
|         TValue *o = &h->array[i]; | ||||
|         if (iscleared(o, 0))  /* value was collected? */ | ||||
|           setnilvalue(o);  /* remove value */ | ||||
|       } | ||||
|     } | ||||
|     i = sizenode(h); | ||||
|     while (i--) { | ||||
|       Node *n = gnode(h, i); | ||||
|       if (!ttisnil(gval(n)) &&  /* non-empty entry? */ | ||||
|           (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { | ||||
|         setnilvalue(gval(n));  /* remove value ... */ | ||||
|         removeentry(n);  /* remove entry from table */ | ||||
|       } | ||||
|     } | ||||
|     l = h->gclist; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void freeobj (lua_State *L, GCObject *o) { | ||||
|   switch (o->gch.tt) { | ||||
|     case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; | ||||
|     case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; | ||||
|     case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; | ||||
|     case LUA_TTABLE: luaH_free(L, gco2h(o)); break; | ||||
|     case LUA_TTHREAD: { | ||||
|       lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); | ||||
|       luaE_freethread(L, gco2th(o)); | ||||
|       break; | ||||
|     } | ||||
|     case LUA_TSTRING: { | ||||
|       G(L)->strt.nuse--; | ||||
|       luaM_freemem(L, o, sizestring(gco2ts(o))); | ||||
|       break; | ||||
|     } | ||||
|     case LUA_TUSERDATA: { | ||||
|       luaM_freemem(L, o, sizeudata(gco2u(o))); | ||||
|       break; | ||||
|     } | ||||
|     default: lua_assert(0); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| #define sweepwholelist(L,p)	sweeplist(L,p,MAX_LUMEM) | ||||
|  | ||||
|  | ||||
| static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | ||||
|   GCObject *curr; | ||||
|   global_State *g = G(L); | ||||
|   int deadmask = otherwhite(g); | ||||
|   while ((curr = *p) != NULL && count-- > 0) { | ||||
|     if (curr->gch.tt == LUA_TTHREAD)  /* sweep open upvalues of each thread */ | ||||
|       sweepwholelist(L, &gco2th(curr)->openupval); | ||||
|     if ((curr->gch.marked ^ WHITEBITS) & deadmask) {  /* not dead? */ | ||||
|       lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); | ||||
|       makewhite(g, curr);  /* make it white (for next cycle) */ | ||||
|       p = &curr->gch.next; | ||||
|     } | ||||
|     else {  /* must erase `curr' */ | ||||
|       lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); | ||||
|       *p = curr->gch.next; | ||||
|       if (curr == g->rootgc)  /* is the first element of the list? */ | ||||
|         g->rootgc = curr->gch.next;  /* adjust first */ | ||||
|       freeobj(L, curr); | ||||
|     } | ||||
|   } | ||||
|   return p; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void checkSizes (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   /* check size of string hash */ | ||||
|   if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && | ||||
|       g->strt.size > MINSTRTABSIZE*2) | ||||
|     luaS_resize(L, g->strt.size/2);  /* table is too big */ | ||||
|   /* check size of buffer */ | ||||
|   if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */ | ||||
|     size_t newsize = luaZ_sizebuffer(&g->buff) / 2; | ||||
|     luaZ_resizebuffer(L, &g->buff, newsize); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void GCTM (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   GCObject *o = g->tmudata->gch.next;  /* get first element */ | ||||
|   Udata *udata = rawgco2u(o); | ||||
|   const TValue *tm; | ||||
|   /* remove udata from `tmudata' */ | ||||
|   if (o == g->tmudata)  /* last element? */ | ||||
|     g->tmudata = NULL; | ||||
|   else | ||||
|     g->tmudata->gch.next = udata->uv.next; | ||||
|   udata->uv.next = g->mainthread->next;  /* return it to `root' list */ | ||||
|   g->mainthread->next = o; | ||||
|   makewhite(g, o); | ||||
|   tm = fasttm(L, udata->uv.metatable, TM_GC); | ||||
|   if (tm != NULL) { | ||||
|     lu_byte oldah = L->allowhook; | ||||
|     lu_mem oldt = g->GCthreshold; | ||||
|     L->allowhook = 0;  /* stop debug hooks during GC tag method */ | ||||
|     g->GCthreshold = 2*g->totalbytes;  /* avoid GC steps */ | ||||
|     setobj2s(L, L->top, tm); | ||||
|     setuvalue(L, L->top+1, udata); | ||||
|     L->top += 2; | ||||
|     luaD_call(L, L->top - 2, 0); | ||||
|     L->allowhook = oldah;  /* restore hooks */ | ||||
|     g->GCthreshold = oldt;  /* restore threshold */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Call all GC tag methods | ||||
| */ | ||||
| void luaC_callGCTM (lua_State *L) { | ||||
|   while (G(L)->tmudata) | ||||
|     GCTM(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaC_freeall (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   int i; | ||||
|   g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);  /* mask to collect all elements */ | ||||
|   sweepwholelist(L, &g->rootgc); | ||||
|   for (i = 0; i < g->strt.size; i++)  /* free all string lists */ | ||||
|     sweepwholelist(L, &g->strt.hash[i]); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void markmt (global_State *g) { | ||||
|   int i; | ||||
|   for (i=0; i<NUM_TAGS; i++) | ||||
|     if (g->mt[i]) markobject(g, g->mt[i]); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* mark root set */ | ||||
| static void markroot (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   g->gray = NULL; | ||||
|   g->grayagain = NULL; | ||||
|   g->weak = NULL; | ||||
|   markobject(g, g->mainthread); | ||||
|   /* make global table be traversed before main stack */ | ||||
|   markvalue(g, gt(g->mainthread)); | ||||
|   markvalue(g, registry(L)); | ||||
|   markmt(g); | ||||
|   g->gcstate = GCSpropagate; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void remarkupvals (global_State *g) { | ||||
|   UpVal *uv; | ||||
|   for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { | ||||
|     lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||||
|     if (isgray(obj2gco(uv))) | ||||
|       markvalue(g, uv->v); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void atomic (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   size_t udsize;  /* total size of userdata to be finalized */ | ||||
|   /* remark occasional upvalues of (maybe) dead threads */ | ||||
|   remarkupvals(g); | ||||
|   /* traverse objects cautch by write barrier and by 'remarkupvals' */ | ||||
|   propagateall(g); | ||||
|   /* remark weak tables */ | ||||
|   g->gray = g->weak; | ||||
|   g->weak = NULL; | ||||
|   lua_assert(!iswhite(obj2gco(g->mainthread))); | ||||
|   markobject(g, L);  /* mark running thread */ | ||||
|   markmt(g);  /* mark basic metatables (again) */ | ||||
|   propagateall(g); | ||||
|   /* remark gray again */ | ||||
|   g->gray = g->grayagain; | ||||
|   g->grayagain = NULL; | ||||
|   propagateall(g); | ||||
|   udsize = luaC_separateudata(L, 0);  /* separate userdata to be finalized */ | ||||
|   marktmu(g);  /* mark `preserved' userdata */ | ||||
|   udsize += propagateall(g);  /* remark, to propagate `preserveness' */ | ||||
|   cleartable(g->weak);  /* remove collected objects from weak tables */ | ||||
|   /* flip current white */ | ||||
|   g->currentwhite = cast_byte(otherwhite(g)); | ||||
|   g->sweepstrgc = 0; | ||||
|   g->sweepgc = &g->rootgc; | ||||
|   g->gcstate = GCSsweepstring; | ||||
|   g->estimate = g->totalbytes - udsize;  /* first estimate */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static l_mem singlestep (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   /*lua_checkmemory(L);*/ | ||||
|   switch (g->gcstate) { | ||||
|     case GCSpause: { | ||||
|       markroot(L);  /* start a new collection */ | ||||
|       return 0; | ||||
|     } | ||||
|     case GCSpropagate: { | ||||
|       if (g->gray) | ||||
|         return propagatemark(g); | ||||
|       else {  /* no more `gray' objects */ | ||||
|         atomic(L);  /* finish mark phase */ | ||||
|         return 0; | ||||
|       } | ||||
|     } | ||||
|     case GCSsweepstring: { | ||||
|       lu_mem old = g->totalbytes; | ||||
|       sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); | ||||
|       if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */ | ||||
|         g->gcstate = GCSsweep;  /* end sweep-string phase */ | ||||
|       lua_assert(old >= g->totalbytes); | ||||
|       g->estimate -= old - g->totalbytes; | ||||
|       return GCSWEEPCOST; | ||||
|     } | ||||
|     case GCSsweep: { | ||||
|       lu_mem old = g->totalbytes; | ||||
|       g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); | ||||
|       if (*g->sweepgc == NULL) {  /* nothing more to sweep? */ | ||||
|         checkSizes(L); | ||||
|         g->gcstate = GCSfinalize;  /* end sweep phase */ | ||||
|       } | ||||
|       lua_assert(old >= g->totalbytes); | ||||
|       g->estimate -= old - g->totalbytes; | ||||
|       return GCSWEEPMAX*GCSWEEPCOST; | ||||
|     } | ||||
|     case GCSfinalize: { | ||||
|       if (g->tmudata) { | ||||
|         GCTM(L); | ||||
|         if (g->estimate > GCFINALIZECOST) | ||||
|           g->estimate -= GCFINALIZECOST; | ||||
|         return GCFINALIZECOST; | ||||
|       } | ||||
|       else { | ||||
|         g->gcstate = GCSpause;  /* end collection */ | ||||
|         g->gcdept = 0; | ||||
|         return 0; | ||||
|       } | ||||
|     } | ||||
|     default: lua_assert(0); return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaC_step (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; | ||||
|   if (lim == 0) | ||||
|     lim = (MAX_LUMEM-1)/2;  /* no limit */ | ||||
|   g->gcdept += g->totalbytes - g->GCthreshold; | ||||
|   do { | ||||
|     lim -= singlestep(L); | ||||
|     if (g->gcstate == GCSpause) | ||||
|       break; | ||||
|   } while (lim > 0); | ||||
|   if (g->gcstate != GCSpause) { | ||||
|     if (g->gcdept < GCSTEPSIZE) | ||||
|       g->GCthreshold = g->totalbytes + GCSTEPSIZE;  /* - lim/g->gcstepmul;*/ | ||||
|     else { | ||||
|       g->gcdept -= GCSTEPSIZE; | ||||
|       g->GCthreshold = g->totalbytes; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     lua_assert(g->totalbytes >= g->estimate); | ||||
|     setthreshold(g); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaC_fullgc (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   if (g->gcstate <= GCSpropagate) { | ||||
|     /* reset sweep marks to sweep all elements (returning them to white) */ | ||||
|     g->sweepstrgc = 0; | ||||
|     g->sweepgc = &g->rootgc; | ||||
|     /* reset other collector lists */ | ||||
|     g->gray = NULL; | ||||
|     g->grayagain = NULL; | ||||
|     g->weak = NULL; | ||||
|     g->gcstate = GCSsweepstring; | ||||
|   } | ||||
|   lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); | ||||
|   /* finish any pending sweep phase */ | ||||
|   while (g->gcstate != GCSfinalize) { | ||||
|     lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); | ||||
|     singlestep(L); | ||||
|   } | ||||
|   markroot(L); | ||||
|   while (g->gcstate != GCSpause) { | ||||
|     singlestep(L); | ||||
|   } | ||||
|   setthreshold(g); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | ||||
|   global_State *g = G(L); | ||||
|   lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | ||||
|   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||||
|   lua_assert(ttype(&o->gch) != LUA_TTABLE); | ||||
|   /* must keep invariant? */ | ||||
|   if (g->gcstate == GCSpropagate) | ||||
|     reallymarkobject(g, v);  /* restore invariant */ | ||||
|   else  /* don't mind */ | ||||
|     makewhite(g, o);  /* mark as white just to avoid other barriers */ | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaC_barrierback (lua_State *L, Table *t) { | ||||
|   global_State *g = G(L); | ||||
|   GCObject *o = obj2gco(t); | ||||
|   lua_assert(isblack(o) && !isdead(g, o)); | ||||
|   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||||
|   black2gray(o);  /* make table gray (again) */ | ||||
|   t->gclist = g->grayagain; | ||||
|   g->grayagain = o; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | ||||
|   global_State *g = G(L); | ||||
|   o->gch.next = g->rootgc; | ||||
|   g->rootgc = o; | ||||
|   o->gch.marked = luaC_white(g); | ||||
|   o->gch.tt = tt; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaC_linkupval (lua_State *L, UpVal *uv) { | ||||
|   global_State *g = G(L); | ||||
|   GCObject *o = obj2gco(uv); | ||||
|   o->gch.next = g->rootgc;  /* link upvalue into `rootgc' list */ | ||||
|   g->rootgc = o; | ||||
|   if (isgray(o)) {  | ||||
|     if (g->gcstate == GCSpropagate) { | ||||
|       gray2black(o);  /* closed upvalues need barrier */ | ||||
|       luaC_barrier(L, uv, uv->v); | ||||
|     } | ||||
|     else {  /* sweep phase: sweep it (turning it into white) */ | ||||
|       makewhite(g, o); | ||||
|       lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										38
									
								
								lua/src/linit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lua/src/linit.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
| ** $Id: linit.c,v 1.14 2005/12/29 15:32:11 roberto Exp $ | ||||
| ** Initialization of libraries for lua.c | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #define linit_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lualib.h" | ||||
| #include "lauxlib.h" | ||||
|  | ||||
|  | ||||
| static const luaL_Reg lualibs[] = { | ||||
|   {"", luaopen_base}, | ||||
|   {LUA_LOADLIBNAME, luaopen_package}, | ||||
|   {LUA_TABLIBNAME, luaopen_table}, | ||||
|   {LUA_IOLIBNAME, luaopen_io}, | ||||
|   {LUA_OSLIBNAME, luaopen_os}, | ||||
|   {LUA_STRLIBNAME, luaopen_string}, | ||||
|   {LUA_MATHLIBNAME, luaopen_math}, | ||||
|   {LUA_DBLIBNAME, luaopen_debug}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| LUALIB_API void luaL_openlibs (lua_State *L) { | ||||
|   const luaL_Reg *lib = lualibs; | ||||
|   for (; lib->func; lib++) { | ||||
|     lua_pushcfunction(L, lib->func); | ||||
|     lua_pushstring(L, lib->name); | ||||
|     lua_call(L, 1, 0); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										532
									
								
								lua/src/liolib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										532
									
								
								lua/src/liolib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,532 @@ | ||||
| /* | ||||
| ** $Id: liolib.c,v 2.73 2006/05/08 20:14:16 roberto Exp $ | ||||
| ** Standard I/O (and system) library | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <errno.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define liolib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| #define IO_INPUT	1 | ||||
| #define IO_OUTPUT	2 | ||||
|  | ||||
|  | ||||
| static const char *const fnames[] = {"input", "output"}; | ||||
|  | ||||
|  | ||||
| static int pushresult (lua_State *L, int i, const char *filename) { | ||||
|   int en = errno;  /* calls to Lua API may change this value */ | ||||
|   if (i) { | ||||
|     lua_pushboolean(L, 1); | ||||
|     return 1; | ||||
|   } | ||||
|   else { | ||||
|     lua_pushnil(L); | ||||
|     if (filename) | ||||
|       lua_pushfstring(L, "%s: %s", filename, strerror(en)); | ||||
|     else | ||||
|       lua_pushfstring(L, "%s", strerror(en)); | ||||
|     lua_pushinteger(L, en); | ||||
|     return 3; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void fileerror (lua_State *L, int arg, const char *filename) { | ||||
|   lua_pushfstring(L, "%s: %s", filename, strerror(errno)); | ||||
|   luaL_argerror(L, arg, lua_tostring(L, -1)); | ||||
| } | ||||
|  | ||||
|  | ||||
| #define topfile(L)	((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) | ||||
|  | ||||
|  | ||||
| static int io_type (lua_State *L) { | ||||
|   void *ud; | ||||
|   luaL_checkany(L, 1); | ||||
|   ud = lua_touserdata(L, 1); | ||||
|   lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); | ||||
|   if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) | ||||
|     lua_pushnil(L);  /* not a file */ | ||||
|   else if (*((FILE **)ud) == NULL) | ||||
|     lua_pushliteral(L, "closed file"); | ||||
|   else | ||||
|     lua_pushliteral(L, "file"); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static FILE *tofile (lua_State *L) { | ||||
|   FILE **f = topfile(L); | ||||
|   if (*f == NULL) | ||||
|     luaL_error(L, "attempt to use a closed file"); | ||||
|   return *f; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** When creating file handles, always creates a `closed' file handle | ||||
| ** before opening the actual file; so, if there is a memory error, the | ||||
| ** file is not left opened. | ||||
| */ | ||||
| static FILE **newfile (lua_State *L) { | ||||
|   FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); | ||||
|   *pf = NULL;  /* file handle is currently `closed' */ | ||||
|   luaL_getmetatable(L, LUA_FILEHANDLE); | ||||
|   lua_setmetatable(L, -2); | ||||
|   return pf; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** this function has a separated environment, which defines the | ||||
| ** correct __close for 'popen' files | ||||
| */ | ||||
| static int io_pclose (lua_State *L) { | ||||
|   FILE **p = topfile(L); | ||||
|   int ok = lua_pclose(L, *p); | ||||
|   *p = NULL; | ||||
|   return pushresult(L, ok, NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_fclose (lua_State *L) { | ||||
|   FILE **p = topfile(L); | ||||
|   int ok = (fclose(*p) == 0); | ||||
|   *p = NULL; | ||||
|   return pushresult(L, ok, NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int aux_close (lua_State *L) { | ||||
|   lua_getfenv(L, 1); | ||||
|   lua_getfield(L, -1, "__close"); | ||||
|   return (lua_tocfunction(L, -1))(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_close (lua_State *L) { | ||||
|   if (lua_isnone(L, 1)) | ||||
|     lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); | ||||
|   tofile(L);  /* make sure argument is a file */ | ||||
|   return aux_close(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_gc (lua_State *L) { | ||||
|   FILE *f = *topfile(L); | ||||
|   /* ignore closed files and standard files */ | ||||
|   if (f != NULL && f != stdin && f != stdout && f != stderr) | ||||
|     aux_close(L); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_tostring (lua_State *L) { | ||||
|   FILE *f = *topfile(L); | ||||
|   if (f == NULL) | ||||
|     lua_pushstring(L, "file (closed)"); | ||||
|   else | ||||
|     lua_pushfstring(L, "file (%p)", f); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_open (lua_State *L) { | ||||
|   const char *filename = luaL_checkstring(L, 1); | ||||
|   const char *mode = luaL_optstring(L, 2, "r"); | ||||
|   FILE **pf = newfile(L); | ||||
|   *pf = fopen(filename, mode); | ||||
|   return (*pf == NULL) ? pushresult(L, 0, filename) : 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_popen (lua_State *L) { | ||||
|   const char *filename = luaL_checkstring(L, 1); | ||||
|   const char *mode = luaL_optstring(L, 2, "r"); | ||||
|   FILE **pf = newfile(L); | ||||
|   *pf = lua_popen(L, filename, mode); | ||||
|   return (*pf == NULL) ? pushresult(L, 0, filename) : 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_tmpfile (lua_State *L) { | ||||
|   FILE **pf = newfile(L); | ||||
|   *pf = tmpfile(); | ||||
|   return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static FILE *getiofile (lua_State *L, int findex) { | ||||
|   FILE *f; | ||||
|   lua_rawgeti(L, LUA_ENVIRONINDEX, findex); | ||||
|   f = *(FILE **)lua_touserdata(L, -1); | ||||
|   if (f == NULL) | ||||
|     luaL_error(L, "standard %s file is closed", fnames[findex - 1]); | ||||
|   return f; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int g_iofile (lua_State *L, int f, const char *mode) { | ||||
|   if (!lua_isnoneornil(L, 1)) { | ||||
|     const char *filename = lua_tostring(L, 1); | ||||
|     if (filename) { | ||||
|       FILE **pf = newfile(L); | ||||
|       *pf = fopen(filename, mode); | ||||
|       if (*pf == NULL) | ||||
|         fileerror(L, 1, filename); | ||||
|     } | ||||
|     else { | ||||
|       tofile(L);  /* check that it's a valid file handle */ | ||||
|       lua_pushvalue(L, 1); | ||||
|     } | ||||
|     lua_rawseti(L, LUA_ENVIRONINDEX, f); | ||||
|   } | ||||
|   /* return current value */ | ||||
|   lua_rawgeti(L, LUA_ENVIRONINDEX, f); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_input (lua_State *L) { | ||||
|   return g_iofile(L, IO_INPUT, "r"); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_output (lua_State *L) { | ||||
|   return g_iofile(L, IO_OUTPUT, "w"); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_readline (lua_State *L); | ||||
|  | ||||
|  | ||||
| static void aux_lines (lua_State *L, int idx, int toclose) { | ||||
|   lua_pushvalue(L, idx); | ||||
|   lua_pushboolean(L, toclose);  /* close/not close file when finished */ | ||||
|   lua_pushcclosure(L, io_readline, 2); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int f_lines (lua_State *L) { | ||||
|   tofile(L);  /* check that it's a valid file handle */ | ||||
|   aux_lines(L, 1, 0); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_lines (lua_State *L) { | ||||
|   if (lua_isnoneornil(L, 1)) {  /* no arguments? */ | ||||
|     /* will iterate over default input */ | ||||
|     lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); | ||||
|     return f_lines(L); | ||||
|   } | ||||
|   else { | ||||
|     const char *filename = luaL_checkstring(L, 1); | ||||
|     FILE **pf = newfile(L); | ||||
|     *pf = fopen(filename, "r"); | ||||
|     if (*pf == NULL) | ||||
|       fileerror(L, 1, filename); | ||||
|     aux_lines(L, lua_gettop(L), 1); | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** READ | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
| static int read_number (lua_State *L, FILE *f) { | ||||
|   lua_Number d; | ||||
|   if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { | ||||
|     lua_pushnumber(L, d); | ||||
|     return 1; | ||||
|   } | ||||
|   else return 0;  /* read fails */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int test_eof (lua_State *L, FILE *f) { | ||||
|   int c = getc(f); | ||||
|   ungetc(c, f); | ||||
|   lua_pushlstring(L, NULL, 0); | ||||
|   return (c != EOF); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int read_line (lua_State *L, FILE *f) { | ||||
|   luaL_Buffer b; | ||||
|   luaL_buffinit(L, &b); | ||||
|   for (;;) { | ||||
|     size_t l; | ||||
|     char *p = luaL_prepbuffer(&b); | ||||
|     if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */ | ||||
|       luaL_pushresult(&b);  /* close buffer */ | ||||
|       return (lua_strlen(L, -1) > 0);  /* check whether read something */ | ||||
|     } | ||||
|     l = strlen(p); | ||||
|     if (l == 0 || p[l-1] != '\n') | ||||
|       luaL_addsize(&b, l); | ||||
|     else { | ||||
|       luaL_addsize(&b, l - 1);  /* do not include `eol' */ | ||||
|       luaL_pushresult(&b);  /* close buffer */ | ||||
|       return 1;  /* read at least an `eol' */ | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int read_chars (lua_State *L, FILE *f, size_t n) { | ||||
|   size_t rlen;  /* how much to read */ | ||||
|   size_t nr;  /* number of chars actually read */ | ||||
|   luaL_Buffer b; | ||||
|   luaL_buffinit(L, &b); | ||||
|   rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */ | ||||
|   do { | ||||
|     char *p = luaL_prepbuffer(&b); | ||||
|     if (rlen > n) rlen = n;  /* cannot read more than asked */ | ||||
|     nr = fread(p, sizeof(char), rlen, f); | ||||
|     luaL_addsize(&b, nr); | ||||
|     n -= nr;  /* still have to read `n' chars */ | ||||
|   } while (n > 0 && nr == rlen);  /* until end of count or eof */ | ||||
|   luaL_pushresult(&b);  /* close buffer */ | ||||
|   return (n == 0 || lua_strlen(L, -1) > 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int g_read (lua_State *L, FILE *f, int first) { | ||||
|   int nargs = lua_gettop(L) - 1; | ||||
|   int success; | ||||
|   int n; | ||||
|   clearerr(f); | ||||
|   if (nargs == 0) {  /* no arguments? */ | ||||
|     success = read_line(L, f); | ||||
|     n = first+1;  /* to return 1 result */ | ||||
|   } | ||||
|   else {  /* ensure stack space for all results and for auxlib's buffer */ | ||||
|     luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); | ||||
|     success = 1; | ||||
|     for (n = first; nargs-- && success; n++) { | ||||
|       if (lua_type(L, n) == LUA_TNUMBER) { | ||||
|         size_t l = (size_t)lua_tointeger(L, n); | ||||
|         success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); | ||||
|       } | ||||
|       else { | ||||
|         const char *p = lua_tostring(L, n); | ||||
|         luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); | ||||
|         switch (p[1]) { | ||||
|           case 'n':  /* number */ | ||||
|             success = read_number(L, f); | ||||
|             break; | ||||
|           case 'l':  /* line */ | ||||
|             success = read_line(L, f); | ||||
|             break; | ||||
|           case 'a':  /* file */ | ||||
|             read_chars(L, f, ~((size_t)0));  /* read MAX_SIZE_T chars */ | ||||
|             success = 1; /* always success */ | ||||
|             break; | ||||
|           default: | ||||
|             return luaL_argerror(L, n, "invalid format"); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if (ferror(f)) | ||||
|     return pushresult(L, 0, NULL); | ||||
|   if (!success) { | ||||
|     lua_pop(L, 1);  /* remove last result */ | ||||
|     lua_pushnil(L);  /* push nil instead */ | ||||
|   } | ||||
|   return n - first; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_read (lua_State *L) { | ||||
|   return g_read(L, getiofile(L, IO_INPUT), 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int f_read (lua_State *L) { | ||||
|   return g_read(L, tofile(L), 2); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_readline (lua_State *L) { | ||||
|   FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); | ||||
|   int sucess; | ||||
|   if (f == NULL)  /* file is already closed? */ | ||||
|     luaL_error(L, "file is already closed"); | ||||
|   sucess = read_line(L, f); | ||||
|   if (ferror(f)) | ||||
|     return luaL_error(L, "%s", strerror(errno)); | ||||
|   if (sucess) return 1; | ||||
|   else {  /* EOF */ | ||||
|     if (lua_toboolean(L, lua_upvalueindex(2))) {  /* generator created file? */ | ||||
|       lua_settop(L, 0); | ||||
|       lua_pushvalue(L, lua_upvalueindex(1)); | ||||
|       aux_close(L);  /* close it */ | ||||
|     } | ||||
|     return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| static int g_write (lua_State *L, FILE *f, int arg) { | ||||
|   int nargs = lua_gettop(L) - 1; | ||||
|   int status = 1; | ||||
|   for (; nargs--; arg++) { | ||||
|     if (lua_type(L, arg) == LUA_TNUMBER) { | ||||
|       /* optimization: could be done exactly as for strings */ | ||||
|       status = status && | ||||
|           fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; | ||||
|     } | ||||
|     else { | ||||
|       size_t l; | ||||
|       const char *s = luaL_checklstring(L, arg, &l); | ||||
|       status = status && (fwrite(s, sizeof(char), l, f) == l); | ||||
|     } | ||||
|   } | ||||
|   return pushresult(L, status, NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int io_write (lua_State *L) { | ||||
|   return g_write(L, getiofile(L, IO_OUTPUT), 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int f_write (lua_State *L) { | ||||
|   return g_write(L, tofile(L), 2); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int f_seek (lua_State *L) { | ||||
|   static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; | ||||
|   static const char *const modenames[] = {"set", "cur", "end", NULL}; | ||||
|   FILE *f = tofile(L); | ||||
|   int op = luaL_checkoption(L, 2, "cur", modenames); | ||||
|   long offset = luaL_optlong(L, 3, 0); | ||||
|   op = fseek(f, offset, mode[op]); | ||||
|   if (op) | ||||
|     return pushresult(L, 0, NULL);  /* error */ | ||||
|   else { | ||||
|     lua_pushinteger(L, ftell(f)); | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int f_setvbuf (lua_State *L) { | ||||
|   static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; | ||||
|   static const char *const modenames[] = {"no", "full", "line", NULL}; | ||||
|   FILE *f = tofile(L); | ||||
|   int op = luaL_checkoption(L, 2, NULL, modenames); | ||||
|   lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); | ||||
|   int res = setvbuf(f, NULL, mode[op], sz); | ||||
|   return pushresult(L, res == 0, NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static int io_flush (lua_State *L) { | ||||
|   return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int f_flush (lua_State *L) { | ||||
|   return pushresult(L, fflush(tofile(L)) == 0, NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const luaL_Reg iolib[] = { | ||||
|   {"close", io_close}, | ||||
|   {"flush", io_flush}, | ||||
|   {"input", io_input}, | ||||
|   {"lines", io_lines}, | ||||
|   {"open", io_open}, | ||||
|   {"output", io_output}, | ||||
|   {"popen", io_popen}, | ||||
|   {"read", io_read}, | ||||
|   {"tmpfile", io_tmpfile}, | ||||
|   {"type", io_type}, | ||||
|   {"write", io_write}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| static const luaL_Reg flib[] = { | ||||
|   {"close", io_close}, | ||||
|   {"flush", f_flush}, | ||||
|   {"lines", f_lines}, | ||||
|   {"read", f_read}, | ||||
|   {"seek", f_seek}, | ||||
|   {"setvbuf", f_setvbuf}, | ||||
|   {"write", f_write}, | ||||
|   {"__gc", io_gc}, | ||||
|   {"__tostring", io_tostring}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| static void createmeta (lua_State *L) { | ||||
|   luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */ | ||||
|   lua_pushvalue(L, -1);  /* push metatable */ | ||||
|   lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */ | ||||
|   luaL_register(L, NULL, flib);  /* file methods */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { | ||||
|   *newfile(L) = f; | ||||
|   if (k > 0) { | ||||
|     lua_pushvalue(L, -1); | ||||
|     lua_rawseti(L, LUA_ENVIRONINDEX, k); | ||||
|   } | ||||
|   lua_setfield(L, -2, fname); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaopen_io (lua_State *L) { | ||||
|   createmeta(L); | ||||
|   /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ | ||||
|   lua_createtable(L, 2, 1); | ||||
|   lua_replace(L, LUA_ENVIRONINDEX); | ||||
|   /* open library */ | ||||
|   luaL_register(L, LUA_IOLIBNAME, iolib); | ||||
|   /* create (and set) default files */ | ||||
|   createstdfile(L, stdin, IO_INPUT, "stdin"); | ||||
|   createstdfile(L, stdout, IO_OUTPUT, "stdout"); | ||||
|   createstdfile(L, stderr, 0, "stderr"); | ||||
|   /* create environment for 'popen' */ | ||||
|   lua_getfield(L, -1, "popen"); | ||||
|   lua_createtable(L, 0, 1); | ||||
|   lua_pushcfunction(L, io_pclose); | ||||
|   lua_setfield(L, -2, "__close"); | ||||
|   lua_setfenv(L, -2); | ||||
|   lua_pop(L, 1);  /* pop 'popen' */ | ||||
|   /* set default close function */ | ||||
|   lua_pushcfunction(L, io_fclose); | ||||
|   lua_setfield(L, LUA_ENVIRONINDEX, "__close"); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
							
								
								
									
										461
									
								
								lua/src/llex.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										461
									
								
								lua/src/llex.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,461 @@ | ||||
| /* | ||||
| ** $Id: llex.c,v 2.20 2006/03/09 18:14:31 roberto Exp $ | ||||
| ** Lexical Analyzer | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include <locale.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define llex_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldo.h" | ||||
| #include "llex.h" | ||||
| #include "lobject.h" | ||||
| #include "lparser.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "ltable.h" | ||||
| #include "lzio.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| #define next(ls) (ls->current = zgetc(ls->z)) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| #define currIsNewline(ls)	(ls->current == '\n' || ls->current == '\r') | ||||
|  | ||||
|  | ||||
| /* ORDER RESERVED */ | ||||
| const char *const luaX_tokens [] = { | ||||
|     "and", "break", "do", "else", "elseif", | ||||
|     "end", "false", "for", "function", "if", | ||||
|     "in", "local", "nil", "not", "or", "repeat", | ||||
|     "return", "then", "true", "until", "while", | ||||
|     "..", "...", "==", ">=", "<=", "~=", | ||||
|     "<number>", "<name>", "<string>", "<eof>", | ||||
|     NULL | ||||
| }; | ||||
|  | ||||
|  | ||||
| #define save_and_next(ls) (save(ls, ls->current), next(ls)) | ||||
|  | ||||
|  | ||||
| static void save (LexState *ls, int c) { | ||||
|   Mbuffer *b = ls->buff; | ||||
|   if (b->n + 1 > b->buffsize) { | ||||
|     size_t newsize; | ||||
|     if (b->buffsize >= MAX_SIZET/2) | ||||
|       luaX_lexerror(ls, "lexical element too long", 0); | ||||
|     newsize = b->buffsize * 2; | ||||
|     luaZ_resizebuffer(ls->L, b, newsize); | ||||
|   } | ||||
|   b->buffer[b->n++] = cast(char, c); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaX_init (lua_State *L) { | ||||
|   int i; | ||||
|   for (i=0; i<NUM_RESERVED; i++) { | ||||
|     TString *ts = luaS_new(L, luaX_tokens[i]); | ||||
|     luaS_fix(ts);  /* reserved words are never collected */ | ||||
|     lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); | ||||
|     ts->tsv.reserved = cast_byte(i+1);  /* reserved word */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| #define MAXSRC          80 | ||||
|  | ||||
|  | ||||
| const char *luaX_token2str (LexState *ls, int token) { | ||||
|   if (token < FIRST_RESERVED) { | ||||
|     lua_assert(token == cast(unsigned char, token)); | ||||
|     return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : | ||||
|                               luaO_pushfstring(ls->L, "%c", token); | ||||
|   } | ||||
|   else | ||||
|     return luaX_tokens[token-FIRST_RESERVED]; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *txtToken (LexState *ls, int token) { | ||||
|   switch (token) { | ||||
|     case TK_NAME: | ||||
|     case TK_STRING: | ||||
|     case TK_NUMBER: | ||||
|       save(ls, '\0'); | ||||
|       return luaZ_buffer(ls->buff); | ||||
|     default: | ||||
|       return luaX_token2str(ls, token); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaX_lexerror (LexState *ls, const char *msg, int token) { | ||||
|   char buff[MAXSRC]; | ||||
|   luaO_chunkid(buff, getstr(ls->source), MAXSRC); | ||||
|   msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); | ||||
|   if (token) | ||||
|     luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); | ||||
|   luaD_throw(ls->L, LUA_ERRSYNTAX); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaX_syntaxerror (LexState *ls, const char *msg) { | ||||
|   luaX_lexerror(ls, msg, ls->t.token); | ||||
| } | ||||
|  | ||||
|  | ||||
| TString *luaX_newstring (LexState *ls, const char *str, size_t l) { | ||||
|   lua_State *L = ls->L; | ||||
|   TString *ts = luaS_newlstr(L, str, l); | ||||
|   TValue *o = luaH_setstr(L, ls->fs->h, ts);  /* entry for `str' */ | ||||
|   if (ttisnil(o)) | ||||
|     setbvalue(o, 1);  /* make sure `str' will not be collected */ | ||||
|   return ts; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void inclinenumber (LexState *ls) { | ||||
|   int old = ls->current; | ||||
|   lua_assert(currIsNewline(ls)); | ||||
|   next(ls);  /* skip `\n' or `\r' */ | ||||
|   if (currIsNewline(ls) && ls->current != old) | ||||
|     next(ls);  /* skip `\n\r' or `\r\n' */ | ||||
|   if (++ls->linenumber >= MAX_INT) | ||||
|     luaX_syntaxerror(ls, "chunk has too many lines"); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { | ||||
|   ls->decpoint = '.'; | ||||
|   ls->L = L; | ||||
|   ls->lookahead.token = TK_EOS;  /* no look-ahead token */ | ||||
|   ls->z = z; | ||||
|   ls->fs = NULL; | ||||
|   ls->linenumber = 1; | ||||
|   ls->lastline = 1; | ||||
|   ls->source = source; | ||||
|   luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);  /* initialize buffer */ | ||||
|   next(ls);  /* read first char */ | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** ======================================================= | ||||
| ** LEXICAL ANALYZER | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
|  | ||||
| static int check_next (LexState *ls, const char *set) { | ||||
|   if (!strchr(set, ls->current)) | ||||
|     return 0; | ||||
|   save_and_next(ls); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void buffreplace (LexState *ls, char from, char to) { | ||||
|   size_t n = luaZ_bufflen(ls->buff); | ||||
|   char *p = luaZ_buffer(ls->buff); | ||||
|   while (n--) | ||||
|     if (p[n] == from) p[n] = to; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void trydecpoint (LexState *ls, SemInfo *seminfo) { | ||||
|   /* format error: try to update decimal point separator */ | ||||
|   struct lconv *cv = localeconv(); | ||||
|   char old = ls->decpoint; | ||||
|   ls->decpoint = (cv ? cv->decimal_point[0] : '.'); | ||||
|   buffreplace(ls, old, ls->decpoint);  /* try updated decimal separator */ | ||||
|   if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { | ||||
|     /* format error with correct decimal point: no more options */ | ||||
|     buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */ | ||||
|     luaX_lexerror(ls, "malformed number", TK_NUMBER); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* LUA_NUMBER */ | ||||
| static void read_numeral (LexState *ls, SemInfo *seminfo) { | ||||
|   lua_assert(isdigit(ls->current)); | ||||
|   do { | ||||
|     save_and_next(ls); | ||||
|   } while (isdigit(ls->current) || ls->current == '.'); | ||||
|   if (check_next(ls, "Ee"))  /* `E'? */ | ||||
|     check_next(ls, "+-");  /* optional exponent sign */ | ||||
|   while (isalnum(ls->current) || ls->current == '_') | ||||
|     save_and_next(ls); | ||||
|   save(ls, '\0'); | ||||
|   buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */ | ||||
|   if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r))  /* format error? */ | ||||
|     trydecpoint(ls, seminfo); /* try to update decimal point separator */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int skip_sep (LexState *ls) { | ||||
|   int count = 0; | ||||
|   int s = ls->current; | ||||
|   lua_assert(s == '[' || s == ']'); | ||||
|   save_and_next(ls); | ||||
|   while (ls->current == '=') { | ||||
|     save_and_next(ls); | ||||
|     count++; | ||||
|   } | ||||
|   return (ls->current == s) ? count : (-count) - 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { | ||||
|   int cont = 0; | ||||
|   (void)(cont);  /* avoid warnings when `cont' is not used */ | ||||
|   save_and_next(ls);  /* skip 2nd `[' */ | ||||
|   if (currIsNewline(ls))  /* string starts with a newline? */ | ||||
|     inclinenumber(ls);  /* skip it */ | ||||
|   for (;;) { | ||||
|     switch (ls->current) { | ||||
|       case EOZ: | ||||
|         luaX_lexerror(ls, (seminfo) ? "unfinished long string" : | ||||
|                                    "unfinished long comment", TK_EOS); | ||||
|         break;  /* to avoid warnings */ | ||||
| #if defined(LUA_COMPAT_LSTR) | ||||
|       case '[': { | ||||
|         if (skip_sep(ls) == sep) { | ||||
|           save_and_next(ls);  /* skip 2nd `[' */ | ||||
|           cont++; | ||||
| #if LUA_COMPAT_LSTR == 1 | ||||
|           if (sep == 0) | ||||
|             luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); | ||||
| #endif | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
| #endif | ||||
|       case ']': { | ||||
|         if (skip_sep(ls) == sep) { | ||||
|           save_and_next(ls);  /* skip 2nd `]' */ | ||||
| #if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 | ||||
|           cont--; | ||||
|           if (sep == 0 && cont >= 0) break; | ||||
| #endif | ||||
|           goto endloop; | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|       case '\n': | ||||
|       case '\r': { | ||||
|         save(ls, '\n'); | ||||
|         inclinenumber(ls); | ||||
|         if (!seminfo) luaZ_resetbuffer(ls->buff);  /* avoid wasting space */ | ||||
|         break; | ||||
|       } | ||||
|       default: { | ||||
|         if (seminfo) save_and_next(ls); | ||||
|         else next(ls); | ||||
|       } | ||||
|     } | ||||
|   } endloop: | ||||
|   if (seminfo) | ||||
|     seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), | ||||
|                                      luaZ_bufflen(ls->buff) - 2*(2 + sep)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void read_string (LexState *ls, int del, SemInfo *seminfo) { | ||||
|   save_and_next(ls); | ||||
|   while (ls->current != del) { | ||||
|     switch (ls->current) { | ||||
|       case EOZ: | ||||
|         luaX_lexerror(ls, "unfinished string", TK_EOS); | ||||
|         continue;  /* to avoid warnings */ | ||||
|       case '\n': | ||||
|       case '\r': | ||||
|         luaX_lexerror(ls, "unfinished string", TK_STRING); | ||||
|         continue;  /* to avoid warnings */ | ||||
|       case '\\': { | ||||
|         int c; | ||||
|         next(ls);  /* do not save the `\' */ | ||||
|         switch (ls->current) { | ||||
|           case 'a': c = '\a'; break; | ||||
|           case 'b': c = '\b'; break; | ||||
|           case 'f': c = '\f'; break; | ||||
|           case 'n': c = '\n'; break; | ||||
|           case 'r': c = '\r'; break; | ||||
|           case 't': c = '\t'; break; | ||||
|           case 'v': c = '\v'; break; | ||||
|           case '\n':  /* go through */ | ||||
|           case '\r': save(ls, '\n'); inclinenumber(ls); continue; | ||||
|           case EOZ: continue;  /* will raise an error next loop */ | ||||
|           default: { | ||||
|             if (!isdigit(ls->current)) | ||||
|               save_and_next(ls);  /* handles \\, \", \', and \? */ | ||||
|             else {  /* \xxx */ | ||||
|               int i = 0; | ||||
|               c = 0; | ||||
|               do { | ||||
|                 c = 10*c + (ls->current-'0'); | ||||
|                 next(ls); | ||||
|               } while (++i<3 && isdigit(ls->current)); | ||||
|               if (c > UCHAR_MAX) | ||||
|                 luaX_lexerror(ls, "escape sequence too large", TK_STRING); | ||||
|               save(ls, c); | ||||
|             } | ||||
|             continue; | ||||
|           } | ||||
|         } | ||||
|         save(ls, c); | ||||
|         next(ls); | ||||
|         continue; | ||||
|       } | ||||
|       default: | ||||
|         save_and_next(ls); | ||||
|     } | ||||
|   } | ||||
|   save_and_next(ls);  /* skip delimiter */ | ||||
|   seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, | ||||
|                                    luaZ_bufflen(ls->buff) - 2); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int llex (LexState *ls, SemInfo *seminfo) { | ||||
|   luaZ_resetbuffer(ls->buff); | ||||
|   for (;;) { | ||||
|     switch (ls->current) { | ||||
|       case '\n': | ||||
|       case '\r': { | ||||
|         inclinenumber(ls); | ||||
|         continue; | ||||
|       } | ||||
|       case '-': { | ||||
|         next(ls); | ||||
|         if (ls->current != '-') return '-'; | ||||
|         /* else is a comment */ | ||||
|         next(ls); | ||||
|         if (ls->current == '[') { | ||||
|           int sep = skip_sep(ls); | ||||
|           luaZ_resetbuffer(ls->buff);  /* `skip_sep' may dirty the buffer */ | ||||
|           if (sep >= 0) { | ||||
|             read_long_string(ls, NULL, sep);  /* long comment */ | ||||
|             luaZ_resetbuffer(ls->buff); | ||||
|             continue; | ||||
|           } | ||||
|         } | ||||
|         /* else short comment */ | ||||
|         while (!currIsNewline(ls) && ls->current != EOZ) | ||||
|           next(ls); | ||||
|         continue; | ||||
|       } | ||||
|       case '[': { | ||||
|         int sep = skip_sep(ls); | ||||
|         if (sep >= 0) { | ||||
|           read_long_string(ls, seminfo, sep); | ||||
|           return TK_STRING; | ||||
|         } | ||||
|         else if (sep == -1) return '['; | ||||
|         else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); | ||||
|       } | ||||
|       case '=': { | ||||
|         next(ls); | ||||
|         if (ls->current != '=') return '='; | ||||
|         else { next(ls); return TK_EQ; } | ||||
|       } | ||||
|       case '<': { | ||||
|         next(ls); | ||||
|         if (ls->current != '=') return '<'; | ||||
|         else { next(ls); return TK_LE; } | ||||
|       } | ||||
|       case '>': { | ||||
|         next(ls); | ||||
|         if (ls->current != '=') return '>'; | ||||
|         else { next(ls); return TK_GE; } | ||||
|       } | ||||
|       case '~': { | ||||
|         next(ls); | ||||
|         if (ls->current != '=') return '~'; | ||||
|         else { next(ls); return TK_NE; } | ||||
|       } | ||||
|       case '"': | ||||
|       case '\'': { | ||||
|         read_string(ls, ls->current, seminfo); | ||||
|         return TK_STRING; | ||||
|       } | ||||
|       case '.': { | ||||
|         save_and_next(ls); | ||||
|         if (check_next(ls, ".")) { | ||||
|           if (check_next(ls, ".")) | ||||
|             return TK_DOTS;   /* ... */ | ||||
|           else return TK_CONCAT;   /* .. */ | ||||
|         } | ||||
|         else if (!isdigit(ls->current)) return '.'; | ||||
|         else { | ||||
|           read_numeral(ls, seminfo); | ||||
|           return TK_NUMBER; | ||||
|         } | ||||
|       } | ||||
|       case EOZ: { | ||||
|         return TK_EOS; | ||||
|       } | ||||
|       default: { | ||||
|         if (isspace(ls->current)) { | ||||
|           lua_assert(!currIsNewline(ls)); | ||||
|           next(ls); | ||||
|           continue; | ||||
|         } | ||||
|         else if (isdigit(ls->current)) { | ||||
|           read_numeral(ls, seminfo); | ||||
|           return TK_NUMBER; | ||||
|         } | ||||
|         else if (isalpha(ls->current) || ls->current == '_') { | ||||
|           /* identifier or reserved word */ | ||||
|           TString *ts; | ||||
|           do { | ||||
|             save_and_next(ls); | ||||
|           } while (isalnum(ls->current) || ls->current == '_'); | ||||
|           ts = luaX_newstring(ls, luaZ_buffer(ls->buff), | ||||
|                                   luaZ_bufflen(ls->buff)); | ||||
|           if (ts->tsv.reserved > 0)  /* reserved word? */ | ||||
|             return ts->tsv.reserved - 1 + FIRST_RESERVED; | ||||
|           else { | ||||
|             seminfo->ts = ts; | ||||
|             return TK_NAME; | ||||
|           } | ||||
|         } | ||||
|         else { | ||||
|           int c = ls->current; | ||||
|           next(ls); | ||||
|           return c;  /* single-char tokens (+ - / ...) */ | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaX_next (LexState *ls) { | ||||
|   ls->lastline = ls->linenumber; | ||||
|   if (ls->lookahead.token != TK_EOS) {  /* is there a look-ahead token? */ | ||||
|     ls->t = ls->lookahead;  /* use this one */ | ||||
|     ls->lookahead.token = TK_EOS;  /* and discharge it */ | ||||
|   } | ||||
|   else | ||||
|     ls->t.token = llex(ls, &ls->t.seminfo);  /* read next token */ | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaX_lookahead (LexState *ls) { | ||||
|   lua_assert(ls->lookahead.token == TK_EOS); | ||||
|   ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); | ||||
| } | ||||
|  | ||||
							
								
								
									
										263
									
								
								lua/src/lmathlib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								lua/src/lmathlib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | ||||
| /* | ||||
| ** $Id: lmathlib.c,v 1.67 2005/08/26 17:36:32 roberto Exp $ | ||||
| ** Standard mathematical library | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
|  | ||||
| #define lmathlib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
| #undef PI | ||||
| #define PI (3.14159265358979323846) | ||||
| #define RADIANS_PER_DEGREE (PI/180.0) | ||||
|  | ||||
|  | ||||
|  | ||||
| static int math_abs (lua_State *L) { | ||||
|   lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_sin (lua_State *L) { | ||||
|   lua_pushnumber(L, sin(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_sinh (lua_State *L) { | ||||
|   lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_cos (lua_State *L) { | ||||
|   lua_pushnumber(L, cos(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_cosh (lua_State *L) { | ||||
|   lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_tan (lua_State *L) { | ||||
|   lua_pushnumber(L, tan(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_tanh (lua_State *L) { | ||||
|   lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_asin (lua_State *L) { | ||||
|   lua_pushnumber(L, asin(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_acos (lua_State *L) { | ||||
|   lua_pushnumber(L, acos(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_atan (lua_State *L) { | ||||
|   lua_pushnumber(L, atan(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_atan2 (lua_State *L) { | ||||
|   lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_ceil (lua_State *L) { | ||||
|   lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_floor (lua_State *L) { | ||||
|   lua_pushnumber(L, floor(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_fmod (lua_State *L) { | ||||
|   lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_modf (lua_State *L) { | ||||
|   double ip; | ||||
|   double fp = modf(luaL_checknumber(L, 1), &ip); | ||||
|   lua_pushnumber(L, ip); | ||||
|   lua_pushnumber(L, fp); | ||||
|   return 2; | ||||
| } | ||||
|  | ||||
| static int math_sqrt (lua_State *L) { | ||||
|   lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_pow (lua_State *L) { | ||||
|   lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_log (lua_State *L) { | ||||
|   lua_pushnumber(L, log(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_log10 (lua_State *L) { | ||||
|   lua_pushnumber(L, log10(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_exp (lua_State *L) { | ||||
|   lua_pushnumber(L, exp(luaL_checknumber(L, 1))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_deg (lua_State *L) { | ||||
|   lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_rad (lua_State *L) { | ||||
|   lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int math_frexp (lua_State *L) { | ||||
|   int e; | ||||
|   lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); | ||||
|   lua_pushinteger(L, e); | ||||
|   return 2; | ||||
| } | ||||
|  | ||||
| static int math_ldexp (lua_State *L) { | ||||
|   lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static int math_min (lua_State *L) { | ||||
|   int n = lua_gettop(L);  /* number of arguments */ | ||||
|   lua_Number dmin = luaL_checknumber(L, 1); | ||||
|   int i; | ||||
|   for (i=2; i<=n; i++) { | ||||
|     lua_Number d = luaL_checknumber(L, i); | ||||
|     if (d < dmin) | ||||
|       dmin = d; | ||||
|   } | ||||
|   lua_pushnumber(L, dmin); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int math_max (lua_State *L) { | ||||
|   int n = lua_gettop(L);  /* number of arguments */ | ||||
|   lua_Number dmax = luaL_checknumber(L, 1); | ||||
|   int i; | ||||
|   for (i=2; i<=n; i++) { | ||||
|     lua_Number d = luaL_checknumber(L, i); | ||||
|     if (d > dmax) | ||||
|       dmax = d; | ||||
|   } | ||||
|   lua_pushnumber(L, dmax); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int math_random (lua_State *L) { | ||||
|   /* the `%' avoids the (rare) case of r==1, and is needed also because on | ||||
|      some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ | ||||
|   lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; | ||||
|   switch (lua_gettop(L)) {  /* check number of arguments */ | ||||
|     case 0: {  /* no arguments */ | ||||
|       lua_pushnumber(L, r);  /* Number between 0 and 1 */ | ||||
|       break; | ||||
|     } | ||||
|     case 1: {  /* only upper limit */ | ||||
|       int u = luaL_checkint(L, 1); | ||||
|       luaL_argcheck(L, 1<=u, 1, "interval is empty"); | ||||
|       lua_pushnumber(L, floor(r*u)+1);  /* int between 1 and `u' */ | ||||
|       break; | ||||
|     } | ||||
|     case 2: {  /* lower and upper limits */ | ||||
|       int l = luaL_checkint(L, 1); | ||||
|       int u = luaL_checkint(L, 2); | ||||
|       luaL_argcheck(L, l<=u, 2, "interval is empty"); | ||||
|       lua_pushnumber(L, floor(r*(u-l+1))+l);  /* int between `l' and `u' */ | ||||
|       break; | ||||
|     } | ||||
|     default: return luaL_error(L, "wrong number of arguments"); | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int math_randomseed (lua_State *L) { | ||||
|   srand(luaL_checkint(L, 1)); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const luaL_Reg mathlib[] = { | ||||
|   {"abs",   math_abs}, | ||||
|   {"acos",  math_acos}, | ||||
|   {"asin",  math_asin}, | ||||
|   {"atan2", math_atan2}, | ||||
|   {"atan",  math_atan}, | ||||
|   {"ceil",  math_ceil}, | ||||
|   {"cosh",   math_cosh}, | ||||
|   {"cos",   math_cos}, | ||||
|   {"deg",   math_deg}, | ||||
|   {"exp",   math_exp}, | ||||
|   {"floor", math_floor}, | ||||
|   {"fmod",   math_fmod}, | ||||
|   {"frexp", math_frexp}, | ||||
|   {"ldexp", math_ldexp}, | ||||
|   {"log10", math_log10}, | ||||
|   {"log",   math_log}, | ||||
|   {"max",   math_max}, | ||||
|   {"min",   math_min}, | ||||
|   {"modf",   math_modf}, | ||||
|   {"pow",   math_pow}, | ||||
|   {"rad",   math_rad}, | ||||
|   {"random",     math_random}, | ||||
|   {"randomseed", math_randomseed}, | ||||
|   {"sinh",   math_sinh}, | ||||
|   {"sin",   math_sin}, | ||||
|   {"sqrt",  math_sqrt}, | ||||
|   {"tanh",   math_tanh}, | ||||
|   {"tan",   math_tan}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Open math library | ||||
| */ | ||||
| LUALIB_API int luaopen_math (lua_State *L) { | ||||
|   luaL_register(L, LUA_MATHLIBNAME, mathlib); | ||||
|   lua_pushnumber(L, PI); | ||||
|   lua_setfield(L, -2, "pi"); | ||||
|   lua_pushnumber(L, HUGE_VAL); | ||||
|   lua_setfield(L, -2, "huge"); | ||||
| #if defined(LUA_COMPAT_MOD) | ||||
|   lua_getfield(L, -1, "fmod"); | ||||
|   lua_setfield(L, -2, "mod"); | ||||
| #endif | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
							
								
								
									
										86
									
								
								lua/src/lmem.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								lua/src/lmem.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| /* | ||||
| ** $Id: lmem.c,v 1.70 2005/12/26 13:35:47 roberto Exp $ | ||||
| ** Interface to Memory Manager | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stddef.h> | ||||
|  | ||||
| #define lmem_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** About the realloc function: | ||||
| ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); | ||||
| ** (`osize' is the old size, `nsize' is the new size) | ||||
| ** | ||||
| ** Lua ensures that (ptr == NULL) iff (osize == 0). | ||||
| ** | ||||
| ** * frealloc(ud, NULL, 0, x) creates a new block of size `x' | ||||
| ** | ||||
| ** * frealloc(ud, p, x, 0) frees the block `p' | ||||
| ** (in this specific case, frealloc must return NULL). | ||||
| ** particularly, frealloc(ud, NULL, 0, 0) does nothing | ||||
| ** (which is equivalent to free(NULL) in ANSI C) | ||||
| ** | ||||
| ** frealloc returns NULL if it cannot create or reallocate the area | ||||
| ** (any reallocation to an equal or smaller size cannot fail!) | ||||
| */ | ||||
|  | ||||
|  | ||||
|  | ||||
| #define MINSIZEARRAY	4 | ||||
|  | ||||
|  | ||||
| void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, | ||||
|                      int limit, const char *errormsg) { | ||||
|   void *newblock; | ||||
|   int newsize; | ||||
|   if (*size >= limit/2) {  /* cannot double it? */ | ||||
|     if (*size >= limit)  /* cannot grow even a little? */ | ||||
|       luaG_runerror(L, errormsg); | ||||
|     newsize = limit;  /* still have at least one free place */ | ||||
|   } | ||||
|   else { | ||||
|     newsize = (*size)*2; | ||||
|     if (newsize < MINSIZEARRAY) | ||||
|       newsize = MINSIZEARRAY;  /* minimum size */ | ||||
|   } | ||||
|   newblock = luaM_reallocv(L, block, *size, newsize, size_elems); | ||||
|   *size = newsize;  /* update only when everything else is OK */ | ||||
|   return newblock; | ||||
| } | ||||
|  | ||||
|  | ||||
| void *luaM_toobig (lua_State *L) { | ||||
|   luaG_runerror(L, "memory allocation error: block too big"); | ||||
|   return NULL;  /* to avoid warnings */ | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** generic allocation routine. | ||||
| */ | ||||
| void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { | ||||
|   global_State *g = G(L); | ||||
|   lua_assert((osize == 0) == (block == NULL)); | ||||
|   block = (*g->frealloc)(g->ud, block, osize, nsize); | ||||
|   if (block == NULL && nsize > 0) | ||||
|     luaD_throw(L, LUA_ERRMEM); | ||||
|   lua_assert((nsize == 0) == (block == NULL)); | ||||
|   g->totalbytes = (g->totalbytes - osize) + nsize; | ||||
|   return block; | ||||
| } | ||||
|  | ||||
							
								
								
									
										664
									
								
								lua/src/loadlib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										664
									
								
								lua/src/loadlib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,664 @@ | ||||
| /* | ||||
| ** $Id: loadlib.c,v 1.54a 2006/07/03 20:16:49 roberto Exp $ | ||||
| ** Dynamic library loader for Lua | ||||
| ** See Copyright Notice in lua.h | ||||
| ** | ||||
| ** This module contains an implementation of loadlib for Unix systems | ||||
| ** that have dlfcn, an implementation for Darwin (Mac OS X), an | ||||
| ** implementation for Windows, and a stub for other systems. | ||||
| */ | ||||
| #include "stdafx.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
|  | ||||
| #define loadlib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
| /* prefix for open functions in C libraries */ | ||||
| #define LUA_POF		"luaopen_" | ||||
|  | ||||
| /* separator for open functions in C libraries */ | ||||
| #define LUA_OFSEP	"_" | ||||
|  | ||||
|  | ||||
| #define LIBPREFIX	"LOADLIB: " | ||||
|  | ||||
| #define POF		LUA_POF | ||||
| #define LIB_FAIL	"open" | ||||
|  | ||||
|  | ||||
| /* error codes for ll_loadfunc */ | ||||
| #define ERRLIB		1 | ||||
| #define ERRFUNC		2 | ||||
|  | ||||
| #define setprogdir(L)		((void)0) | ||||
|  | ||||
|  | ||||
| static void ll_unloadlib (void *lib); | ||||
| static void *ll_load (lua_State *L, const char *path); | ||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); | ||||
|  | ||||
|  | ||||
|  | ||||
| #if defined(LUA_DL_DLOPEN) | ||||
| /* | ||||
| ** {======================================================================== | ||||
| ** This is an implementation of loadlib based on the dlfcn interface. | ||||
| ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, | ||||
| ** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least | ||||
| ** as an emulation layer on top of native functions. | ||||
| ** ========================================================================= | ||||
| */ | ||||
|  | ||||
| #include <dlfcn.h> | ||||
|  | ||||
| static void ll_unloadlib (void *lib) { | ||||
|   dlclose(lib); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void *ll_load (lua_State *L, const char *path) { | ||||
|   void *lib = dlopen(path, RTLD_NOW); | ||||
|   if (lib == NULL) lua_pushstring(L, dlerror()); | ||||
|   return lib; | ||||
| } | ||||
|  | ||||
|  | ||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||||
|   lua_CFunction f = (lua_CFunction)dlsym(lib, sym); | ||||
|   if (f == NULL) lua_pushstring(L, dlerror()); | ||||
|   return f; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
|  | ||||
| #elif defined(LUA_DL_DLL) | ||||
| /* | ||||
| ** {====================================================================== | ||||
| ** This is an implementation of loadlib for Windows using native functions. | ||||
| ** ======================================================================= | ||||
| */ | ||||
|  | ||||
| #include <windows.h> | ||||
|  | ||||
|  | ||||
| #undef setprogdir | ||||
|  | ||||
| static void setprogdir (lua_State *L) { | ||||
|   char buff[MAX_PATH + 1]; | ||||
|   char *lb; | ||||
|   DWORD nsize = sizeof(buff)/sizeof(char); | ||||
|   DWORD n = GetModuleFileNameA(NULL, buff, nsize); | ||||
|   if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) | ||||
|     luaL_error(L, "unable to get ModuleFileName"); | ||||
|   else { | ||||
|     *lb = '\0'; | ||||
|     luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); | ||||
|     lua_remove(L, -2);  /* remove original string */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void pusherror (lua_State *L) { | ||||
|   int error = GetLastError(); | ||||
|   char buffer[128]; | ||||
|   if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, | ||||
|       NULL, error, 0, buffer, sizeof(buffer), NULL)) | ||||
|     lua_pushstring(L, buffer); | ||||
|   else | ||||
|     lua_pushfstring(L, "system error %d\n", error); | ||||
| } | ||||
|  | ||||
| static void ll_unloadlib (void *lib) { | ||||
|   FreeLibrary((HINSTANCE)lib); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void *ll_load (lua_State *L, const char *path) { | ||||
|   HINSTANCE lib = LoadLibraryA(path); | ||||
|   if (lib == NULL) pusherror(L); | ||||
|   return lib; | ||||
| } | ||||
|  | ||||
|  | ||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||||
|   lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); | ||||
|   if (f == NULL) pusherror(L); | ||||
|   return f; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
|  | ||||
| #elif defined(LUA_DL_DYLD) | ||||
| /* | ||||
| ** {====================================================================== | ||||
| ** Native Mac OS X / Darwin Implementation | ||||
| ** ======================================================================= | ||||
| */ | ||||
|  | ||||
| #include <mach-o/dyld.h> | ||||
|  | ||||
|  | ||||
| /* Mac appends a `_' before C function names */ | ||||
| #undef POF | ||||
| #define POF	"_" LUA_POF | ||||
|  | ||||
|  | ||||
| static void pusherror (lua_State *L) { | ||||
|   const char *err_str; | ||||
|   const char *err_file; | ||||
|   NSLinkEditErrors err; | ||||
|   int err_num; | ||||
|   NSLinkEditError(&err, &err_num, &err_file, &err_str); | ||||
|   lua_pushstring(L, err_str); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *errorfromcode (NSObjectFileImageReturnCode ret) { | ||||
|   switch (ret) { | ||||
|     case NSObjectFileImageInappropriateFile: | ||||
|       return "file is not a bundle"; | ||||
|     case NSObjectFileImageArch: | ||||
|       return "library is for wrong CPU type"; | ||||
|     case NSObjectFileImageFormat: | ||||
|       return "bad format"; | ||||
|     case NSObjectFileImageAccess: | ||||
|       return "cannot access file"; | ||||
|     case NSObjectFileImageFailure: | ||||
|     default: | ||||
|       return "unable to load library"; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void ll_unloadlib (void *lib) { | ||||
|   NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void *ll_load (lua_State *L, const char *path) { | ||||
|   NSObjectFileImage img; | ||||
|   NSObjectFileImageReturnCode ret; | ||||
|   /* this would be a rare case, but prevents crashing if it happens */ | ||||
|   if(!_dyld_present()) { | ||||
|     lua_pushliteral(L, "dyld not present"); | ||||
|     return NULL; | ||||
|   } | ||||
|   ret = NSCreateObjectFileImageFromFile(path, &img); | ||||
|   if (ret == NSObjectFileImageSuccess) { | ||||
|     NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | | ||||
|                        NSLINKMODULE_OPTION_RETURN_ON_ERROR); | ||||
|     NSDestroyObjectFileImage(img); | ||||
|     if (mod == NULL) pusherror(L); | ||||
|     return mod; | ||||
|   } | ||||
|   lua_pushstring(L, errorfromcode(ret)); | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||||
|   NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); | ||||
|   if (nss == NULL) { | ||||
|     lua_pushfstring(L, "symbol " LUA_QS " not found", sym); | ||||
|     return NULL; | ||||
|   } | ||||
|   return (lua_CFunction)NSAddressOfSymbol(nss); | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
|  | ||||
| #else | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Fallback for other systems | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
| #undef LIB_FAIL | ||||
| #define LIB_FAIL	"absent" | ||||
|  | ||||
|  | ||||
| #define DLMSG	"dynamic libraries not enabled; check your Lua installation" | ||||
|  | ||||
|  | ||||
| static void ll_unloadlib (void *lib) { | ||||
|   (void)lib;  /* to avoid warnings */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static void *ll_load (lua_State *L, const char *path) { | ||||
|   (void)path;  /* to avoid warnings */ | ||||
|   lua_pushliteral(L, DLMSG); | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||||
|   (void)lib; (void)sym;  /* to avoid warnings */ | ||||
|   lua_pushliteral(L, DLMSG); | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
| static void **ll_register (lua_State *L, const char *path) { | ||||
|   void **plib; | ||||
|   lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||||
|   lua_gettable(L, LUA_REGISTRYINDEX);  /* check library in registry? */ | ||||
|   if (!lua_isnil(L, -1))  /* is there an entry? */ | ||||
|     plib = (void **)lua_touserdata(L, -1); | ||||
|   else {  /* no entry yet; create one */ | ||||
|     lua_pop(L, 1); | ||||
|     plib = (void **)lua_newuserdata(L, sizeof(const void *)); | ||||
|     *plib = NULL; | ||||
|     luaL_getmetatable(L, "_LOADLIB"); | ||||
|     lua_setmetatable(L, -2); | ||||
|     lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||||
|     lua_pushvalue(L, -2); | ||||
|     lua_settable(L, LUA_REGISTRYINDEX); | ||||
|   } | ||||
|   return plib; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** __gc tag method: calls library's `ll_unloadlib' function with the lib | ||||
| ** handle | ||||
| */ | ||||
| static int gctm (lua_State *L) { | ||||
|   void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); | ||||
|   if (*lib) ll_unloadlib(*lib); | ||||
|   *lib = NULL;  /* mark library as closed */ | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { | ||||
|   void **reg = ll_register(L, path); | ||||
|   if (*reg == NULL) *reg = ll_load(L, path); | ||||
|   if (*reg == NULL) | ||||
|     return ERRLIB;  /* unable to load library */ | ||||
|   else { | ||||
|     lua_CFunction f = ll_sym(L, *reg, sym); | ||||
|     if (f == NULL) | ||||
|       return ERRFUNC;  /* unable to find function */ | ||||
|     lua_pushcfunction(L, f); | ||||
|     return 0;  /* return function */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int ll_loadlib (lua_State *L) { | ||||
|   const char *path = luaL_checkstring(L, 1); | ||||
|   const char *init = luaL_checkstring(L, 2); | ||||
|   int stat = ll_loadfunc(L, path, init); | ||||
|   if (stat == 0)  /* no errors? */ | ||||
|     return 1;  /* return the loaded function */ | ||||
|   else {  /* error; error message is on stack top */ | ||||
|     lua_pushnil(L); | ||||
|     lua_insert(L, -2); | ||||
|     lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : "init"); | ||||
|     return 3;  /* return nil, error message, and where */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** 'require' function | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
| static int readable (const char *filename) { | ||||
|   FILE *f = fopen(filename, "r");  /* try to open file */ | ||||
|   if (f == NULL) return 0;  /* open failed */ | ||||
|   fclose(f); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *pushnexttemplate (lua_State *L, const char *path) { | ||||
|   const char *l; | ||||
|   while (*path == *LUA_PATHSEP) path++;  /* skip separators */ | ||||
|   if (*path == '\0') return NULL;  /* no more templates */ | ||||
|   l = strchr(path, *LUA_PATHSEP);  /* find next separator */ | ||||
|   if (l == NULL) l = path + strlen(path); | ||||
|   lua_pushlstring(L, path, l - path);  /* template */ | ||||
|   return l; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *findfile (lua_State *L, const char *name, | ||||
|                                            const char *pname) { | ||||
|   const char *path; | ||||
|   name = luaL_gsub(L, name, ".", LUA_DIRSEP); | ||||
|   lua_getfield(L, LUA_ENVIRONINDEX, pname); | ||||
|   path = lua_tostring(L, -1); | ||||
|   if (path == NULL) | ||||
|     luaL_error(L, LUA_QL("package.%s") " must be a string", pname); | ||||
|   lua_pushliteral(L, "");  /* error accumulator */ | ||||
|   while ((path = pushnexttemplate(L, path)) != NULL) { | ||||
|     const char *filename; | ||||
|     filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); | ||||
|     lua_remove(L, -2);  /* remove path template */ | ||||
|     if (readable(filename))  /* does file exist and is readable? */ | ||||
|       return filename;  /* return that file name */ | ||||
|     lua_pushfstring(L, "\n\tno file " LUA_QS, filename); | ||||
|     lua_remove(L, -2);  /* remove file name */ | ||||
|     lua_concat(L, 2);  /* add entry to possible error message */ | ||||
|   } | ||||
|   return NULL;  /* not found */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static void loaderror (lua_State *L, const char *filename) { | ||||
|   luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", | ||||
|                 lua_tostring(L, 1), filename, lua_tostring(L, -1)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int loader_Lua (lua_State *L) { | ||||
|   const char *filename; | ||||
|   const char *name = luaL_checkstring(L, 1); | ||||
|   filename = findfile(L, name, "path"); | ||||
|   if (filename == NULL) return 1;  /* library not found in this path */ | ||||
|   if (luaL_loadfile(L, filename) != 0) | ||||
|     loaderror(L, filename); | ||||
|   return 1;  /* library loaded successfully */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *mkfuncname (lua_State *L, const char *modname) { | ||||
|   const char *funcname; | ||||
|   const char *mark = strchr(modname, *LUA_IGMARK); | ||||
|   if (mark) modname = mark + 1; | ||||
|   funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); | ||||
|   funcname = lua_pushfstring(L, POF"%s", funcname); | ||||
|   lua_remove(L, -2);  /* remove 'gsub' result */ | ||||
|   return funcname; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int loader_C (lua_State *L) { | ||||
|   const char *funcname; | ||||
|   const char *name = luaL_checkstring(L, 1); | ||||
|   const char *filename = findfile(L, name, "cpath"); | ||||
|   if (filename == NULL) return 1;  /* library not found in this path */ | ||||
|   funcname = mkfuncname(L, name); | ||||
|   if (ll_loadfunc(L, filename, funcname) != 0) | ||||
|     loaderror(L, filename); | ||||
|   return 1;  /* library loaded successfully */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int loader_Croot (lua_State *L) { | ||||
|   const char *funcname; | ||||
|   const char *filename; | ||||
|   const char *name = luaL_checkstring(L, 1); | ||||
|   const char *p = strchr(name, '.'); | ||||
|   int stat; | ||||
|   if (p == NULL) return 0;  /* is root */ | ||||
|   lua_pushlstring(L, name, p - name); | ||||
|   filename = findfile(L, lua_tostring(L, -1), "cpath"); | ||||
|   if (filename == NULL) return 1;  /* root not found */ | ||||
|   funcname = mkfuncname(L, name); | ||||
|   if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { | ||||
|     if (stat != ERRFUNC) loaderror(L, filename);  /* real error */ | ||||
|     lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, | ||||
|                        name, filename); | ||||
|     return 1;  /* function not found */ | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int loader_preload (lua_State *L) { | ||||
|   const char *name = luaL_checkstring(L, 1); | ||||
|   lua_getfield(L, LUA_ENVIRONINDEX, "preload"); | ||||
|   if (!lua_istable(L, -1)) | ||||
|     luaL_error(L, LUA_QL("package.preload") " must be a table"); | ||||
|   lua_getfield(L, -1, name); | ||||
|   if (lua_isnil(L, -1))  /* not found? */ | ||||
|     lua_pushfstring(L, "\n\tno field package.preload['%s']", name); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const int sentinel_ = 0; | ||||
| #define sentinel	((void *)&sentinel_) | ||||
|  | ||||
|  | ||||
| static int ll_require (lua_State *L) { | ||||
|   const char *name = luaL_checkstring(L, 1); | ||||
|   int i; | ||||
|   lua_settop(L, 1);  /* _LOADED table will be at index 2 */ | ||||
|   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); | ||||
|   lua_getfield(L, 2, name); | ||||
|   if (lua_toboolean(L, -1)) {  /* is it there? */ | ||||
|     if (lua_touserdata(L, -1) == sentinel)  /* check loops */ | ||||
|       luaL_error(L, "loop or previous error loading module " LUA_QS, name); | ||||
|     return 1;  /* package is already loaded */ | ||||
|   } | ||||
|   /* else must load it; iterate over available loaders */ | ||||
|   lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); | ||||
|   if (!lua_istable(L, -1)) | ||||
|     luaL_error(L, LUA_QL("package.loaders") " must be a table"); | ||||
|   lua_pushliteral(L, "");  /* error message accumulator */ | ||||
|   for (i=1; ; i++) { | ||||
|     lua_rawgeti(L, -2, i);  /* get a loader */ | ||||
|     if (lua_isnil(L, -1)) | ||||
|       luaL_error(L, "module " LUA_QS " not found:%s", | ||||
|                     name, lua_tostring(L, -2)); | ||||
|     lua_pushstring(L, name); | ||||
|     lua_call(L, 1, 1);  /* call it */ | ||||
|     if (lua_isfunction(L, -1))  /* did it find module? */ | ||||
|       break;  /* module loaded successfully */ | ||||
|     else if (lua_isstring(L, -1))  /* loader returned error message? */ | ||||
|       lua_concat(L, 2);  /* accumulate it */ | ||||
|     else | ||||
|       lua_pop(L, 1); | ||||
|   } | ||||
|   lua_pushlightuserdata(L, sentinel); | ||||
|   lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */ | ||||
|   lua_pushstring(L, name);  /* pass name as argument to module */ | ||||
|   lua_call(L, 1, 1);  /* run loaded module */ | ||||
|   if (!lua_isnil(L, -1))  /* non-nil return? */ | ||||
|     lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */ | ||||
|   lua_getfield(L, 2, name); | ||||
|   if (lua_touserdata(L, -1) == sentinel) {   /* module did not set a value? */ | ||||
|     lua_pushboolean(L, 1);  /* use true as result */ | ||||
|     lua_pushvalue(L, -1);  /* extra copy to be returned */ | ||||
|     lua_setfield(L, 2, name);  /* _LOADED[name] = true */ | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** 'module' function | ||||
| ** ======================================================= | ||||
| */ | ||||
|    | ||||
|  | ||||
| static void setfenv (lua_State *L) { | ||||
|   lua_Debug ar; | ||||
|   lua_getstack(L, 1, &ar); | ||||
|   lua_getinfo(L, "f", &ar); | ||||
|   lua_pushvalue(L, -2); | ||||
|   lua_setfenv(L, -2); | ||||
|   lua_pop(L, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void dooptions (lua_State *L, int n) { | ||||
|   int i; | ||||
|   for (i = 2; i <= n; i++) { | ||||
|     lua_pushvalue(L, i);  /* get option (a function) */ | ||||
|     lua_pushvalue(L, -2);  /* module */ | ||||
|     lua_call(L, 1, 0); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void modinit (lua_State *L, const char *modname) { | ||||
|   const char *dot; | ||||
|   lua_pushvalue(L, -1); | ||||
|   lua_setfield(L, -2, "_M");  /* module._M = module */ | ||||
|   lua_pushstring(L, modname); | ||||
|   lua_setfield(L, -2, "_NAME"); | ||||
|   dot = strrchr(modname, '.');  /* look for last dot in module name */ | ||||
|   if (dot == NULL) dot = modname; | ||||
|   else dot++; | ||||
|   /* set _PACKAGE as package name (full module name minus last part) */ | ||||
|   lua_pushlstring(L, modname, dot - modname); | ||||
|   lua_setfield(L, -2, "_PACKAGE"); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int ll_module (lua_State *L) { | ||||
|   const char *modname = luaL_checkstring(L, 1); | ||||
|   int loaded = lua_gettop(L) + 1;  /* index of _LOADED table */ | ||||
|   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); | ||||
|   lua_getfield(L, loaded, modname);  /* get _LOADED[modname] */ | ||||
|   if (!lua_istable(L, -1)) {  /* not found? */ | ||||
|     lua_pop(L, 1);  /* remove previous result */ | ||||
|     /* try global variable (and create one if it does not exist) */ | ||||
|     if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) | ||||
|       return luaL_error(L, "name conflict for module " LUA_QS, modname); | ||||
|     lua_pushvalue(L, -1); | ||||
|     lua_setfield(L, loaded, modname);  /* _LOADED[modname] = new table */ | ||||
|   } | ||||
|   /* check whether table already has a _NAME field */ | ||||
|   lua_getfield(L, -1, "_NAME"); | ||||
|   if (!lua_isnil(L, -1))  /* is table an initialized module? */ | ||||
|     lua_pop(L, 1); | ||||
|   else {  /* no; initialize it */ | ||||
|     lua_pop(L, 1); | ||||
|     modinit(L, modname); | ||||
|   } | ||||
|   lua_pushvalue(L, -1); | ||||
|   setfenv(L); | ||||
|   dooptions(L, loaded - 1); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int ll_seeall (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   if (!lua_getmetatable(L, 1)) { | ||||
|     lua_createtable(L, 0, 1); /* create new metatable */ | ||||
|     lua_pushvalue(L, -1); | ||||
|     lua_setmetatable(L, 1); | ||||
|   } | ||||
|   lua_pushvalue(L, LUA_GLOBALSINDEX); | ||||
|   lua_setfield(L, -2, "__index");  /* mt.__index = _G */ | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
|  | ||||
| /* auxiliary mark (for internal use) */ | ||||
| #define AUXMARK		"\1" | ||||
|  | ||||
| static void setpath (lua_State *L, const char *fieldname, const char *envname, | ||||
|                                    const char *def) { | ||||
|   const char *path = getenv(envname); | ||||
|   if (path == NULL)  /* no environment variable? */ | ||||
|     lua_pushstring(L, def);  /* use default */ | ||||
|   else { | ||||
|     /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ | ||||
|     path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, | ||||
|                               LUA_PATHSEP AUXMARK LUA_PATHSEP); | ||||
|     luaL_gsub(L, path, AUXMARK, def); | ||||
|     lua_remove(L, -2); | ||||
|   } | ||||
|   setprogdir(L); | ||||
|   lua_setfield(L, -2, fieldname); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const luaL_Reg pk_funcs[] = { | ||||
|   {"loadlib", ll_loadlib}, | ||||
|   {"seeall", ll_seeall}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| static const luaL_Reg ll_funcs[] = { | ||||
|   {"module", ll_module}, | ||||
|   {"require", ll_require}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| static const lua_CFunction loaders[] = | ||||
|   {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaopen_package (lua_State *L) { | ||||
|   int i; | ||||
|   /* create new type _LOADLIB */ | ||||
|   luaL_newmetatable(L, "_LOADLIB"); | ||||
|   lua_pushcfunction(L, gctm); | ||||
|   lua_setfield(L, -2, "__gc"); | ||||
|   /* create `package' table */ | ||||
|   luaL_register(L, LUA_LOADLIBNAME, pk_funcs); | ||||
| #if defined(LUA_COMPAT_LOADLIB)  | ||||
|   lua_getfield(L, -1, "loadlib"); | ||||
|   lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); | ||||
| #endif | ||||
|   lua_pushvalue(L, -1); | ||||
|   lua_replace(L, LUA_ENVIRONINDEX); | ||||
|   /* create `loaders' table */ | ||||
|   lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); | ||||
|   /* fill it with pre-defined loaders */ | ||||
|   for (i=0; loaders[i] != NULL; i++) { | ||||
|     lua_pushcfunction(L, loaders[i]); | ||||
|     lua_rawseti(L, -2, i+1); | ||||
|   } | ||||
|   lua_setfield(L, -2, "loaders");  /* put it in field `loaders' */ | ||||
|   setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT);  /* set field `path' */ | ||||
|   setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ | ||||
|   /* store config information */ | ||||
|   lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" | ||||
|                      LUA_EXECDIR "\n" LUA_IGMARK); | ||||
|   lua_setfield(L, -2, "config"); | ||||
|   /* set field `loaded' */ | ||||
|   luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); | ||||
|   lua_setfield(L, -2, "loaded"); | ||||
|   /* set field `preload' */ | ||||
|   lua_newtable(L); | ||||
|   lua_setfield(L, -2, "preload"); | ||||
|   lua_pushvalue(L, LUA_GLOBALSINDEX); | ||||
|   luaL_register(L, NULL, ll_funcs);  /* open lib into global table */ | ||||
|   lua_pop(L, 1); | ||||
|   return 1;  /* return 'package' table */ | ||||
| } | ||||
|  | ||||
							
								
								
									
										214
									
								
								lua/src/lobject.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								lua/src/lobject.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,214 @@ | ||||
| /* | ||||
| ** $Id: lobject.c,v 2.22 2006/02/10 17:43:52 roberto Exp $ | ||||
| ** Some generic functions over Lua objects | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
| #include <ctype.h> | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define lobject_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldo.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "lvm.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** converts an integer to a "floating point byte", represented as | ||||
| ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if | ||||
| ** eeeee != 0 and (xxx) otherwise. | ||||
| */ | ||||
| int luaO_int2fb (unsigned int x) { | ||||
|   int e = 0;  /* expoent */ | ||||
|   while (x >= 16) { | ||||
|     x = (x+1) >> 1; | ||||
|     e++; | ||||
|   } | ||||
|   if (x < 8) return x; | ||||
|   else return ((e+1) << 3) | (cast_int(x) - 8); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* converts back */ | ||||
| int luaO_fb2int (int x) { | ||||
|   int e = (x >> 3) & 31; | ||||
|   if (e == 0) return x; | ||||
|   else return ((x & 7)+8) << (e - 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaO_log2 (unsigned int x) { | ||||
|   static const lu_byte log_2[256] = { | ||||
|     0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, | ||||
|     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, | ||||
|     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, | ||||
|     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, | ||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | ||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | ||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | ||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 | ||||
|   }; | ||||
|   int l = -1; | ||||
|   while (x >= 256) { l += 8; x >>= 8; } | ||||
|   return l + log_2[x]; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaO_rawequalObj (const TValue *t1, const TValue *t2) { | ||||
|   if (ttype(t1) != ttype(t2)) return 0; | ||||
|   else switch (ttype(t1)) { | ||||
|     case LUA_TNIL: | ||||
|       return 1; | ||||
|     case LUA_TNUMBER: | ||||
|       return luai_numeq(nvalue(t1), nvalue(t2)); | ||||
|     case LUA_TBOOLEAN: | ||||
|       return bvalue(t1) == bvalue(t2);  /* boolean true must be 1 !! */ | ||||
|     case LUA_TLIGHTUSERDATA: | ||||
|       return pvalue(t1) == pvalue(t2); | ||||
|     default: | ||||
|       lua_assert(iscollectable(t1)); | ||||
|       return gcvalue(t1) == gcvalue(t2); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaO_str2d (const char *s, lua_Number *result) { | ||||
|   char *endptr; | ||||
|   *result = lua_str2number(s, &endptr); | ||||
|   if (endptr == s) return 0;  /* conversion failed */ | ||||
|   if (*endptr == 'x' || *endptr == 'X')  /* maybe an hexadecimal constant? */ | ||||
|     *result = cast_num(strtoul(s, &endptr, 16)); | ||||
|   if (*endptr == '\0') return 1;  /* most common case */ | ||||
|   while (isspace(cast(unsigned char, *endptr))) endptr++; | ||||
|   if (*endptr != '\0') return 0;  /* invalid trailing characters? */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static void pushstr (lua_State *L, const char *str) { | ||||
|   setsvalue2s(L, L->top, luaS_new(L, str)); | ||||
|   incr_top(L); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ | ||||
| const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { | ||||
|   int n = 1; | ||||
|   pushstr(L, ""); | ||||
|   for (;;) { | ||||
|     const char *e = strchr(fmt, '%'); | ||||
|     if (e == NULL) break; | ||||
|     setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); | ||||
|     incr_top(L); | ||||
|     switch (*(e+1)) { | ||||
|       case 's': { | ||||
|         const char *s = va_arg(argp, char *); | ||||
|         if (s == NULL) s = "(null)"; | ||||
|         pushstr(L, s); | ||||
|         break; | ||||
|       } | ||||
|       case 'c': { | ||||
|         char buff[2]; | ||||
|         buff[0] = cast(char, va_arg(argp, int)); | ||||
|         buff[1] = '\0'; | ||||
|         pushstr(L, buff); | ||||
|         break; | ||||
|       } | ||||
|       case 'd': { | ||||
|         setnvalue(L->top, cast_num(va_arg(argp, int))); | ||||
|         incr_top(L); | ||||
|         break; | ||||
|       } | ||||
|       case 'f': { | ||||
|         setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); | ||||
|         incr_top(L); | ||||
|         break; | ||||
|       } | ||||
|       case 'p': { | ||||
|         char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ | ||||
|         sprintf(buff, "%p", va_arg(argp, void *)); | ||||
|         pushstr(L, buff); | ||||
|         break; | ||||
|       } | ||||
|       case '%': { | ||||
|         pushstr(L, "%"); | ||||
|         break; | ||||
|       } | ||||
|       default: { | ||||
|         char buff[3]; | ||||
|         buff[0] = '%'; | ||||
|         buff[1] = *(e+1); | ||||
|         buff[2] = '\0'; | ||||
|         pushstr(L, buff); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     n += 2; | ||||
|     fmt = e+2; | ||||
|   } | ||||
|   pushstr(L, fmt); | ||||
|   luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); | ||||
|   L->top -= n; | ||||
|   return svalue(L->top - 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { | ||||
|   const char *msg; | ||||
|   va_list argp; | ||||
|   va_start(argp, fmt); | ||||
|   msg = luaO_pushvfstring(L, fmt, argp); | ||||
|   va_end(argp); | ||||
|   return msg; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaO_chunkid (char *out, const char *source, size_t bufflen) { | ||||
|   if (*source == '=') { | ||||
|     strncpy(out, source+1, bufflen);  /* remove first char */ | ||||
|     out[bufflen-1] = '\0';  /* ensures null termination */ | ||||
|   } | ||||
|   else {  /* out = "source", or "...source" */ | ||||
|     if (*source == '@') { | ||||
|       size_t l; | ||||
|       source++;  /* skip the `@' */ | ||||
|       bufflen -= sizeof(" '...' "); | ||||
|       l = strlen(source); | ||||
|       strcpy(out, ""); | ||||
|       if (l > bufflen) { | ||||
|         source += (l-bufflen);  /* get last part of file name */ | ||||
|         strcat(out, "..."); | ||||
|       } | ||||
|       strcat(out, source); | ||||
|     } | ||||
|     else {  /* out = [string "string"] */ | ||||
|       size_t len = strcspn(source, "\n\r");  /* stop at first newline */ | ||||
|       bufflen -= sizeof(" [string \"...\"] "); | ||||
|       if (len > bufflen) len = bufflen; | ||||
|       strcpy(out, "[string \""); | ||||
|       if (source[len] != '\0') {  /* must truncate? */ | ||||
|         strncat(out, source, len); | ||||
|         strcat(out, "..."); | ||||
|       } | ||||
|       else | ||||
|         strcat(out, source); | ||||
|       strcat(out, "\"]"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										102
									
								
								lua/src/lopcodes.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								lua/src/lopcodes.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| /* | ||||
| ** $Id: lopcodes.c,v 1.37 2005/11/08 19:45:36 roberto Exp $ | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #define lopcodes_c | ||||
| #define LUA_CORE | ||||
|  | ||||
|  | ||||
| #include "lopcodes.h" | ||||
|  | ||||
|  | ||||
| /* ORDER OP */ | ||||
|  | ||||
| const char *const luaP_opnames[NUM_OPCODES+1] = { | ||||
|   "MOVE", | ||||
|   "LOADK", | ||||
|   "LOADBOOL", | ||||
|   "LOADNIL", | ||||
|   "GETUPVAL", | ||||
|   "GETGLOBAL", | ||||
|   "GETTABLE", | ||||
|   "SETGLOBAL", | ||||
|   "SETUPVAL", | ||||
|   "SETTABLE", | ||||
|   "NEWTABLE", | ||||
|   "SELF", | ||||
|   "ADD", | ||||
|   "SUB", | ||||
|   "MUL", | ||||
|   "DIV", | ||||
|   "MOD", | ||||
|   "POW", | ||||
|   "UNM", | ||||
|   "NOT", | ||||
|   "LEN", | ||||
|   "CONCAT", | ||||
|   "JMP", | ||||
|   "EQ", | ||||
|   "LT", | ||||
|   "LE", | ||||
|   "TEST", | ||||
|   "TESTSET", | ||||
|   "CALL", | ||||
|   "TAILCALL", | ||||
|   "RETURN", | ||||
|   "FORLOOP", | ||||
|   "FORPREP", | ||||
|   "TFORLOOP", | ||||
|   "SETLIST", | ||||
|   "CLOSE", | ||||
|   "CLOSURE", | ||||
|   "VARARG", | ||||
|   NULL | ||||
| }; | ||||
|  | ||||
|  | ||||
| #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) | ||||
|  | ||||
| const lu_byte luaP_opmodes[NUM_OPCODES] = { | ||||
| /*       T  A    B       C     mode		   opcode	*/ | ||||
|   opmode(0, 1, OpArgR, OpArgN, iABC) 		/* OP_MOVE */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */ | ||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LOADNIL */ | ||||
|  ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_GETGLOBAL */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */ | ||||
|  ,opmode(0, 0, OpArgK, OpArgN, iABx)		/* OP_SETGLOBAL */ | ||||
|  ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */ | ||||
|  ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */ | ||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */ | ||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */ | ||||
|  ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */ | ||||
|  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */ | ||||
|  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */ | ||||
|  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */ | ||||
|  ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TEST */ | ||||
|  ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */ | ||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */ | ||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */ | ||||
|  ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */ | ||||
|  ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */ | ||||
|  ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TFORLOOP */ | ||||
|  ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */ | ||||
|  ,opmode(0, 0, OpArgN, OpArgN, iABC)		/* OP_CLOSE */ | ||||
|  ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */ | ||||
|  ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */ | ||||
| }; | ||||
|  | ||||
							
								
								
									
										244
									
								
								lua/src/loslib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								lua/src/loslib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | ||||
| /* | ||||
| ** $Id: loslib.c,v 1.20 2006/09/19 13:57:08 roberto Exp $ | ||||
| ** Standard Operating System library | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <locale.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #define loslib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
| static int os_pushresult (lua_State *L, int i, const char *filename) { | ||||
|   int en = errno;  /* calls to Lua API may change this value */ | ||||
|   if (i) { | ||||
|     lua_pushboolean(L, 1); | ||||
|     return 1; | ||||
|   } | ||||
|   else { | ||||
|     lua_pushnil(L); | ||||
|     lua_pushfstring(L, "%s: %s", filename, strerror(en)); | ||||
|     lua_pushinteger(L, en); | ||||
|     return 3; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_execute (lua_State *L) { | ||||
|   lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_remove (lua_State *L) { | ||||
|   const char *filename = luaL_checkstring(L, 1); | ||||
|   return os_pushresult(L, remove(filename) == 0, filename); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_rename (lua_State *L) { | ||||
|   const char *fromname = luaL_checkstring(L, 1); | ||||
|   const char *toname = luaL_checkstring(L, 2); | ||||
|   return os_pushresult(L, rename(fromname, toname) == 0, fromname); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_tmpname (lua_State *L) { | ||||
|   char buff[LUA_TMPNAMBUFSIZE]; | ||||
|   int err; | ||||
|   lua_tmpnam(buff, err); | ||||
|   if (err) | ||||
|     return luaL_error(L, "unable to generate a unique filename"); | ||||
|   lua_pushstring(L, buff); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_getenv (lua_State *L) { | ||||
|   lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_clock (lua_State *L) { | ||||
|   lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Time/Date operations | ||||
| ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, | ||||
| **   wday=%w+1, yday=%j, isdst=? } | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
| static void setfield (lua_State *L, const char *key, int value) { | ||||
|   lua_pushinteger(L, value); | ||||
|   lua_setfield(L, -2, key); | ||||
| } | ||||
|  | ||||
| static void setboolfield (lua_State *L, const char *key, int value) { | ||||
|   if (value < 0)  /* undefined? */ | ||||
|     return;  /* does not set field */ | ||||
|   lua_pushboolean(L, value); | ||||
|   lua_setfield(L, -2, key); | ||||
| } | ||||
|  | ||||
| static int getboolfield (lua_State *L, const char *key) { | ||||
|   int res; | ||||
|   lua_getfield(L, -1, key); | ||||
|   res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); | ||||
|   lua_pop(L, 1); | ||||
|   return res; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int getfield (lua_State *L, const char *key, int d) { | ||||
|   int res; | ||||
|   lua_getfield(L, -1, key); | ||||
|   if (lua_isnumber(L, -1)) | ||||
|     res = (int)lua_tointeger(L, -1); | ||||
|   else { | ||||
|     if (d < 0) | ||||
|       return luaL_error(L, "field " LUA_QS " missing in date table", key); | ||||
|     res = d; | ||||
|   } | ||||
|   lua_pop(L, 1); | ||||
|   return res; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_date (lua_State *L) { | ||||
|   const char *s = luaL_optstring(L, 1, "%c"); | ||||
|   time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); | ||||
|   struct tm *stm; | ||||
|   if (*s == '!') {  /* UTC? */ | ||||
|     stm = gmtime(&t); | ||||
|     s++;  /* skip `!' */ | ||||
|   } | ||||
|   else | ||||
|     stm = localtime(&t); | ||||
|   if (stm == NULL)  /* invalid date? */ | ||||
|     lua_pushnil(L); | ||||
|   else if (strcmp(s, "*t") == 0) { | ||||
|     lua_createtable(L, 0, 9);  /* 9 = number of fields */ | ||||
|     setfield(L, "sec", stm->tm_sec); | ||||
|     setfield(L, "min", stm->tm_min); | ||||
|     setfield(L, "hour", stm->tm_hour); | ||||
|     setfield(L, "day", stm->tm_mday); | ||||
|     setfield(L, "month", stm->tm_mon+1); | ||||
|     setfield(L, "year", stm->tm_year+1900); | ||||
|     setfield(L, "wday", stm->tm_wday+1); | ||||
|     setfield(L, "yday", stm->tm_yday+1); | ||||
|     setboolfield(L, "isdst", stm->tm_isdst); | ||||
|   } | ||||
|   else { | ||||
|     char cc[3]; | ||||
|     luaL_Buffer b; | ||||
|     cc[0] = '%'; cc[2] = '\0'; | ||||
|     luaL_buffinit(L, &b); | ||||
|     for (; *s; s++) { | ||||
|       if (*s != '%' || *(s + 1) == '\0')  /* no conversion specifier? */ | ||||
|         luaL_addchar(&b, *s); | ||||
|       else { | ||||
|         size_t reslen; | ||||
|         char buff[200];  /* should be big enough for any conversion result */ | ||||
|         cc[1] = *(++s); | ||||
|         reslen = strftime(buff, sizeof(buff), cc, stm); | ||||
|         luaL_addlstring(&b, buff, reslen); | ||||
|       } | ||||
|     } | ||||
|     luaL_pushresult(&b); | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_time (lua_State *L) { | ||||
|   time_t t; | ||||
|   if (lua_isnoneornil(L, 1))  /* called without args? */ | ||||
|     t = time(NULL);  /* get current time */ | ||||
|   else { | ||||
|     struct tm ts; | ||||
|     luaL_checktype(L, 1, LUA_TTABLE); | ||||
|     lua_settop(L, 1);  /* make sure table is at the top */ | ||||
|     ts.tm_sec = getfield(L, "sec", 0); | ||||
|     ts.tm_min = getfield(L, "min", 0); | ||||
|     ts.tm_hour = getfield(L, "hour", 12); | ||||
|     ts.tm_mday = getfield(L, "day", -1); | ||||
|     ts.tm_mon = getfield(L, "month", -1) - 1; | ||||
|     ts.tm_year = getfield(L, "year", -1) - 1900; | ||||
|     ts.tm_isdst = getboolfield(L, "isdst"); | ||||
|     t = mktime(&ts); | ||||
|   } | ||||
|   if (t == (time_t)(-1)) | ||||
|     lua_pushnil(L); | ||||
|   else | ||||
|     lua_pushnumber(L, (lua_Number)t); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_difftime (lua_State *L) { | ||||
|   lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), | ||||
|                              (time_t)(luaL_optnumber(L, 2, 0)))); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| static int os_setlocale (lua_State *L) { | ||||
|   static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, | ||||
|                       LC_NUMERIC, LC_TIME}; | ||||
|   static const char *const catnames[] = {"all", "collate", "ctype", "monetary", | ||||
|      "numeric", "time", NULL}; | ||||
|   const char *l = luaL_optstring(L, 1, NULL); | ||||
|   int op = luaL_checkoption(L, 2, "all", catnames); | ||||
|   lua_pushstring(L, setlocale(cat[op], l)); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int os_exit (lua_State *L) { | ||||
|   exit(luaL_optint(L, 1, EXIT_SUCCESS)); | ||||
|   return 0;  /* to avoid warnings */ | ||||
| } | ||||
|  | ||||
| static const luaL_Reg syslib[] = { | ||||
|   {"clock",     os_clock}, | ||||
|   {"date",      os_date}, | ||||
|   {"difftime",  os_difftime}, | ||||
|   {"execute",   os_execute}, | ||||
|   {"exit",      os_exit}, | ||||
|   {"getenv",    os_getenv}, | ||||
|   {"remove",    os_remove}, | ||||
|   {"rename",    os_rename}, | ||||
|   {"setlocale", os_setlocale}, | ||||
|   {"time",      os_time}, | ||||
|   {"tmpname",   os_tmpname}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaopen_os (lua_State *L) { | ||||
|   luaL_register(L, LUA_OSLIBNAME, syslib); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
							
								
								
									
										1337
									
								
								lua/src/lparser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1337
									
								
								lua/src/lparser.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										214
									
								
								lua/src/lstate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								lua/src/lstate.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,214 @@ | ||||
| /* | ||||
| ** $Id: lstate.c,v 2.36 2006/05/24 14:15:50 roberto Exp $ | ||||
| ** Global State | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stddef.h> | ||||
|  | ||||
| #define lstate_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lfunc.h" | ||||
| #include "lgc.h" | ||||
| #include "llex.h" | ||||
| #include "lmem.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "ltable.h" | ||||
| #include "ltm.h" | ||||
|  | ||||
|  | ||||
| #define state_size(x)	(sizeof(x) + LUAI_EXTRASPACE) | ||||
| #define fromstate(l)	(cast(lu_byte *, (l)) - LUAI_EXTRASPACE) | ||||
| #define tostate(l)   (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Main thread combines a thread state and the global state | ||||
| */ | ||||
| typedef struct LG { | ||||
|   lua_State l; | ||||
|   global_State g; | ||||
| } LG; | ||||
|    | ||||
|  | ||||
|  | ||||
| static void stack_init (lua_State *L1, lua_State *L) { | ||||
|   /* initialize CallInfo array */ | ||||
|   L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); | ||||
|   L1->ci = L1->base_ci; | ||||
|   L1->size_ci = BASIC_CI_SIZE; | ||||
|   L1->end_ci = L1->base_ci + L1->size_ci - 1; | ||||
|   /* initialize stack array */ | ||||
|   L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); | ||||
|   L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; | ||||
|   L1->top = L1->stack; | ||||
|   L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; | ||||
|   /* initialize first ci */ | ||||
|   L1->ci->func = L1->top; | ||||
|   setnilvalue(L1->top++);  /* `function' entry for this `ci' */ | ||||
|   L1->base = L1->ci->base = L1->top; | ||||
|   L1->ci->top = L1->top + LUA_MINSTACK; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void freestack (lua_State *L, lua_State *L1) { | ||||
|   luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); | ||||
|   luaM_freearray(L, L1->stack, L1->stacksize, TValue); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** open parts that may cause memory-allocation errors | ||||
| */ | ||||
| static void f_luaopen (lua_State *L, void *ud) { | ||||
|   global_State *g = G(L); | ||||
|   UNUSED(ud); | ||||
|   stack_init(L, L);  /* init stack */ | ||||
|   sethvalue(L, gt(L), luaH_new(L, 0, 2));  /* table of globals */ | ||||
|   sethvalue(L, registry(L), luaH_new(L, 0, 2));  /* registry */ | ||||
|   luaS_resize(L, MINSTRTABSIZE);  /* initial size of string table */ | ||||
|   luaT_init(L); | ||||
|   luaX_init(L); | ||||
|   luaS_fix(luaS_newliteral(L, MEMERRMSG)); | ||||
|   g->GCthreshold = 4*g->totalbytes; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void preinit_state (lua_State *L, global_State *g) { | ||||
|   G(L) = g; | ||||
|   L->stack = NULL; | ||||
|   L->stacksize = 0; | ||||
|   L->errorJmp = NULL; | ||||
|   L->hook = NULL; | ||||
|   L->hookmask = 0; | ||||
|   L->basehookcount = 0; | ||||
|   L->allowhook = 1; | ||||
|   resethookcount(L); | ||||
|   L->openupval = NULL; | ||||
|   L->size_ci = 0; | ||||
|   L->nCcalls = 0; | ||||
|   L->status = 0; | ||||
|   L->base_ci = L->ci = NULL; | ||||
|   L->savedpc = NULL; | ||||
|   L->errfunc = 0; | ||||
|   setnilvalue(gt(L)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void close_state (lua_State *L) { | ||||
|   global_State *g = G(L); | ||||
|   luaF_close(L, L->stack);  /* close all upvalues for this thread */ | ||||
|   luaC_freeall(L);  /* collect all objects */ | ||||
|   lua_assert(g->rootgc == obj2gco(L)); | ||||
|   lua_assert(g->strt.nuse == 0); | ||||
|   luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); | ||||
|   luaZ_freebuffer(L, &g->buff); | ||||
|   freestack(L, L); | ||||
|   lua_assert(g->totalbytes == sizeof(LG)); | ||||
|   (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| lua_State *luaE_newthread (lua_State *L) { | ||||
|   lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); | ||||
|   luaC_link(L, obj2gco(L1), LUA_TTHREAD); | ||||
|   preinit_state(L1, G(L)); | ||||
|   stack_init(L1, L);  /* init stack */ | ||||
|   setobj2n(L, gt(L1), gt(L));  /* share table of globals */ | ||||
|   L1->hookmask = L->hookmask; | ||||
|   L1->basehookcount = L->basehookcount; | ||||
|   L1->hook = L->hook; | ||||
|   resethookcount(L1); | ||||
|   lua_assert(iswhite(obj2gco(L1))); | ||||
|   return L1; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaE_freethread (lua_State *L, lua_State *L1) { | ||||
|   luaF_close(L1, L1->stack);  /* close all upvalues for this thread */ | ||||
|   lua_assert(L1->openupval == NULL); | ||||
|   luai_userstatefree(L1); | ||||
|   freestack(L, L1); | ||||
|   luaM_freemem(L, fromstate(L1), state_size(lua_State)); | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | ||||
|   int i; | ||||
|   lua_State *L; | ||||
|   global_State *g; | ||||
|   void *l = (*f)(ud, NULL, 0, state_size(LG)); | ||||
|   if (l == NULL) return NULL; | ||||
|   L = tostate(l); | ||||
|   g = &((LG *)L)->g; | ||||
|   L->next = NULL; | ||||
|   L->tt = LUA_TTHREAD; | ||||
|   g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); | ||||
|   L->marked = luaC_white(g); | ||||
|   set2bits(L->marked, FIXEDBIT, SFIXEDBIT); | ||||
|   preinit_state(L, g); | ||||
|   g->frealloc = f; | ||||
|   g->ud = ud; | ||||
|   g->mainthread = L; | ||||
|   g->uvhead.u.l.prev = &g->uvhead; | ||||
|   g->uvhead.u.l.next = &g->uvhead; | ||||
|   g->GCthreshold = 0;  /* mark it as unfinished state */ | ||||
|   g->strt.size = 0; | ||||
|   g->strt.nuse = 0; | ||||
|   g->strt.hash = NULL; | ||||
|   setnilvalue(registry(L)); | ||||
|   luaZ_initbuffer(L, &g->buff); | ||||
|   g->panic = NULL; | ||||
|   g->gcstate = GCSpause; | ||||
|   g->rootgc = obj2gco(L); | ||||
|   g->sweepstrgc = 0; | ||||
|   g->sweepgc = &g->rootgc; | ||||
|   g->gray = NULL; | ||||
|   g->grayagain = NULL; | ||||
|   g->weak = NULL; | ||||
|   g->tmudata = NULL; | ||||
|   g->totalbytes = sizeof(LG); | ||||
|   g->gcpause = LUAI_GCPAUSE; | ||||
|   g->gcstepmul = LUAI_GCMUL; | ||||
|   g->gcdept = 0; | ||||
|   for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL; | ||||
|   if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { | ||||
|     /* memory allocation error: free partial state */ | ||||
|     close_state(L); | ||||
|     L = NULL; | ||||
|   } | ||||
|   else | ||||
|     luai_userstateopen(L); | ||||
|   return L; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void callallgcTM (lua_State *L, void *ud) { | ||||
|   UNUSED(ud); | ||||
|   luaC_callGCTM(L);  /* call GC metamethods for all udata */ | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API void lua_close (lua_State *L) { | ||||
|   L = G(L)->mainthread;  /* only the main thread can be closed */ | ||||
|   lua_lock(L); | ||||
|   luaF_close(L, L->stack);  /* close all upvalues for this thread */ | ||||
|   luaC_separateudata(L, 1);  /* separate udata that have GC metamethods */ | ||||
|   L->errfunc = 0;  /* no error function during GC metamethods */ | ||||
|   do {  /* repeat until no more errors */ | ||||
|     L->ci = L->base_ci; | ||||
|     L->base = L->top = L->ci->base; | ||||
|     L->nCcalls = 0; | ||||
|   } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); | ||||
|   lua_assert(G(L)->tmudata == NULL); | ||||
|   luai_userstateclose(L); | ||||
|   close_state(L); | ||||
| } | ||||
|  | ||||
							
								
								
									
										140
									
								
								lua/src/lstring.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								lua/src/lstring.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | ||||
| /* | ||||
| ** $Id: lstring.c,v 2.8 2005/12/22 16:19:56 roberto Exp $ | ||||
| ** String table (keeps all strings handled by Lua) | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
|  | ||||
| #include <string.h> | ||||
|  | ||||
| #define lstring_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| void luaS_resize (lua_State *L, int newsize) { | ||||
|   GCObject **newhash; | ||||
|   stringtable *tb; | ||||
|   int i; | ||||
|   if (G(L)->gcstate == GCSsweepstring) | ||||
|     return;  /* cannot resize during GC traverse */ | ||||
|   newhash = luaM_newvector(L, newsize, GCObject *); | ||||
|   tb = &G(L)->strt; | ||||
|   for (i=0; i<newsize; i++) newhash[i] = NULL; | ||||
|   /* rehash */ | ||||
|   for (i=0; i<tb->size; i++) { | ||||
|     GCObject *p = tb->hash[i]; | ||||
|     while (p) {  /* for each node in the list */ | ||||
|       GCObject *next = p->gch.next;  /* save next */ | ||||
|       unsigned int h = gco2ts(p)->hash; | ||||
|       int h1 = lmod(h, newsize);  /* new position */ | ||||
|       lua_assert(cast_int(h%newsize) == lmod(h, newsize)); | ||||
|       p->gch.next = newhash[h1];  /* chain it */ | ||||
|       newhash[h1] = p; | ||||
|       p = next; | ||||
|     } | ||||
|   } | ||||
|   luaM_freearray(L, tb->hash, tb->size, TString *); | ||||
|   tb->size = newsize; | ||||
|   tb->hash = newhash; | ||||
| } | ||||
|  | ||||
|  | ||||
| static TString *newlstr (lua_State *L, const char *str, size_t l, | ||||
|                                        unsigned int h) { | ||||
|   TString *ts; | ||||
|   stringtable *tb; | ||||
|   if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) | ||||
|     luaM_toobig(L); | ||||
|   ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); | ||||
|   ts->tsv.len = l; | ||||
|   ts->tsv.hash = h; | ||||
|   ts->tsv.marked = luaC_white(G(L)); | ||||
|   ts->tsv.tt = LUA_TSTRING; | ||||
|   ts->tsv.reserved = 0; | ||||
|   memcpy(ts+1, str, l*sizeof(char)); | ||||
|   ((char *)(ts+1))[l] = '\0';  /* ending 0 */ | ||||
|   tb = &G(L)->strt; | ||||
|   h = lmod(h, tb->size); | ||||
|   ts->tsv.next = tb->hash[h];  /* chain new entry */ | ||||
|   tb->hash[h] = obj2gco(ts); | ||||
|   tb->nuse++; | ||||
|   if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) | ||||
|     luaS_resize(L, tb->size*2);  /* too crowded */ | ||||
|   return ts; | ||||
| } | ||||
|  | ||||
|  | ||||
| static inline lua_Hash calchash(const char *str, size_t l) { | ||||
|   lua_Hash h = cast(unsigned int, l);  /* seed */ | ||||
|   size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */ | ||||
|   size_t l1; | ||||
|   for (l1=l; l1>=step; l1-=step) {  /* compute hash */ | ||||
|     h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); | ||||
|   } | ||||
|   return h; | ||||
| } | ||||
|  | ||||
|  | ||||
| LUA_API lua_Hash lua_calchash(const char *str, size_t l) { | ||||
|   return calchash(str, l); | ||||
| } | ||||
|  | ||||
|  | ||||
| TString *luaS_newhstr (lua_State *L, lua_Hash h, const char *str, size_t l) { | ||||
|   GCObject *o; | ||||
|   for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; | ||||
|        o != NULL; | ||||
|        o = o->gch.next) { | ||||
|     TString *ts = rawgco2ts(o); | ||||
|     if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { | ||||
|       /* string may be dead */ | ||||
|       if (isdead(G(L), o)) changewhite(o); | ||||
|       return ts; | ||||
|     } | ||||
|   } | ||||
|   return newlstr(L, str, l, h);  /* not found */ | ||||
| } | ||||
|  | ||||
|  | ||||
| TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { | ||||
|   GCObject *o; | ||||
|   const lua_Hash h = calchash(str, l); | ||||
|   for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; | ||||
|        o != NULL; | ||||
|        o = o->gch.next) { | ||||
|     TString *ts = rawgco2ts(o); | ||||
|     if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { | ||||
|       /* string may be dead */ | ||||
|       if (isdead(G(L), o)) changewhite(o); | ||||
|       return ts; | ||||
|     } | ||||
|   } | ||||
|   return newlstr(L, str, l, h);  /* not found */ | ||||
| } | ||||
|  | ||||
|  | ||||
| Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { | ||||
|   Udata *u; | ||||
|   if (s > MAX_SIZET - sizeof(Udata)) | ||||
|     luaM_toobig(L); | ||||
|   u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); | ||||
|   u->uv.marked = luaC_white(G(L));  /* is not finalized */ | ||||
|   u->uv.tt = LUA_TUSERDATA; | ||||
|   u->uv.len = s; | ||||
|   u->uv.metatable = NULL; | ||||
|   u->uv.env = e; | ||||
|   /* chain it on udata list (after main thread) */ | ||||
|   u->uv.next = G(L)->mainthread->next; | ||||
|   G(L)->mainthread->next = obj2gco(u); | ||||
|   return u; | ||||
| } | ||||
|  | ||||
							
								
								
									
										868
									
								
								lua/src/lstrlib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										868
									
								
								lua/src/lstrlib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,868 @@ | ||||
| /* | ||||
| ** $Id: lstrlib.c,v 1.132a 2006/04/26 20:41:19 roberto Exp $ | ||||
| ** Standard library for string operations and pattern-matching | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include <stddef.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define lstrlib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
| /* macro to `unsign' a character */ | ||||
| #define uchar(c)        ((unsigned char)(c)) | ||||
|  | ||||
|  | ||||
|  | ||||
| static int str_len (lua_State *L) { | ||||
|   size_t l; | ||||
|   luaL_checklstring(L, 1, &l); | ||||
|   lua_pushinteger(L, l); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { | ||||
|   /* relative string position: negative means back from end */ | ||||
|   return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_sub (lua_State *L) { | ||||
|   size_t l; | ||||
|   const char *s = luaL_checklstring(L, 1, &l); | ||||
|   ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); | ||||
|   ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); | ||||
|   if (start < 1) start = 1; | ||||
|   if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; | ||||
|   if (start <= end) | ||||
|     lua_pushlstring(L, s+start-1, end-start+1); | ||||
|   else lua_pushliteral(L, ""); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_reverse (lua_State *L) { | ||||
|   size_t l; | ||||
|   luaL_Buffer b; | ||||
|   const char *s = luaL_checklstring(L, 1, &l); | ||||
|   luaL_buffinit(L, &b); | ||||
|   while (l--) luaL_addchar(&b, s[l]); | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_lower (lua_State *L) { | ||||
|   size_t l; | ||||
|   size_t i; | ||||
|   luaL_Buffer b; | ||||
|   const char *s = luaL_checklstring(L, 1, &l); | ||||
|   luaL_buffinit(L, &b); | ||||
|   for (i=0; i<l; i++) | ||||
|     luaL_addchar(&b, tolower(uchar(s[i]))); | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_upper (lua_State *L) { | ||||
|   size_t l; | ||||
|   size_t i; | ||||
|   luaL_Buffer b; | ||||
|   const char *s = luaL_checklstring(L, 1, &l); | ||||
|   luaL_buffinit(L, &b); | ||||
|   for (i=0; i<l; i++) | ||||
|     luaL_addchar(&b, toupper(uchar(s[i]))); | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int str_rep (lua_State *L) { | ||||
|   size_t l; | ||||
|   luaL_Buffer b; | ||||
|   const char *s = luaL_checklstring(L, 1, &l); | ||||
|   int n = luaL_checkint(L, 2); | ||||
|   luaL_buffinit(L, &b); | ||||
|   while (n-- > 0) | ||||
|     luaL_addlstring(&b, s, l); | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_byte (lua_State *L) { | ||||
|   size_t l; | ||||
|   const char *s = luaL_checklstring(L, 1, &l); | ||||
|   ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); | ||||
|   ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); | ||||
|   int n, i; | ||||
|   if (posi <= 0) posi = 1; | ||||
|   if ((size_t)pose > l) pose = l; | ||||
|   if (posi > pose) return 0;  /* empty interval; return no values */ | ||||
|   n = (int)(pose -  posi + 1); | ||||
|   if (posi + n <= pose)  /* overflow? */ | ||||
|     luaL_error(L, "string slice too long"); | ||||
|   luaL_checkstack(L, n, "string slice too long"); | ||||
|   for (i=0; i<n; i++) | ||||
|     lua_pushinteger(L, uchar(s[posi+i-1])); | ||||
|   return n; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_char (lua_State *L) { | ||||
|   int n = lua_gettop(L);  /* number of arguments */ | ||||
|   int i; | ||||
|   luaL_Buffer b; | ||||
|   luaL_buffinit(L, &b); | ||||
|   for (i=1; i<=n; i++) { | ||||
|     int c = luaL_checkint(L, i); | ||||
|     luaL_argcheck(L, uchar(c) == c, i, "invalid value"); | ||||
|     luaL_addchar(&b, uchar(c)); | ||||
|   } | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int writer (lua_State *L, const void* b, size_t size, void* B) { | ||||
|   (void)L; | ||||
|   luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_dump (lua_State *L) { | ||||
|   luaL_Buffer b; | ||||
|   luaL_checktype(L, 1, LUA_TFUNCTION); | ||||
|   lua_settop(L, 1); | ||||
|   luaL_buffinit(L,&b); | ||||
|   if (lua_dump(L, writer, &b) != 0) | ||||
|     luaL_error(L, "unable to dump given function"); | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** PATTERN MATCHING | ||||
| ** ======================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
| #define CAP_UNFINISHED	(-1) | ||||
| #define CAP_POSITION	(-2) | ||||
|  | ||||
| typedef struct MatchState { | ||||
|   const char *src_init;  /* init of source string */ | ||||
|   const char *src_end;  /* end (`\0') of source string */ | ||||
|   lua_State *L; | ||||
|   int level;  /* total number of captures (finished or unfinished) */ | ||||
|   struct { | ||||
|     const char *init; | ||||
|     ptrdiff_t len; | ||||
|   } capture[LUA_MAXCAPTURES]; | ||||
| } MatchState; | ||||
|  | ||||
|  | ||||
| #define L_ESC		'%' | ||||
| #define SPECIALS	"^$*+?.([%-" | ||||
|  | ||||
|  | ||||
| static int check_capture (MatchState *ms, int l) { | ||||
|   l -= '1'; | ||||
|   if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) | ||||
|     return luaL_error(ms->L, "invalid capture index"); | ||||
|   return l; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int capture_to_close (MatchState *ms) { | ||||
|   int level = ms->level; | ||||
|   for (level--; level>=0; level--) | ||||
|     if (ms->capture[level].len == CAP_UNFINISHED) return level; | ||||
|   return luaL_error(ms->L, "invalid pattern capture"); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *classend (MatchState *ms, const char *p) { | ||||
|   switch (*p++) { | ||||
|     case L_ESC: { | ||||
|       if (*p == '\0') | ||||
|         luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); | ||||
|       return p+1; | ||||
|     } | ||||
|     case '[': { | ||||
|       if (*p == '^') p++; | ||||
|       do {  /* look for a `]' */ | ||||
|         if (*p == '\0') | ||||
|           luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); | ||||
|         if (*(p++) == L_ESC && *p != '\0') | ||||
|           p++;  /* skip escapes (e.g. `%]') */ | ||||
|       } while (*p != ']'); | ||||
|       return p+1; | ||||
|     } | ||||
|     default: { | ||||
|       return p; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int match_class (int c, int cl) { | ||||
|   int res; | ||||
|   switch (tolower(cl)) { | ||||
|     case 'a' : res = isalpha(c); break; | ||||
|     case 'c' : res = iscntrl(c); break; | ||||
|     case 'd' : res = isdigit(c); break; | ||||
|     case 'l' : res = islower(c); break; | ||||
|     case 'p' : res = ispunct(c); break; | ||||
|     case 's' : res = isspace(c); break; | ||||
|     case 'u' : res = isupper(c); break; | ||||
|     case 'w' : res = isalnum(c); break; | ||||
|     case 'x' : res = isxdigit(c); break; | ||||
|     case 'z' : res = (c == 0); break; | ||||
|     default: return (cl == c); | ||||
|   } | ||||
|   return (islower(cl) ? res : !res); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int matchbracketclass (int c, const char *p, const char *ec) { | ||||
|   int sig = 1; | ||||
|   if (*(p+1) == '^') { | ||||
|     sig = 0; | ||||
|     p++;  /* skip the `^' */ | ||||
|   } | ||||
|   while (++p < ec) { | ||||
|     if (*p == L_ESC) { | ||||
|       p++; | ||||
|       if (match_class(c, uchar(*p))) | ||||
|         return sig; | ||||
|     } | ||||
|     else if ((*(p+1) == '-') && (p+2 < ec)) { | ||||
|       p+=2; | ||||
|       if (uchar(*(p-2)) <= c && c <= uchar(*p)) | ||||
|         return sig; | ||||
|     } | ||||
|     else if (uchar(*p) == c) return sig; | ||||
|   } | ||||
|   return !sig; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int singlematch (int c, const char *p, const char *ep) { | ||||
|   switch (*p) { | ||||
|     case '.': return 1;  /* matches any char */ | ||||
|     case L_ESC: return match_class(c, uchar(*(p+1))); | ||||
|     case '[': return matchbracketclass(c, p, ep-1); | ||||
|     default:  return (uchar(*p) == c); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *match (MatchState *ms, const char *s, const char *p); | ||||
|  | ||||
|  | ||||
| static const char *matchbalance (MatchState *ms, const char *s, | ||||
|                                    const char *p) { | ||||
|   if (*p == 0 || *(p+1) == 0) | ||||
|     luaL_error(ms->L, "unbalanced pattern"); | ||||
|   if (*s != *p) return NULL; | ||||
|   else { | ||||
|     int b = *p; | ||||
|     int e = *(p+1); | ||||
|     int cont = 1; | ||||
|     while (++s < ms->src_end) { | ||||
|       if (*s == e) { | ||||
|         if (--cont == 0) return s+1; | ||||
|       } | ||||
|       else if (*s == b) cont++; | ||||
|     } | ||||
|   } | ||||
|   return NULL;  /* string ends out of balance */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *max_expand (MatchState *ms, const char *s, | ||||
|                                  const char *p, const char *ep) { | ||||
|   ptrdiff_t i = 0;  /* counts maximum expand for item */ | ||||
|   while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) | ||||
|     i++; | ||||
|   /* keeps trying to match with the maximum repetitions */ | ||||
|   while (i>=0) { | ||||
|     const char *res = match(ms, (s+i), ep+1); | ||||
|     if (res) return res; | ||||
|     i--;  /* else didn't match; reduce 1 repetition to try again */ | ||||
|   } | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *min_expand (MatchState *ms, const char *s, | ||||
|                                  const char *p, const char *ep) { | ||||
|   for (;;) { | ||||
|     const char *res = match(ms, s, ep+1); | ||||
|     if (res != NULL) | ||||
|       return res; | ||||
|     else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) | ||||
|       s++;  /* try with one more repetition */ | ||||
|     else return NULL; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *start_capture (MatchState *ms, const char *s, | ||||
|                                     const char *p, int what) { | ||||
|   const char *res; | ||||
|   int level = ms->level; | ||||
|   if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); | ||||
|   ms->capture[level].init = s; | ||||
|   ms->capture[level].len = what; | ||||
|   ms->level = level+1; | ||||
|   if ((res=match(ms, s, p)) == NULL)  /* match failed? */ | ||||
|     ms->level--;  /* undo capture */ | ||||
|   return res; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *end_capture (MatchState *ms, const char *s, | ||||
|                                   const char *p) { | ||||
|   int l = capture_to_close(ms); | ||||
|   const char *res; | ||||
|   ms->capture[l].len = s - ms->capture[l].init;  /* close capture */ | ||||
|   if ((res = match(ms, s, p)) == NULL)  /* match failed? */ | ||||
|     ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */ | ||||
|   return res; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *match_capture (MatchState *ms, const char *s, int l) { | ||||
|   size_t len; | ||||
|   l = check_capture(ms, l); | ||||
|   len = ms->capture[l].len; | ||||
|   if ((size_t)(ms->src_end-s) >= len && | ||||
|       memcmp(ms->capture[l].init, s, len) == 0) | ||||
|     return s+len; | ||||
|   else return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *match (MatchState *ms, const char *s, const char *p) { | ||||
|   init: /* using goto's to optimize tail recursion */ | ||||
|   switch (*p) { | ||||
|     case '(': {  /* start capture */ | ||||
|       if (*(p+1) == ')')  /* position capture? */ | ||||
|         return start_capture(ms, s, p+2, CAP_POSITION); | ||||
|       else | ||||
|         return start_capture(ms, s, p+1, CAP_UNFINISHED); | ||||
|     } | ||||
|     case ')': {  /* end capture */ | ||||
|       return end_capture(ms, s, p+1); | ||||
|     } | ||||
|     case L_ESC: { | ||||
|       switch (*(p+1)) { | ||||
|         case 'b': {  /* balanced string? */ | ||||
|           s = matchbalance(ms, s, p+2); | ||||
|           if (s == NULL) return NULL; | ||||
|           p+=4; goto init;  /* else return match(ms, s, p+4); */ | ||||
|         } | ||||
|         case 'f': {  /* frontier? */ | ||||
|           const char *ep; char previous; | ||||
|           p += 2; | ||||
|           if (*p != '[') | ||||
|             luaL_error(ms->L, "missing " LUA_QL("[") " after " | ||||
|                                LUA_QL("%%f") " in pattern"); | ||||
|           ep = classend(ms, p);  /* points to what is next */ | ||||
|           previous = (s == ms->src_init) ? '\0' : *(s-1); | ||||
|           if (matchbracketclass(uchar(previous), p, ep-1) || | ||||
|              !matchbracketclass(uchar(*s), p, ep-1)) return NULL; | ||||
|           p=ep; goto init;  /* else return match(ms, s, ep); */ | ||||
|         } | ||||
|         default: { | ||||
|           if (isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */ | ||||
|             s = match_capture(ms, s, uchar(*(p+1))); | ||||
|             if (s == NULL) return NULL; | ||||
|             p+=2; goto init;  /* else return match(ms, s, p+2) */ | ||||
|           } | ||||
|           goto dflt;  /* case default */ | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     case '\0': {  /* end of pattern */ | ||||
|       return s;  /* match succeeded */ | ||||
|     } | ||||
|     case '$': { | ||||
|       if (*(p+1) == '\0')  /* is the `$' the last char in pattern? */ | ||||
|         return (s == ms->src_end) ? s : NULL;  /* check end of string */ | ||||
|       else goto dflt; | ||||
|     } | ||||
|     default: dflt: {  /* it is a pattern item */ | ||||
|       const char *ep = classend(ms, p);  /* points to what is next */ | ||||
|       int m = s<ms->src_end && singlematch(uchar(*s), p, ep); | ||||
|       switch (*ep) { | ||||
|         case '?': {  /* optional */ | ||||
|           const char *res; | ||||
|           if (m && ((res=match(ms, s+1, ep+1)) != NULL)) | ||||
|             return res; | ||||
|           p=ep+1; goto init;  /* else return match(ms, s, ep+1); */ | ||||
|         } | ||||
|         case '*': {  /* 0 or more repetitions */ | ||||
|           return max_expand(ms, s, p, ep); | ||||
|         } | ||||
|         case '+': {  /* 1 or more repetitions */ | ||||
|           return (m ? max_expand(ms, s+1, p, ep) : NULL); | ||||
|         } | ||||
|         case '-': {  /* 0 or more repetitions (minimum) */ | ||||
|           return min_expand(ms, s, p, ep); | ||||
|         } | ||||
|         default: { | ||||
|           if (!m) return NULL; | ||||
|           s++; p=ep; goto init;  /* else return match(ms, s+1, ep); */ | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static const char *lmemfind (const char *s1, size_t l1, | ||||
|                                const char *s2, size_t l2) { | ||||
|   if (l2 == 0) return s1;  /* empty strings are everywhere */ | ||||
|   else if (l2 > l1) return NULL;  /* avoids a negative `l1' */ | ||||
|   else { | ||||
|     const char *init;  /* to search for a `*s2' inside `s1' */ | ||||
|     l2--;  /* 1st char will be checked by `memchr' */ | ||||
|     l1 = l1-l2;  /* `s2' cannot be found after that */ | ||||
|     while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { | ||||
|       init++;   /* 1st char is already checked */ | ||||
|       if (memcmp(init, s2+1, l2) == 0) | ||||
|         return init-1; | ||||
|       else {  /* correct `l1' and `s1' to try again */ | ||||
|         l1 -= init-s1; | ||||
|         s1 = init; | ||||
|       } | ||||
|     } | ||||
|     return NULL;  /* not found */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void push_onecapture (MatchState *ms, int i, const char *s, | ||||
|                                                     const char *e) { | ||||
|   if (i >= ms->level) { | ||||
|     if (i == 0)  /* ms->level == 0, too */ | ||||
|       lua_pushlstring(ms->L, s, e - s);  /* add whole match */ | ||||
|     else | ||||
|       luaL_error(ms->L, "invalid capture index"); | ||||
|   } | ||||
|   else { | ||||
|     ptrdiff_t l = ms->capture[i].len; | ||||
|     if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); | ||||
|     if (l == CAP_POSITION) | ||||
|       lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); | ||||
|     else | ||||
|       lua_pushlstring(ms->L, ms->capture[i].init, l); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int push_captures (MatchState *ms, const char *s, const char *e) { | ||||
|   int i; | ||||
|   int nlevels = (ms->level == 0 && s) ? 1 : ms->level; | ||||
|   luaL_checkstack(ms->L, nlevels, "too many captures"); | ||||
|   for (i = 0; i < nlevels; i++) | ||||
|     push_onecapture(ms, i, s, e); | ||||
|   return nlevels;  /* number of strings pushed */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_find_aux (lua_State *L, int find) { | ||||
|   size_t l1, l2; | ||||
|   const char *s = luaL_checklstring(L, 1, &l1); | ||||
|   const char *p = luaL_checklstring(L, 2, &l2); | ||||
|   ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; | ||||
|   if (init < 0) init = 0; | ||||
|   else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; | ||||
|   if (find && (lua_toboolean(L, 4) ||  /* explicit request? */ | ||||
|       strpbrk(p, SPECIALS) == NULL)) {  /* or no special characters? */ | ||||
|     /* do a plain search */ | ||||
|     const char *s2 = lmemfind(s+init, l1-init, p, l2); | ||||
|     if (s2) { | ||||
|       lua_pushinteger(L, s2-s+1); | ||||
|       lua_pushinteger(L, s2-s+l2); | ||||
|       return 2; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     MatchState ms; | ||||
|     int anchor = (*p == '^') ? (p++, 1) : 0; | ||||
|     const char *s1=s+init; | ||||
|     ms.L = L; | ||||
|     ms.src_init = s; | ||||
|     ms.src_end = s+l1; | ||||
|     do { | ||||
|       const char *res; | ||||
|       ms.level = 0; | ||||
|       if ((res=match(&ms, s1, p)) != NULL) { | ||||
|         if (find) { | ||||
|           lua_pushinteger(L, s1-s+1);  /* start */ | ||||
|           lua_pushinteger(L, res-s);   /* end */ | ||||
|           return push_captures(&ms, NULL, 0) + 2; | ||||
|         } | ||||
|         else | ||||
|           return push_captures(&ms, s1, res); | ||||
|       } | ||||
|     } while (s1++ < ms.src_end && !anchor); | ||||
|   } | ||||
|   lua_pushnil(L);  /* not found */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_find (lua_State *L) { | ||||
|   return str_find_aux(L, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_match (lua_State *L) { | ||||
|   return str_find_aux(L, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int gmatch_aux (lua_State *L) { | ||||
|   MatchState ms; | ||||
|   size_t ls; | ||||
|   const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); | ||||
|   const char *p = lua_tostring(L, lua_upvalueindex(2)); | ||||
|   const char *src; | ||||
|   ms.L = L; | ||||
|   ms.src_init = s; | ||||
|   ms.src_end = s+ls; | ||||
|   for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); | ||||
|        src <= ms.src_end; | ||||
|        src++) { | ||||
|     const char *e; | ||||
|     ms.level = 0; | ||||
|     if ((e = match(&ms, src, p)) != NULL) { | ||||
|       lua_Integer newstart = e-s; | ||||
|       if (e == src) newstart++;  /* empty match? go at least one position */ | ||||
|       lua_pushinteger(L, newstart); | ||||
|       lua_replace(L, lua_upvalueindex(3)); | ||||
|       return push_captures(&ms, src, e); | ||||
|     } | ||||
|   } | ||||
|   return 0;  /* not found */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int gmatch (lua_State *L) { | ||||
|   luaL_checkstring(L, 1); | ||||
|   luaL_checkstring(L, 2); | ||||
|   lua_settop(L, 2); | ||||
|   lua_pushinteger(L, 0); | ||||
|   lua_pushcclosure(L, gmatch_aux, 3); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int gfind_nodef (lua_State *L) { | ||||
|   return luaL_error(L, LUA_QL("string.gfind") " was renamed to " | ||||
|                        LUA_QL("string.gmatch")); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, | ||||
|                                                    const char *e) { | ||||
|   size_t l, i; | ||||
|   const char *news = lua_tolstring(ms->L, 3, &l); | ||||
|   for (i = 0; i < l; i++) { | ||||
|     if (news[i] != L_ESC) | ||||
|       luaL_addchar(b, news[i]); | ||||
|     else { | ||||
|       i++;  /* skip ESC */ | ||||
|       if (!isdigit(uchar(news[i]))) | ||||
|         luaL_addchar(b, news[i]); | ||||
|       else if (news[i] == '0') | ||||
|           luaL_addlstring(b, s, e - s); | ||||
|       else { | ||||
|         push_onecapture(ms, news[i] - '1', s, e); | ||||
|         luaL_addvalue(b);  /* add capture to accumulated result */ | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, | ||||
|                                                        const char *e) { | ||||
|   lua_State *L = ms->L; | ||||
|   switch (lua_type(L, 3)) { | ||||
|     case LUA_TNUMBER: | ||||
|     case LUA_TSTRING: { | ||||
|       add_s(ms, b, s, e); | ||||
|       return; | ||||
|     } | ||||
|     case LUA_TFUNCTION: { | ||||
|       int n; | ||||
|       lua_pushvalue(L, 3); | ||||
|       n = push_captures(ms, s, e); | ||||
|       lua_call(L, n, 1); | ||||
|       break; | ||||
|     } | ||||
|     case LUA_TTABLE: { | ||||
|       push_onecapture(ms, 0, s, e); | ||||
|       lua_gettable(L, 3); | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       luaL_argerror(L, 3, "string/function/table expected");  | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   if (!lua_toboolean(L, -1)) {  /* nil or false? */ | ||||
|     lua_pop(L, 1); | ||||
|     lua_pushlstring(L, s, e - s);  /* keep original text */ | ||||
|   } | ||||
|   else if (!lua_isstring(L, -1)) | ||||
|     luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));  | ||||
|   luaL_addvalue(b);  /* add result to accumulator */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_gsub (lua_State *L) { | ||||
|   size_t srcl; | ||||
|   const char *src = luaL_checklstring(L, 1, &srcl); | ||||
|   const char *p = luaL_checkstring(L, 2); | ||||
|   int max_s = luaL_optint(L, 4, srcl+1); | ||||
|   int anchor = (*p == '^') ? (p++, 1) : 0; | ||||
|   int n = 0; | ||||
|   MatchState ms; | ||||
|   luaL_Buffer b; | ||||
|   luaL_buffinit(L, &b); | ||||
|   ms.L = L; | ||||
|   ms.src_init = src; | ||||
|   ms.src_end = src+srcl; | ||||
|   while (n < max_s) { | ||||
|     const char *e; | ||||
|     ms.level = 0; | ||||
|     e = match(&ms, src, p); | ||||
|     if (e) { | ||||
|       n++; | ||||
|       add_value(&ms, &b, src, e); | ||||
|     } | ||||
|     if (e && e>src) /* non empty match? */ | ||||
|       src = e;  /* skip it */ | ||||
|     else if (src < ms.src_end) | ||||
|       luaL_addchar(&b, *src++); | ||||
|     else break; | ||||
|     if (anchor) break; | ||||
|   } | ||||
|   luaL_addlstring(&b, src, ms.src_end-src); | ||||
|   luaL_pushresult(&b); | ||||
|   lua_pushinteger(L, n);  /* number of substitutions */ | ||||
|   return 2; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ | ||||
| #define MAX_ITEM	512 | ||||
| /* valid flags in a format specification */ | ||||
| #define FLAGS	"-+ #0" | ||||
| /* | ||||
| ** maximum size of each format specification (such as '%-099.99d') | ||||
| ** (+10 accounts for %99.99x plus margin of error) | ||||
| */ | ||||
| #define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) | ||||
|  | ||||
|  | ||||
| static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { | ||||
|   size_t l; | ||||
|   const char *s = luaL_checklstring(L, arg, &l); | ||||
|   luaL_addchar(b, '"'); | ||||
|   while (l--) { | ||||
|     switch (*s) { | ||||
|       case '"': case '\\': case '\n': { | ||||
|         luaL_addchar(b, '\\'); | ||||
|         luaL_addchar(b, *s); | ||||
|         break; | ||||
|       } | ||||
|       case '\r': { | ||||
|         luaL_addlstring(b, "\\r", 2); | ||||
|         break; | ||||
|       } | ||||
|       case '\0': { | ||||
|         luaL_addlstring(b, "\\000", 4); | ||||
|         break; | ||||
|       } | ||||
|       default: { | ||||
|         luaL_addchar(b, *s); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     s++; | ||||
|   } | ||||
|   luaL_addchar(b, '"'); | ||||
| } | ||||
|  | ||||
| static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { | ||||
|   const char *p = strfrmt; | ||||
|   while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */ | ||||
|   if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) | ||||
|     luaL_error(L, "invalid format (repeated flags)"); | ||||
|   if (isdigit(uchar(*p))) p++;  /* skip width */ | ||||
|   if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */ | ||||
|   if (*p == '.') { | ||||
|     p++; | ||||
|     if (isdigit(uchar(*p))) p++;  /* skip precision */ | ||||
|     if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */ | ||||
|   } | ||||
|   if (isdigit(uchar(*p))) | ||||
|     luaL_error(L, "invalid format (width or precision too long)"); | ||||
|   *(form++) = '%'; | ||||
|   strncpy(form, strfrmt, p - strfrmt + 1); | ||||
|   form += p - strfrmt + 1; | ||||
|   *form = '\0'; | ||||
|   return p; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void addintlen (char *form) { | ||||
|   size_t l = strlen(form); | ||||
|   char spec = form[l - 1]; | ||||
|   strcpy(form + l - 1, LUA_INTFRMLEN); | ||||
|   form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; | ||||
|   form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int str_format (lua_State *L) { | ||||
|   int arg = 1; | ||||
|   size_t sfl; | ||||
|   const char *strfrmt = luaL_checklstring(L, arg, &sfl); | ||||
|   const char *strfrmt_end = strfrmt+sfl; | ||||
|   luaL_Buffer b; | ||||
|   luaL_buffinit(L, &b); | ||||
|   while (strfrmt < strfrmt_end) { | ||||
|     if (*strfrmt != L_ESC) | ||||
|       luaL_addchar(&b, *strfrmt++); | ||||
|     else if (*++strfrmt == L_ESC) | ||||
|       luaL_addchar(&b, *strfrmt++);  /* %% */ | ||||
|     else { /* format item */ | ||||
|       char form[MAX_FORMAT];  /* to store the format (`%...') */ | ||||
|       char buff[MAX_ITEM];  /* to store the formatted item */ | ||||
|       arg++; | ||||
|       strfrmt = scanformat(L, strfrmt, form); | ||||
|       switch (*strfrmt++) { | ||||
|         case 'c': { | ||||
|           sprintf(buff, form, (int)luaL_checknumber(L, arg)); | ||||
|           break; | ||||
|         } | ||||
|         case 'd':  case 'i': { | ||||
|           addintlen(form); | ||||
|           sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); | ||||
|           break; | ||||
|         } | ||||
|         case 'o':  case 'u':  case 'x':  case 'X': { | ||||
|           addintlen(form); | ||||
|           sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); | ||||
|           break; | ||||
|         } | ||||
|         case 'e':  case 'E': case 'f': | ||||
|         case 'g': case 'G': { | ||||
|           sprintf(buff, form, (double)luaL_checknumber(L, arg)); | ||||
|           break; | ||||
|         } | ||||
|         case 'q': { | ||||
|           addquoted(L, &b, arg); | ||||
|           continue;  /* skip the 'addsize' at the end */ | ||||
|         } | ||||
|         case 's': { | ||||
|           size_t l; | ||||
|           const char *s = luaL_checklstring(L, arg, &l); | ||||
|           if (!strchr(form, '.') && l >= 100) { | ||||
|             /* no precision and string is too long to be formatted; | ||||
|                keep original string */ | ||||
|             lua_pushvalue(L, arg); | ||||
|             luaL_addvalue(&b); | ||||
|             continue;  /* skip the `addsize' at the end */ | ||||
|           } | ||||
|           else { | ||||
|             sprintf(buff, form, s); | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|         default: {  /* also treat cases `pnLlh' */ | ||||
|           return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " | ||||
|                                LUA_QL("format"), *(strfrmt - 1)); | ||||
|         } | ||||
|       } | ||||
|       luaL_addlstring(&b, buff, strlen(buff)); | ||||
|     } | ||||
|   } | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const luaL_Reg strlib[] = { | ||||
|   {"byte", str_byte}, | ||||
|   {"char", str_char}, | ||||
|   {"dump", str_dump}, | ||||
|   {"find", str_find}, | ||||
|   {"format", str_format}, | ||||
|   {"gfind", gfind_nodef}, | ||||
|   {"gmatch", gmatch}, | ||||
|   {"gsub", str_gsub}, | ||||
|   {"len", str_len}, | ||||
|   {"lower", str_lower}, | ||||
|   {"match", str_match}, | ||||
|   {"rep", str_rep}, | ||||
|   {"reverse", str_reverse}, | ||||
|   {"sub", str_sub}, | ||||
|   {"upper", str_upper}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| static void createmetatable (lua_State *L) { | ||||
|   lua_createtable(L, 0, 1);  /* create metatable for strings */ | ||||
|   lua_pushliteral(L, "");  /* dummy string */ | ||||
|   lua_pushvalue(L, -2); | ||||
|   lua_setmetatable(L, -2);  /* set string metatable */ | ||||
|   lua_pop(L, 1);  /* pop dummy string */ | ||||
|   lua_pushvalue(L, -2);  /* string library... */ | ||||
|   lua_setfield(L, -2, "__index");  /* ...is the __index metamethod */ | ||||
|   lua_pop(L, 1);  /* pop metatable */ | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Open string library | ||||
| */ | ||||
| LUALIB_API int luaopen_string (lua_State *L) { | ||||
|   luaL_register(L, LUA_STRLIBNAME, strlib); | ||||
| #if defined(LUA_COMPAT_GFIND) | ||||
|   lua_getfield(L, -1, "gmatch"); | ||||
|   lua_setfield(L, -2, "gfind"); | ||||
| #endif | ||||
|   createmetatable(L); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
							
								
								
									
										588
									
								
								lua/src/ltable.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										588
									
								
								lua/src/ltable.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,588 @@ | ||||
| /* | ||||
| ** $Id: ltable.c,v 2.32 2006/01/18 11:49:02 roberto Exp $ | ||||
| ** Lua tables (hash) | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Implementation of tables (aka arrays, objects, or hash tables). | ||||
| ** Tables keep its elements in two parts: an array part and a hash part. | ||||
| ** Non-negative integer keys are all candidates to be kept in the array | ||||
| ** part. The actual size of the array is the largest `n' such that at | ||||
| ** least half the slots between 0 and n are in use. | ||||
| ** Hash uses a mix of chained scatter table with Brent's variation. | ||||
| ** A main invariant of these tables is that, if an element is not | ||||
| ** in its main position (i.e. the `original' position that its hash gives | ||||
| ** to it), then the colliding element is in its own main position. | ||||
| ** Hence even when the load factor reaches 100%, performance remains good. | ||||
| */ | ||||
| #include "stdafx.h" | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define ltable_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lgc.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
| #include "ltable.h" | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** max size of array part is 2^MAXBITS | ||||
| */ | ||||
| #if LUAI_BITSINT > 26 | ||||
| #define MAXBITS		26 | ||||
| #else | ||||
| #define MAXBITS		(LUAI_BITSINT-2) | ||||
| #endif | ||||
|  | ||||
| #define MAXASIZE	(1 << MAXBITS) | ||||
|  | ||||
|  | ||||
| #define hashpow2(t,n)      (gnode(t, lmod((n), sizenode(t)))) | ||||
|    | ||||
| #define hashstr(t,str)  hashpow2(t, (str)->tsv.hash) | ||||
| #define hashboolean(t,p)        hashpow2(t, p) | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** for some types, it is better to avoid modulus by power of 2, as | ||||
| ** they tend to have many 2 factors. | ||||
| */ | ||||
| #define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1)))) | ||||
|  | ||||
|  | ||||
| #define hashpointer(t,p)	hashmod(t, IntPoint(p)) | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** number of ints inside a lua_Number | ||||
| */ | ||||
| #define numints		cast_int(sizeof(lua_Number)/sizeof(int)) | ||||
|  | ||||
|  | ||||
|  | ||||
| #define dummynode		(&dummynode_) | ||||
|  | ||||
| static const Node dummynode_ = { | ||||
|   {{NULL}, LUA_TNIL},  /* value */ | ||||
|   {{{NULL}, LUA_TNIL, NULL}}  /* key */ | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** hash for lua_Numbers | ||||
| */ | ||||
| static Node *hashnum (const Table *t, lua_Number n) { | ||||
|   unsigned int a[numints]; | ||||
|   int i; | ||||
|   n += 1;  /* normalize number (avoid -0) */ | ||||
|   lua_assert(sizeof(a) <= sizeof(n)); | ||||
|   memcpy(a, &n, sizeof(a)); | ||||
|   for (i = 1; i < numints; i++) a[0] += a[i]; | ||||
|   return hashmod(t, a[0]); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** returns the `main' position of an element in a table (that is, the index | ||||
| ** of its hash value) | ||||
| */ | ||||
| static Node *mainposition (const Table *t, const TValue *key) { | ||||
|   switch (ttype(key)) { | ||||
|     case LUA_TNUMBER: | ||||
|       return hashnum(t, nvalue(key)); | ||||
|     case LUA_TSTRING: | ||||
|       return hashstr(t, rawtsvalue(key)); | ||||
|     case LUA_TBOOLEAN: | ||||
|       return hashboolean(t, bvalue(key)); | ||||
|     case LUA_TLIGHTUSERDATA: | ||||
|       return hashpointer(t, pvalue(key)); | ||||
|     default: | ||||
|       return hashpointer(t, gcvalue(key)); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** returns the index for `key' if `key' is an appropriate key to live in | ||||
| ** the array part of the table, -1 otherwise. | ||||
| */ | ||||
| static int arrayindex (const TValue *key) { | ||||
|   if (ttisnumber(key)) { | ||||
|     lua_Number n = nvalue(key); | ||||
|     int k; | ||||
|     lua_number2int(k, n); | ||||
|     if (luai_numeq(cast_num(k), n)) | ||||
|       return k; | ||||
|   } | ||||
|   return -1;  /* `key' did not match some condition */ | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** returns the index of a `key' for table traversals. First goes all | ||||
| ** elements in the array part, then elements in the hash part. The | ||||
| ** beginning of a traversal is signalled by -1. | ||||
| */ | ||||
| static int findindex (lua_State *L, Table *t, StkId key) { | ||||
|   int i; | ||||
|   if (ttisnil(key)) return -1;  /* first iteration */ | ||||
|   i = arrayindex(key); | ||||
|   if (0 < i && i <= t->sizearray)  /* is `key' inside array part? */ | ||||
|     return i-1;  /* yes; that's the index (corrected to C) */ | ||||
|   else { | ||||
|     Node *n = mainposition(t, key); | ||||
|     do {  /* check whether `key' is somewhere in the chain */ | ||||
|       /* key may be dead already, but it is ok to use it in `next' */ | ||||
|       if (luaO_rawequalObj(key2tval(n), key) || | ||||
|             (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && | ||||
|              gcvalue(gkey(n)) == gcvalue(key))) { | ||||
|         i = cast_int(n - gnode(t, 0));  /* key index in hash table */ | ||||
|         /* hash elements are numbered after array ones */ | ||||
|         return i + t->sizearray; | ||||
|       } | ||||
|       else n = gnext(n); | ||||
|     } while (n); | ||||
|     luaG_runerror(L, "invalid key to " LUA_QL("next"));  /* key not found */ | ||||
|     return 0;  /* to avoid warnings */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaH_next (lua_State *L, Table *t, StkId key) { | ||||
|   int i = findindex(L, t, key);  /* find original element */ | ||||
|   for (i++; i < t->sizearray; i++) {  /* try first array part */ | ||||
|     if (!ttisnil(&t->array[i])) {  /* a non-nil value? */ | ||||
|       setnvalue(key, cast_num(i+1)); | ||||
|       setobj2s(L, key+1, &t->array[i]); | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
|   for (i -= t->sizearray; i < sizenode(t); i++) {  /* then hash part */ | ||||
|     if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */ | ||||
|       setobj2s(L, key, key2tval(gnode(t, i))); | ||||
|       setobj2s(L, key+1, gval(gnode(t, i))); | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
|   return 0;  /* no more elements */ | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {============================================================= | ||||
| ** Rehash | ||||
| ** ============================================================== | ||||
| */ | ||||
|  | ||||
|  | ||||
| static int computesizes (int nums[], int *narray) { | ||||
|   int i; | ||||
|   int twotoi;  /* 2^i */ | ||||
|   int a = 0;  /* number of elements smaller than 2^i */ | ||||
|   int na = 0;  /* number of elements to go to array part */ | ||||
|   int n = 0;  /* optimal size for array part */ | ||||
|   for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { | ||||
|     if (nums[i] > 0) { | ||||
|       a += nums[i]; | ||||
|       if (a > twotoi/2) {  /* more than half elements present? */ | ||||
|         n = twotoi;  /* optimal size (till now) */ | ||||
|         na = a;  /* all elements smaller than n will go to array part */ | ||||
|       } | ||||
|     } | ||||
|     if (a == *narray) break;  /* all elements already counted */ | ||||
|   } | ||||
|   *narray = n; | ||||
|   lua_assert(*narray/2 <= na && na <= *narray); | ||||
|   return na; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int countint (const TValue *key, int *nums) { | ||||
|   int k = arrayindex(key); | ||||
|   if (0 < k && k <= MAXASIZE) {  /* is `key' an appropriate array index? */ | ||||
|     nums[ceillog2(k)]++;  /* count as such */ | ||||
|     return 1; | ||||
|   } | ||||
|   else | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int numusearray (const Table *t, int *nums) { | ||||
|   int lg; | ||||
|   int ttlg;  /* 2^lg */ | ||||
|   int ause = 0;  /* summation of `nums' */ | ||||
|   int i = 1;  /* count to traverse all array keys */ | ||||
|   for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) {  /* for each slice */ | ||||
|     int lc = 0;  /* counter */ | ||||
|     int lim = ttlg; | ||||
|     if (lim > t->sizearray) { | ||||
|       lim = t->sizearray;  /* adjust upper limit */ | ||||
|       if (i > lim) | ||||
|         break;  /* no more elements to count */ | ||||
|     } | ||||
|     /* count elements in range (2^(lg-1), 2^lg] */ | ||||
|     for (; i <= lim; i++) { | ||||
|       if (!ttisnil(&t->array[i-1])) | ||||
|         lc++; | ||||
|     } | ||||
|     nums[lg] += lc; | ||||
|     ause += lc; | ||||
|   } | ||||
|   return ause; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int numusehash (const Table *t, int *nums, int *pnasize) { | ||||
|   int totaluse = 0;  /* total number of elements */ | ||||
|   int ause = 0;  /* summation of `nums' */ | ||||
|   int i = sizenode(t); | ||||
|   while (i--) { | ||||
|     Node *n = &t->node[i]; | ||||
|     if (!ttisnil(gval(n))) { | ||||
|       ause += countint(key2tval(n), nums); | ||||
|       totaluse++; | ||||
|     } | ||||
|   } | ||||
|   *pnasize += ause; | ||||
|   return totaluse; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void setarrayvector (lua_State *L, Table *t, int size) { | ||||
|   int i; | ||||
|   luaM_reallocvector(L, t->array, t->sizearray, size, TValue); | ||||
|   for (i=t->sizearray; i<size; i++) | ||||
|      setnilvalue(&t->array[i]); | ||||
|   t->sizearray = size; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void setnodevector (lua_State *L, Table *t, int size) { | ||||
|   int lsize; | ||||
|   if (size == 0) {  /* no elements to hash part? */ | ||||
|     t->node = cast(Node *, dummynode);  /* use common `dummynode' */ | ||||
|     lsize = 0; | ||||
|   } | ||||
|   else { | ||||
|     int i; | ||||
|     lsize = ceillog2(size); | ||||
|     if (lsize > MAXBITS) | ||||
|       luaG_runerror(L, "table overflow"); | ||||
|     size = twoto(lsize); | ||||
|     t->node = luaM_newvector(L, size, Node); | ||||
|     for (i=0; i<size; i++) { | ||||
|       Node *n = gnode(t, i); | ||||
|       gnext(n) = NULL; | ||||
|       setnilvalue(gkey(n)); | ||||
|       setnilvalue(gval(n)); | ||||
|     } | ||||
|   } | ||||
|   t->lsizenode = cast_byte(lsize); | ||||
|   t->lastfree = gnode(t, size);  /* all positions are free */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static void resize (lua_State *L, Table *t, int nasize, int nhsize) { | ||||
|   int i; | ||||
|   int oldasize = t->sizearray; | ||||
|   int oldhsize = t->lsizenode; | ||||
|   Node *nold = t->node;  /* save old hash ... */ | ||||
|   if (nasize > oldasize)  /* array part must grow? */ | ||||
|     setarrayvector(L, t, nasize); | ||||
|   /* create new hash part with appropriate size */ | ||||
|   setnodevector(L, t, nhsize);   | ||||
|   if (nasize < oldasize) {  /* array part must shrink? */ | ||||
|     t->sizearray = nasize; | ||||
|     /* re-insert elements from vanishing slice */ | ||||
|     for (i=nasize; i<oldasize; i++) { | ||||
|       if (!ttisnil(&t->array[i])) | ||||
|         setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); | ||||
|     } | ||||
|     /* shrink array */ | ||||
|     luaM_reallocvector(L, t->array, oldasize, nasize, TValue); | ||||
|   } | ||||
|   /* re-insert elements from hash part */ | ||||
|   for (i = twoto(oldhsize) - 1; i >= 0; i--) { | ||||
|     Node *old = nold+i; | ||||
|     if (!ttisnil(gval(old))) | ||||
|       setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); | ||||
|   } | ||||
|   if (nold != dummynode) | ||||
|     luaM_freearray(L, nold, twoto(oldhsize), Node);  /* free old array */ | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaH_resizearray (lua_State *L, Table *t, int nasize) { | ||||
|   int nsize = (t->node == dummynode) ? 0 : sizenode(t); | ||||
|   resize(L, t, nasize, nsize); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void rehash (lua_State *L, Table *t, const TValue *ek) { | ||||
|   int nasize, na; | ||||
|   int nums[MAXBITS+1];  /* nums[i] = number of keys between 2^(i-1) and 2^i */ | ||||
|   int i; | ||||
|   int totaluse; | ||||
|   for (i=0; i<=MAXBITS; i++) nums[i] = 0;  /* reset counts */ | ||||
|   nasize = numusearray(t, nums);  /* count keys in array part */ | ||||
|   totaluse = nasize;  /* all those keys are integer keys */ | ||||
|   totaluse += numusehash(t, nums, &nasize);  /* count keys in hash part */ | ||||
|   /* count extra key */ | ||||
|   nasize += countint(ek, nums); | ||||
|   totaluse++; | ||||
|   /* compute new size for array part */ | ||||
|   na = computesizes(nums, &nasize); | ||||
|   /* resize the table to new computed sizes */ | ||||
|   resize(L, t, nasize, totaluse - na); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** }============================================================= | ||||
| */ | ||||
|  | ||||
|  | ||||
| Table *luaH_new (lua_State *L, int narray, int nhash) { | ||||
|   Table *t = luaM_new(L, Table); | ||||
|   luaC_link(L, obj2gco(t), LUA_TTABLE); | ||||
|   t->metatable = NULL; | ||||
|   t->flags = cast_byte(~0); | ||||
|   /* temporary values (kept only if some malloc fails) */ | ||||
|   t->array = NULL; | ||||
|   t->sizearray = 0; | ||||
|   t->lsizenode = 0; | ||||
|   t->node = cast(Node *, dummynode); | ||||
|   setarrayvector(L, t, narray); | ||||
|   setnodevector(L, t, nhash); | ||||
|   return t; | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaH_free (lua_State *L, Table *t) { | ||||
|   if (t->node != dummynode) | ||||
|     luaM_freearray(L, t->node, sizenode(t), Node); | ||||
|   luaM_freearray(L, t->array, t->sizearray, TValue); | ||||
|   luaM_free(L, t); | ||||
| } | ||||
|  | ||||
|  | ||||
| static Node *getfreepos (Table *t) { | ||||
|   while (t->lastfree-- > t->node) { | ||||
|     if (ttisnil(gkey(t->lastfree))) | ||||
|       return t->lastfree; | ||||
|   } | ||||
|   return NULL;  /* could not find a free place */ | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** inserts a new key into a hash table; first, check whether key's main  | ||||
| ** position is free. If not, check whether colliding node is in its main  | ||||
| ** position or not: if it is not, move colliding node to an empty place and  | ||||
| ** put new key in its main position; otherwise (colliding node is in its main  | ||||
| ** position), new key goes to an empty position.  | ||||
| */ | ||||
| static TValue *newkey (lua_State *L, Table *t, const TValue *key) { | ||||
|   Node *mp = mainposition(t, key); | ||||
|   if (!ttisnil(gval(mp)) || mp == dummynode) { | ||||
|     Node *othern; | ||||
|     Node *n = getfreepos(t);  /* get a free place */ | ||||
|     if (n == NULL) {  /* cannot find a free place? */ | ||||
|       rehash(L, t, key);  /* grow table */ | ||||
|       return luaH_set(L, t, key);  /* re-insert key into grown table */ | ||||
|     } | ||||
|     lua_assert(n != dummynode); | ||||
|     othern = mainposition(t, key2tval(mp)); | ||||
|     if (othern != mp) {  /* is colliding node out of its main position? */ | ||||
|       /* yes; move colliding node into free position */ | ||||
|       while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */ | ||||
|       gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */ | ||||
|       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */ | ||||
|       gnext(mp) = NULL;  /* now `mp' is free */ | ||||
|       setnilvalue(gval(mp)); | ||||
|     } | ||||
|     else {  /* colliding node is in its own main position */ | ||||
|       /* new node will go into free position */ | ||||
|       gnext(n) = gnext(mp);  /* chain new position */ | ||||
|       gnext(mp) = n; | ||||
|       mp = n; | ||||
|     } | ||||
|   } | ||||
|   gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; | ||||
|   luaC_barriert(L, t, key); | ||||
|   lua_assert(ttisnil(gval(mp))); | ||||
|   return gval(mp); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** search function for integers | ||||
| */ | ||||
| const TValue *luaH_getnum (Table *t, int key) { | ||||
|   /* (1 <= key && key <= t->sizearray) */ | ||||
|   if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) | ||||
|     return &t->array[key-1]; | ||||
|   else { | ||||
|     lua_Number nk = cast_num(key); | ||||
|     Node *n = hashnum(t, nk); | ||||
|     do {  /* check whether `key' is somewhere in the chain */ | ||||
|       if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) | ||||
|         return gval(n);  /* that's it */ | ||||
|       else n = gnext(n); | ||||
|     } while (n); | ||||
|     return luaO_nilobject; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** search function for strings | ||||
| */ | ||||
| const TValue *luaH_getstr (Table *t, TString *key) { | ||||
|   Node *n = hashstr(t, key); | ||||
|   do {  /* check whether `key' is somewhere in the chain */ | ||||
|     if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) | ||||
|       return gval(n);  /* that's it */ | ||||
|     else n = gnext(n); | ||||
|   } while (n); | ||||
|   return luaO_nilobject; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** main search function | ||||
| */ | ||||
| const TValue *luaH_get (Table *t, const TValue *key) { | ||||
|   switch (ttype(key)) { | ||||
|     case LUA_TNIL: return luaO_nilobject; | ||||
|     case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); | ||||
|     case LUA_TNUMBER: { | ||||
|       int k; | ||||
|       lua_Number n = nvalue(key); | ||||
|       lua_number2int(k, n); | ||||
|       if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ | ||||
|         return luaH_getnum(t, k);  /* use specialized version */ | ||||
|       /* else go through */ | ||||
|     } | ||||
|     default: { | ||||
|       Node *n = mainposition(t, key); | ||||
|       do {  /* check whether `key' is somewhere in the chain */ | ||||
|         if (luaO_rawequalObj(key2tval(n), key)) | ||||
|           return gval(n);  /* that's it */ | ||||
|         else n = gnext(n); | ||||
|       } while (n); | ||||
|       return luaO_nilobject; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { | ||||
|   const TValue *p = luaH_get(t, key); | ||||
|   t->flags = 0; | ||||
|   if (p != luaO_nilobject) | ||||
|     return cast(TValue *, p); | ||||
|   else { | ||||
|     if (ttisnil(key)) luaG_runerror(L, "table index is nil"); | ||||
|     else if (ttisnumber(key) && luai_numisnan(nvalue(key))) | ||||
|       luaG_runerror(L, "table index is NaN"); | ||||
|     return newkey(L, t, key); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| TValue *luaH_setnum (lua_State *L, Table *t, int key) { | ||||
|   const TValue *p = luaH_getnum(t, key); | ||||
|   if (p != luaO_nilobject) | ||||
|     return cast(TValue *, p); | ||||
|   else { | ||||
|     TValue k; | ||||
|     setnvalue(&k, cast_num(key)); | ||||
|     return newkey(L, t, &k); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { | ||||
|   const TValue *p = luaH_getstr(t, key); | ||||
|   if (p != luaO_nilobject) | ||||
|     return cast(TValue *, p); | ||||
|   else { | ||||
|     TValue k; | ||||
|     setsvalue(L, &k, key); | ||||
|     return newkey(L, t, &k); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int unbound_search (Table *t, unsigned int j) { | ||||
|   unsigned int i = j;  /* i is zero or a present index */ | ||||
|   j++; | ||||
|   /* find `i' and `j' such that i is present and j is not */ | ||||
|   while (!ttisnil(luaH_getnum(t, j))) { | ||||
|     i = j; | ||||
|     j *= 2; | ||||
|     if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */ | ||||
|       /* table was built with bad purposes: resort to linear search */ | ||||
|       i = 1; | ||||
|       while (!ttisnil(luaH_getnum(t, i))) i++; | ||||
|       return i - 1; | ||||
|     } | ||||
|   } | ||||
|   /* now do a binary search between them */ | ||||
|   while (j - i > 1) { | ||||
|     unsigned int m = (i+j)/2; | ||||
|     if (ttisnil(luaH_getnum(t, m))) j = m; | ||||
|     else i = m; | ||||
|   } | ||||
|   return i; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** Try to find a boundary in table `t'. A `boundary' is an integer index | ||||
| ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). | ||||
| */ | ||||
| int luaH_getn (Table *t) { | ||||
|   unsigned int j = t->sizearray; | ||||
|   if (j > 0 && ttisnil(&t->array[j - 1])) { | ||||
|     /* there is a boundary in the array part: (binary) search for it */ | ||||
|     unsigned int i = 0; | ||||
|     while (j - i > 1) { | ||||
|       unsigned int m = (i+j)/2; | ||||
|       if (ttisnil(&t->array[m - 1])) j = m; | ||||
|       else i = m; | ||||
|     } | ||||
|     return i; | ||||
|   } | ||||
|   /* else must find a boundary in hash part */ | ||||
|   else if (t->node == dummynode)  /* hash part is empty? */ | ||||
|     return j;  /* that is easy... */ | ||||
|   else return unbound_search(t, j); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| #if defined(LUA_DEBUG) | ||||
|  | ||||
| Node *luaH_mainposition (const Table *t, const TValue *key) { | ||||
|   return mainposition(t, key); | ||||
| } | ||||
|  | ||||
| int luaH_isdummy (Node *n) { return n == dummynode; } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										278
									
								
								lua/src/ltablib.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								lua/src/ltablib.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,278 @@ | ||||
| /* | ||||
| ** $Id: ltablib.c,v 1.38 2005/10/23 17:38:15 roberto Exp $ | ||||
| ** Library for Table Manipulation | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
|  | ||||
| #include <stddef.h> | ||||
|  | ||||
| #define ltablib_c | ||||
| #define LUA_LIB | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
| #define aux_getn(L,n)	(luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) | ||||
|  | ||||
|  | ||||
| static int foreachi (lua_State *L) { | ||||
|   int i; | ||||
|   int n = aux_getn(L, 1); | ||||
|   luaL_checktype(L, 2, LUA_TFUNCTION); | ||||
|   for (i=1; i <= n; i++) { | ||||
|     lua_pushvalue(L, 2);  /* function */ | ||||
|     lua_pushinteger(L, i);  /* 1st argument */ | ||||
|     lua_rawgeti(L, 1, i);  /* 2nd argument */ | ||||
|     lua_call(L, 2, 1); | ||||
|     if (!lua_isnil(L, -1)) | ||||
|       return 1; | ||||
|     lua_pop(L, 1);  /* remove nil result */ | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int foreach (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   luaL_checktype(L, 2, LUA_TFUNCTION); | ||||
|   lua_pushnil(L);  /* first key */ | ||||
|   while (lua_next(L, 1)) { | ||||
|     lua_pushvalue(L, 2);  /* function */ | ||||
|     lua_pushvalue(L, -3);  /* key */ | ||||
|     lua_pushvalue(L, -3);  /* value */ | ||||
|     lua_call(L, 2, 1); | ||||
|     if (!lua_isnil(L, -1)) | ||||
|       return 1; | ||||
|     lua_pop(L, 2);  /* remove value and result */ | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int maxn (lua_State *L) { | ||||
|   lua_Number max = 0; | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   lua_pushnil(L);  /* first key */ | ||||
|   while (lua_next(L, 1)) { | ||||
|     lua_pop(L, 1);  /* remove value */ | ||||
|     if (lua_type(L, -1) == LUA_TNUMBER) { | ||||
|       lua_Number v = lua_tonumber(L, -1); | ||||
|       if (v > max) max = v; | ||||
|     } | ||||
|   } | ||||
|   lua_pushnumber(L, max); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int getn (lua_State *L) { | ||||
|   lua_pushinteger(L, aux_getn(L, 1)); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int setn (lua_State *L) { | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
| #ifndef luaL_setn | ||||
|   luaL_setn(L, 1, luaL_checkint(L, 2)); | ||||
| #else | ||||
|   luaL_error(L, LUA_QL("setn") " is obsolete"); | ||||
| #endif | ||||
|   lua_pushvalue(L, 1); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int tinsert (lua_State *L) { | ||||
|   int e = aux_getn(L, 1) + 1;  /* first empty element */ | ||||
|   int pos;  /* where to insert new element */ | ||||
|   switch (lua_gettop(L)) { | ||||
|     case 2: {  /* called with only 2 arguments */ | ||||
|       pos = e;  /* insert new element at the end */ | ||||
|       break; | ||||
|     } | ||||
|     case 3: { | ||||
|       int i; | ||||
|       pos = luaL_checkint(L, 2);  /* 2nd argument is the position */ | ||||
|       if (pos > e) e = pos;  /* `grow' array if necessary */ | ||||
|       for (i = e; i > pos; i--) {  /* move up elements */ | ||||
|         lua_rawgeti(L, 1, i-1); | ||||
|         lua_rawseti(L, 1, i);  /* t[i] = t[i-1] */ | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); | ||||
|     } | ||||
|   } | ||||
|   luaL_setn(L, 1, e);  /* new size */ | ||||
|   lua_rawseti(L, 1, pos);  /* t[pos] = v */ | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int tremove (lua_State *L) { | ||||
|   int e = aux_getn(L, 1); | ||||
|   int pos = luaL_optint(L, 2, e); | ||||
|   if (e == 0) return 0;  /* table is `empty' */ | ||||
|   luaL_setn(L, 1, e - 1);  /* t.n = n-1 */ | ||||
|   lua_rawgeti(L, 1, pos);  /* result = t[pos] */ | ||||
|   for ( ;pos<e; pos++) { | ||||
|     lua_rawgeti(L, 1, pos+1); | ||||
|     lua_rawseti(L, 1, pos);  /* t[pos] = t[pos+1] */ | ||||
|   } | ||||
|   lua_pushnil(L); | ||||
|   lua_rawseti(L, 1, e);  /* t[e] = nil */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int tconcat (lua_State *L) { | ||||
|   luaL_Buffer b; | ||||
|   size_t lsep; | ||||
|   int i, last; | ||||
|   const char *sep = luaL_optlstring(L, 2, "", &lsep); | ||||
|   luaL_checktype(L, 1, LUA_TTABLE); | ||||
|   i = luaL_optint(L, 3, 1); | ||||
|   last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1)); | ||||
|   luaL_buffinit(L, &b); | ||||
|   for (; i <= last; i++) { | ||||
|     lua_rawgeti(L, 1, i); | ||||
|     luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings"); | ||||
|     luaL_addvalue(&b); | ||||
|     if (i != last) | ||||
|       luaL_addlstring(&b, sep, lsep); | ||||
|   } | ||||
|   luaL_pushresult(&b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** {====================================================== | ||||
| ** Quicksort | ||||
| ** (based on `Algorithms in MODULA-3', Robert Sedgewick; | ||||
| **  Addison-Wesley, 1993.) | ||||
| */ | ||||
|  | ||||
|  | ||||
| static void set2 (lua_State *L, int i, int j) { | ||||
|   lua_rawseti(L, 1, i); | ||||
|   lua_rawseti(L, 1, j); | ||||
| } | ||||
|  | ||||
| static int sort_comp (lua_State *L, int a, int b) { | ||||
|   if (!lua_isnil(L, 2)) {  /* function? */ | ||||
|     int res; | ||||
|     lua_pushvalue(L, 2); | ||||
|     lua_pushvalue(L, a-1);  /* -1 to compensate function */ | ||||
|     lua_pushvalue(L, b-2);  /* -2 to compensate function and `a' */ | ||||
|     lua_call(L, 2, 1); | ||||
|     res = lua_toboolean(L, -1); | ||||
|     lua_pop(L, 1); | ||||
|     return res; | ||||
|   } | ||||
|   else  /* a < b? */ | ||||
|     return lua_lessthan(L, a, b); | ||||
| } | ||||
|  | ||||
| static void auxsort (lua_State *L, int l, int u) { | ||||
|   while (l < u) {  /* for tail recursion */ | ||||
|     int i, j; | ||||
|     /* sort elements a[l], a[(l+u)/2] and a[u] */ | ||||
|     lua_rawgeti(L, 1, l); | ||||
|     lua_rawgeti(L, 1, u); | ||||
|     if (sort_comp(L, -1, -2))  /* a[u] < a[l]? */ | ||||
|       set2(L, l, u);  /* swap a[l] - a[u] */ | ||||
|     else | ||||
|       lua_pop(L, 2); | ||||
|     if (u-l == 1) break;  /* only 2 elements */ | ||||
|     i = (l+u)/2; | ||||
|     lua_rawgeti(L, 1, i); | ||||
|     lua_rawgeti(L, 1, l); | ||||
|     if (sort_comp(L, -2, -1))  /* a[i]<a[l]? */ | ||||
|       set2(L, i, l); | ||||
|     else { | ||||
|       lua_pop(L, 1);  /* remove a[l] */ | ||||
|       lua_rawgeti(L, 1, u); | ||||
|       if (sort_comp(L, -1, -2))  /* a[u]<a[i]? */ | ||||
|         set2(L, i, u); | ||||
|       else | ||||
|         lua_pop(L, 2); | ||||
|     } | ||||
|     if (u-l == 2) break;  /* only 3 elements */ | ||||
|     lua_rawgeti(L, 1, i);  /* Pivot */ | ||||
|     lua_pushvalue(L, -1); | ||||
|     lua_rawgeti(L, 1, u-1); | ||||
|     set2(L, i, u-1); | ||||
|     /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ | ||||
|     i = l; j = u-1; | ||||
|     for (;;) {  /* invariant: a[l..i] <= P <= a[j..u] */ | ||||
|       /* repeat ++i until a[i] >= P */ | ||||
|       while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { | ||||
|         if (i>u) luaL_error(L, "invalid order function for sorting"); | ||||
|         lua_pop(L, 1);  /* remove a[i] */ | ||||
|       } | ||||
|       /* repeat --j until a[j] <= P */ | ||||
|       while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { | ||||
|         if (j<l) luaL_error(L, "invalid order function for sorting"); | ||||
|         lua_pop(L, 1);  /* remove a[j] */ | ||||
|       } | ||||
|       if (j<i) { | ||||
|         lua_pop(L, 3);  /* pop pivot, a[i], a[j] */ | ||||
|         break; | ||||
|       } | ||||
|       set2(L, i, j); | ||||
|     } | ||||
|     lua_rawgeti(L, 1, u-1); | ||||
|     lua_rawgeti(L, 1, i); | ||||
|     set2(L, u-1, i);  /* swap pivot (a[u-1]) with a[i] */ | ||||
|     /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ | ||||
|     /* adjust so that smaller half is in [j..i] and larger one in [l..u] */ | ||||
|     if (i-l < u-i) { | ||||
|       j=l; i=i-1; l=i+2; | ||||
|     } | ||||
|     else { | ||||
|       j=i+1; i=u; u=j-2; | ||||
|     } | ||||
|     auxsort(L, j, i);  /* call recursively the smaller one */ | ||||
|   }  /* repeat the routine for the larger one */ | ||||
| } | ||||
|  | ||||
| static int sort (lua_State *L) { | ||||
|   int n = aux_getn(L, 1); | ||||
|   luaL_checkstack(L, 40, "");  /* assume array is smaller than 2^40 */ | ||||
|   if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */ | ||||
|     luaL_checktype(L, 2, LUA_TFUNCTION); | ||||
|   lua_settop(L, 2);  /* make sure there is two arguments */ | ||||
|   auxsort(L, 1, n); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* }====================================================== */ | ||||
|  | ||||
|  | ||||
| static const luaL_Reg tab_funcs[] = { | ||||
|   {"concat", tconcat}, | ||||
|   {"foreach", foreach}, | ||||
|   {"foreachi", foreachi}, | ||||
|   {"getn", getn}, | ||||
|   {"maxn", maxn}, | ||||
|   {"insert", tinsert}, | ||||
|   {"remove", tremove}, | ||||
|   {"setn", setn}, | ||||
|   {"sort", sort}, | ||||
|   {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|  | ||||
| LUALIB_API int luaopen_table (lua_State *L) { | ||||
|   luaL_register(L, LUA_TABLIBNAME, tab_funcs); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
							
								
								
									
										75
									
								
								lua/src/ltm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								lua/src/ltm.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| /* | ||||
| ** $Id: ltm.c,v 2.8 2006/01/10 12:50:00 roberto Exp $ | ||||
| ** Tag methods | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <string.h> | ||||
|  | ||||
| #define ltm_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lobject.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "ltable.h" | ||||
| #include "ltm.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| const char *const luaT_typenames[] = { | ||||
|   "nil", "boolean", "userdata", "number", | ||||
|   "string", "table", "function", "userdata", "thread", | ||||
|   "proto", "upval" | ||||
| }; | ||||
|  | ||||
|  | ||||
| void luaT_init (lua_State *L) { | ||||
|   static const char *const luaT_eventname[] = {  /* ORDER TM */ | ||||
|     "__index", "__newindex", | ||||
|     "__gc", "__mode", "__eq", | ||||
|     "__add", "__sub", "__mul", "__div", "__mod", | ||||
|     "__pow", "__unm", "__len", "__lt", "__le", | ||||
|     "__concat", "__call" | ||||
|   }; | ||||
|   int i; | ||||
|   for (i=0; i<TM_N; i++) { | ||||
|     G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]); | ||||
|     luaS_fix(G(L)->tmname[i]);  /* never collect these names */ | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** function to be used with macro "fasttm": optimized for absence of | ||||
| ** tag methods | ||||
| */ | ||||
| const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { | ||||
|   const TValue *tm = luaH_getstr(events, ename); | ||||
|   lua_assert(event <= TM_EQ); | ||||
|   if (ttisnil(tm)) {  /* no tag method? */ | ||||
|     events->flags |= cast_byte(1u<<event);  /* cache this fact */ | ||||
|     return NULL; | ||||
|   } | ||||
|   else return tm; | ||||
| } | ||||
|  | ||||
|  | ||||
| const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { | ||||
|   Table *mt; | ||||
|   switch (ttype(o)) { | ||||
|     case LUA_TTABLE: | ||||
|       mt = hvalue(o)->metatable; | ||||
|       break; | ||||
|     case LUA_TUSERDATA: | ||||
|       mt = uvalue(o)->metatable; | ||||
|       break; | ||||
|     default: | ||||
|       mt = G(L)->mt[ttype(o)]; | ||||
|   } | ||||
|   return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); | ||||
| } | ||||
|  | ||||
							
								
								
									
										390
									
								
								lua/src/lua.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								lua/src/lua.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,390 @@ | ||||
| /* | ||||
| ** $Id: lua.c,v 1.160 2006/06/02 15:34:00 roberto Exp $ | ||||
| ** Lua stand-alone interpreter | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
|  | ||||
| #include <signal.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define lua_c | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "lauxlib.h" | ||||
| #include "lualib.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| static lua_State *globalL = NULL; | ||||
|  | ||||
| static const char *progname = LUA_PROGNAME; | ||||
|  | ||||
|  | ||||
|  | ||||
| static void lstop (lua_State *L, lua_Debug *ar) { | ||||
|   (void)ar;  /* unused arg. */ | ||||
|   lua_sethook(L, NULL, 0, 0); | ||||
|   luaL_error(L, "interrupted!"); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void laction (int i) { | ||||
|   signal(i, SIG_DFL); /* if another SIGINT happens before lstop, | ||||
|                               terminate process (default action) */ | ||||
|   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void print_usage (void) { | ||||
|   fprintf(stderr, | ||||
|   "usage: %s [options] [script [args]].\n" | ||||
|   "Available options are:\n" | ||||
|   "  -e stat  execute string " LUA_QL("stat") "\n" | ||||
|   "  -l name  require library " LUA_QL("name") "\n" | ||||
|   "  -i       enter interactive mode after executing " LUA_QL("script") "\n" | ||||
|   "  -v       show version information\n" | ||||
|   "  --       stop handling options\n" | ||||
|   "  -        execute stdin and stop handling options\n" | ||||
|   , | ||||
|   progname); | ||||
|   fflush(stderr); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void l_message (const char *pname, const char *msg) { | ||||
|   if (pname) fprintf(stderr, "%s: ", pname); | ||||
|   fprintf(stderr, "%s\n", msg); | ||||
|   fflush(stderr); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int report (lua_State *L, int status) { | ||||
|   if (status && !lua_isnil(L, -1)) { | ||||
|     const char *msg = lua_tostring(L, -1); | ||||
|     if (msg == NULL) msg = "(error object is not a string)"; | ||||
|     l_message(progname, msg); | ||||
|     lua_pop(L, 1); | ||||
|   } | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int traceback (lua_State *L) { | ||||
|   lua_getfield(L, LUA_GLOBALSINDEX, "debug"); | ||||
|   if (!lua_istable(L, -1)) { | ||||
|     lua_pop(L, 1); | ||||
|     return 1; | ||||
|   } | ||||
|   lua_getfield(L, -1, "traceback"); | ||||
|   if (!lua_isfunction(L, -1)) { | ||||
|     lua_pop(L, 2); | ||||
|     return 1; | ||||
|   } | ||||
|   lua_pushvalue(L, 1);  /* pass error message */ | ||||
|   lua_pushinteger(L, 2);  /* skip this function and traceback */ | ||||
|   lua_call(L, 2, 1);  /* call debug.traceback */ | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int docall (lua_State *L, int narg, int clear) { | ||||
|   int status; | ||||
|   int base = lua_gettop(L) - narg;  /* function index */ | ||||
|   lua_pushcfunction(L, traceback);  /* push traceback function */ | ||||
|   lua_insert(L, base);  /* put it under chunk and args */ | ||||
|   signal(SIGINT, laction); | ||||
|   status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); | ||||
|   signal(SIGINT, SIG_DFL); | ||||
|   lua_remove(L, base);  /* remove traceback function */ | ||||
|   /* force a complete garbage collection in case of errors */ | ||||
|   if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void print_version (void) { | ||||
|   l_message(NULL, LUA_RELEASE "  " LUA_COPYRIGHT); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int getargs (lua_State *L, char **argv, int n) { | ||||
|   int narg; | ||||
|   int i; | ||||
|   int argc = 0; | ||||
|   while (argv[argc]) argc++;  /* count total number of arguments */ | ||||
|   narg = argc - (n + 1);  /* number of arguments to the script */ | ||||
|   luaL_checkstack(L, narg + 3, "too many arguments to script"); | ||||
|   for (i=n+1; i < argc; i++) | ||||
|     lua_pushstring(L, argv[i]); | ||||
|   lua_createtable(L, narg, n + 1); | ||||
|   for (i=0; i < argc; i++) { | ||||
|     lua_pushstring(L, argv[i]); | ||||
|     lua_rawseti(L, -2, i - n); | ||||
|   } | ||||
|   return narg; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int dofile (lua_State *L, const char *name) { | ||||
|   int status = luaL_loadfile(L, name) || docall(L, 0, 1); | ||||
|   return report(L, status); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int dostring (lua_State *L, const char *s, const char *name) { | ||||
|   int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); | ||||
|   return report(L, status); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int dolibrary (lua_State *L, const char *name) { | ||||
|   lua_getglobal(L, "require"); | ||||
|   lua_pushstring(L, name); | ||||
|   return report(L, lua_pcall(L, 1, 0, 0)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *get_prompt (lua_State *L, int firstline) { | ||||
|   const char *p; | ||||
|   lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); | ||||
|   p = lua_tostring(L, -1); | ||||
|   if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); | ||||
|   lua_pop(L, 1);  /* remove global */ | ||||
|   return p; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int incomplete (lua_State *L, int status) { | ||||
|   if (status == LUA_ERRSYNTAX) { | ||||
|     size_t lmsg; | ||||
|     const char *msg = lua_tolstring(L, -1, &lmsg); | ||||
|     const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); | ||||
|     if (strstr(msg, LUA_QL("<eof>")) == tp) { | ||||
|       lua_pop(L, 1); | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
|   return 0;  /* else... */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static int pushline (lua_State *L, int firstline) { | ||||
|   char buffer[LUA_MAXINPUT]; | ||||
|   char *b = buffer; | ||||
|   size_t l; | ||||
|   const char *prmt = get_prompt(L, firstline); | ||||
|   if (lua_readline(L, b, prmt) == 0) | ||||
|     return 0;  /* no input */ | ||||
|   l = strlen(b); | ||||
|   if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */ | ||||
|     b[l-1] = '\0';  /* remove it */ | ||||
|   if (firstline && b[0] == '=')  /* first line starts with `=' ? */ | ||||
|     lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */ | ||||
|   else | ||||
|     lua_pushstring(L, b); | ||||
|   lua_freeline(L, b); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int loadline (lua_State *L) { | ||||
|   int status; | ||||
|   lua_settop(L, 0); | ||||
|   if (!pushline(L, 1)) | ||||
|     return -1;  /* no input */ | ||||
|   for (;;) {  /* repeat until gets a complete line */ | ||||
|     status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); | ||||
|     if (!incomplete(L, status)) break;  /* cannot try to add lines? */ | ||||
|     if (!pushline(L, 0))  /* no more input? */ | ||||
|       return -1; | ||||
|     lua_pushliteral(L, "\n");  /* add a new line... */ | ||||
|     lua_insert(L, -2);  /* ...between the two lines */ | ||||
|     lua_concat(L, 3);  /* join them */ | ||||
|   } | ||||
|   lua_saveline(L, 1); | ||||
|   lua_remove(L, 1);  /* remove line */ | ||||
|   return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void dotty (lua_State *L) { | ||||
|   int status; | ||||
|   const char *oldprogname = progname; | ||||
|   progname = NULL; | ||||
|   while ((status = loadline(L)) != -1) { | ||||
|     if (status == 0) status = docall(L, 0, 0); | ||||
|     report(L, status); | ||||
|     if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */ | ||||
|       lua_getglobal(L, "print"); | ||||
|       lua_insert(L, 1); | ||||
|       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) | ||||
|         l_message(progname, lua_pushfstring(L, | ||||
|                                "error calling " LUA_QL("print") " (%s)", | ||||
|                                lua_tostring(L, -1))); | ||||
|     } | ||||
|   } | ||||
|   lua_settop(L, 0);  /* clear stack */ | ||||
|   fputs("\n", stdout); | ||||
|   fflush(stdout); | ||||
|   progname = oldprogname; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int handle_script (lua_State *L, char **argv, int n) { | ||||
|   int status; | ||||
|   const char *fname; | ||||
|   int narg = getargs(L, argv, n);  /* collect arguments */ | ||||
|   lua_setglobal(L, "arg"); | ||||
|   fname = argv[n]; | ||||
|   if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)  | ||||
|     fname = NULL;  /* stdin */ | ||||
|   status = luaL_loadfile(L, fname); | ||||
|   lua_insert(L, -(narg+1)); | ||||
|   if (status == 0) | ||||
|     status = docall(L, narg, 0); | ||||
|   else | ||||
|     lua_pop(L, narg);       | ||||
|   return report(L, status); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* check that argument has no extra characters at the end */ | ||||
| #define notail(x)	{if ((x)[2] != '\0') return -1;} | ||||
|  | ||||
|  | ||||
| static int collectargs (char **argv, int *pi, int *pv, int *pe) { | ||||
|   int i; | ||||
|   for (i = 1; argv[i] != NULL; i++) { | ||||
|     if (argv[i][0] != '-')  /* not an option? */ | ||||
|         return i; | ||||
|     switch (argv[i][1]) {  /* option */ | ||||
|       case '-': | ||||
|         notail(argv[i]); | ||||
|         return (argv[i+1] != NULL ? i+1 : 0); | ||||
|       case '\0': | ||||
|         return i; | ||||
|       case 'i': | ||||
|         notail(argv[i]); | ||||
|         *pi = 1;  /* go through */ | ||||
|       case 'v': | ||||
|         notail(argv[i]); | ||||
|         *pv = 1; | ||||
|         break; | ||||
|       case 'e': | ||||
|         *pe = 1;  /* go through */ | ||||
|       case 'l': | ||||
|         if (argv[i][2] == '\0') { | ||||
|           i++; | ||||
|           if (argv[i] == NULL) return -1; | ||||
|         } | ||||
|         break; | ||||
|       default: return -1;  /* invalid option */ | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int runargs (lua_State *L, char **argv, int n) { | ||||
|   int i; | ||||
|   for (i = 1; i < n; i++) { | ||||
|     if (argv[i] == NULL) continue; | ||||
|     lua_assert(argv[i][0] == '-'); | ||||
|     switch (argv[i][1]) {  /* option */ | ||||
|       case 'e': { | ||||
|         const char *chunk = argv[i] + 2; | ||||
|         if (*chunk == '\0') chunk = argv[++i]; | ||||
|         lua_assert(chunk != NULL); | ||||
|         if (dostring(L, chunk, "=(command line)") != 0) | ||||
|           return 1; | ||||
|         break; | ||||
|       } | ||||
|       case 'l': { | ||||
|         const char *filename = argv[i] + 2; | ||||
|         if (*filename == '\0') filename = argv[++i]; | ||||
|         lua_assert(filename != NULL); | ||||
|         if (dolibrary(L, filename)) | ||||
|           return 1;  /* stop if file fails */ | ||||
|         break; | ||||
|       } | ||||
|       default: break; | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int handle_luainit (lua_State *L) { | ||||
|   const char *init = getenv(LUA_INIT); | ||||
|   if (init == NULL) return 0;  /* status OK */ | ||||
|   else if (init[0] == '@') | ||||
|     return dofile(L, init+1); | ||||
|   else | ||||
|     return dostring(L, init, "=" LUA_INIT); | ||||
| } | ||||
|  | ||||
|  | ||||
| struct Smain { | ||||
|   int argc; | ||||
|   char **argv; | ||||
|   int status; | ||||
| }; | ||||
|  | ||||
|  | ||||
| static int pmain (lua_State *L) { | ||||
|   struct Smain *s = (struct Smain *)lua_touserdata(L, 1); | ||||
|   char **argv = s->argv; | ||||
|   int script; | ||||
|   int has_i = 0, has_v = 0, has_e = 0; | ||||
|   globalL = L; | ||||
|   if (argv[0] && argv[0][0]) progname = argv[0]; | ||||
|   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */ | ||||
|   luaL_openlibs(L);  /* open libraries */ | ||||
|   lua_gc(L, LUA_GCRESTART, 0); | ||||
|   s->status = handle_luainit(L); | ||||
|   if (s->status != 0) return 0; | ||||
|   script = collectargs(argv, &has_i, &has_v, &has_e); | ||||
|   if (script < 0) {  /* invalid args? */ | ||||
|     print_usage(); | ||||
|     s->status = 1; | ||||
|     return 0; | ||||
|   } | ||||
|   if (has_v) print_version(); | ||||
|   s->status = runargs(L, argv, (script > 0) ? script : s->argc); | ||||
|   if (s->status != 0) return 0; | ||||
|   if (script) | ||||
|     s->status = handle_script(L, argv, script); | ||||
|   if (s->status != 0) return 0; | ||||
|   if (has_i) | ||||
|     dotty(L); | ||||
|   else if (script == 0 && !has_e && !has_v) { | ||||
|     if (lua_stdin_is_tty()) { | ||||
|       print_version(); | ||||
|       dotty(L); | ||||
|     } | ||||
|     else dofile(L, NULL);  /* executes stdin as a file */ | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| int mainold (int argc, char **argv) { | ||||
|   int status; | ||||
|   struct Smain s; | ||||
|   lua_State *L = lua_open();  /* create state */ | ||||
|   if (L == NULL) { | ||||
|     l_message(argv[0], "cannot create state: not enough memory"); | ||||
|     return EXIT_FAILURE; | ||||
|   } | ||||
|   s.argc = argc; | ||||
|   s.argv = argv; | ||||
|   status = lua_cpcall(L, &pmain, &s); | ||||
|   report(L, status); | ||||
|   lua_close(L); | ||||
|   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; | ||||
| } | ||||
|  | ||||
							
								
								
									
										200
									
								
								lua/src/luac.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								lua/src/luac.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | ||||
| /* | ||||
| ** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ | ||||
| ** Lua compiler (saves bytecodes to files; also list bytecodes) | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
| #include <errno.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define luac_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
| #include "lauxlib.h" | ||||
|  | ||||
| #include "ldo.h" | ||||
| #include "lfunc.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lopcodes.h" | ||||
| #include "lstring.h" | ||||
| #include "lundump.h" | ||||
|  | ||||
| #define PROGNAME	"luac"		/* default program name */ | ||||
| #define	OUTPUT		PROGNAME ".out"	/* default output file */ | ||||
|  | ||||
| static int listing=0;			/* list bytecodes? */ | ||||
| static int dumping=1;			/* dump bytecodes? */ | ||||
| static int stripping=0;			/* strip debug information? */ | ||||
| static char Output[]={ OUTPUT };	/* default output file name */ | ||||
| static const char* output=Output;	/* actual output file name */ | ||||
| static const char* progname=PROGNAME;	/* actual program name */ | ||||
|  | ||||
| static void fatal(const char* message) | ||||
| { | ||||
|  fprintf(stderr,"%s: %s\n",progname,message); | ||||
|  exit(EXIT_FAILURE); | ||||
| } | ||||
|  | ||||
| static void cannot(const char* what) | ||||
| { | ||||
|  fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); | ||||
|  exit(EXIT_FAILURE); | ||||
| } | ||||
|  | ||||
| static void usage(const char* message) | ||||
| { | ||||
|  if (*message=='-') | ||||
|   fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); | ||||
|  else | ||||
|   fprintf(stderr,"%s: %s\n",progname,message); | ||||
|  fprintf(stderr, | ||||
|  "usage: %s [options] [filenames].\n" | ||||
|  "Available options are:\n" | ||||
|  "  -        process stdin\n" | ||||
|  "  -l       list\n" | ||||
|  "  -o name  output to file " LUA_QL("name") " (default is \"%s\")\n" | ||||
|  "  -p       parse only\n" | ||||
|  "  -s       strip debug information\n" | ||||
|  "  -v       show version information\n" | ||||
|  "  --       stop handling options\n", | ||||
|  progname,Output); | ||||
|  exit(EXIT_FAILURE); | ||||
| } | ||||
|  | ||||
| #define	IS(s)	(strcmp(argv[i],s)==0) | ||||
|  | ||||
| static int doargs(int argc, char* argv[]) | ||||
| { | ||||
|  int i; | ||||
|  int version=0; | ||||
|  if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; | ||||
|  for (i=1; i<argc; i++) | ||||
|  { | ||||
|   if (*argv[i]!='-')			/* end of options; keep it */ | ||||
|    break; | ||||
|   else if (IS("--"))			/* end of options; skip it */ | ||||
|   { | ||||
|    ++i; | ||||
|    if (version) ++version; | ||||
|    break; | ||||
|   } | ||||
|   else if (IS("-"))			/* end of options; use stdin */ | ||||
|    break; | ||||
|   else if (IS("-l"))			/* list */ | ||||
|    ++listing; | ||||
|   else if (IS("-o"))			/* output file */ | ||||
|   { | ||||
|    output=argv[++i]; | ||||
|    if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument"); | ||||
|    if (IS("-")) output=NULL; | ||||
|   } | ||||
|   else if (IS("-p"))			/* parse only */ | ||||
|    dumping=0; | ||||
|   else if (IS("-s"))			/* strip debug information */ | ||||
|    stripping=1; | ||||
|   else if (IS("-v"))			/* show version */ | ||||
|    ++version; | ||||
|   else					/* unknown option */ | ||||
|    usage(argv[i]); | ||||
|  } | ||||
|  if (i==argc && (listing || !dumping)) | ||||
|  { | ||||
|   dumping=0; | ||||
|   argv[--i]=Output; | ||||
|  } | ||||
|  if (version) | ||||
|  { | ||||
|   printf("%s  %s\n",LUA_RELEASE,LUA_COPYRIGHT); | ||||
|   if (version==argc-1) exit(EXIT_SUCCESS); | ||||
|  } | ||||
|  return i; | ||||
| } | ||||
|  | ||||
| #define toproto(L,i) (clvalue(L->top+(i))->l.p) | ||||
|  | ||||
| static const Proto* combine(lua_State* L, int n) | ||||
| { | ||||
|  if (n==1) | ||||
|   return toproto(L,-1); | ||||
|  else | ||||
|  { | ||||
|   int i,pc; | ||||
|   Proto* f=luaF_newproto(L); | ||||
|   setptvalue2s(L,L->top,f); incr_top(L); | ||||
|   f->source=luaS_newliteral(L,"=(" PROGNAME ")"); | ||||
|   f->maxstacksize=1; | ||||
|   pc=2*n+1; | ||||
|   f->code=luaM_newvector(L,pc,Instruction); | ||||
|   f->sizecode=pc; | ||||
|   f->p=luaM_newvector(L,n,Proto*); | ||||
|   f->sizep=n; | ||||
|   pc=0; | ||||
|   for (i=0; i<n; i++) | ||||
|   { | ||||
|    f->p[i]=toproto(L,i-n-1); | ||||
|    f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); | ||||
|    f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); | ||||
|   } | ||||
|   f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); | ||||
|   return f; | ||||
|  } | ||||
| } | ||||
|  | ||||
| static int writer(lua_State* L, const void* p, size_t size, void* u) | ||||
| { | ||||
|  UNUSED(L); | ||||
|  return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); | ||||
| } | ||||
|  | ||||
| struct Smain { | ||||
|  int argc; | ||||
|  char** argv; | ||||
| }; | ||||
|  | ||||
| static int pmain(lua_State* L) | ||||
| { | ||||
|  struct Smain* s = (struct Smain*)lua_touserdata(L, 1); | ||||
|  int argc=s->argc; | ||||
|  char** argv=s->argv; | ||||
|  const Proto* f; | ||||
|  int i; | ||||
|  if (!lua_checkstack(L,argc)) fatal("too many input files"); | ||||
|  for (i=0; i<argc; i++) | ||||
|  { | ||||
|   const char* filename=IS("-") ? NULL : argv[i]; | ||||
|   if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1)); | ||||
|  } | ||||
|  f=combine(L,argc); | ||||
|  if (listing) luaU_print(f,listing>1); | ||||
|  if (dumping) | ||||
|  { | ||||
|   FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); | ||||
|   if (D==NULL) cannot("open"); | ||||
|   lua_lock(L); | ||||
|   luaU_dump(L,f,writer,D,stripping); | ||||
|   lua_unlock(L); | ||||
|   if (ferror(D)) cannot("write"); | ||||
|   if (fclose(D)) cannot("close"); | ||||
|  } | ||||
|  return 0; | ||||
| } | ||||
|  | ||||
| int main_ool(int argc, char* argv[]) | ||||
| { | ||||
|  lua_State* L; | ||||
|  struct Smain s; | ||||
|  int i=doargs(argc,argv); | ||||
|  argc-=i; argv+=i; | ||||
|  if (argc<=0) usage("no input files given"); | ||||
|  L=lua_open(); | ||||
|  if (L==NULL) fatal("not enough memory for state"); | ||||
|  s.argc=argc; | ||||
|  s.argv=argv; | ||||
|  if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); | ||||
|  lua_close(L); | ||||
|  return EXIT_SUCCESS; | ||||
| } | ||||
							
								
								
									
										223
									
								
								lua/src/lundump.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								lua/src/lundump.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,223 @@ | ||||
| /* | ||||
| ** $Id: lundump.c,v 1.60 2006/02/16 15:53:49 lhf Exp $ | ||||
| ** load precompiled Lua chunks | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
| #include <string.h> | ||||
|  | ||||
| #define lundump_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lfunc.h" | ||||
| #include "lmem.h" | ||||
| #include "lobject.h" | ||||
| #include "lstring.h" | ||||
| #include "lundump.h" | ||||
| #include "lzio.h" | ||||
|  | ||||
| typedef struct { | ||||
|  lua_State* L; | ||||
|  ZIO* Z; | ||||
|  Mbuffer* b; | ||||
|  const char* name; | ||||
| } LoadState; | ||||
|  | ||||
| #ifdef LUAC_TRUST_BINARIES | ||||
| #define IF(c,s) | ||||
| #else | ||||
| #define IF(c,s)		if (c) error(S,s) | ||||
|  | ||||
| static void error(LoadState* S, const char* why) | ||||
| { | ||||
|  luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); | ||||
|  luaD_throw(S->L,LUA_ERRSYNTAX); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #define LoadMem(S,b,n,size)	LoadBlock(S,b,(n)*(size)) | ||||
| #define	LoadByte(S)		(lu_byte)LoadChar(S) | ||||
| #define LoadVar(S,x)		LoadMem(S,&x,1,sizeof(x)) | ||||
| #define LoadVector(S,b,n,size)	LoadMem(S,b,n,size) | ||||
|  | ||||
| static void LoadBlock(LoadState* S, void* b, size_t size) | ||||
| { | ||||
|  size_t r=luaZ_read(S->Z,b,size); | ||||
|  IF (r!=0, "unexpected end"); | ||||
| } | ||||
|  | ||||
| static int LoadChar(LoadState* S) | ||||
| { | ||||
|  char x; | ||||
|  LoadVar(S,x); | ||||
|  return x; | ||||
| } | ||||
|  | ||||
| static int LoadInt(LoadState* S) | ||||
| { | ||||
|  int x; | ||||
|  LoadVar(S,x); | ||||
|  IF (x<0, "bad integer"); | ||||
|  return x; | ||||
| } | ||||
|  | ||||
| static lua_Number LoadNumber(LoadState* S) | ||||
| { | ||||
|  lua_Number x; | ||||
|  LoadVar(S,x); | ||||
|  return x; | ||||
| } | ||||
|  | ||||
| static TString* LoadString(LoadState* S) | ||||
| { | ||||
|  size_t size; | ||||
|  LoadVar(S,size); | ||||
|  if (size==0) | ||||
|   return NULL; | ||||
|  else | ||||
|  { | ||||
|   char* s=luaZ_openspace(S->L,S->b,size); | ||||
|   LoadBlock(S,s,size); | ||||
|   return luaS_newlstr(S->L,s,size-1);		/* remove trailing '\0' */ | ||||
|  } | ||||
| } | ||||
|  | ||||
| static void LoadCode(LoadState* S, Proto* f) | ||||
| { | ||||
|  int n=LoadInt(S); | ||||
|  f->code=luaM_newvector(S->L,n,Instruction); | ||||
|  f->sizecode=n; | ||||
|  LoadVector(S,f->code,n,sizeof(Instruction)); | ||||
| } | ||||
|  | ||||
| static Proto* LoadFunction(LoadState* S, TString* p); | ||||
|  | ||||
| static void LoadConstants(LoadState* S, Proto* f) | ||||
| { | ||||
|  int i,n; | ||||
|  n=LoadInt(S); | ||||
|  f->k=luaM_newvector(S->L,n,TValue); | ||||
|  f->sizek=n; | ||||
|  for (i=0; i<n; i++) setnilvalue(&f->k[i]); | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   TValue* o=&f->k[i]; | ||||
|   int t=LoadChar(S); | ||||
|   switch (t) | ||||
|   { | ||||
|    case LUA_TNIL: | ||||
|    	setnilvalue(o); | ||||
| 	break; | ||||
|    case LUA_TBOOLEAN: | ||||
|    	setbvalue(o,LoadChar(S)); | ||||
| 	break; | ||||
|    case LUA_TNUMBER: | ||||
| 	setnvalue(o,LoadNumber(S)); | ||||
| 	break; | ||||
|    case LUA_TSTRING: | ||||
| 	setsvalue2n(S->L,o,LoadString(S)); | ||||
| 	break; | ||||
|    default: | ||||
| 	IF (1, "bad constant"); | ||||
| 	break; | ||||
|   } | ||||
|  } | ||||
|  n=LoadInt(S); | ||||
|  f->p=luaM_newvector(S->L,n,Proto*); | ||||
|  f->sizep=n; | ||||
|  for (i=0; i<n; i++) f->p[i]=NULL; | ||||
|  for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source); | ||||
| } | ||||
|  | ||||
| static void LoadDebug(LoadState* S, Proto* f) | ||||
| { | ||||
|  int i,n; | ||||
|  n=LoadInt(S); | ||||
|  f->lineinfo=luaM_newvector(S->L,n,int); | ||||
|  f->sizelineinfo=n; | ||||
|  LoadVector(S,f->lineinfo,n,sizeof(int)); | ||||
|  n=LoadInt(S); | ||||
|  f->locvars=luaM_newvector(S->L,n,LocVar); | ||||
|  f->sizelocvars=n; | ||||
|  for (i=0; i<n; i++) f->locvars[i].varname=NULL; | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   f->locvars[i].varname=LoadString(S); | ||||
|   f->locvars[i].startpc=LoadInt(S); | ||||
|   f->locvars[i].endpc=LoadInt(S); | ||||
|  } | ||||
|  n=LoadInt(S); | ||||
|  f->upvalues=luaM_newvector(S->L,n,TString*); | ||||
|  f->sizeupvalues=n; | ||||
|  for (i=0; i<n; i++) f->upvalues[i]=NULL; | ||||
|  for (i=0; i<n; i++) f->upvalues[i]=LoadString(S); | ||||
| } | ||||
|  | ||||
| static Proto* LoadFunction(LoadState* S, TString* p) | ||||
| { | ||||
|  Proto* f=luaF_newproto(S->L); | ||||
|  setptvalue2s(S->L,S->L->top,f); incr_top(S->L); | ||||
|  f->source=LoadString(S); if (f->source==NULL) f->source=p; | ||||
|  f->linedefined=LoadInt(S); | ||||
|  f->lastlinedefined=LoadInt(S); | ||||
|  f->nups=LoadByte(S); | ||||
|  f->numparams=LoadByte(S); | ||||
|  f->is_vararg=LoadByte(S); | ||||
|  f->maxstacksize=LoadByte(S); | ||||
|  LoadCode(S,f); | ||||
|  LoadConstants(S,f); | ||||
|  LoadDebug(S,f); | ||||
|  IF (!luaG_checkcode(f), "bad code"); | ||||
|  S->L->top--; | ||||
|  return f; | ||||
| } | ||||
|  | ||||
| static void LoadHeader(LoadState* S) | ||||
| { | ||||
|  char h[LUAC_HEADERSIZE]; | ||||
|  char s[LUAC_HEADERSIZE]; | ||||
|  luaU_header(h); | ||||
|  LoadBlock(S,s,LUAC_HEADERSIZE); | ||||
|  IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ** load precompiled chunk | ||||
| */ | ||||
| Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) | ||||
| { | ||||
|  LoadState S; | ||||
|  if (*name=='@' || *name=='=') | ||||
|   S.name=name+1; | ||||
|  else if (*name==LUA_SIGNATURE[0]) | ||||
|   S.name="binary string"; | ||||
|  else | ||||
|   S.name=name; | ||||
|  S.L=L; | ||||
|  S.Z=Z; | ||||
|  S.b=buff; | ||||
|  LoadHeader(&S); | ||||
|  return LoadFunction(&S,luaS_newliteral(L,"=?")); | ||||
| } | ||||
|  | ||||
| /* | ||||
| * make header | ||||
| */ | ||||
| void luaU_header (char* h) | ||||
| { | ||||
|  int x=1; | ||||
|  memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); | ||||
|  h+=sizeof(LUA_SIGNATURE)-1; | ||||
|  *h++=(char)LUAC_VERSION; | ||||
|  *h++=(char)LUAC_FORMAT; | ||||
|  *h++=(char)*(char*)&x;				/* endianness */ | ||||
|  *h++=(char)sizeof(int); | ||||
|  *h++=(char)sizeof(size_t); | ||||
|  *h++=(char)sizeof(Instruction); | ||||
|  *h++=(char)sizeof(lua_Number); | ||||
|  *h++=(char)(((lua_Number)0.5)==0);		/* is lua_Number integral? */ | ||||
| } | ||||
							
								
								
									
										765
									
								
								lua/src/lvm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										765
									
								
								lua/src/lvm.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,765 @@ | ||||
| /* | ||||
| ** $Id: lvm.c,v 2.63a 2006/06/05 15:58:59 roberto Exp $ | ||||
| ** Lua virtual machine | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define lvm_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "ldo.h" | ||||
| #include "lfunc.h" | ||||
| #include "lgc.h" | ||||
| #include "lobject.h" | ||||
| #include "lopcodes.h" | ||||
| #include "lstate.h" | ||||
| #include "lstring.h" | ||||
| #include "ltable.h" | ||||
| #include "ltm.h" | ||||
| #include "lvm.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| /* limit for table tag-method chains (to avoid loops) */ | ||||
| #define MAXTAGLOOP	100 | ||||
|  | ||||
|  | ||||
| const TValue *luaV_tonumber (const TValue *obj, TValue *n) { | ||||
|   lua_Number num; | ||||
|   if (ttisnumber(obj)) return obj; | ||||
|   if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { | ||||
|     setnvalue(n, num); | ||||
|     return n; | ||||
|   } | ||||
|   else | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaV_tostring (lua_State *L, StkId obj) { | ||||
|   if (!ttisnumber(obj)) | ||||
|     return 0; | ||||
|   else { | ||||
|     char s[LUAI_MAXNUMBER2STR]; | ||||
|     lua_Number n = nvalue(obj); | ||||
|     lua_number2str(s, n); | ||||
|     setsvalue2s(L, obj, luaS_new(L, s)); | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void traceexec (lua_State *L, const Instruction *pc) { | ||||
|   lu_byte mask = L->hookmask; | ||||
|   const Instruction *oldpc = L->savedpc; | ||||
|   L->savedpc = pc; | ||||
|   if (mask > LUA_MASKLINE) {  /* instruction-hook set? */ | ||||
|     if (L->hookcount == 0) { | ||||
|       resethookcount(L); | ||||
|       luaD_callhook(L, LUA_HOOKCOUNT, -1); | ||||
|     } | ||||
|   } | ||||
|   if (mask & LUA_MASKLINE) { | ||||
|     Proto *p = ci_func(L->ci)->l.p; | ||||
|     int npc = pcRel(pc, p); | ||||
|     int newline = getline(p, npc); | ||||
|     /* call linehook when enter a new function, when jump back (loop), | ||||
|        or when enter a new line */ | ||||
|     if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) | ||||
|       luaD_callhook(L, LUA_HOOKLINE, newline); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| static void callTMres (lua_State *L, StkId res, const TValue *f, | ||||
|                         const TValue *p1, const TValue *p2) { | ||||
|   ptrdiff_t result = savestack(L, res); | ||||
|   setobj2s(L, L->top, f);  /* push function */ | ||||
|   setobj2s(L, L->top+1, p1);  /* 1st argument */ | ||||
|   setobj2s(L, L->top+2, p2);  /* 2nd argument */ | ||||
|   luaD_checkstack(L, 3); | ||||
|   L->top += 3; | ||||
|   luaD_call(L, L->top - 3, 1); | ||||
|   res = restorestack(L, result); | ||||
|   L->top--; | ||||
|   setobjs2s(L, res, L->top); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static void callTM (lua_State *L, const TValue *f, const TValue *p1, | ||||
|                     const TValue *p2, const TValue *p3) { | ||||
|   setobj2s(L, L->top, f);  /* push function */ | ||||
|   setobj2s(L, L->top+1, p1);  /* 1st argument */ | ||||
|   setobj2s(L, L->top+2, p2);  /* 2nd argument */ | ||||
|   setobj2s(L, L->top+3, p3);  /* 3th argument */ | ||||
|   luaD_checkstack(L, 4); | ||||
|   L->top += 4; | ||||
|   luaD_call(L, L->top - 4, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { | ||||
|   int loop; | ||||
|   for (loop = 0; loop < MAXTAGLOOP; loop++) { | ||||
|     const TValue *tm; | ||||
|     if (ttistable(t)) {  /* `t' is a table? */ | ||||
|       Table *h = hvalue(t); | ||||
|       const TValue *res = luaH_get(h, key); /* do a primitive get */ | ||||
|       if (!ttisnil(res) ||  /* result is no nil? */ | ||||
|           (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ | ||||
|         setobj2s(L, val, res); | ||||
|         return; | ||||
|       } | ||||
|       /* else will try the tag method */ | ||||
|     } | ||||
|     else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) | ||||
|       luaG_typeerror(L, t, "index"); | ||||
|     if (ttisfunction(tm)) { | ||||
|       callTMres(L, val, tm, t, key); | ||||
|       return; | ||||
|     } | ||||
|     t = tm;  /* else repeat with `tm' */  | ||||
|   } | ||||
|   luaG_runerror(L, "loop in gettable"); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { | ||||
|   int loop; | ||||
|   for (loop = 0; loop < MAXTAGLOOP; loop++) { | ||||
|     const TValue *tm; | ||||
|     if (ttistable(t)) {  /* `t' is a table? */ | ||||
|       Table *h = hvalue(t); | ||||
|       TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ | ||||
|       if (!ttisnil(oldval) ||  /* result is no nil? */ | ||||
|           (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ | ||||
|         setobj2t(L, oldval, val); | ||||
|         luaC_barriert(L, h, val); | ||||
|         return; | ||||
|       } | ||||
|       /* else will try the tag method */ | ||||
|     } | ||||
|     else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) | ||||
|       luaG_typeerror(L, t, "index"); | ||||
|     if (ttisfunction(tm)) { | ||||
|       callTM(L, tm, t, key, val); | ||||
|       return; | ||||
|     } | ||||
|     t = tm;  /* else repeat with `tm' */  | ||||
|   } | ||||
|   luaG_runerror(L, "loop in settable"); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, | ||||
|                        StkId res, TMS event) { | ||||
|   const TValue *tm = luaT_gettmbyobj(L, p1, event);  /* try first operand */ | ||||
|   if (ttisnil(tm)) | ||||
|     tm = luaT_gettmbyobj(L, p2, event);  /* try second operand */ | ||||
|   if (ttisnil(tm)) return 0; | ||||
|   callTMres(L, res, tm, p1, p2); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, | ||||
|                                   TMS event) { | ||||
|   const TValue *tm1 = fasttm(L, mt1, event); | ||||
|   const TValue *tm2; | ||||
|   if (tm1 == NULL) return NULL;  /* no metamethod */ | ||||
|   if (mt1 == mt2) return tm1;  /* same metatables => same metamethods */ | ||||
|   tm2 = fasttm(L, mt2, event); | ||||
|   if (tm2 == NULL) return NULL;  /* no metamethod */ | ||||
|   if (luaO_rawequalObj(tm1, tm2))  /* same metamethods? */ | ||||
|     return tm1; | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, | ||||
|                          TMS event) { | ||||
|   const TValue *tm1 = luaT_gettmbyobj(L, p1, event); | ||||
|   const TValue *tm2; | ||||
|   if (ttisnil(tm1)) return -1;  /* no metamethod? */ | ||||
|   tm2 = luaT_gettmbyobj(L, p2, event); | ||||
|   if (!luaO_rawequalObj(tm1, tm2))  /* different metamethods? */ | ||||
|     return -1; | ||||
|   callTMres(L, L->top, tm1, p1, p2); | ||||
|   return !l_isfalse(L->top); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int l_strcmp (const TString *ls, const TString *rs) { | ||||
|   const char *l = getstr(ls); | ||||
|   size_t ll = ls->tsv.len; | ||||
|   const char *r = getstr(rs); | ||||
|   size_t lr = rs->tsv.len; | ||||
|   for (;;) { | ||||
|     int temp = strcoll(l, r); | ||||
|     if (temp != 0) return temp; | ||||
|     else {  /* strings are equal up to a `\0' */ | ||||
|       size_t len = strlen(l);  /* index of first `\0' in both strings */ | ||||
|       if (len == lr)  /* r is finished? */ | ||||
|         return (len == ll) ? 0 : 1; | ||||
|       else if (len == ll)  /* l is finished? */ | ||||
|         return -1;  /* l is smaller than r (because r is not finished) */ | ||||
|       /* both strings longer than `len'; go on comparing (after the `\0') */ | ||||
|       len++; | ||||
|       l += len; ll -= len; r += len; lr -= len; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { | ||||
|   int res; | ||||
|   if (ttype(l) != ttype(r)) | ||||
|     return luaG_ordererror(L, l, r); | ||||
|   else if (ttisnumber(l)) | ||||
|     return luai_numlt(nvalue(l), nvalue(r)); | ||||
|   else if (ttisstring(l)) | ||||
|     return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; | ||||
|   else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) | ||||
|     return res; | ||||
|   return luaG_ordererror(L, l, r); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int lessequal (lua_State *L, const TValue *l, const TValue *r) { | ||||
|   int res; | ||||
|   if (ttype(l) != ttype(r)) | ||||
|     return luaG_ordererror(L, l, r); | ||||
|   else if (ttisnumber(l)) | ||||
|     return luai_numle(nvalue(l), nvalue(r)); | ||||
|   else if (ttisstring(l)) | ||||
|     return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; | ||||
|   else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */ | ||||
|     return res; | ||||
|   else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */ | ||||
|     return !res; | ||||
|   return luaG_ordererror(L, l, r); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { | ||||
|   const TValue *tm; | ||||
|   lua_assert(ttype(t1) == ttype(t2)); | ||||
|   switch (ttype(t1)) { | ||||
|     case LUA_TNIL: return 1; | ||||
|     case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); | ||||
|     case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */ | ||||
|     case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); | ||||
|     case LUA_TUSERDATA: { | ||||
|       if (uvalue(t1) == uvalue(t2)) return 1; | ||||
|       tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, | ||||
|                          TM_EQ); | ||||
|       break;  /* will try TM */ | ||||
|     } | ||||
|     case LUA_TTABLE: { | ||||
|       if (hvalue(t1) == hvalue(t2)) return 1; | ||||
|       tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); | ||||
|       break;  /* will try TM */ | ||||
|     } | ||||
|     default: return gcvalue(t1) == gcvalue(t2); | ||||
|   } | ||||
|   if (tm == NULL) return 0;  /* no TM? */ | ||||
|   callTMres(L, L->top, tm, t1, t2);  /* call TM */ | ||||
|   return !l_isfalse(L->top); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaV_concat (lua_State *L, int total, int last) { | ||||
|   do { | ||||
|     StkId top = L->base + last + 1; | ||||
|     int n = 2;  /* number of elements handled in this pass (at least 2) */ | ||||
|     if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { | ||||
|       if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) | ||||
|         luaG_concaterror(L, top-2, top-1); | ||||
|     } else if (tsvalue(top-1)->len == 0)  /* second op is empty? */ | ||||
|       (void)tostring(L, top - 2);  /* result is first op (as string) */ | ||||
|     else { | ||||
|       /* at least two string values; get as many as possible */ | ||||
|       size_t tl = tsvalue(top-1)->len; | ||||
|       char *buffer; | ||||
|       int i; | ||||
|       /* collect total length */ | ||||
|       for (n = 1; n < total && tostring(L, top-n-1); n++) { | ||||
|         size_t l = tsvalue(top-n-1)->len; | ||||
|         if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); | ||||
|         tl += l; | ||||
|       } | ||||
|       buffer = luaZ_openspace(L, &G(L)->buff, tl); | ||||
|       tl = 0; | ||||
|       for (i=n; i>0; i--) {  /* concat all strings */ | ||||
|         size_t l = tsvalue(top-i)->len; | ||||
|         memcpy(buffer+tl, svalue(top-i), l); | ||||
|         tl += l; | ||||
|       } | ||||
|       setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); | ||||
|     } | ||||
|     total -= n-1;  /* got `n' strings to create 1 new */ | ||||
|     last -= n-1; | ||||
|   } while (total > 1);  /* repeat until only 1 result left */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static void Arith (lua_State *L, StkId ra, const TValue *rb, | ||||
|                    const TValue *rc, TMS op) { | ||||
|   TValue tempb, tempc; | ||||
|   const TValue *b, *c; | ||||
|   if ((b = luaV_tonumber(rb, &tempb)) != NULL && | ||||
|       (c = luaV_tonumber(rc, &tempc)) != NULL) { | ||||
|     lua_Number nb = nvalue(b), nc = nvalue(c); | ||||
|     switch (op) { | ||||
|       case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; | ||||
|       case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; | ||||
|       case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; | ||||
|       case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; | ||||
|       case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; | ||||
|       case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; | ||||
|       case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; | ||||
|       default: lua_assert(0); break; | ||||
|     } | ||||
|   } | ||||
|   else if (!call_binTM(L, rb, rc, ra, op)) | ||||
|     luaG_aritherror(L, rb, rc); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| ** some macros for common tasks in `luaV_execute' | ||||
| */ | ||||
|  | ||||
| #define runtime_check(L, c)	{ if (!(c)) break; } | ||||
|  | ||||
| #define RA(i)	(base+GETARG_A(i)) | ||||
| /* to be used after possible stack reallocation */ | ||||
| #define RB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) | ||||
| #define RC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) | ||||
| #define RKB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ | ||||
| 	ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) | ||||
| #define RKC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ | ||||
| 	ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) | ||||
| #define KBx(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) | ||||
|  | ||||
|  | ||||
| #define dojump(L,pc,i)	{(pc) += (i); luai_threadyield(L);} | ||||
|  | ||||
|  | ||||
| #define Protect(x)	{ L->savedpc = pc; {x;}; base = L->base; } | ||||
|  | ||||
|  | ||||
| #define arith_op(op,tm) { \ | ||||
|         TValue *rb = RKB(i); \ | ||||
|         TValue *rc = RKC(i); \ | ||||
|         if (ttisnumber(rb) && ttisnumber(rc)) { \ | ||||
|           lua_Number nb = nvalue(rb), nc = nvalue(rc); \ | ||||
|           setnvalue(ra, op(nb, nc)); \ | ||||
|         } \ | ||||
|         else \ | ||||
|           Protect(Arith(L, ra, rb, rc, tm)); \ | ||||
|       } | ||||
|  | ||||
|  | ||||
|  | ||||
| void luaV_execute (lua_State *L, int nexeccalls) { | ||||
|   LClosure *cl; | ||||
|   StkId base; | ||||
|   TValue *k; | ||||
|   const Instruction *pc; | ||||
|  reentry:  /* entry point */ | ||||
|   lua_assert(isLua(L->ci)); | ||||
|   pc = L->savedpc; | ||||
|   cl = &clvalue(L->ci->func)->l; | ||||
|   base = L->base; | ||||
|   k = cl->p->k; | ||||
|   /* main loop of interpreter */ | ||||
|   for (;;) { | ||||
|     const Instruction i = *pc++; | ||||
|     StkId ra; | ||||
|     if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && | ||||
|         (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { | ||||
|       traceexec(L, pc); | ||||
|       if (L->status == LUA_YIELD) {  /* did hook yield? */ | ||||
|         L->savedpc = pc - 1; | ||||
|         return; | ||||
|       } | ||||
|       base = L->base; | ||||
|     } | ||||
|     /* warning!! several calls may realloc the stack and invalidate `ra' */ | ||||
|     ra = RA(i); | ||||
|     lua_assert(base == L->base && L->base == L->ci->base); | ||||
|     lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); | ||||
|     lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); | ||||
|     switch (GET_OPCODE(i)) { | ||||
|       case OP_MOVE: { | ||||
|         setobjs2s(L, ra, RB(i)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_LOADK: { | ||||
|         setobj2s(L, ra, KBx(i)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_LOADBOOL: { | ||||
|         setbvalue(ra, GETARG_B(i)); | ||||
|         if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */ | ||||
|         continue; | ||||
|       } | ||||
|       case OP_LOADNIL: { | ||||
|         TValue *rb = RB(i); | ||||
|         do { | ||||
|           setnilvalue(rb--); | ||||
|         } while (rb >= ra); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_GETUPVAL: { | ||||
|         int b = GETARG_B(i); | ||||
|         setobj2s(L, ra, cl->upvals[b]->v); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_GETGLOBAL: { | ||||
|         TValue g; | ||||
|         TValue *rb = KBx(i); | ||||
|         sethvalue(L, &g, cl->env); | ||||
|         lua_assert(ttisstring(rb)); | ||||
|         Protect(luaV_gettable(L, &g, rb, ra)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_GETTABLE: { | ||||
|         Protect(luaV_gettable(L, RB(i), RKC(i), ra)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_SETGLOBAL: { | ||||
|         TValue g; | ||||
|         sethvalue(L, &g, cl->env); | ||||
|         lua_assert(ttisstring(KBx(i))); | ||||
|         Protect(luaV_settable(L, &g, KBx(i), ra)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_SETUPVAL: { | ||||
|         UpVal *uv = cl->upvals[GETARG_B(i)]; | ||||
|         setobj(L, uv->v, ra); | ||||
|         luaC_barrier(L, uv, ra); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_SETTABLE: { | ||||
|         Protect(luaV_settable(L, ra, RKB(i), RKC(i))); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_NEWTABLE: { | ||||
|         int b = GETARG_B(i); | ||||
|         int c = GETARG_C(i); | ||||
|         sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); | ||||
|         Protect(luaC_checkGC(L)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_SELF: { | ||||
|         StkId rb = RB(i); | ||||
|         setobjs2s(L, ra+1, rb); | ||||
|         Protect(luaV_gettable(L, rb, RKC(i), ra)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_ADD: { | ||||
|         arith_op(luai_numadd, TM_ADD); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_SUB: { | ||||
|         arith_op(luai_numsub, TM_SUB); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_MUL: { | ||||
|         arith_op(luai_nummul, TM_MUL); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_DIV: { | ||||
|         arith_op(luai_numdiv, TM_DIV); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_MOD: { | ||||
|         arith_op(luai_nummod, TM_MOD); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_POW: { | ||||
|         arith_op(luai_numpow, TM_POW); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_UNM: { | ||||
|         TValue *rb = RB(i); | ||||
|         if (ttisnumber(rb)) { | ||||
|           lua_Number nb = nvalue(rb); | ||||
|           setnvalue(ra, luai_numunm(nb)); | ||||
|         } | ||||
|         else { | ||||
|           Protect(Arith(L, ra, rb, rb, TM_UNM)); | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
|       case OP_NOT: { | ||||
|         int res = l_isfalse(RB(i));  /* next assignment may change this value */ | ||||
|         setbvalue(ra, res); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_LEN: { | ||||
|         const TValue *rb = RB(i); | ||||
|         switch (ttype(rb)) { | ||||
|           case LUA_TTABLE: { | ||||
|             setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); | ||||
|             break; | ||||
|           } | ||||
|           case LUA_TSTRING: { | ||||
|             setnvalue(ra, cast_num(tsvalue(rb)->len)); | ||||
|             break; | ||||
|           } | ||||
|           default: {  /* try metamethod */ | ||||
|             Protect( | ||||
|               if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) | ||||
|                 luaG_typeerror(L, rb, "get length of"); | ||||
|             ) | ||||
|           } | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
|       case OP_CONCAT: { | ||||
|         int b = GETARG_B(i); | ||||
|         int c = GETARG_C(i); | ||||
|         Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); | ||||
|         setobjs2s(L, RA(i), base+b); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_JMP: { | ||||
|         dojump(L, pc, GETARG_sBx(i)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_EQ: { | ||||
|         TValue *rb = RKB(i); | ||||
|         TValue *rc = RKC(i); | ||||
|         Protect( | ||||
|           if (equalobj(L, rb, rc) == GETARG_A(i)) | ||||
|             dojump(L, pc, GETARG_sBx(*pc)); | ||||
|         ) | ||||
|         pc++; | ||||
|         continue; | ||||
|       } | ||||
|       case OP_LT: { | ||||
|         Protect( | ||||
|           if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) | ||||
|             dojump(L, pc, GETARG_sBx(*pc)); | ||||
|         ) | ||||
|         pc++; | ||||
|         continue; | ||||
|       } | ||||
|       case OP_LE: { | ||||
|         Protect( | ||||
|           if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) | ||||
|             dojump(L, pc, GETARG_sBx(*pc)); | ||||
|         ) | ||||
|         pc++; | ||||
|         continue; | ||||
|       } | ||||
|       case OP_TEST: { | ||||
|         if (l_isfalse(ra) != GETARG_C(i)) | ||||
|           dojump(L, pc, GETARG_sBx(*pc)); | ||||
|         pc++; | ||||
|         continue; | ||||
|       } | ||||
|       case OP_TESTSET: { | ||||
|         TValue *rb = RB(i); | ||||
|         if (l_isfalse(rb) != GETARG_C(i)) { | ||||
|           setobjs2s(L, ra, rb); | ||||
|           dojump(L, pc, GETARG_sBx(*pc)); | ||||
|         } | ||||
|         pc++; | ||||
|         continue; | ||||
|       } | ||||
|       case OP_CALL: { | ||||
|         int b = GETARG_B(i); | ||||
|         int nresults = GETARG_C(i) - 1; | ||||
|         if (b != 0) L->top = ra+b;  /* else previous instruction set top */ | ||||
|         L->savedpc = pc; | ||||
|         switch (luaD_precall(L, ra, nresults)) { | ||||
|           case PCRLUA: { | ||||
|             nexeccalls++; | ||||
|             goto reentry;  /* restart luaV_execute over new Lua function */ | ||||
|           } | ||||
|           case PCRC: { | ||||
|             /* it was a C function (`precall' called it); adjust results */ | ||||
|             if (nresults >= 0) L->top = L->ci->top; | ||||
|             base = L->base; | ||||
|             continue; | ||||
|           } | ||||
|           default: { | ||||
|             return;  /* yield */ | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       case OP_TAILCALL: { | ||||
|         int b = GETARG_B(i); | ||||
|         if (b != 0) L->top = ra+b;  /* else previous instruction set top */ | ||||
|         L->savedpc = pc; | ||||
|         lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); | ||||
|         switch (luaD_precall(L, ra, LUA_MULTRET)) { | ||||
|           case PCRLUA: { | ||||
|             /* tail call: put new frame in place of previous one */ | ||||
|             CallInfo *ci = L->ci - 1;  /* previous frame */ | ||||
|             int aux; | ||||
|             StkId func = ci->func; | ||||
|             StkId pfunc = (ci+1)->func;  /* previous function index */ | ||||
|             if (L->openupval) luaF_close(L, ci->base); | ||||
|             L->base = ci->base = ci->func + ((ci+1)->base - pfunc); | ||||
|             for (aux = 0; pfunc+aux < L->top; aux++)  /* move frame down */ | ||||
|               setobjs2s(L, func+aux, pfunc+aux); | ||||
|             ci->top = L->top = func+aux;  /* correct top */ | ||||
|             lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); | ||||
|             ci->savedpc = L->savedpc; | ||||
|             ci->tailcalls++;  /* one more call lost */ | ||||
|             L->ci--;  /* remove new frame */ | ||||
|             goto reentry; | ||||
|           } | ||||
|           case PCRC: {  /* it was a C function (`precall' called it) */ | ||||
|             base = L->base; | ||||
|             continue; | ||||
|           } | ||||
|           default: { | ||||
|             return;  /* yield */ | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       case OP_RETURN: { | ||||
|         int b = GETARG_B(i); | ||||
|         if (b != 0) L->top = ra+b-1; | ||||
|         if (L->openupval) luaF_close(L, base); | ||||
|         L->savedpc = pc; | ||||
|         b = luaD_poscall(L, ra); | ||||
|         if (--nexeccalls == 0)  /* was previous function running `here'? */ | ||||
|           return;  /* no: return */ | ||||
|         else {  /* yes: continue its execution */ | ||||
|           if (b) L->top = L->ci->top; | ||||
|           lua_assert(isLua(L->ci)); | ||||
|           lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); | ||||
|           goto reentry; | ||||
|         } | ||||
|       } | ||||
|       case OP_FORLOOP: { | ||||
|         lua_Number step = nvalue(ra+2); | ||||
|         lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ | ||||
|         lua_Number limit = nvalue(ra+1); | ||||
|         if (luai_numlt(0, step) ? luai_numle(idx, limit) | ||||
|                                 : luai_numle(limit, idx)) { | ||||
|           dojump(L, pc, GETARG_sBx(i));  /* jump back */ | ||||
|           setnvalue(ra, idx);  /* update internal index... */ | ||||
|           setnvalue(ra+3, idx);  /* ...and external index */ | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
|       case OP_FORPREP: { | ||||
|         const TValue *init = ra; | ||||
|         const TValue *plimit = ra+1; | ||||
|         const TValue *pstep = ra+2; | ||||
|         L->savedpc = pc;  /* next steps may throw errors */ | ||||
|         if (!tonumber(init, ra)) | ||||
|           luaG_runerror(L, LUA_QL("for") " initial value must be a number"); | ||||
|         else if (!tonumber(plimit, ra+1)) | ||||
|           luaG_runerror(L, LUA_QL("for") " limit must be a number"); | ||||
|         else if (!tonumber(pstep, ra+2)) | ||||
|           luaG_runerror(L, LUA_QL("for") " step must be a number"); | ||||
|         setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); | ||||
|         dojump(L, pc, GETARG_sBx(i)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_TFORLOOP: { | ||||
|         StkId cb = ra + 3;  /* call base */ | ||||
|         setobjs2s(L, cb+2, ra+2); | ||||
|         setobjs2s(L, cb+1, ra+1); | ||||
|         setobjs2s(L, cb, ra); | ||||
|         L->top = cb+3;  /* func. + 2 args (state and index) */ | ||||
|         Protect(luaD_call(L, cb, GETARG_C(i))); | ||||
|         L->top = L->ci->top; | ||||
|         cb = RA(i) + 3;  /* previous call may change the stack */ | ||||
|         if (!ttisnil(cb)) {  /* continue loop? */ | ||||
|           setobjs2s(L, cb-1, cb);  /* save control variable */ | ||||
|           dojump(L, pc, GETARG_sBx(*pc));  /* jump back */ | ||||
|         } | ||||
|         pc++; | ||||
|         continue; | ||||
|       } | ||||
|       case OP_SETLIST: { | ||||
|         int n = GETARG_B(i); | ||||
|         int c = GETARG_C(i); | ||||
|         int last; | ||||
|         Table *h; | ||||
|         if (n == 0) { | ||||
|           n = cast_int(L->top - ra) - 1; | ||||
|           L->top = L->ci->top; | ||||
|         } | ||||
|         if (c == 0) c = cast_int(*pc++); | ||||
|         runtime_check(L, ttistable(ra)); | ||||
|         h = hvalue(ra); | ||||
|         last = ((c-1)*LFIELDS_PER_FLUSH) + n; | ||||
|         if (last > h->sizearray)  /* needs more space? */ | ||||
|           luaH_resizearray(L, h, last);  /* pre-alloc it at once */ | ||||
|         for (; n > 0; n--) { | ||||
|           TValue *val = ra+n; | ||||
|           setobj2t(L, luaH_setnum(L, h, last--), val); | ||||
|           luaC_barriert(L, h, val); | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
|       case OP_CLOSE: { | ||||
|         luaF_close(L, ra); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_CLOSURE: { | ||||
|         Proto *p; | ||||
|         Closure *ncl; | ||||
|         int nup, j; | ||||
|         p = cl->p->p[GETARG_Bx(i)]; | ||||
|         nup = p->nups; | ||||
|         ncl = luaF_newLclosure(L, nup, cl->env); | ||||
|         ncl->l.p = p; | ||||
|         for (j=0; j<nup; j++, pc++) { | ||||
|           if (GET_OPCODE(*pc) == OP_GETUPVAL) | ||||
|             ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; | ||||
|           else { | ||||
|             lua_assert(GET_OPCODE(*pc) == OP_MOVE); | ||||
|             ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); | ||||
|           } | ||||
|         } | ||||
|         setclvalue(L, ra, ncl); | ||||
|         Protect(luaC_checkGC(L)); | ||||
|         continue; | ||||
|       } | ||||
|       case OP_VARARG: { | ||||
|         int b = GETARG_B(i) - 1; | ||||
|         int j; | ||||
|         CallInfo *ci = L->ci; | ||||
|         int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; | ||||
|         if (b == LUA_MULTRET) { | ||||
|           Protect(luaD_checkstack(L, n)); | ||||
|           ra = RA(i);  /* previous call may change the stack */ | ||||
|           b = n; | ||||
|           L->top = ra + n; | ||||
|         } | ||||
|         for (j = 0; j < b; j++) { | ||||
|           if (j < n) { | ||||
|             setobjs2s(L, ra + j, ci->base - n + j); | ||||
|           } | ||||
|           else { | ||||
|             setnilvalue(ra + j); | ||||
|           } | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										82
									
								
								lua/src/lzio.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								lua/src/lzio.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| /* | ||||
| ** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ | ||||
| ** a generic input stream interface | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
|  | ||||
| #include "stdafx.h" | ||||
| #include <string.h> | ||||
|  | ||||
| #define lzio_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "lua.h" | ||||
|  | ||||
| #include "llimits.h" | ||||
| #include "lmem.h" | ||||
| #include "lstate.h" | ||||
| #include "lzio.h" | ||||
|  | ||||
|  | ||||
| int luaZ_fill (ZIO *z) { | ||||
|   size_t size; | ||||
|   lua_State *L = z->L; | ||||
|   const char *buff; | ||||
|   lua_unlock(L); | ||||
|   buff = z->reader(L, z->data, &size); | ||||
|   lua_lock(L); | ||||
|   if (buff == NULL || size == 0) return EOZ; | ||||
|   z->n = size - 1; | ||||
|   z->p = buff; | ||||
|   return char2int(*(z->p++)); | ||||
| } | ||||
|  | ||||
|  | ||||
| int luaZ_lookahead (ZIO *z) { | ||||
|   if (z->n == 0) { | ||||
|     if (luaZ_fill(z) == EOZ) | ||||
|       return EOZ; | ||||
|     else { | ||||
|       z->n++;  /* luaZ_fill removed first byte; put back it */ | ||||
|       z->p--; | ||||
|     } | ||||
|   } | ||||
|   return char2int(*z->p); | ||||
| } | ||||
|  | ||||
|  | ||||
| void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { | ||||
|   z->L = L; | ||||
|   z->reader = reader; | ||||
|   z->data = data; | ||||
|   z->n = 0; | ||||
|   z->p = NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* --------------------------------------------------------------- read --- */ | ||||
| size_t luaZ_read (ZIO *z, void *b, size_t n) { | ||||
|   while (n) { | ||||
|     size_t m; | ||||
|     if (luaZ_lookahead(z) == EOZ) | ||||
|       return n;  /* return number of missing bytes */ | ||||
|     m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */ | ||||
|     memcpy(b, z->p, m); | ||||
|     z->n -= m; | ||||
|     z->p += m; | ||||
|     b = (char *)b + m; | ||||
|     n -= m; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------------------------ */ | ||||
| char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { | ||||
|   if (n > buff->buffsize) { | ||||
|     if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; | ||||
|     luaZ_resizebuffer(L, buff, n); | ||||
|   } | ||||
|   return buff->buffer; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										227
									
								
								lua/src/print.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								lua/src/print.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| /* | ||||
| ** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ | ||||
| ** print bytecodes | ||||
| ** See Copyright Notice in lua.h | ||||
| */ | ||||
| #include "stdafx.h" | ||||
| #include <ctype.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #define luac_c | ||||
| #define LUA_CORE | ||||
|  | ||||
| #include "ldebug.h" | ||||
| #include "lobject.h" | ||||
| #include "lopcodes.h" | ||||
| #include "lundump.h" | ||||
|  | ||||
| #define PrintFunction	luaU_print | ||||
|  | ||||
| #define Sizeof(x)	((int)sizeof(x)) | ||||
| #define VOID(p)		((const void*)(p)) | ||||
|  | ||||
| static void PrintString(const TString* ts) | ||||
| { | ||||
|  const char* s=getstr(ts); | ||||
|  size_t i,n=ts->tsv.len; | ||||
|  putchar('"'); | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   int c=s[i]; | ||||
|   switch (c) | ||||
|   { | ||||
|    case '"': printf("\\\""); break; | ||||
|    case '\\': printf("\\\\"); break; | ||||
|    case '\a': printf("\\a"); break; | ||||
|    case '\b': printf("\\b"); break; | ||||
|    case '\f': printf("\\f"); break; | ||||
|    case '\n': printf("\\n"); break; | ||||
|    case '\r': printf("\\r"); break; | ||||
|    case '\t': printf("\\t"); break; | ||||
|    case '\v': printf("\\v"); break; | ||||
|    default:	if (isprint((unsigned char)c)) | ||||
|    			putchar(c); | ||||
| 		else | ||||
| 			printf("\\%03u",(unsigned char)c); | ||||
|   } | ||||
|  } | ||||
|  putchar('"'); | ||||
| } | ||||
|  | ||||
| static void PrintConstant(const Proto* f, int i) | ||||
| { | ||||
|  const TValue* o=&f->k[i]; | ||||
|  switch (ttype(o)) | ||||
|  { | ||||
|   case LUA_TNIL: | ||||
| 	printf("nil"); | ||||
| 	break; | ||||
|   case LUA_TBOOLEAN: | ||||
| 	printf(bvalue(o) ? "true" : "false"); | ||||
| 	break; | ||||
|   case LUA_TNUMBER: | ||||
| 	printf(LUA_NUMBER_FMT,nvalue(o)); | ||||
| 	break; | ||||
|   case LUA_TSTRING: | ||||
| 	PrintString(rawtsvalue(o)); | ||||
| 	break; | ||||
|   default:				/* cannot happen */ | ||||
| 	printf("? type=%d",ttype(o)); | ||||
| 	break; | ||||
|  } | ||||
| } | ||||
|  | ||||
| static void PrintCode(const Proto* f) | ||||
| { | ||||
|  const Instruction* code=f->code; | ||||
|  int pc,n=f->sizecode; | ||||
|  for (pc=0; pc<n; pc++) | ||||
|  { | ||||
|   Instruction i=code[pc]; | ||||
|   OpCode o=GET_OPCODE(i); | ||||
|   int a=GETARG_A(i); | ||||
|   int b=GETARG_B(i); | ||||
|   int c=GETARG_C(i); | ||||
|   int bx=GETARG_Bx(i); | ||||
|   int sbx=GETARG_sBx(i); | ||||
|   int line=getline(f,pc); | ||||
|   printf("\t%d\t",pc+1); | ||||
|   if (line>0) printf("[%d]\t",line); else printf("[-]\t"); | ||||
|   printf("%-9s\t",luaP_opnames[o]); | ||||
|   switch (getOpMode(o)) | ||||
|   { | ||||
|    case iABC: | ||||
|     printf("%d",a); | ||||
|     if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); | ||||
|     if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); | ||||
|     break; | ||||
|    case iABx: | ||||
|     if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); | ||||
|     break; | ||||
|    case iAsBx: | ||||
|     if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); | ||||
|     break; | ||||
|   } | ||||
|   switch (o) | ||||
|   { | ||||
|    case OP_LOADK: | ||||
|     printf("\t; "); PrintConstant(f,bx); | ||||
|     break; | ||||
|    case OP_GETUPVAL: | ||||
|    case OP_SETUPVAL: | ||||
|     printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); | ||||
|     break; | ||||
|    case OP_GETGLOBAL: | ||||
|    case OP_SETGLOBAL: | ||||
|     printf("\t; %s",svalue(&f->k[bx])); | ||||
|     break; | ||||
|    case OP_GETTABLE: | ||||
|    case OP_SELF: | ||||
|     if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } | ||||
|     break; | ||||
|    case OP_SETTABLE: | ||||
|    case OP_ADD: | ||||
|    case OP_SUB: | ||||
|    case OP_MUL: | ||||
|    case OP_DIV: | ||||
|    case OP_POW: | ||||
|    case OP_EQ: | ||||
|    case OP_LT: | ||||
|    case OP_LE: | ||||
|     if (ISK(b) || ISK(c)) | ||||
|     { | ||||
|      printf("\t; "); | ||||
|      if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); | ||||
|      printf(" "); | ||||
|      if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); | ||||
|     } | ||||
|     break; | ||||
|    case OP_JMP: | ||||
|    case OP_FORLOOP: | ||||
|    case OP_FORPREP: | ||||
|     printf("\t; to %d",sbx+pc+2); | ||||
|     break; | ||||
|    case OP_CLOSURE: | ||||
|     printf("\t; %p",VOID(f->p[bx])); | ||||
|     break; | ||||
|    case OP_SETLIST: | ||||
|     if (c==0) printf("\t; %d",(int)code[++pc]); | ||||
|     else printf("\t; %d",c); | ||||
|     break; | ||||
|    default: | ||||
|     break; | ||||
|   } | ||||
|   printf("\n"); | ||||
|  } | ||||
| } | ||||
|  | ||||
| #define SS(x)	(x==1)?"":"s" | ||||
| #define S(x)	x,SS(x) | ||||
|  | ||||
| static void PrintHeader(const Proto* f) | ||||
| { | ||||
|  const char* s=getstr(f->source); | ||||
|  if (*s=='@' || *s=='=') | ||||
|   s++; | ||||
|  else if (*s==LUA_SIGNATURE[0]) | ||||
|   s="(bstring)"; | ||||
|  else | ||||
|   s="(string)"; | ||||
|  printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", | ||||
|  	(f->linedefined==0)?"main":"function",s, | ||||
| 	f->linedefined,f->lastlinedefined, | ||||
| 	S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); | ||||
|  printf("%d%s param%s, %d slot%s, %d upvalue%s, ", | ||||
| 	f->numparams,f->is_vararg?"+":"",SS(f->numparams), | ||||
| 	S(f->maxstacksize),S(f->nups)); | ||||
|  printf("%d local%s, %d constant%s, %d function%s\n", | ||||
| 	S(f->sizelocvars),S(f->sizek),S(f->sizep)); | ||||
| } | ||||
|  | ||||
| static void PrintConstants(const Proto* f) | ||||
| { | ||||
|  int i,n=f->sizek; | ||||
|  printf("constants (%d) for %p:\n",n,VOID(f)); | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   printf("\t%d\t",i+1); | ||||
|   PrintConstant(f,i); | ||||
|   printf("\n"); | ||||
|  } | ||||
| } | ||||
|  | ||||
| static void PrintLocals(const Proto* f) | ||||
| { | ||||
|  int i,n=f->sizelocvars; | ||||
|  printf("locals (%d) for %p:\n",n,VOID(f)); | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   printf("\t%d\t%s\t%d\t%d\n", | ||||
|   i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); | ||||
|  } | ||||
| } | ||||
|  | ||||
| static void PrintUpvalues(const Proto* f) | ||||
| { | ||||
|  int i,n=f->sizeupvalues; | ||||
|  printf("upvalues (%d) for %p:\n",n,VOID(f)); | ||||
|  if (f->upvalues==NULL) return; | ||||
|  for (i=0; i<n; i++) | ||||
|  { | ||||
|   printf("\t%d\t%s\n",i,getstr(f->upvalues[i])); | ||||
|  } | ||||
| } | ||||
|  | ||||
| void PrintFunction(const Proto* f, int full) | ||||
| { | ||||
|  int i,n=f->sizep; | ||||
|  PrintHeader(f); | ||||
|  PrintCode(f); | ||||
|  if (full) | ||||
|  { | ||||
|   PrintConstants(f); | ||||
|   PrintLocals(f); | ||||
|   PrintUpvalues(f); | ||||
|  } | ||||
|  for (i=0; i<n; i++) PrintFunction(f->p[i],full); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user