]>
Dogcows Code - chaz/yoink/blob - src/moof/script.hh
ae582fcbe07f566005370383335e2bbbedf72911
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 bool is_boolean() const
132 return (bool)lua_isboolean(script_
->state_
, index
);
134 bool is_imported_function() const
136 return (bool)lua_iscfunction(script_
->state_
, index
);
138 bool is_function() const
140 return (bool)lua_isfunction(script_
->state_
, index
);
144 return (bool)lua_isnil(script_
->state_
, index
);
148 return (bool)lua_isnone(script_
->state_
, index
);
150 bool is_none_or_nil() const
152 return (bool)lua_isnoneornil(script_
->state_
, index
);
154 bool is_number() const
156 return (bool)lua_isnumber(script_
->state_
, index
);
158 bool is_string() const
160 return (bool)lua_isstring(script_
->state_
, index
);
162 bool is_table() const
164 return (bool)lua_istable(script_
->state_
, index
);
166 bool is_thread() const
168 return (bool)lua_isthread(script_
->state_
, index
);
172 return (bool)lua_isuserdata(script_
->state_
, index
);
174 bool is_light_data() const
176 return (bool)lua_islightuserdata(script_
->state_
, index
);
180 * Check the value and throw an error if its the wrong type.
182 const slot
& require_type(type t
) const
184 if (t
!= type()) raise_type_error(type_name(t
));
189 require_boolean(const std::string
& what
= "boolean") const
191 if (!is_boolean()) raise_type_error(what
);
195 require_number(const std::string
& what
= "number") const
197 if (!is_number()) raise_type_error(what
);
201 require_string(const std::string
& what
= "string") const
203 if (!is_string()) raise_type_error(what
);
207 require_table(const std::string
& what
= "table") const
209 if (!is_table()) raise_type_error(what
);
213 require_function(const std::string
& what
= "function") const
215 if (!is_function()) raise_type_error(what
);
219 require_data(const std::string
& what
= "userdata") const
221 if (!is_data()) raise_type_error(what
);
225 require_nil(const std::string
& what
= "nil") const
227 if (!is_nil()) raise_type_error(what
);
231 require_thread(const std::string
& what
= "thread") const
233 if (!is_thread()) raise_type_error(what
);
239 require_object(const std::string
& what
= typeid(T
).name()) const
241 if (!is_data()) raise_type_error(what
);
243 slot metatable
= push_metatable();
244 if (!metatable
.is_table())
247 raise_type_error(what
);
250 slot type
= metatable
.push_field("__cxxtype");
251 std::type_info
* typeinfo
;
252 if (!type
.get(typeinfo
))
255 raise_type_error(what
);
259 if (*typeinfo
!= typeid(T
)) raise_type_error(what
);
264 * Get the type of the value.
266 enum type
type() const
268 return (enum type
)lua_type(script_
->state_
, index
);
272 * Get the name of the type of the value as a string.
274 std::string
type_name() const
280 else if (is_data() && !is_light_data())
282 slot metatable
= push_metatable();
283 if (!metatable
.is_table())
289 slot type
= metatable
.push_field("__cxxtype");
290 std::type_info
* typeinfo
;
291 if (!type
.get(typeinfo
))
298 return typeinfo
->name();
300 return luaL_typename(script_
->state_
, index
);
304 * Get the length of the value according to the definition
309 return lua_objlen(script_
->state_
, index
);
311 size_t length() const
316 int positive_index() const
319 return index
+ lua_gettop(script_
->state_
) + 1;
325 * Get a pointer value (for userdata, tables, threads, and
328 const void* id() const
330 return lua_topointer(script_
->state_
, index
);
333 bool is_identical(const slot
& rhs
) const
335 return script_
== rhs
.script_
&& index
== rhs
.index
;
338 operator bool () const
343 bool operator == (const slot
& rhs
) const
345 return (bool)lua_equal(script_
->state_
,
349 bool operator < (const slot
& rhs
) const
351 return (bool)lua_lessthan(script_
->state_
,
356 * Convert the underlying value to a C++ type.
359 bool get(T
& value
) const
363 value
= (T
)lua_tointeger(script_
->state_
, index
);
369 bool get(float& value
) const
373 value
= (float)lua_tonumber(script_
->state_
, index
);
378 bool get(double& value
) const
382 value
= (double)lua_tonumber(script_
->state_
, index
);
388 bool get(bool& value
) const
392 value
= (bool)lua_toboolean(script_
->state_
, index
);
398 bool get(const char*& value
, size_t& size
) const
402 value
= lua_tolstring(script_
->state_
, index
, &size
);
408 bool get(std::string
& value
) const
414 value
.assign(str
, size
);
421 bool get(T
*& value
) const
425 value
= reinterpret_cast<T
*>(lua_touserdata(script_
->state_
, index
));
430 void* get_data() const
432 return lua_touserdata(script_
->state_
, index
);
436 bool get(std::vector
<T
>& array
) const
438 if (!is_table()) return false;
442 slot value
= (*script_
)[-1];
443 int realIndex
= positive_index();
446 for (int i
= 1; !done
; ++i
)
448 lua_rawgeti(script_
->state_
, realIndex
, i
);
463 bool get(std::map
<std::string
,T
>& dictionary
) const
465 if (!is_table()) return false;
469 slot key
= (*script_
)[-2];
470 slot value
= (*script_
)[-1];
471 int realIndex
= positive_index();
474 while (lua_next(script_
->state_
, realIndex
) != 0)
477 if (!key
.is_number() && key
.get(k
))
480 if (value
.get(v
)) dictionary
[k
] = v
;
490 * Get the value of a field from the table.
492 template <class T
, class V
>
493 bool get(T
& value
, const V
& field
) const
495 bool ret
= push_field(field
).get(value
);
500 template <class T
, class V
>
501 void set_field(const T
& field
, const V
& value
)
503 script_
->push(field
);
504 script_
->push(value
);
510 lua_settable(script_
->state_
, index
);
513 void set_field(const std::string
& field
)
515 set_field(field
.c_str());
517 void set_field(const char* field
)
519 lua_setfield(script_
->state_
, index
, field
);
523 void set_field(const std::string
& field
, const T
& value
)
525 set_field(field
.c_str(), value
);
528 void set_field(const char* field
, const T
& value
)
530 script_
->push(value
);
535 * Set the top value to be the metatable of this value.
539 lua_setmetatable(script_
->state_
, index
);
543 * This set method, as opposed to the others, sets the value of the
544 * actual slot. The others set table values.
549 script_
->push(value
);
554 * Replace this value with the value at the top of the stack.
558 lua_replace(script_
->state_
, index
);
569 lua_remove(script_
->state_
, index
);
573 * Remove this value and everything above it.
578 (index
< 0) script_
->pop(-index
);
580 script_
->pop(script_
->stack_size() -
585 * Inserts the top-most value on the stack at position index,
586 * shifting other values as needed.
588 void insert_top_here()
590 lua_insert(script_
->state_
, index
);
594 * Copy the value and push the copy to the stack.
596 slot
push_copy() const
598 lua_pushvalue(script_
->state_
, index
);
599 return script_
->top();
602 slot
push_metatable() const
604 lua_getmetatable(script_
->state_
, index
);
605 return script_
->top();
608 slot
push_environment() const
610 lua_getfenv(script_
->state_
, index
);
611 return script_
->top();
614 slot
push_field() const
616 lua_gettable(script_
->state_
, index
);
617 return script_
->top();
621 slot
push_field(T index
) const
623 script_
->push(index
);
627 slot
push_field(const std::string
& name
) const
629 return push_field(name
.c_str());
631 slot
push_field(const char* name
) const
633 lua_getfield(script_
->state_
, index
, name
);
634 return script_
->top();
637 class script
& script()
642 const class script
& script() const
648 * Throw an exception with a message formatted to communicate
649 * a type mismatch with the argument represented by this slot.
651 int raise_type_error(const std::string
& expected
) const
654 lua_getstack(script_
->state_
, 0, &ar
);
655 lua_getinfo(script_
->state_
, "n", &ar
);
656 const char* func
= ar
.name
? ar
.name
: "unknown function";
658 std::ostringstream stream
;
659 stream
<< "bad argument " << index
<< " to '" << func
660 << "' (" << expected
<< " expected, got "
661 << type_name() << ")";
663 throw std::invalid_argument(stream
.str());
668 * Throw a generic error concerning this particular slot.
670 int raise(const std::string
& message
) const
673 lua_getstack(script_
->state_
, 0, &ar
);
674 lua_getinfo(script_
->state_
, "n", &ar
);
675 const char* func
= ar
.name
? ar
.name
: "unknown function";
677 std::ostringstream stream
;
678 stream
<< "bad argument " << index
<< " to '" << func
679 << "' (" << message
<< ")";
681 throw std::invalid_argument(stream
.str());
687 mutable class script
* script_
;
701 static script_ptr
alloc()
703 return script_ptr(new script
);
708 if (state_
) destroy();
709 state_
= luaL_newstate();
712 void import_standard_libraries()
714 luaL_openlibs(state_
);
717 void import_safe_standard_libraries()
719 import_base_library();
720 import_string_library();
721 import_table_library();
722 import_math_library();
724 import_debug_library();
728 push_nil(); g
.set_field("dofile");
729 push_nil(); g
.set_field("loadfile");
730 push_nil(); g
.set_field("require");
731 push_nil(); g
.set_field("io");
732 push_nil(); g
.set_field("package");
733 slot os
= g
.push_field("os");
734 push_nil(); os
.set_field("execute");
735 push_nil(); os
.set_field("exit");
736 push_nil(); os
.set_field("getenv");
737 push_nil(); os
.set_field("remove");
738 push_nil(); os
.set_field("rename");
739 push_nil(); os
.set_field("tmpname");
743 void import_base_library()
749 void import_package_library()
751 push(luaopen_package
);
752 push(LUA_LOADLIBNAME
);
755 void import_string_library()
757 push(luaopen_string
);
758 push(LUA_STRLIBNAME
);
761 void import_table_library()
764 push(LUA_TABLIBNAME
);
767 void import_math_library()
770 push(LUA_MATHLIBNAME
);
773 void import_io_library()
779 void import_os_library()
785 void import_debug_library()
793 import_function(const std::string
& name
, const function
& function
)
796 lua_setglobal(state_
, name
.c_str());
799 status
do_string(const std::string
& commands
)
801 return status(luaL_dostring(state_
, commands
.c_str()));
804 status
do_file(const std::string
& file
)
806 return status(luaL_dofile(state_
, file
.c_str()));
810 * Thread-handling methods.
813 script
push_new_thread()
815 return script(state_
);
820 lua_pushthread(state_
);
824 status
resume(int nargs
)
826 return status(lua_resume(state_
, nargs
));
829 status
thread_status() const
831 return status(lua_status(state_
));
834 int yield(int results
)
836 return lua_yield(state_
, results
);
839 bool is_main_thread() const
841 bool is_main
= lua_pushthread(state_
);
847 * Throw an error with the value at the top of the stack. If this is
848 * called from an imported function, the error will be caught and
849 * returned on the stack when the execution aborts.
853 throw std::runtime_error("");
858 * Throw an error with a given message describing the problem. If this
859 * is called from an imported function, the error will be caught and
860 * returned on the stack when the execution aborts.
862 int raise(const std::string
& message
)
864 throw std::runtime_error(message
);
869 * Get significant values.
874 return slot(*this, globals_index
);
876 slot
registry() const
878 return slot(*this, registry_index
);
880 slot
environment() const
882 return slot(*this, environment_index
);
886 return slot(*this, stack_size());
890 * Set the size of the stack.
891 * \param size The stack size.
893 void stack_size(int size
)
895 lua_settop(state_
, size
);
899 * Get the size of the stack; this is also the index of the top-most
901 * \return The stack size.
903 int stack_size() const
905 return lua_gettop(state_
);
909 * Clear the stack, setting its size to zero.
917 * Makes sure there is at least extra more places on the stack.
918 * Returns false if space couldn't be created. Just like with the
919 * regular Lua API, you are responsible to make sure the stack is big
920 * enough to hold whatever you want to push on it. This is usually
921 * only an issue if you're pushing stuff in a loop.
923 bool check_stack(int extra
)
925 return (bool)lua_checkstack(state_
, extra
);
929 * Concatenates the top-most n slots on the stack.
931 void concatenate(int n
= 2)
933 lua_concat(state_
, n
);
937 * Push some values onto the stack.
940 slot
push(char value
)
942 lua_pushinteger(state_
, lua_Integer(value
));
945 slot
push(unsigned char value
)
947 lua_pushinteger(state_
, lua_Integer(value
));
950 slot
push(short value
)
952 lua_pushinteger(state_
, lua_Integer(value
));
955 slot
push(unsigned short value
)
957 lua_pushinteger(state_
, lua_Integer(value
));
962 lua_pushinteger(state_
, lua_Integer(value
));
965 slot
push(unsigned int value
)
967 lua_pushinteger(state_
, lua_Integer(value
));
970 slot
push(long value
)
972 lua_pushinteger(state_
, lua_Integer(value
));
975 slot
push(unsigned long value
)
977 lua_pushinteger(state_
, lua_Integer(value
));
980 slot
push(long long value
)
982 lua_pushinteger(state_
, lua_Integer(value
));
985 slot
push(unsigned long long value
)
987 lua_pushinteger(state_
, lua_Integer(value
));
991 slot
push(bool value
)
993 lua_pushboolean(state_
, int(value
));
997 slot
push(float value
)
999 lua_pushnumber(state_
, lua_Number(value
));
1002 slot
push(double value
)
1004 lua_pushnumber(state_
, lua_Number(value
));
1008 slot
push(const std::string
& value
)
1010 lua_pushlstring(state_
, value
.c_str(), value
.length());
1013 slot
push(const char* value
)
1015 lua_pushstring(state_
, value
);
1018 slot
push(const char* value
, size_t length
)
1020 lua_pushlstring(state_
, value
, length
);
1024 slot
push(const function
& function
)
1026 push
<script::function
>(function
);
1028 push(call_functor
, 2);
1031 slot
push(cfunction function
)
1033 push_pointer(function
);
1035 push(call_function
, 2);
1040 slot
push(const T
& object
)
1043 slot copy
= push_data(storage
, sizeof(T
));
1044 new(storage
) T(object
);
1046 push_class_metatable
<T
>();
1047 copy
.set_metatable();
1052 slot
push_class(const function
& ctor
)
1054 slot metatable
= push_class_metatable
<T
>();
1056 slot constructor
= push_table();
1058 constructor
.set_field("__call");
1059 metatable
.set_metatable();
1064 slot
push_class(cfunction ctor
)
1066 slot metatable
= push_class_metatable
<T
>();
1068 slot constructor
= push_table();
1070 constructor
.set_field("__call");
1071 metatable
.set_metatable();
1078 lua_pushnil(state_
);
1082 slot
push_from_thread(script
& thread
, int n
)
1084 lua_xmove(thread
.state_
, state_
, n
);
1088 slot
push_code(const std::string
& file
, status
& result
)
1090 result
= status(luaL_loadfile(state_
, file
.c_str()));
1094 slot
push_code(const std::string
& name
,
1095 const char* buffer
, size_t size
, status
& result
)
1097 result
= status(luaL_loadbuffer(state_
,
1098 buffer
, size
, name
.c_str()));
1102 slot
push_data(void*& data
, size_t size
)
1104 data
= lua_newuserdata(state_
, size
);
1109 slot
push_pointer(const T
* ptr
)
1111 lua_pushlightuserdata(state_
,
1112 const_cast<void*>((const void*)ptr
));
1115 slot
push_pointer(cfunction function
)
1117 return push_pointer((void*)function
);
1120 slot
push_table(const std::string
& name
, int narr
= 0, int nrec
= 0)
1122 if (name
.empty()) return globals().push_field("_G");
1124 slot table
= globals().push_field(name
);
1125 if (table
.is_table()) return table
;
1128 push_table(narr
, nrec
);
1129 globals().set_field(name
);
1131 return globals().push_field(name
);
1133 slot
push_table(int narr
= 0, int nrec
= 0)
1135 lua_createtable(state_
, narr
, nrec
);
1139 slot
push_metatable(const std::string
& type
, bool& is_new
)
1141 is_new
= luaL_newmetatable(state_
, type
.c_str());
1144 slot
push_metatable(const std::string
& type
)
1146 luaL_newmetatable(state_
, type
.c_str());
1153 return push_pointer(&typeid(T
));
1157 * Call a function on the stack. The correct procedure is to push a
1158 * function onto the stack followed by nargs arguments. This method
1159 * will pop them off upon return, leaving up to nresults return values
1160 * (default is any number of return values, depending on the callee).
1162 status
call(int nargs
= 0, int nresults
= LUA_MULTRET
)
1164 return status(lua_pcall(state_
, nargs
, nresults
, 0));
1168 * Pops n values from the top of the stack.
1176 * Index into the stack to get a slot.
1178 slot
operator [] (int index
) const
1180 return slot(*this, index
);
1184 * Control over the garbage collection process.
1187 void collect_garbage()
1189 lua_gc(state_
, LUA_GCCOLLECT
, 0);
1191 void collect_garbage(int step
)
1193 lua_gc(state_
, LUA_GCSTEP
, step
);
1196 void disable_garbage_collector()
1198 lua_gc(state_
, LUA_GCSTOP
, 0);
1200 void enable_garbage_collector()
1202 lua_gc(state_
, LUA_GCRESTART
, 0);
1205 float memory_used() const
1208 return lua_gc(state_
, LUA_GCCOUNT
, 0) +
1209 lua_gc(state_
, LUA_GCCOUNTB
, 0) / 1024.0f
;
1212 void tune_garbage_collector(int pause
, int step
= 200)
1214 lua_gc(state_
, LUA_GCSETPAUSE
, pause
);
1215 lua_gc(state_
, LUA_GCSETSTEPMUL
, step
);
1220 script(lua_State
* state
) :
1221 state_(lua_newthread(state
)) {}
1223 slot
push(lua_CFunction function
, int upvalues
= 0)
1225 lua_pushcclosure(state_
, function
, upvalues
);
1230 slot
push_class_metatable()
1233 slot metatable
= push_metatable(typeid(T
).name(), is_new
);
1236 metatable
.push_copy(); // class behavior
1237 metatable
.set_field("__index");
1239 metatable
.set_field("__cxxtype"); // type_info
1240 push(object_finalizer_
<T
>);
1241 metatable
.set_field("__gc"); // finalizer
1242 //push(object_tostring_<T>);
1243 //metatable.set_field("__tostring"); // tostring
1249 static int object_tostring_(lua_State
* state
)
1251 std::ostringstream stream
;
1252 stream
<< *reinterpret_cast<T
*>(lua_touserdata(state
, 1));
1253 lua_pushlstring(state
,
1254 stream
.str().c_str(), stream
.str().length());
1259 static int object_finalizer_(lua_State
* state
)
1261 reinterpret_cast<T
*>(lua_touserdata(state
, 1))->~T();
1265 static int call_functor(lua_State
* state
)
1267 function
* function
= (script::function
*)lua_touserdata(state
,
1268 lua_upvalueindex(1));
1270 script
* script
= (moof::script
*)lua_touserdata(state
,
1271 lua_upvalueindex(2));
1275 return (*function
)(*script
);
1277 catch (const std::exception
& e
)
1279 if (0 < std::strlen(e
.what()))
1281 luaL_where(state
, 1);
1282 lua_pushstring(state
, e
.what());
1283 lua_concat(state
, 2);
1285 return lua_error(state
);
1287 catch (const char* e
)
1289 luaL_where(state
, 1);
1290 lua_pushstring(state
, e
);
1291 lua_concat(state
, 2);
1292 return lua_error(state
);
1296 return lua_error(state
);
1300 static int call_function(lua_State
* state
)
1302 cfunction function
= (cfunction
)lua_touserdata(state
,
1303 lua_upvalueindex(1));
1305 script
* script
= (moof::script
*)lua_touserdata(state
,
1306 lua_upvalueindex(2));
1310 return function(*script
);
1312 catch (const std::exception
& e
)
1314 if (0 < std::strlen(e
.what()))
1316 luaL_where(state
, 1);
1317 lua_pushstring(state
, e
.what());
1318 lua_concat(state
, 2);
1320 return lua_error(state
);
1322 catch (const char* e
)
1324 luaL_where(state
, 1);
1325 lua_pushstring(state
, e
);
1326 lua_concat(state
, 2);
1327 return lua_error(state
);
1331 return lua_error(state
);
1337 if (is_main_thread()) lua_close(state_
);
1343 using namespace std::rel_ops
;
1346 * Output a script value to a stream.
1348 inline std::ostream
&
1349 operator << (std::ostream
& stream
, const script::slot
& slot
)
1358 else if (slot
.get(boolean
))
1360 if (boolean
) stream
<< "true";
1361 else stream
<< "false";
1363 else if (slot
.is_nil())
1369 stream
<< slot
.type_name() << " (" << slot
.id() << ")";
1378 #endif // _MOOF_SCRIPT_HH_
This page took 0.088355 seconds and 3 git commands to generate.