]>
Dogcows Code - chaz/yoink/blob - src/moof/script.hh
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
5 * Distributable under the terms and conditions of the 2-clause BSD license;
6 * see the file COPYING for a complete text of the license.
8 *****************************************************************************/
10 #ifndef _MOOF_SCRIPT_HH_
11 #define _MOOF_SCRIPT_HH_
22 #include <boost/bind.hpp>
23 #include <boost/function.hpp>
24 #include <boost/shared_ptr.hpp>
30 * A thin wrapper over Lua 5.1. This is not meant as a complicated binding
31 * package between C++ and Lua. It is not meant to obscure the division
32 * between C++ and Lua but rather to clarify it and make it more manageable.
33 * It does not hide the concept of the Lua stack, but rather provides that
34 * mechanism with a certain level of abstraction while also providing a
35 * cleaner, more consistent API.
42 typedef boost::shared_ptr
<script
> script_ptr
;
48 typedef boost::function
<int(script
&)> function
;
49 typedef int (*cfunction
)(script
&);
55 runtime_error
= LUA_ERRRUN
,
56 syntax_error
= LUA_ERRSYNTAX
,
57 memory_error
= LUA_ERRMEM
,
58 handler_error
= LUA_ERRERR
,
59 file_error
= LUA_ERRFILE
64 registry_index
= LUA_REGISTRYINDEX
,
65 environment_index
= LUA_ENVIRONINDEX
,
66 globals_index
= LUA_GLOBALSINDEX
70 static int object_finalizer(script
& script
)
72 reinterpret_cast<T
*>(script
[1].get_data())->~T();
77 * This is the most prominent abstraction on top of the standard Lua
78 * API. A slot object represents a value on the stack. More
79 * specifically, it represents a position on the stack. The
80 * distinction is only important when objects are moved around on the
81 * stack or if the slot represents a negative index on the stack (the
82 * value of which will change as things are pushed onto and popped
88 * You have direct access to the index of the value on the
89 * stack being represented.
97 boolean
= LUA_TBOOLEAN
,
98 light_data
= LUA_TLIGHTUSERDATA
,
100 string
= LUA_TSTRING
,
102 function
= LUA_TFUNCTION
,
103 data
= LUA_TUSERDATA
,
107 static std::string
type_name(type type
)
111 case none
: return "none";
112 case nil
: return "nil";
113 case boolean
: return "boolean";
115 case data
: return "userdata";
116 case number
: return "number";
117 case string
: return "string";
118 case table
: return "table";
119 case function
: return "function";
120 case thread
: return "thread";
125 slot(const class script
& s
, int i
= 0) :
127 script_(const_cast<class script
*>(&s
)) {}
129 // check the type of the value
130 #define IS_TYPE(T, N) \
131 bool is_##N() const \
133 return (bool)lua_is##T(script_->state_, index); \
135 IS_TYPE(boolean
, boolean
);
136 IS_TYPE(cfunction
, imported_function
);
137 IS_TYPE(function
, function
);
138 IS_TYPE(lightuserdata
, light_data
);
141 IS_TYPE(noneornil
, none_or_nil
);
142 IS_TYPE(number
, number
);
143 IS_TYPE(string
, string
);
144 IS_TYPE(table
, table
);
145 IS_TYPE(thread
, thread
);
146 IS_TYPE(userdata
, data
);
150 * Check the value and throw an error if its the wrong type.
152 const slot
& require_type(type t
) const
154 if (t
!= type()) raise_type_error(type_name(t
));
158 #define REQUIRE_TYPE(T) \
159 const slot& require_##T(const std::string& what = #T) const \
161 if (!is_##T()) raise_type_error(what); \
164 REQUIRE_TYPE(boolean
);
165 REQUIRE_TYPE(number
);
166 REQUIRE_TYPE(string
);
168 REQUIRE_TYPE(function
);
171 REQUIRE_TYPE(thread
);
176 require_object(const std::string
& what
= typeid(T
).name()) const
178 if (!is_data()) raise_type_error(what
);
180 slot metatable
= push_metatable();
181 if (!metatable
.is_table())
184 raise_type_error(what
);
187 slot type
= metatable
.push_field("__cxxtype");
188 std::type_info
* typeinfo
;
189 if (!type
.get(typeinfo
))
192 raise_type_error(what
);
196 if (*typeinfo
!= typeid(T
)) raise_type_error(what
);
201 * Get the type of the value.
203 enum type
type() const
205 return (enum type
)lua_type(script_
->state_
, index
);
209 * Get the name of the type of the value as a string.
211 std::string
type_name() const
217 else if (is_data() && !is_light_data())
219 slot metatable
= push_metatable();
220 if (!metatable
.is_table())
226 slot type
= metatable
.push_field("__cxxtype");
227 std::type_info
* typeinfo
;
228 if (!type
.get(typeinfo
))
235 return typeinfo
->name();
237 return luaL_typename(script_
->state_
, index
);
241 * Get the length of the value according to the definition
246 return lua_objlen(script_
->state_
, index
);
248 size_t length() const
253 int positive_index() const
256 return index
+ lua_gettop(script_
->state_
) + 1;
262 * Get a pointer value (for userdata, tables, threads, and
265 const void* id() const
267 return lua_topointer(script_
->state_
, index
);
270 bool is_identical(const slot
& rhs
) const
272 return script_
== rhs
.script_
&& index
== rhs
.index
;
275 operator bool () const
280 bool operator == (const slot
& rhs
) const
282 return (bool)lua_equal(script_
->state_
,
286 bool operator < (const slot
& rhs
) const
288 return (bool)lua_lessthan(script_
->state_
,
293 * Convert the underlying value to a C++ type.
296 #define GET_INT_OF_TYPE(T) \
297 bool get(T& value) const \
301 value = static_cast<T>(lua_tointeger(script_->state_, index)); \
306 GET_INT_OF_TYPE(char);
307 GET_INT_OF_TYPE(unsigned char);
308 GET_INT_OF_TYPE(short);
309 GET_INT_OF_TYPE(unsigned short);
310 GET_INT_OF_TYPE(int);
311 GET_INT_OF_TYPE(unsigned int);
312 GET_INT_OF_TYPE(long);
313 GET_INT_OF_TYPE(unsigned long);
314 GET_INT_OF_TYPE(long long);
315 GET_INT_OF_TYPE(unsigned long long);
316 #undef GET_INT_OF_TYPE
318 bool get(float& value
) const
322 value
= (float)lua_tonumber(script_
->state_
, index
);
327 bool get(double& value
) const
331 value
= (double)lua_tonumber(script_
->state_
, index
);
337 bool get(bool& value
) const
341 value
= (bool)lua_toboolean(script_
->state_
, index
);
347 bool get(const char*& value
, size_t& size
) const
351 value
= lua_tolstring(script_
->state_
, index
, &size
);
356 bool get(std::string
& value
) const
362 value
.assign(str
, size
);
369 bool get(T
*& value
) const
373 value
= reinterpret_cast<T
*>(lua_touserdata(script_
->state_
, index
));
379 bool get(T
& value
) const
383 value
= *reinterpret_cast<T
*>(lua_touserdata(script_
->state_
, index
));
388 void* get_data() const
390 return lua_touserdata(script_
->state_
, index
);
394 bool get(std::vector
<T
>& array
) const
396 if (!is_table()) return false;
400 slot value
= (*script_
)[-1];
401 int realIndex
= positive_index();
404 for (int i
= 1; !done
; ++i
)
406 lua_rawgeti(script_
->state_
, realIndex
, i
);
421 bool get(std::map
<std::string
,T
>& dictionary
) const
423 if (!is_table()) return false;
427 slot key
= (*script_
)[-2];
428 slot value
= (*script_
)[-1];
429 int realIndex
= positive_index();
432 while (lua_next(script_
->state_
, realIndex
) != 0)
435 if (!key
.is_number() && key
.get(k
))
438 if (value
.get(v
)) dictionary
[k
] = v
;
448 * Get the value of a field from the table.
450 template <class T
, class V
>
451 bool get(T
& value
, const V
& field
) const
453 bool ret
= push_field(field
).get(value
);
458 template <class T
, class V
>
459 void set_field(const T
& field
, const V
& value
)
461 script_
->push(field
);
462 script_
->push(value
);
468 lua_settable(script_
->state_
, index
);
471 void set_field(const std::string
& field
)
473 set_field(field
.c_str());
475 void set_field(const char* field
)
477 lua_setfield(script_
->state_
, index
, field
);
481 void set_field(const std::string
& field
, const T
& value
)
483 set_field(field
.c_str(), value
);
486 void set_field(const char* field
, const T
& value
)
488 script_
->push(value
);
493 * Set the top value to be the metatable of this value.
497 lua_setmetatable(script_
->state_
, index
);
501 * This set method, as opposed to the others, sets the value of the
502 * actual slot. The others set table values.
507 script_
->push(value
);
512 * Replace this value with the value at the top of the stack.
516 lua_replace(script_
->state_
, index
);
527 lua_remove(script_
->state_
, index
);
531 * Remove this value and everything above it.
535 if (index
< 0) script_
->pop(-index
);
536 else script_
->pop(script_
->stack_size() - index
+ 1);
540 * Inserts the top-most value on the stack at position index,
541 * shifting other values as needed.
543 void insert_top_here()
545 lua_insert(script_
->state_
, index
);
549 * Copy the value and push the copy to the stack.
551 slot
push_copy() const
553 lua_pushvalue(script_
->state_
, index
);
554 return script_
->top();
557 slot
push_metatable() const
559 lua_getmetatable(script_
->state_
, index
);
560 return script_
->top();
563 slot
push_environment() const
565 lua_getfenv(script_
->state_
, index
);
566 return script_
->top();
569 slot
push_field() const
571 lua_gettable(script_
->state_
, index
);
572 return script_
->top();
576 slot
push_field(T index
) const
578 script_
->push(index
);
582 slot
push_field(const std::string
& name
) const
584 return push_field(name
.c_str());
586 slot
push_field(const char* name
) const
588 lua_getfield(script_
->state_
, index
, name
);
589 return script_
->top();
592 class script
& script()
597 const class script
& script() const
603 * Throw an exception with a message formatted to communicate
604 * a type mismatch with the argument represented by this slot.
606 int raise_type_error(const std::string
& expected
) const
609 lua_getstack(script_
->state_
, 0, &ar
);
610 lua_getinfo(script_
->state_
, "n", &ar
);
611 const char* func
= ar
.name
? ar
.name
: "unknown function";
613 std::ostringstream stream
;
614 stream
<< "bad argument " << index
<< " to '" << func
615 << "' (" << expected
<< " expected, got "
616 << type_name() << ")";
618 throw std::invalid_argument(stream
.str());
623 * Throw a generic error concerning this particular slot.
625 int raise(const std::string
& message
) const
628 lua_getstack(script_
->state_
, 0, &ar
);
629 lua_getinfo(script_
->state_
, "n", &ar
);
630 const char* func
= ar
.name
? ar
.name
: "unknown function";
632 std::ostringstream stream
;
633 stream
<< "bad argument " << index
<< " to '" << func
634 << "' (" << message
<< ")";
636 throw std::invalid_argument(stream
.str());
642 mutable class script
* script_
;
657 static script_ptr
alloc()
659 return script_ptr(new script
);
664 if (state_
) destroy();
665 state_
= luaL_newstate();
668 void import_standard_libraries()
670 luaL_openlibs(state_
);
673 void import_safe_standard_libraries()
675 import_base_library();
676 import_string_library();
677 import_table_library();
678 import_math_library();
680 import_debug_library();
684 push_nil(); g
.set_field("dofile");
685 push_nil(); g
.set_field("loadfile");
686 push_nil(); g
.set_field("require");
687 push_nil(); g
.set_field("io");
688 push_nil(); g
.set_field("package");
689 slot os
= g
.push_field("os");
690 push_nil(); os
.set_field("execute");
691 push_nil(); os
.set_field("exit");
692 push_nil(); os
.set_field("getenv");
693 push_nil(); os
.set_field("remove");
694 push_nil(); os
.set_field("rename");
695 push_nil(); os
.set_field("tmpname");
699 #define IMPORT_LIBRARY(L, K) \
700 void import_##L##_library() \
703 push(LUA_##K##LIBNAME); \
706 IMPORT_LIBRARY(base
, CO
);
707 IMPORT_LIBRARY(debug
, DB
);
708 IMPORT_LIBRARY(io
, IO
);
709 IMPORT_LIBRARY(math
, MATH
);
710 IMPORT_LIBRARY(os
, OS
);
711 IMPORT_LIBRARY(package
, LOAD
);
712 IMPORT_LIBRARY(string
, STR
);
713 IMPORT_LIBRARY(table
, TAB
);
714 #undef IMPORT_LIBRARY
717 import_function(const std::string
& name
, const function
& function
)
720 lua_setglobal(state_
, name
.c_str());
723 status
do_string(const std::string
& commands
)
725 return status(luaL_dostring(state_
, commands
.c_str()));
728 status
do_file(const std::string
& file
)
730 return status(luaL_dofile(state_
, file
.c_str()));
734 * Thread-handling methods.
737 script
push_new_thread()
739 return script(state_
);
744 lua_pushthread(state_
);
748 status
resume(int nargs
)
750 return status(lua_resume(state_
, nargs
));
753 status
thread_status() const
755 return status(lua_status(state_
));
758 int yield(int results
)
760 return lua_yield(state_
, results
);
763 bool is_main_thread() const
765 bool is_main
= lua_pushthread(state_
);
771 * Throw an error with the value at the top of the stack. If this is
772 * called from an imported function, the error will be caught and
773 * returned on the stack when the execution aborts.
777 throw std::runtime_error("");
782 * Throw an error with a given message describing the problem. If this
783 * is called from an imported function, the error will be caught and
784 * returned on the stack when the execution aborts.
786 int raise(const std::string
& message
)
788 throw std::runtime_error(message
);
793 * Get significant values.
798 return slot(*this, globals_index
);
800 slot
registry() const
802 return slot(*this, registry_index
);
804 slot
environment() const
806 return slot(*this, environment_index
);
810 return slot(*this, stack_size());
814 * Set the size of the stack.
815 * \param size The stack size.
817 void stack_size(int size
)
819 lua_settop(state_
, size
);
823 * Get the size of the stack; this is also the index of the top-most
825 * \return The stack size.
827 int stack_size() const
829 return lua_gettop(state_
);
833 * Clear the stack, setting its size to zero.
841 * Makes sure there is at least extra more places on the stack.
842 * Returns false if space couldn't be created. Just like with the
843 * regular Lua API, you are responsible to make sure the stack is big
844 * enough to hold whatever you want to push on it. This is usually
845 * only an issue if you're pushing stuff in a loop.
847 bool check_stack(int extra
)
849 return (bool)lua_checkstack(state_
, extra
);
853 * Concatenates the top-most n slots on the stack.
855 void concatenate(int n
= 2)
857 lua_concat(state_
, n
);
861 * Push some values onto the stack.
864 #define PUSH_INT_OF_TYPE(T) \
867 lua_pushinteger(state_, static_cast<lua_Integer>(value)); \
870 PUSH_INT_OF_TYPE(char);
871 PUSH_INT_OF_TYPE(unsigned char);
872 PUSH_INT_OF_TYPE(short);
873 PUSH_INT_OF_TYPE(unsigned short);
874 PUSH_INT_OF_TYPE(int);
875 PUSH_INT_OF_TYPE(unsigned int);
876 PUSH_INT_OF_TYPE(long);
877 PUSH_INT_OF_TYPE(unsigned long);
878 PUSH_INT_OF_TYPE(long long);
879 PUSH_INT_OF_TYPE(unsigned long long);
880 #undef PUSH_INT_OF_TYPE
882 slot
push(bool value
)
884 lua_pushboolean(state_
, int(value
));
888 slot
push(float value
)
890 lua_pushnumber(state_
, lua_Number(value
));
893 slot
push(double value
)
895 lua_pushnumber(state_
, lua_Number(value
));
899 slot
push(const std::string
& value
)
901 lua_pushlstring(state_
, value
.c_str(), value
.length());
904 slot
push(const char* value
)
906 lua_pushstring(state_
, value
);
909 slot
push(const char* value
, size_t length
)
911 lua_pushlstring(state_
, value
, length
);
915 slot
push(const function
& function
)
917 push
<script::function
>(function
);
919 push(call_functor
, 2);
922 slot
push(cfunction function
)
924 push_pointer(function
);
926 push(call_function
, 2);
931 slot
push(const T
& object
)
934 slot copy
= push_data(storage
, sizeof(T
));
935 new(storage
) T(object
);
937 push_class_metatable
<T
>();
938 copy
.set_metatable();
943 slot
push_class(const function
& ctor
)
945 slot metatable
= push_class_metatable
<T
>();
947 slot constructor
= push_table();
949 constructor
.set_field("__call");
950 metatable
.set_metatable();
955 slot
push_class(cfunction ctor
)
957 slot metatable
= push_class_metatable
<T
>();
959 slot constructor
= push_table();
961 constructor
.set_field("__call");
962 metatable
.set_metatable();
973 slot
push_from_thread(script
& thread
, int n
)
975 lua_xmove(thread
.state_
, state_
, n
);
979 slot
push_code(const std::string
& file
, status
& result
)
981 result
= status(luaL_loadfile(state_
, file
.c_str()));
985 slot
push_code(const std::string
& name
,
986 const char* buffer
, size_t size
, status
& result
)
988 result
= status(luaL_loadbuffer(state_
,
989 buffer
, size
, name
.c_str()));
993 slot
push_data(void*& data
, size_t size
)
995 data
= lua_newuserdata(state_
, size
);
1000 slot
push_pointer(const T
* ptr
)
1002 lua_pushlightuserdata(state_
,
1003 const_cast<void*>((const void*)ptr
));
1006 slot
push_pointer(cfunction function
)
1008 return push_pointer((void*)function
);
1011 slot
push_table(const std::string
& name
, int narr
= 0, int nrec
= 0)
1013 if (name
.empty()) return globals().push_field("_G");
1015 slot table
= globals().push_field(name
);
1016 if (table
.is_table()) return table
;
1019 push_table(narr
, nrec
);
1020 globals().set_field(name
);
1022 return globals().push_field(name
);
1024 slot
push_table(int narr
= 0, int nrec
= 0)
1026 lua_createtable(state_
, narr
, nrec
);
1030 slot
push_metatable(const std::string
& type
, bool& is_new
)
1032 is_new
= luaL_newmetatable(state_
, type
.c_str());
1035 slot
push_metatable(const std::string
& type
)
1037 luaL_newmetatable(state_
, type
.c_str());
1044 return push_pointer(&typeid(T
));
1048 * Call a function on the stack. The correct procedure is to push a
1049 * function onto the stack followed by nargs arguments. This method
1050 * will pop them off upon return, leaving up to nresults return values
1051 * (default is any number of return values, depending on the callee).
1053 status
call(int nargs
= 0, int nresults
= LUA_MULTRET
)
1055 return status(lua_pcall(state_
, nargs
, nresults
, 0));
1059 * Pops n values from the top of the stack.
1067 * Index into the stack to get a slot.
1069 slot
operator [] (int index
) const
1071 return slot(*this, index
);
1075 * Control over the garbage collection process.
1078 void collect_garbage()
1080 lua_gc(state_
, LUA_GCCOLLECT
, 0);
1082 void collect_garbage(int step
)
1084 lua_gc(state_
, LUA_GCSTEP
, step
);
1087 void disable_garbage_collector()
1089 lua_gc(state_
, LUA_GCSTOP
, 0);
1091 void enable_garbage_collector()
1093 lua_gc(state_
, LUA_GCRESTART
, 0);
1096 float memory_used() const
1099 return lua_gc(state_
, LUA_GCCOUNT
, 0) +
1100 lua_gc(state_
, LUA_GCCOUNTB
, 0) / 1024.0f
;
1103 void tune_garbage_collector(int pause
, int step
= 200)
1105 lua_gc(state_
, LUA_GCSETPAUSE
, pause
);
1106 lua_gc(state_
, LUA_GCSETSTEPMUL
, step
);
1111 script(lua_State
* state
) :
1112 state_(lua_newthread(state
)) {}
1114 slot
push(lua_CFunction function
, int upvalues
= 0)
1116 lua_pushcclosure(state_
, function
, upvalues
);
1121 slot
push_class_metatable()
1124 slot metatable
= push_metatable(typeid(T
).name(), is_new
);
1127 metatable
.push_copy(); // class behavior
1128 metatable
.set_field("__index");
1130 metatable
.set_field("__cxxtype"); // type_info
1131 push(object_finalizer_
<T
>);
1132 metatable
.set_field("__gc"); // finalizer
1133 //push(object_tostring_<T>);
1134 //metatable.set_field("__tostring"); // tostring
1140 static int object_tostring_(lua_State
* state
)
1142 std::ostringstream stream
;
1143 stream
<< *reinterpret_cast<T
*>(lua_touserdata(state
, 1));
1144 lua_pushlstring(state
,
1145 stream
.str().c_str(), stream
.str().length());
1150 static int object_finalizer_(lua_State
* state
)
1152 reinterpret_cast<T
*>(lua_touserdata(state
, 1))->~T();
1156 static int call_functor(lua_State
* state
)
1158 function
* function
= (script::function
*)lua_touserdata(state
,
1159 lua_upvalueindex(1));
1161 script
* script
= (moof::script
*)lua_touserdata(state
,
1162 lua_upvalueindex(2));
1166 return (*function
)(*script
);
1168 catch (const std::exception
& e
)
1170 if (0 < std::strlen(e
.what()))
1172 luaL_where(state
, 1);
1173 lua_pushstring(state
, e
.what());
1174 lua_concat(state
, 2);
1176 return lua_error(state
);
1178 catch (const char* e
)
1180 luaL_where(state
, 1);
1181 lua_pushstring(state
, e
);
1182 lua_concat(state
, 2);
1183 return lua_error(state
);
1187 return lua_error(state
);
1191 static int call_function(lua_State
* state
)
1193 cfunction function
= (cfunction
)lua_touserdata(state
,
1194 lua_upvalueindex(1));
1196 script
* script
= (moof::script
*)lua_touserdata(state
,
1197 lua_upvalueindex(2));
1201 return function(*script
);
1203 catch (const std::exception
& e
)
1205 if (0 < std::strlen(e
.what()))
1207 luaL_where(state
, 1);
1208 lua_pushstring(state
, e
.what());
1209 lua_concat(state
, 2);
1211 return lua_error(state
);
1213 catch (const char* e
)
1215 luaL_where(state
, 1);
1216 lua_pushstring(state
, e
);
1217 lua_concat(state
, 2);
1218 return lua_error(state
);
1222 return lua_error(state
);
1228 if (is_main_thread()) lua_close(state_
);
1234 using namespace std::rel_ops
;
1237 * Output a script value to a stream.
1239 inline std::ostream
&
1240 operator << (std::ostream
& stream
, const script::slot
& slot
)
1249 else if (slot
.get(boolean
))
1251 if (boolean
) stream
<< "true";
1252 else stream
<< "false";
1254 else if (slot
.is_nil())
1260 stream
<< slot
.type_name() << " (" << slot
.id() << ")";
1269 #endif // _MOOF_SCRIPT_HH_
This page took 0.0935780000000001 seconds and 4 git commands to generate.