]>
Dogcows Code - chaz/yoink/blob - src/moof/script.hh
35e80d22eb6a8e57cec4d2b81fc148249888b863
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
10 **************************************************************************/
12 #ifndef _MOOF_SCRIPT_HH_
13 #define _MOOF_SCRIPT_HH_
17 * A thin wrapper over Lua 5.1. This is not meant as a complicated binding
18 * package between C++ and Lua. It is not meant to obscure the division
19 * between C++ and Lua but rather to clarify it and make it more
20 * manageable. It does not hide the concept of the Lua stack, but rather
21 * provides that mechanism with a certain level of abstraction while also
22 * providing a cleaner, more consistent API.
34 #include <boost/bind.hpp>
35 #include <boost/function.hpp>
36 #include <boost/shared_ptr.hpp>
44 typedef boost::shared_ptr
<script
> script_ptr
;
51 typedef boost::function
<int(script
&)> function
;
52 typedef int (*cfunction
)(script
&);
58 runtime_error
= LUA_ERRRUN
,
59 syntax_error
= LUA_ERRSYNTAX
,
60 memory_error
= LUA_ERRMEM
,
61 handler_error
= LUA_ERRERR
,
62 file_error
= LUA_ERRFILE
67 registry_index
= LUA_REGISTRYINDEX
,
68 environment_index
= LUA_ENVIRONINDEX
,
69 globals_index
= LUA_GLOBALSINDEX
74 static int object_finalizer(script
& script
)
76 reinterpret_cast<T
*>(script
[1].get_data())->~T();
82 * This is the most prominent abstraction on top of the standard Lua
83 * API. A slot object represents a value on the stack. More
84 * specifically, it represents a position on the stack. The
85 * distinction is only important when objects are moved around on the
86 * stack or if the slot represents a negative index on the stack (the
87 * value of which will change as things are pushed onto and popped from
93 * You have direct access to the index of the value on the stack
103 boolean
= LUA_TBOOLEAN
,
104 light_data
= LUA_TLIGHTUSERDATA
,
105 number
= LUA_TNUMBER
,
106 string
= LUA_TSTRING
,
108 function
= LUA_TFUNCTION
,
109 data
= LUA_TUSERDATA
,
113 static std::string
type_name(type type
)
117 case none
: return "none";
118 case nil
: return "nil";
119 case boolean
: return "boolean";
121 case data
: return "userdata";
122 case number
: return "number";
123 case string
: return "string";
124 case table
: return "table";
125 case function
: return "function";
126 case thread
: return "thread";
132 slot(const class script
& s
, int i
= 0) :
134 script_(const_cast<class script
*>(&s
)) {}
137 // check the type of the value
138 bool is_boolean() const
139 { return (bool)lua_isboolean(script_
->state_
, index
); }
140 bool is_imported_function() const
141 { return (bool)lua_iscfunction(script_
->state_
, index
); }
142 bool is_function() const
143 { return (bool)lua_isfunction(script_
->state_
, index
); }
145 { return (bool)lua_isnil(script_
->state_
, index
); }
147 { return (bool)lua_isnone(script_
->state_
, index
); }
148 bool is_none_or_nil() const
149 { return (bool)lua_isnoneornil(script_
->state_
, index
); }
150 bool is_number() const
151 { return (bool)lua_isnumber(script_
->state_
, index
); }
152 bool is_string() const
153 { return (bool)lua_isstring(script_
->state_
, index
); }
154 bool is_table() const
155 { return (bool)lua_istable(script_
->state_
, index
); }
156 bool is_thread() const
157 { return (bool)lua_isthread(script_
->state_
, index
); }
159 { return (bool)lua_isuserdata(script_
->state_
, index
); }
160 bool is_light_data() const
161 { return (bool)lua_islightuserdata(script_
->state_
, index
); }
164 * Check the value and throw an error if its the wrong type.
166 const slot
& require_type(type t
) const
168 if (t
!= type()) raise_type_error(type_name(t
));
172 const slot
& require_boolean(const std::string
& what
= "boolean") const
174 if (!is_boolean()) raise_type_error(what
);
177 const slot
& require_number(const std::string
& what
= "number") const
179 if (!is_number()) raise_type_error(what
);
182 const slot
& require_string(const std::string
& what
= "string") const
184 if (!is_string()) raise_type_error(what
);
187 const slot
& require_table(const std::string
& what
= "table") const
189 if (!is_table()) raise_type_error(what
);
192 const slot
& require_function(const std::string
& what
= "function") const
194 if (!is_function()) raise_type_error(what
);
197 const slot
& require_data(const std::string
& what
= "userdata") const
199 if (!is_data()) raise_type_error(what
);
202 const slot
& require_nil(const std::string
& what
= "nil") const
204 if (!is_nil()) raise_type_error(what
);
207 const slot
& require_thread(const std::string
& what
= "thread") const
209 if (!is_thread()) raise_type_error(what
);
214 const slot
& require_object(const std::string
& what
= typeid(T
).name()) const
216 if (!is_data()) raise_type_error(what
);
218 slot metatable
= push_metatable();
219 if (!metatable
.is_table())
222 raise_type_error(what
);
225 slot type
= metatable
.push_field("__cxxtype");
226 std::type_info
* typeinfo
;
227 if (!type
.get(typeinfo
))
230 raise_type_error(what
);
234 if (*typeinfo
!= typeid(T
)) raise_type_error(what
);
240 * Get the type of the value.
242 enum type
type() const
244 return (enum type
)lua_type(script_
->state_
, index
);
248 * Get the name of the type of the value as a string.
250 std::string
type_name() const
252 if (is_none()) return "none";
253 else if (is_data() && !is_light_data())
255 slot metatable
= push_metatable();
256 if (!metatable
.is_table())
262 slot type
= metatable
.push_field("__cxxtype");
263 std::type_info
* typeinfo
;
264 if (!type
.get(typeinfo
))
271 return typeinfo
->name();
273 return luaL_typename(script_
->state_
, index
);
278 * Get the length of the value according to the definition given by
283 return lua_objlen(script_
->state_
, index
);
286 size_t length() const
291 int positive_index() const
293 if (index
< 0) return index
+ lua_gettop(script_
->state_
) + 1;
299 * Get a pointer value (for userdata, tables, threads, and
302 const void* id() const
304 return lua_topointer(script_
->state_
, index
);
307 bool is_identical(const slot
& rhs
) const
309 return script_
== rhs
.script_
&& index
== rhs
.index
;
312 operator bool () const
318 bool operator == (const slot
& rhs
) const
320 return (bool)lua_equal(script_
->state_
, index
, rhs
.index
);
323 bool operator < (const slot
& rhs
) const
325 return (bool)lua_lessthan(script_
->state_
, index
, rhs
.index
);
330 * Convert the underlying value to a C++ type.
333 bool get(T
& value
) const
337 value
= (T
)lua_tointeger(script_
->state_
, index
);
343 bool get(float& value
) const
347 value
= (float)lua_tonumber(script_
->state_
, index
);
352 bool get(double& value
) const
356 value
= (double)lua_tonumber(script_
->state_
, index
);
362 bool get(bool& value
) const
366 value
= (bool)lua_toboolean(script_
->state_
, index
);
372 bool get(const char*& value
, size_t& size
) const
376 value
= lua_tolstring(script_
->state_
, index
, &size
);
382 bool get(std::string
& value
) const
388 value
.assign(str
, size
);
395 bool get(T
*& value
) const
399 value
= reinterpret_cast<T
*>(lua_touserdata(script_
->state_
, index
));
404 void* get_data() const
406 return lua_touserdata(script_
->state_
, index
);
410 bool get(std::vector
<T
>& array
) const
412 if (!is_table()) return false;
416 slot value
= (*script_
)[-1];
417 int realIndex
= positive_index();
420 for (int i
= 1; !done
; ++i
)
422 lua_rawgeti(script_
->state_
, realIndex
, i
);
425 if (value
.get(v
)) array
.push_back(v
);
435 bool get(std::map
<std::string
,T
>& dictionary
) const
437 if (!is_table()) return false;
441 slot key
= (*script_
)[-2];
442 slot value
= (*script_
)[-1];
443 int realIndex
= positive_index();
446 while (lua_next(script_
->state_
, realIndex
) != 0)
449 if (!key
.is_number() && key
.get(k
))
452 if (value
.get(v
)) dictionary
[k
] = v
;
462 * Get the value of a field from the table.
464 template <class T
, class V
>
465 bool get(T
& value
, const V
& field
) const
467 bool ret
= push_field(field
).get(value
);
473 template <class T
, class V
>
474 void set_field(const T
& field
, const V
& value
)
476 script_
->push(field
);
477 script_
->push(value
);
483 lua_settable(script_
->state_
, index
);
487 void set_field(const std::string
& field
)
489 set_field(field
.c_str());
491 void set_field(const char* field
)
493 lua_setfield(script_
->state_
, index
, field
);
498 void set_field(const std::string
& field
, const T
& value
)
500 set_field(field
.c_str(), value
);
503 void set_field(const char* field
, const T
& value
)
505 script_
->push(value
);
510 * Set the top value to be the metatable of this value.
514 lua_setmetatable(script_
->state_
, index
);
518 * This set method, as opposed to the others, sets the value of the
519 * actual slot. The others set table values.
524 script_
->push(value
);
529 * Replace this value with the value at the top of the stack.
533 lua_replace(script_
->state_
, index
);
545 lua_remove(script_
->state_
, index
);
549 * Remove this value and everything above it.
553 if (index
< 0) script_
->pop(-index
);
554 else script_
->pop(script_
->stack_size() - index
+ 1);
558 * Inserts the top-most value on the stack at position index,
559 * shifting other values as needed.
561 void insert_top_here()
563 lua_insert(script_
->state_
, index
);
568 * Copy the value and push the copy to the stack.
570 slot
push_copy() const
572 lua_pushvalue(script_
->state_
, index
);
573 return script_
->top();
576 slot
push_metatable() const
578 lua_getmetatable(script_
->state_
, index
);
579 return script_
->top();
582 slot
push_environment() const
584 lua_getfenv(script_
->state_
, index
);
585 return script_
->top();
589 slot
push_field() const
591 lua_gettable(script_
->state_
, index
);
592 return script_
->top();
596 slot
push_field(T index
) const
598 script_
->push(index
);
602 slot
push_field(const std::string
& name
) const
604 return push_field(name
.c_str());
606 slot
push_field(const char* name
) const
608 lua_getfield(script_
->state_
, index
, name
);
609 return script_
->top();
613 class script
& script()
618 const class script
& script() const
625 * Throw an exception with a message formatted to communicate a
626 * type mismatch with the argument represented by this slot.
628 int raise_type_error(const std::string
& expected
) const
631 lua_getstack(script_
->state_
, 0, &ar
);
632 lua_getinfo(script_
->state_
, "n", &ar
);
633 const char* func
= ar
.name
? ar
.name
: "unknown function";
635 std::ostringstream stream
;
636 stream
<< "bad argument " << index
<< " to '" << func
637 << "' (" << expected
<< " expected, got "
638 << type_name() << ")";
640 throw std::invalid_argument(stream
.str());
645 * Throw a generic error concerning this particular slot.
647 int raise(const std::string
& message
) const
650 lua_getstack(script_
->state_
, 0, &ar
);
651 lua_getinfo(script_
->state_
, "n", &ar
);
652 const char* func
= ar
.name
? ar
.name
: "unknown function";
654 std::ostringstream stream
;
655 stream
<< "bad argument " << index
<< " to '" << func
656 << "' (" << message
<< ")";
658 throw std::invalid_argument(stream
.str());
665 mutable class script
* script_
;
681 static script_ptr
alloc()
683 return script_ptr(new script
);
688 if (state_
) destroy();
689 state_
= luaL_newstate();
693 void import_standard_libraries()
695 luaL_openlibs(state_
);
698 void import_safe_standard_libraries()
700 import_base_library();
701 import_string_library();
702 import_table_library();
703 import_math_library();
705 import_debug_library();
709 push_nil(); g
.set_field("dofile");
710 push_nil(); g
.set_field("loadfile");
711 push_nil(); g
.set_field("require");
712 push_nil(); g
.set_field("io");
713 push_nil(); g
.set_field("package");
714 slot os
= g
.push_field("os");
715 push_nil(); os
.set_field("execute");
716 push_nil(); os
.set_field("exit");
717 push_nil(); os
.set_field("getenv");
718 push_nil(); os
.set_field("remove");
719 push_nil(); os
.set_field("rename");
720 push_nil(); os
.set_field("tmpname");
724 void import_base_library()
731 void import_package_library()
733 push(luaopen_package
);
734 push(LUA_LOADLIBNAME
);
738 void import_string_library()
740 push(luaopen_string
);
741 push(LUA_STRLIBNAME
);
745 void import_table_library()
748 push(LUA_TABLIBNAME
);
752 void import_math_library()
755 push(LUA_MATHLIBNAME
);
759 void import_io_library()
766 void import_os_library()
773 void import_debug_library()
781 void import_function(const std::string
& name
, const function
& function
)
784 lua_setglobal(state_
, name
.c_str());
787 status
do_string(const std::string
& commands
)
789 return status(luaL_dostring(state_
, commands
.c_str()));
792 status
do_file(const std::string
& file
)
794 return status(luaL_dofile(state_
, file
.c_str()));
799 * Thread-handling methods.
802 script
push_new_thread()
804 return script(state_
);
809 lua_pushthread(state_
);
813 status
resume(int nargs
)
815 return status(lua_resume(state_
, nargs
));
818 status
thread_status() const
820 return status(lua_status(state_
));
823 int yield(int results
)
825 return lua_yield(state_
, results
);
828 bool is_main_thread() const
830 bool is_main
= lua_pushthread(state_
);
837 * Throw an error with the value at the top of the stack. If this is
838 * called from an imported function, the error will be caught and
839 * returned on the stack when the execution aborts.
843 throw std::runtime_error("");
848 * Throw an error with a given message describing the problem. If this
849 * is called from an imported function, the error will be caught and
850 * returned on the stack when the execution aborts.
852 int raise(const std::string
& message
)
854 throw std::runtime_error(message
);
860 * Get significant values.
865 return slot(*this, globals_index
);
868 slot
registry() const
870 return slot(*this, registry_index
);
873 slot
environment() const
875 return slot(*this, environment_index
);
880 return slot(*this, stack_size());
885 * Set the size of the stack.
886 * \param size The stack size.
888 void stack_size(int size
)
890 lua_settop(state_
, size
);
894 * Get the size of the stack; this is also the index of the top-most
896 * \return The stack size.
898 int stack_size() const
900 return lua_gettop(state_
);
904 * Clear the stack, setting its size to zero.
913 * Makes sure there is at least extra more places on the stack.
914 * Returns false if space couldn't be created. Just like with the
915 * regular Lua API, you are responsible to make sure the stack is big
916 * enough to hold whatever you want to push on it. This is usually
917 * only an issue if you're pushing stuff in a loop.
919 bool check_stack(int extra
)
921 return (bool)lua_checkstack(state_
, extra
);
926 * Concatenates the top-most n slots on the stack.
928 void concatenate(int n
= 2)
930 lua_concat(state_
, n
);
935 * Push some values onto the stack.
938 slot
push(char value
)
940 lua_pushinteger(state_
, lua_Integer(value
));
943 slot
push(unsigned char value
)
945 lua_pushinteger(state_
, lua_Integer(value
));
948 slot
push(short value
)
950 lua_pushinteger(state_
, lua_Integer(value
));
953 slot
push(unsigned short value
)
955 lua_pushinteger(state_
, lua_Integer(value
));
960 lua_pushinteger(state_
, lua_Integer(value
));
963 slot
push(unsigned int value
)
965 lua_pushinteger(state_
, lua_Integer(value
));
968 slot
push(long value
)
970 lua_pushinteger(state_
, lua_Integer(value
));
973 slot
push(unsigned long value
)
975 lua_pushinteger(state_
, lua_Integer(value
));
978 slot
push(long long value
)
980 lua_pushinteger(state_
, lua_Integer(value
));
983 slot
push(unsigned long long value
)
985 lua_pushinteger(state_
, lua_Integer(value
));
989 slot
push(bool value
)
991 lua_pushboolean(state_
, int(value
));
995 slot
push(float value
)
997 lua_pushnumber(state_
, lua_Number(value
));
1000 slot
push(double value
)
1002 lua_pushnumber(state_
, lua_Number(value
));
1006 slot
push(const std::string
& value
)
1008 lua_pushlstring(state_
, value
.c_str(), value
.length());
1011 slot
push(const char* value
)
1013 lua_pushstring(state_
, value
);
1016 slot
push(const char* value
, size_t length
)
1018 lua_pushlstring(state_
, value
, length
);
1022 slot
push(const function
& function
)
1024 push
<script::function
>(function
);
1026 push(call_functor
, 2);
1029 slot
push(cfunction function
)
1031 push_pointer(function
);
1033 push(call_function
, 2);
1038 slot
push(const T
& object
)
1041 slot copy
= push_data(storage
, sizeof(T
));
1042 new(storage
) T(object
);
1044 push_class_metatable
<T
>();
1045 copy
.set_metatable();
1050 slot
push_class(const function
& ctor
)
1052 slot metatable
= push_class_metatable
<T
>();
1054 slot constructor
= push_table();
1056 constructor
.set_field("__call");
1057 metatable
.set_metatable();
1062 slot
push_class(cfunction ctor
)
1064 slot metatable
= push_class_metatable
<T
>();
1066 slot constructor
= push_table();
1068 constructor
.set_field("__call");
1069 metatable
.set_metatable();
1076 lua_pushnil(state_
);
1080 slot
push_from_thread(script
& thread
, int n
)
1082 lua_xmove(thread
.state_
, state_
, n
);
1086 slot
push_code(const std::string
& file
, status
& result
)
1088 result
= status(luaL_loadfile(state_
, file
.c_str()));
1092 slot
push_code(const std::string
& name
,
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_
, const_cast<void*>((const void*)ptr
));
1114 slot
push_pointer(cfunction function
)
1116 return push_pointer((void*)function
);
1119 slot
push_table(const std::string
& name
, int narr
= 0, int nrec
= 0)
1121 if (name
.empty()) return globals().push_field("_G");
1123 slot table
= globals().push_field(name
);
1124 if (table
.is_table()) return table
;
1127 push_table(narr
, nrec
);
1128 globals().set_field(name
);
1130 return globals().push_field(name
);
1132 slot
push_table(int narr
= 0, int nrec
= 0)
1134 lua_createtable(state_
, narr
, nrec
);
1138 slot
push_metatable(const std::string
& type
, bool& is_new
)
1140 is_new
= luaL_newmetatable(state_
, type
.c_str());
1143 slot
push_metatable(const std::string
& type
)
1145 luaL_newmetatable(state_
, type
.c_str());
1152 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));
1169 * Pops n values from the top of the stack.
1178 * Index into the stack to get a slot.
1180 slot
operator [] (int index
) const
1182 return slot(*this, index
);
1187 * Control over the garbage collection process.
1190 void collect_garbage()
1192 lua_gc(state_
, LUA_GCCOLLECT
, 0);
1194 void collect_garbage(int step
)
1196 lua_gc(state_
, LUA_GCSTEP
, step
);
1199 void disable_garbage_collector()
1201 lua_gc(state_
, LUA_GCSTOP
, 0);
1203 void enable_garbage_collector()
1205 lua_gc(state_
, LUA_GCRESTART
, 0);
1208 float memory_used() const
1211 return lua_gc(state_
, LUA_GCCOUNT
, 0) +
1212 lua_gc(state_
, LUA_GCCOUNTB
, 0) / 1024.0f
;
1215 void tune_garbage_collector(int pause
, int step
= 200)
1217 lua_gc(state_
, LUA_GCSETPAUSE
, pause
);
1218 lua_gc(state_
, LUA_GCSETSTEPMUL
, step
);
1224 script(lua_State
* state
) :
1225 state_(lua_newthread(state
)) {}
1227 slot
push(lua_CFunction function
, int upvalues
= 0)
1229 lua_pushcclosure(state_
, function
, upvalues
);
1234 slot
push_class_metatable()
1237 slot metatable
= push_metatable(typeid(T
).name(), is_new
);
1240 metatable
.push_copy(); // class behavior
1241 metatable
.set_field("__index");
1244 metatable
.set_field("__cxxtype"); // type_info
1246 push(object_finalizer_
<T
>);
1247 metatable
.set_field("__gc"); // finalizer
1249 //push(object_tostring_<T>);
1250 //metatable.set_field("__tostring"); // tostring
1256 static int object_tostring_(lua_State
* state
)
1258 std::ostringstream stream
;
1259 stream
<< *reinterpret_cast<T
*>(lua_touserdata(state
, 1));
1260 lua_pushlstring(state
, stream
.str().c_str(), stream
.str().length());
1265 static int object_finalizer_(lua_State
* state
)
1267 reinterpret_cast<T
*>(lua_touserdata(state
, 1))->~T();
1271 static int call_functor(lua_State
* state
)
1273 function
* function
= (script::function
*)lua_touserdata(state
,
1274 lua_upvalueindex(1));
1276 script
* script
= (moof::script
*)lua_touserdata(state
,
1277 lua_upvalueindex(2));
1281 return (*function
)(*script
);
1283 catch (const std::exception
& e
)
1285 if (0 < std::strlen(e
.what()))
1287 luaL_where(state
, 1);
1288 lua_pushstring(state
, e
.what());
1289 lua_concat(state
, 2);
1291 return lua_error(state
);
1293 catch (const char* e
)
1295 luaL_where(state
, 1);
1296 lua_pushstring(state
, e
);
1297 lua_concat(state
, 2);
1298 return lua_error(state
);
1302 return lua_error(state
);
1307 static int call_function(lua_State
* state
)
1309 cfunction function
= (cfunction
)lua_touserdata(state
,
1310 lua_upvalueindex(1));
1312 script
* script
= (moof::script
*)lua_touserdata(state
,
1313 lua_upvalueindex(2));
1317 return function(*script
);
1319 catch (const std::exception
& e
)
1321 if (0 < std::strlen(e
.what()))
1323 luaL_where(state
, 1);
1324 lua_pushstring(state
, e
.what());
1325 lua_concat(state
, 2);
1327 return lua_error(state
);
1329 catch (const char* e
)
1331 luaL_where(state
, 1);
1332 lua_pushstring(state
, e
);
1333 lua_concat(state
, 2);
1334 return lua_error(state
);
1338 return lua_error(state
);
1345 if (is_main_thread()) lua_close(state_
);
1352 using namespace std::rel_ops
;
1356 * Output a script value to a stream.
1358 inline std::ostream
& operator << (std::ostream
& stream
,
1359 const script::slot
& slot
)
1368 else if (slot
.get(boolean
))
1370 if (boolean
) stream
<< "true";
1371 else stream
<< "false";
1373 else if (slot
.is_nil())
1379 stream
<< slot
.type_name() << " (" << slot
.id() << ")";
1388 #endif // _MOOF_SCRIPT_HH_
This page took 0.105499 seconds and 4 git commands to generate.