*/
#include <list>
+#include <map>
#include <string>
+#include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <lua.hpp>
#include <Moof/Exception.hh>
+#include <Moof/Log.hh>
namespace Mf {
* Value will be invalid even if index is manually changed to a valid
* index. You have to index the script itself to get a valid Value.
*/
- Value() :
- index(0),
- state(0) {}
-
- Value(lua_State* s, int i) :
+ Value(lua_State* s = 0, int i = 0) :
index(i),
state(s) {}
+ /**
+ * A copied value presently points to the same value, except the real
+ * index is used. That means that if a value that refers to a frame
+ * referenced from the top of the stack will have its normalized index
+ * copied into the new value object.
+ */
+
+ Value(const Value& copy) :
+ index(copy.getRealIndex()),
+ state(copy.state) {}
+
+
// check the type of the value
bool isBoolean() const { return (bool)lua_isboolean(state, index); }
bool isFunction() const { return (bool)lua_isfunction(state, index); }
bool isData() const { return (bool)lua_isuserdata(state, index); }
bool isLightData() const { return (bool)lua_islightuserdata(state, index); }
+ /**
+ * Check the value and throw and error if its the wrong type. This
+ * method never returns because it does a long jump. Consequently,
+ * constructed C++ objects which exist on the stack between the current
+ * frame and some lua function will not be destructed. That's not a
+ * problem for objects that only exist on the stack, but any objects
+ * that allocate memory on the heap (such as containers or strings) will
+ * leak. Therefore, you should only call this method after cleaning up
+ * such objects.
+ */
+
+ void requireType(TYPE type) const
+ {
+ if (type != getType())
+ {
+ luaL_typerror(state, index, lua_typename(state, type));
+ }
+ }
+
+ void throwError(const char* error)
+ {
+ luaL_argerror(state, index, error);
+ }
+
+
+ Value& requireBoolean()
+ {
+ if (!isBoolean()) luaL_typerror(state, index, "boolean");
+ return *this;
+ }
+ Value& requireNumber()
+ {
+ if (!isNumber()) luaL_typerror(state, index, "number");
+ return *this;
+ }
+ Value& requireString()
+ {
+ if (!isString()) luaL_typerror(state, index, "string");
+ return *this;
+ }
+ Value& requireTable()
+ {
+ if (!isTable()) luaL_typerror(state, index, "table");
+ return *this;
+ }
+ Value& requireFunction()
+ {
+ if (!isFunction()) luaL_typerror(state, index, "function");
+ return *this;
+ }
+ Value& requireData()
+ {
+ if (!isData()) luaL_typerror(state, index, "data");
+ return *this;
+ }
+ Value& requireNil()
+ {
+ if (!isNil()) luaL_typerror(state, index, "nil");
+ return *this;
+ }
+ Value& requireThread()
+ {
+ if (!isThread()) luaL_typerror(state, index, "thread");
+ return *this;
+ }
+
+
/**
* Get the type of the value.
*/
std::string getTypeName() const
{
- return std::string(lua_typename(state, (int)getType()));
+ return std::string(luaL_typename(state, index));
}
+
+ /**
+ * Get the length of the value according to the definition given by Lua.
+ */
+
+ size_t getLength() const
+ {
+ return lua_objlen(state, index);
+ }
+
+ int getRealIndex() const
+ {
+ if (index < 0) return lua_gettop(state) + 1 + index;
+ else return index;
+ }
+
+
/**
* Get a pointer value (for userdata, tables, threads, and functions).
*/
}
- /**
- * Get the length of the value according to the definition given by Lua.
- */
-
- size_t getLength() const
- {
- return lua_objlen(state, index);
- }
-
-
/**
* Convert the underlying value to a C++ type.
*/
template <typename T>
- void get(T& value) const
+ bool get(T& value) const
{
- value = (T)lua_tointeger(state, index);
+ if (isNumber())
+ {
+ value = (T)lua_tointeger(state, index);
+ return true;
+ }
+ return false;
}
- void get(bool& value) const
+ bool get(float& value) const
{
- value = (bool)lua_toboolean(state, index);
+ if (isNumber())
+ {
+ value = (float)lua_tonumber(state, index);
+ return true;
+ }
+ return false;
}
-
- void get(float& value) const
+ bool get(double& value) const
{
- value = (float)lua_tonumber(state, index);
+ if (isNumber())
+ {
+ value = (double)lua_tonumber(state, index);
+ return true;
+ }
+ return false;
}
- void get(double& value) const
+
+ bool get(bool& value) const
{
- value = (double)lua_tonumber(state, index);
+ if (isBoolean())
+ {
+ value = (bool)lua_toboolean(state, index);
+ return true;
+ }
+ return false;
}
- void get(std::string& value) const
+ bool get(std::string& value) const
{
- size_t size;
- const char* str = lua_tolstring(state, index, &size);
- value.assign(str, size);
+ if (isString())
+ {
+ size_t size;
+ const char* str = lua_tolstring(state, index, &size);
+ value.assign(str, size);
+ return true;
+ }
+ return false;
}
+ template <typename T>
+ bool get(std::vector<T>& array) const
+ {
+ if (!isTable()) return false;
+
+ array.clear();
+
+ Value value(state, -1);
+ int realIndex = getRealIndex();
+
+ bool done = false;
+ for (int i = 1; !done; ++i)
+ {
+ lua_rawgeti(state, realIndex, i);
- void set(std::string& value)
+ T v;
+ if (value.get(v)) array.push_back(v);
+ else done = true;
+
+ lua_pop(state, 1);
+ }
+
+ return true;
+ }
+
+ template <typename T>
+ bool get(std::map<std::string,T>& dictionary) const
{
+ if (!isTable()) return false;
+
+ dictionary.clear();
+
+ Value key(state, -2);
+ Value value(state, -1);
+ int realIndex = getRealIndex();
+
+ lua_pushnil(state);
+ while (lua_next(state, realIndex) != 0)
+ {
+ std::string k;
+ if (!key.isNumber() && key.get(k))
+ {
+ T v;
+ if (value.get(v)) dictionary[k] = v;
+ }
+ lua_pop(state, 1);
+ }
+ lua_pop(state, 1);
+
+ return true;
}
- //template <typename T>
- //void get(const std::string& field, T& value) const
- //{
- ////lua_getfield(state_, field.c_str());
- //pushField(field);
- //get(-1, value);
- //lua_pop(state_, 1);
- //}
-
+
/**
* Copy the value and push the copy to the stack.
}
+ /**
+ * Throw an error with the value at the top of the stack. This method never
+ * returns because it does a long jump. Consequently, constructed C++
+ * objects which exist on the stack between the current frame and some lua
+ * function will not be destructed. That's not a problem for objects that
+ * only exist on the stack, but any objects that allocate memory on the heap
+ * (such as containers or strings) will leak. Therefore, you should only
+ * call this method after cleaning up such objects.
+ */
+
+ void throwError()
+ {
+ lua_error(state_);
+ }
+
+
/**
* Get significant values.
*/
{
lua_pushlstring(state_, value.c_str(), value.length());
}
+ void push(const char* value)
+ {
+ lua_pushstring(state_, value);
+ }
void push(const char* value, size_t length)
{
lua_pushlstring(state_, value, length);
* Pops n values from the top of the stack.
*/
- void pop(int n)
+ void pop(int n = 1)
{
lua_pop(state_, n);
}