diff options
Diffstat (limited to 'Sluift/Lua')
-rw-r--r-- | Sluift/Lua/Check.cpp | 60 | ||||
-rw-r--r-- | Sluift/Lua/Check.h | 26 | ||||
-rw-r--r-- | Sluift/Lua/Debug.h | 28 | ||||
-rw-r--r-- | Sluift/Lua/Exception.cpp | 15 | ||||
-rw-r--r-- | Sluift/Lua/Exception.h | 20 | ||||
-rw-r--r-- | Sluift/Lua/FunctionRegistration.cpp | 16 | ||||
-rw-r--r-- | Sluift/Lua/FunctionRegistration.h | 36 | ||||
-rw-r--r-- | Sluift/Lua/FunctionRegistry.cpp | 55 | ||||
-rw-r--r-- | Sluift/Lua/FunctionRegistry.h | 46 | ||||
-rw-r--r-- | Sluift/Lua/LuaUtils.cpp | 79 | ||||
-rw-r--r-- | Sluift/Lua/LuaUtils.h | 32 | ||||
-rw-r--r-- | Sluift/Lua/Value.cpp | 11 | ||||
-rw-r--r-- | Sluift/Lua/Value.h | 28 |
13 files changed, 447 insertions, 5 deletions
diff --git a/Sluift/Lua/Check.cpp b/Sluift/Lua/Check.cpp new file mode 100644 index 0000000..cfb726a --- /dev/null +++ b/Sluift/Lua/Check.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/Check.h> + +#include <boost/numeric/conversion/cast.hpp> +#include <iostream> +#include <sstream> +#include <lua.hpp> + +#include <Sluift/Lua/Exception.h> + +using namespace Swift; + + +static std::string getArgTypeError(lua_State* L, int arg, int tag) { + std::ostringstream s; + s << "Arg " << arg << ": expected " << lua_typename(L, tag) << ", got " << luaL_typename(L, arg); + return s.str(); +} + +void Lua::checkType(lua_State* L, int arg, int type) { + if (lua_type(L, arg) != type) { + throw Lua::Exception(getArgTypeError(L, arg, type)); + } +} + +int Lua::checkIntNumber(lua_State* L, int arg) { + if (!lua_isnumber(L, arg)) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TNUMBER)); + } + return boost::numeric_cast<int>(lua_tonumber(L, arg)); +} + +std::string Lua::checkString(lua_State* L, int arg) { + const char *s = lua_tolstring(L, arg, NULL); + if (!s) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TSTRING)); + } + return std::string(s); +} + +void* Lua::checkUserDataRaw(lua_State* L, int arg, const char* tableName) { + void* userData = lua_touserdata(L, arg); + if (!userData) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA)); + } + if (!lua_getmetatable(L, arg)) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA)); + } + lua_getfield(L, LUA_REGISTRYINDEX, tableName); + if (!lua_rawequal(L, -1, -2)) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA)); + } + lua_pop(L, 2); + return userData; +} diff --git a/Sluift/Lua/Check.h b/Sluift/Lua/Check.h new file mode 100644 index 0000000..a569826 --- /dev/null +++ b/Sluift/Lua/Check.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <string> + +struct lua_State; + +namespace Swift { + namespace Lua { + void checkType(lua_State* L, int arg, int type); + int checkIntNumber(lua_State* L, int arg); + std::string checkString(lua_State* L, int arg); + + void* checkUserDataRaw(lua_State* L, int arg, const char* tableName); + + template<typename T> + T** checkUserData(lua_State* L, int arg, const char* tableName) { + return reinterpret_cast<T**>(checkUserDataRaw(L, arg, tableName)); + } + } +} diff --git a/Sluift/Lua/Debug.h b/Sluift/Lua/Debug.h new file mode 100644 index 0000000..8e86b89 --- /dev/null +++ b/Sluift/Lua/Debug.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <lua.hpp> +#include <iostream> + +namespace Swift { + namespace Lua { + inline void dumpStack(lua_State *L) { + for (int i = 1; i <= lua_gettop(L); i++) { + int type = lua_type(L, i); + std::cout << i << ": [" << lua_typename(L, type) << "] "; + switch (type) { + case LUA_TSTRING: std::cout << lua_tostring(L, i); break; + case LUA_TNUMBER: std::cout << lua_tonumber(L, i); break; + case LUA_TBOOLEAN: std::cout << lua_toboolean(L, i); break; + default: break; + } + std::cout << std::endl; + } + } + } +} diff --git a/Sluift/Lua/Exception.cpp b/Sluift/Lua/Exception.cpp new file mode 100644 index 0000000..d80b9fb --- /dev/null +++ b/Sluift/Lua/Exception.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/Exception.h> + +using namespace Swift::Lua; + +Exception::Exception(const std::string& what) : std::runtime_error(what) { +} + +Exception::~Exception() throw() { +} diff --git a/Sluift/Lua/Exception.h b/Sluift/Lua/Exception.h new file mode 100644 index 0000000..6d00d01 --- /dev/null +++ b/Sluift/Lua/Exception.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <stdexcept> + +namespace Swift { + namespace Lua { + class Exception : public std::runtime_error { + public: + Exception(const std::string& what); + virtual ~Exception() throw(); + }; + } +} + diff --git a/Sluift/Lua/FunctionRegistration.cpp b/Sluift/Lua/FunctionRegistration.cpp new file mode 100644 index 0000000..b773952 --- /dev/null +++ b/Sluift/Lua/FunctionRegistration.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/FunctionRegistration.h> + +using namespace Swift::Lua; + +FunctionRegistration::FunctionRegistration(const std::string& name, lua_CFunction function, const std::string& type) { + FunctionRegistry::getInstance().addFunction(name, function, type); +} + +FunctionRegistration::~FunctionRegistration() { +} diff --git a/Sluift/Lua/FunctionRegistration.h b/Sluift/Lua/FunctionRegistration.h new file mode 100644 index 0000000..0df1da1 --- /dev/null +++ b/Sluift/Lua/FunctionRegistration.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Sluift/Lua/FunctionRegistry.h> +#include <lua.hpp> +#include <string> + +namespace Swift { + namespace Lua { + class FunctionRegistration { + public: + FunctionRegistration(const std::string& name, lua_CFunction function, const std::string& type); + ~FunctionRegistration(); + }; + } +} +#define SLUIFT_LUA_FUNCTION(TYPE, NAME) \ + static int TYPE##_##NAME(lua_State* L); \ + static int TYPE##_##NAME##_wrapper(lua_State* L); \ + static ::Swift::Lua::FunctionRegistration TYPE##_##NAME##_registration( #NAME , TYPE##_##NAME##_wrapper, #TYPE); \ + static int TYPE##_##NAME##_wrapper(lua_State* L) { \ + try { \ + return TYPE ## _ ## NAME (L); \ + } \ + catch (const std::exception& e) { \ + return luaL_error(L, e.what()); \ + } \ + } \ + static int TYPE ## _ ## NAME (lua_State* L) diff --git a/Sluift/Lua/FunctionRegistry.cpp b/Sluift/Lua/FunctionRegistry.cpp new file mode 100644 index 0000000..99ea096 --- /dev/null +++ b/Sluift/Lua/FunctionRegistry.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/FunctionRegistry.h> + +#include <Swiften/Base/foreach.h> + +using namespace Swift::Lua; + +FunctionRegistry::FunctionRegistry() { +} + +FunctionRegistry::~FunctionRegistry() { +} + +FunctionRegistry& FunctionRegistry::getInstance() { + static FunctionRegistry instance; + return instance; +} + +void FunctionRegistry::addFunction(const std::string& name, lua_CFunction function, const std::string& type) { + Registration registration; + registration.name = name; + registration.function = function; + registration.type = type; + registrations.push_back(registration); +} + +std::string FunctionRegistry::getMetaTableNameForType(const std::string& type) { + return "Sluift_" + type; +} + +void FunctionRegistry::registerTypeMetaTable(lua_State* L, const std::string& type) { + luaL_newmetatable(L, getMetaTableNameForType(type).c_str()); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + addFunctionsToTable(L, type); +} + +void FunctionRegistry::createFunctionTable(lua_State* L, const std::string& type) { + lua_newtable(L); + addFunctionsToTable(L, type); +} + +void FunctionRegistry::addFunctionsToTable(lua_State* L, const std::string& type) { + foreach(const Registration& registration, registrations) { + if (registration.type == type) { + lua_pushcclosure(L, registration.function, 0); + lua_setfield(L, -2, registration.name.c_str()); + } + } +} diff --git a/Sluift/Lua/FunctionRegistry.h b/Sluift/Lua/FunctionRegistry.h new file mode 100644 index 0000000..e3ad620 --- /dev/null +++ b/Sluift/Lua/FunctionRegistry.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <lua.hpp> +#include <string> +#include <vector> + +namespace Swift { + namespace Lua { + class FunctionRegistry { + public: + ~FunctionRegistry(); + static FunctionRegistry& getInstance(); + + void addFunction(const std::string& name, lua_CFunction function, const std::string& type); + + static std::string getMetaTableNameForType(const std::string& type); + void registerTypeMetaTable(lua_State* L, const std::string& type); + + void createFunctionTable(lua_State* L, const std::string& type); + + /** + * Adds the functions to the table on the top of the stack. + */ + void addFunctionsToTable(lua_State* L, const std::string& type); + + private: + FunctionRegistry(); + + + private: + struct Registration { + std::string name; + lua_CFunction function; + std::string type; + }; + std::vector<Registration> registrations; + }; + } +} diff --git a/Sluift/Lua/LuaUtils.cpp b/Sluift/Lua/LuaUtils.cpp new file mode 100644 index 0000000..7052abe --- /dev/null +++ b/Sluift/Lua/LuaUtils.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/LuaUtils.h> + +#include <lua.hpp> + +#include <boost/scope_exit.hpp> +#include <Sluift/Lua/Exception.h> +#include <iostream> +#include <cassert> +#include <sstream> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/globals.h> + +using namespace Swift::Lua; + +static const std::string INDENT = " "; + +void Swift::Lua::registerTableToString(lua_State* L, int index) { + index = Lua::absoluteOffset(L, index); + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, "register_table_tostring"); + lua_pushvalue(L, index); + if (lua_pcall(L, 1, 0, 0) != 0) { + throw Lua::Exception(lua_tostring(L, -1)); + } + lua_pop(L, 1); +} + +void Swift::Lua::registerGetByTypeIndex(lua_State* L, int index) { + index = Lua::absoluteOffset(L, index); + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, "register_get_by_type_index"); + lua_pushvalue(L, index); + if (lua_pcall(L, 1, 0, 0) != 0) { + throw Lua::Exception(lua_tostring(L, -1)); + } + lua_pop(L, 1); +} + +boost::optional<std::string> Swift::Lua::getStringField(lua_State* L, int index, const std::string& field) { + lua_getfield(L, index, field.c_str()); + // Seems to generate warnings with some versions of CLang that i can't turn off. + // Leaving the more elegant code here, hoping we can re-enable it later (newer boost? c++11?). + // The same applies to the other get*Field functions. + //BOOST_SCOPE_EXIT(&L) { lua_pop(L,1); } BOOST_SCOPE_EXIT_END + //return lua_isstring(L, -1) ? std::string(lua_tostring(L, -1)) : boost::optional<std::string>(); + + boost::optional<std::string> result; + if (lua_isstring(L, -1)) { + result = std::string(lua_tostring(L, -1)); + } + lua_pop(L, 1); + return result; +} + +boost::optional<bool> Swift::Lua::getBooleanField(lua_State* L, int index, const std::string& field) { + lua_getfield(L, index, field.c_str()); + boost::optional<bool> result; + if (lua_isboolean(L, -1)) { + result = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return result; +} + +boost::optional<int> Swift::Lua::getIntField(lua_State* L, int index, const std::string& field) { + lua_getfield(L, index, field.c_str()); + boost::optional<int> result; + if (lua_isnumber(L, -1)) { + result = boost::numeric_cast<int>(lua_tonumber(L, -1)); + } + lua_pop(L, 1); + return result; +} diff --git a/Sluift/Lua/LuaUtils.h b/Sluift/Lua/LuaUtils.h new file mode 100644 index 0000000..bad307c --- /dev/null +++ b/Sluift/Lua/LuaUtils.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <lua.hpp> +#include <boost/optional.hpp> + +struct lua_State; + +namespace Swift { + namespace Lua { + /** + * Can be used as __tostring metamethod on a table. + */ + int convertTableToString(lua_State* L); + + void registerTableToString(lua_State* L, int index); + void registerGetByTypeIndex(lua_State* L, int index); + + inline int absoluteOffset(lua_State* L, int index) { + return index > 0 ? index : lua_gettop(L) + index + 1; + } + + boost::optional<std::string> getStringField(lua_State* L, int index, const std::string&); + boost::optional<bool> getBooleanField(lua_State* L, int index, const std::string&); + boost::optional<int> getIntField(lua_State* L, int index, const std::string&); + } +} diff --git a/Sluift/Lua/Value.cpp b/Sluift/Lua/Value.cpp index 3164ec6..4f8078e 100644 --- a/Sluift/Lua/Value.cpp +++ b/Sluift/Lua/Value.cpp @@ -6,8 +6,11 @@ #include "Value.h" -#include <lualib.h> +extern "C" { + #include <lualib.h> +} #include <boost/variant/apply_visitor.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/foreach.h> using namespace Swift; @@ -35,15 +38,15 @@ namespace { } void operator()(const std::vector<Value>& values) const { - lua_createtable(state, values.size(), 0); + lua_createtable(state, boost::numeric_cast<int>(values.size()), 0); for(size_t i = 0; i < values.size(); ++i) { boost::apply_visitor(PushVisitor(state), values[i]); - lua_rawseti(state, -2, i + 1); + lua_rawseti(state, -2, boost::numeric_cast<int>(i + 1)); } } void operator()(const std::map<std::string, boost::shared_ptr<Value> >& table) const { - lua_createtable(state, 0, table.size()); + lua_createtable(state, 0, boost::numeric_cast<int>(table.size())); for(std::map<std::string, boost::shared_ptr<Value> >::const_iterator i = table.begin(); i != table.end(); ++i) { boost::apply_visitor(PushVisitor(state), *i->second); lua_setfield(state, -2, i->first.c_str()); diff --git a/Sluift/Lua/Value.h b/Sluift/Lua/Value.h index 7b10cd2..55aa347 100644 --- a/Sluift/Lua/Value.h +++ b/Sluift/Lua/Value.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,6 +11,7 @@ #include <vector> #include <boost/variant.hpp> #include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> struct lua_State; @@ -28,7 +29,32 @@ namespace Swift { >::type Value; typedef std::map<std::string, boost::shared_ptr<Value> > Table; + typedef std::vector<Value> Array; + inline boost::shared_ptr<Value> nilRef() { + return boost::make_shared<Value>(Nil()); + } + + inline boost::shared_ptr<Value> valueRef(const std::string& value) { + return boost::make_shared<Value>(value); + } + + inline boost::shared_ptr<Value> intRef(int value) { + return boost::make_shared<Value>(value); + } + + inline boost::shared_ptr<Value> boolRef(bool value) { + return boost::make_shared<Value>(value); + } + + inline boost::shared_ptr<Value> valueRef(const Table& table) { + return boost::make_shared<Value>(table); + } + + inline boost::shared_ptr<Value> valueRef(const Array& array) { + return boost::make_shared<Value>(array); + } + void pushValue(lua_State* state, const Value& value); } } |