-/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
+/*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
**] All rights reserved.
*
-* vi:ts=4 sw=4 tw=75
-*
* Distributable under the terms and conditions of the 2-clause BSD license;
* see the file COPYING for a complete text of the license.
*
-**************************************************************************/
+*****************************************************************************/
#ifndef _MOOF_SCRIPT_HH_
#define _MOOF_SCRIPT_HH_
* \file script.hh
* A thin wrapper over Lua 5.1. This is not meant as a complicated binding
* package between C++ and Lua. It is not meant to obscure the division
- * between C++ and Lua but rather to clarify it and make it more
- * manageable. It does not hide the concept of the Lua stack, but rather
- * provides that mechanism with a certain level of abstraction while also
- * providing a cleaner, more consistent API.
+ * between C++ and Lua but rather to clarify it and make it more manageable.
+ * It does not hide the concept of the Lua stack, but rather provides that
+ * mechanism with a certain level of abstraction while also providing a
+ * cleaner, more consistent API.
*/
#include <cstring>
class script;
typedef boost::shared_ptr<script> script_ptr;
-
class script
{
public:
enum status
{
- success = 0,
- yielding = LUA_YIELD,
+ success = 0,
+ yielding = LUA_YIELD,
runtime_error = LUA_ERRRUN,
syntax_error = LUA_ERRSYNTAX,
memory_error = LUA_ERRMEM,
handler_error = LUA_ERRERR,
- file_error = LUA_ERRFILE
+ file_error = LUA_ERRFILE
};
enum pseudoindex
globals_index = LUA_GLOBALSINDEX
};
-
template <class T>
static int object_finalizer(script& script)
{
return 0;
}
-
/**
* This is the most prominent abstraction on top of the standard Lua
* API. A slot object represents a value on the stack. More
* specifically, it represents a position on the stack. The
* distinction is only important when objects are moved around on the
* stack or if the slot represents a negative index on the stack (the
- * value of which will change as things are pushed onto and popped from
- * the stack).
+ * value of which will change as things are pushed onto and popped
+ * from the stack).
*/
struct slot
{
/**
- * You have direct access to the index of the value on the stack
- * being represented.
+ * You have direct access to the index of the value on the
+ * stack being represented.
*/
int index;
-
enum type
{
- none = LUA_TNONE,
- nil = LUA_TNIL,
- boolean = LUA_TBOOLEAN,
- light_data = LUA_TLIGHTUSERDATA,
- number = LUA_TNUMBER,
- string = LUA_TSTRING,
- table = LUA_TTABLE,
- function = LUA_TFUNCTION,
- data = LUA_TUSERDATA,
- thread = LUA_TTHREAD
+ none = LUA_TNONE,
+ nil = LUA_TNIL,
+ boolean = LUA_TBOOLEAN,
+ light_data = LUA_TLIGHTUSERDATA,
+ number = LUA_TNUMBER,
+ string = LUA_TSTRING,
+ table = LUA_TTABLE,
+ function = LUA_TFUNCTION,
+ data = LUA_TUSERDATA,
+ thread = LUA_TTHREAD
};
static std::string type_name(type type)
{
switch (type)
{
- case none: return "none";
- case nil: return "nil";
- case boolean: return "boolean";
+ case none: return "none";
+ case nil: return "nil";
+ case boolean: return "boolean";
case light_data:
- case data: return "userdata";
- case number: return "number";
- case string: return "string";
- case table: return "table";
- case function: return "function";
- case thread: return "thread";
+ case data: return "userdata";
+ case number: return "number";
+ case string: return "string";
+ case table: return "table";
+ case function: return "function";
+ case thread: return "thread";
}
return "?";
}
-
slot(const class script& s, int i = 0) :
index(i),
script_(const_cast<class script*>(&s)) {}
-
// check the type of the value
bool is_boolean() const
- { return (bool)lua_isboolean(script_->state_, index); }
+ {
+ return (bool)lua_isboolean(script_->state_, index);
+ }
bool is_imported_function() const
- { return (bool)lua_iscfunction(script_->state_, index); }
+ {
+ return (bool)lua_iscfunction(script_->state_, index);
+ }
bool is_function() const
- { return (bool)lua_isfunction(script_->state_, index); }
+ {
+ return (bool)lua_isfunction(script_->state_, index);
+ }
bool is_nil() const
- { return (bool)lua_isnil(script_->state_, index); }
+ {
+ return (bool)lua_isnil(script_->state_, index);
+ }
bool is_none() const
- { return (bool)lua_isnone(script_->state_, index); }
+ {
+ return (bool)lua_isnone(script_->state_, index);
+ }
bool is_none_or_nil() const
- { return (bool)lua_isnoneornil(script_->state_, index); }
+ {
+ return (bool)lua_isnoneornil(script_->state_, index);
+ }
bool is_number() const
- { return (bool)lua_isnumber(script_->state_, index); }
+ {
+ return (bool)lua_isnumber(script_->state_, index);
+ }
bool is_string() const
- { return (bool)lua_isstring(script_->state_, index); }
+ {
+ return (bool)lua_isstring(script_->state_, index);
+ }
bool is_table() const
- { return (bool)lua_istable(script_->state_, index); }
+ {
+ return (bool)lua_istable(script_->state_, index);
+ }
bool is_thread() const
- { return (bool)lua_isthread(script_->state_, index); }
+ {
+ return (bool)lua_isthread(script_->state_, index);
+ }
bool is_data() const
- { return (bool)lua_isuserdata(script_->state_, index); }
+ {
+ return (bool)lua_isuserdata(script_->state_, index);
+ }
bool is_light_data() const
- { return (bool)lua_islightuserdata(script_->state_, index); }
+ {
+ return (bool)lua_islightuserdata(script_->state_, index);
+ }
/**
* Check the value and throw an error if its the wrong type.
return *this;
}
- const slot& require_boolean(const std::string& what = "boolean") const
+ const slot&
+ require_boolean(const std::string& what = "boolean") const
{
if (!is_boolean()) raise_type_error(what);
return *this;
}
- const slot& require_number(const std::string& what = "number") const
+ const slot&
+ require_number(const std::string& what = "number") const
{
if (!is_number()) raise_type_error(what);
return *this;
}
- const slot& require_string(const std::string& what = "string") const
+ const slot&
+ require_string(const std::string& what = "string") const
{
if (!is_string()) raise_type_error(what);
return *this;
}
- const slot& require_table(const std::string& what = "table") const
+ const slot&
+ require_table(const std::string& what = "table") const
{
if (!is_table()) raise_type_error(what);
return *this;
}
- const slot& require_function(const std::string& what = "function") const
+ const slot&
+ require_function(const std::string& what = "function") const
{
if (!is_function()) raise_type_error(what);
return *this;
}
- const slot& require_data(const std::string& what = "userdata") const
+ const slot&
+ require_data(const std::string& what = "userdata") const
{
if (!is_data()) raise_type_error(what);
return *this;
}
- const slot& require_nil(const std::string& what = "nil") const
+ const slot&
+ require_nil(const std::string& what = "nil") const
{
if (!is_nil()) raise_type_error(what);
return *this;
}
- const slot& require_thread(const std::string& what = "thread") const
+ const slot&
+ require_thread(const std::string& what = "thread") const
{
if (!is_thread()) raise_type_error(what);
return *this;
}
template <class T>
- const slot& require_object(const std::string& what = typeid(T).name()) const
+ const slot&
+ require_object(const std::string& what = typeid(T).name()) const
{
if (!is_data()) raise_type_error(what);
return *this;
}
-
/**
* Get the type of the value.
*/
*/
std::string type_name() const
{
- if (is_none()) return "none";
+ if (is_none())
+ {
+ return "none";
+ }
else if (is_data() && !is_light_data())
{
slot metatable = push_metatable();
return luaL_typename(script_->state_, index);
}
-
/**
- * Get the length of the value according to the definition given by
- * Lua.
+ * Get the length of the value according to the definition
+ * given by Lua.
*/
size_t size() const
{
return lua_objlen(script_->state_, index);
}
-
size_t length() const
{
return size();
int positive_index() const
{
- if (index < 0) return index + lua_gettop(script_->state_) + 1;
- else return index;
+ if (index < 0)
+ return index + lua_gettop(script_->state_) + 1;
+ else
+ return index;
}
-
/**
* Get a pointer value (for userdata, tables, threads, and
* functions).
return !is_none();
}
-
bool operator == (const slot& rhs) const
{
- return (bool)lua_equal(script_->state_, index, rhs.index);
+ return (bool)lua_equal(script_->state_,
+ index, rhs.index);
}
bool operator < (const slot& rhs) const
{
- return (bool)lua_lessthan(script_->state_, index, rhs.index);
+ return (bool)lua_lessthan(script_->state_,
+ index, rhs.index);
}
-
/**
* Convert the underlying value to a C++ type.
*/
array.clear();
slot value = (*script_)[-1];
- int realIndex = positive_index();
+ int realIndex = positive_index();
bool done = false;
for (int i = 1; !done; ++i)
lua_rawgeti(script_->state_, realIndex, i);
T v;
- if (value.get(v)) array.push_back(v);
- else done = true;
+ if (value.get(v))
+ array.push_back(v);
+ else
+ done = true;
script_->pop();
}
slot key = (*script_)[-2];
slot value = (*script_)[-1];
- int realIndex = positive_index();
+ int realIndex = positive_index();
script_->push_nil();
while (lua_next(script_->state_, realIndex) != 0)
return ret;
}
-
template <class T, class V>
void set_field(const T& field, const V& value)
{
lua_settable(script_->state_, index);
}
-
void set_field(const std::string& field)
{
set_field(field.c_str());
lua_setfield(script_->state_, index, field);
}
-
template <class T>
void set_field(const std::string& field, const T& value)
{
set();
}
-
void remove()
{
lua_remove(script_->state_, index);
*/
void pop()
{
- if (index < 0) script_->pop(-index);
- else script_->pop(script_->stack_size() - index + 1);
+ if
+ (index < 0) script_->pop(-index);
+ else
+ script_->pop(script_->stack_size() -
+ index + 1);
}
/**
lua_insert(script_->state_, index);
}
-
/**
* Copy the value and push the copy to the stack.
*/
return script_->top();
}
-
slot push_field() const
{
lua_gettable(script_->state_, index);
return script_->top();
}
-
class script& script()
{
return *script_;
return *script_;
}
-
/**
- * Throw an exception with a message formatted to communicate a
- * type mismatch with the argument represented by this slot.
+ * Throw an exception with a message formatted to communicate
+ * a type mismatch with the argument represented by this slot.
*/
int raise_type_error(const std::string& expected) const
{
return 0;
}
-
private:
mutable class script* script_;
};
-
script() :
state_(0)
{
destroy();
}
-
static script_ptr alloc()
{
return script_ptr(new script);
state_ = luaL_newstate();
}
-
void import_standard_libraries()
{
luaL_openlibs(state_);
push(LUA_COLIBNAME);
call(1, 0);
}
-
void import_package_library()
{
push(luaopen_package);
push(LUA_LOADLIBNAME);
call(1, 0);
}
-
void import_string_library()
{
push(luaopen_string);
push(LUA_STRLIBNAME);
call(1, 0);
}
-
void import_table_library()
{
push(luaopen_table);
push(LUA_TABLIBNAME);
call(1, 0);
}
-
void import_math_library()
{
push(luaopen_math);
push(LUA_MATHLIBNAME);
call(1, 0);
}
-
void import_io_library()
{
push(luaopen_io);
push(LUA_IOLIBNAME);
call(1, 0);
}
-
void import_os_library()
{
push(luaopen_os);
push(LUA_OSLIBNAME);
call(1, 0);
}
-
void import_debug_library()
{
push(luaopen_debug);
call(1, 0);
}
-
- void import_function(const std::string& name, const function& function)
+ void
+ import_function(const std::string& name, const function& function)
{
push(function);
lua_setglobal(state_, name.c_str());
return status(luaL_dofile(state_, file.c_str()));
}
-
/*
* Thread-handling methods.
*/
return is_main;
}
-
/**
* Throw an error with the value at the top of the stack. If this is
* called from an imported function, the error will be caught and
return 0;
}
-
/*
* Get significant values.
*/
{
return slot(*this, globals_index);
}
-
slot registry() const
{
return slot(*this, registry_index);
}
-
slot environment() const
{
return slot(*this, environment_index);
}
-
slot top() const
{
return slot(*this, stack_size());
}
-
/**
* Set the size of the stack.
* \param size The stack size.
stack_size(0);
}
-
/**
* Makes sure there is at least extra more places on the stack.
* Returns false if space couldn't be created. Just like with the
return (bool)lua_checkstack(state_, extra);
}
-
/**
* Concatenates the top-most n slots on the stack.
*/
lua_concat(state_, n);
}
-
/*
* Push some values onto the stack.
*/
}
slot push_code(const std::string& name,
- const char* buffer,
- size_t size,
- status& result)
+ const char* buffer, size_t size, status& result)
{
result = status(luaL_loadbuffer(state_,
- buffer, size, name.c_str()));
+ buffer, size, name.c_str()));
return top();
}
template <class T>
slot push_pointer(const T* ptr)
{
- lua_pushlightuserdata(state_, const_cast<void*>((const void*)ptr));
+ lua_pushlightuserdata(state_,
+ const_cast<void*>((const void*)ptr));
return top();
}
slot push_pointer(cfunction function)
return push_pointer(&typeid(T));
}
-
/**
* Call a function on the stack. The correct procedure is to push a
* function onto the stack followed by nargs arguments. This method
return status(lua_pcall(state_, nargs, nresults, 0));
}
-
/**
* Pops n values from the top of the stack.
*/
lua_pop(state_, n);
}
-
/**
* Index into the stack to get a slot.
*/
return slot(*this, index);
}
-
/*
* Control over the garbage collection process.
*/
lua_gc(state_, LUA_GCSETSTEPMUL, step);
}
-
private:
script(lua_State* state) :
slot metatable = push_metatable(typeid(T).name(), is_new);
if (is_new)
{
- metatable.push_copy(); // class behavior
+ metatable.push_copy(); // class behavior
metatable.set_field("__index");
-
push_type<T>();
metatable.set_field("__cxxtype"); // type_info
-
push(object_finalizer_<T>);
metatable.set_field("__gc"); // finalizer
-
//push(object_tostring_<T>);
//metatable.set_field("__tostring"); // tostring
}
{
std::ostringstream stream;
stream << *reinterpret_cast<T*>(lua_touserdata(state, 1));
- lua_pushlstring(state, stream.str().c_str(), stream.str().length());
+ lua_pushlstring(state,
+ stream.str().c_str(), stream.str().length());
return 1;
}
}
}
-
static int call_function(lua_State* state)
{
cfunction function = (cfunction)lua_touserdata(state,
}
}
-
void destroy()
{
if (is_main_thread()) lua_close(state_);
}
-
lua_State* state_;
};
using namespace std::rel_ops;
-
/**
* Output a script value to a stream.
*/
-inline std::ostream& operator << (std::ostream& stream,
- const script::slot& slot)
+inline std::ostream&
+operator << (std::ostream& stream, const script::slot& slot)
{
std::string str;
bool boolean;
else if (slot.get(boolean))
{
if (boolean) stream << "true";
- else stream << "false";
+ else stream << "false";
}
else if (slot.is_nil())
{