summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Sluift/Lua')
-rw-r--r--Sluift/Lua/Check.cpp60
-rw-r--r--Sluift/Lua/Check.h26
-rw-r--r--Sluift/Lua/Debug.h28
-rw-r--r--Sluift/Lua/Exception.cpp15
-rw-r--r--Sluift/Lua/Exception.h20
-rw-r--r--Sluift/Lua/FunctionRegistration.cpp16
-rw-r--r--Sluift/Lua/FunctionRegistration.h36
-rw-r--r--Sluift/Lua/FunctionRegistry.cpp55
-rw-r--r--Sluift/Lua/FunctionRegistry.h46
-rw-r--r--Sluift/Lua/LuaUtils.cpp79
-rw-r--r--Sluift/Lua/LuaUtils.h32
-rw-r--r--Sluift/Lua/Value.cpp11
-rw-r--r--Sluift/Lua/Value.h28
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);
}
}