]>
Dogcows Code - chaz/yoink/blob - src/Moof/Script.hh
2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *******************************************************************************/
29 #ifndef _MOOF_SCRIPT_HH_
30 #define _MOOF_SCRIPT_HH_
34 * A thin wrapper over Lua. This is not meant as a complicated binding package
35 * between C++ and Lua. It does not try to make the boundary invisible. It
36 * does not hide the concept of the Lua stack, but rather provides that
37 * mechanism with a certain level of abstraction while also providing a cleaner,
38 * more consistent API.
46 #include <boost/bind.hpp>
47 #include <boost/function.hpp>
48 #include <boost/shared_ptr.hpp>
52 #include <Moof/Exception.hh>
53 #include <Moof/Log.hh>
60 typedef boost::shared_ptr
<Script
> ScriptP
;
65 typedef boost::function
<int(Script
&)> Function
;
71 BOOLEAN
= LUA_TBOOLEAN
,
72 LIGHTUSERDATA
= LUA_TLIGHTUSERDATA
,
76 FUNCTION
= LUA_TFUNCTION
,
77 USERDATA
= LUA_TUSERDATA
,
85 RUNTIME_ERROR
= LUA_ERRRUN
,
86 SYNTAX_ERROR
= LUA_ERRSYNTAX
,
87 MEMORY_ERROR
= LUA_ERRMEM
,
88 HANDLER_ERROR
= LUA_ERRERR
,
89 FILE_ERROR
= LUA_ERRFILE
94 REGISTRY
= LUA_REGISTRYINDEX
,
95 ENVIRONMENT
= LUA_ENVIRONINDEX
,
96 GLOBALS
= LUA_GLOBALSINDEX
100 * This is the most noticeable abstraction on top of the standard Lua API.
101 * A Value object represents a value on the stack. More specifically, it
102 * represents a position on the stack. The distinction is only important
103 * when values are moved around on the stack or if the Value represents a
104 * negative index on the stack (the value of which will change as things are
105 * pushed onto and popped from the stack).
111 * You have direct access to the index of the value on the stack being
119 * A default-constructed Value is invalid until a valid Value is
120 * assigned to it. The only method that should be called on such a
121 * Value is isValid(), otherwise chaos may ensue. In this case, the
122 * Value will be invalid even if index is manually changed to a valid
123 * index. You have to index the script itself to get a valid Value.
125 Value(lua_State
* s
= 0, int i
= 0) :
130 * A copied value presently points to the same value, except the real
131 * index is used. That means that if a value that refers to a frame
132 * referenced from the top of the stack will have its normalized index
133 * copied into the new value object.
136 Value(const Value
& copy
) :
137 index(copy
.getRealIndex()),
141 // check the type of the value
142 bool isBoolean() const { return (bool)lua_isboolean(state
, index
); }
143 bool isFunction() const { return (bool)lua_isfunction(state
, index
); }
144 bool isNil() const { return (bool)lua_isnil(state
, index
); }
145 bool isNone() const { return (bool)lua_isnone(state
, index
); }
146 bool isValid() const { return state
!= 0 && !isNone(); }
147 bool isNoneOrNil() const { return (bool)lua_isnoneornil(state
, index
); }
148 bool isNumber() const { return (bool)lua_isnumber(state
, index
); }
149 bool isString() const { return (bool)lua_isstring(state
, index
); }
150 bool isTable() const { return (bool)lua_istable(state
, index
); }
151 bool isThread() const { return (bool)lua_isthread(state
, index
); }
152 bool isData() const { return (bool)lua_isuserdata(state
, index
); }
153 bool isLightData() const { return (bool)lua_islightuserdata(state
, index
); }
156 * Check the value and throw and error if its the wrong type. This
157 * method never returns because it does a long jump. Consequently,
158 * constructed C++ objects which exist on the stack between the current
159 * frame and some lua function will not be destructed. That's not a
160 * problem for objects that only exist on the stack, but any objects
161 * that allocate memory on the heap (such as containers or strings) will
162 * leak. Therefore, you should only call this method after cleaning up
166 void requireType(TYPE type
) const
168 if (type
!= getType())
170 luaL_typerror(state
, index
, lua_typename(state
, type
));
174 void throwError(const char* error
)
176 luaL_argerror(state
, index
, error
);
180 Value
& requireBoolean()
182 if (!isBoolean()) luaL_typerror(state
, index
, "boolean");
185 Value
& requireNumber()
187 if (!isNumber()) luaL_typerror(state
, index
, "number");
190 Value
& requireString()
192 if (!isString()) luaL_typerror(state
, index
, "string");
195 Value
& requireTable()
197 if (!isTable()) luaL_typerror(state
, index
, "table");
200 Value
& requireFunction()
202 if (!isFunction()) luaL_typerror(state
, index
, "function");
207 if (!isData()) luaL_typerror(state
, index
, "data");
212 if (!isNil()) luaL_typerror(state
, index
, "nil");
215 Value
& requireThread()
217 if (!isThread()) luaL_typerror(state
, index
, "thread");
223 * Get the type of the value.
228 return (TYPE
)lua_type(state
, index
);
232 * Get the name of the type of the value as a string.
235 std::string
getTypeName() const
237 return std::string(luaL_typename(state
, index
));
242 * Get the length of the value according to the definition given by Lua.
245 size_t getLength() const
247 return lua_objlen(state
, index
);
250 int getRealIndex() const
252 if (index
< 0) return lua_gettop(state
) + 1 + index
;
258 * Get a pointer value (for userdata, tables, threads, and functions).
261 const void* getIdentifier() const
263 return lua_topointer(state
, index
);
267 bool operator == (const Value
& rhs
) const
269 return (bool)lua_equal(state
, index
, rhs
.index
);
271 bool operator != (const Value
& rhs
) const
273 return !(*this == rhs
);
275 bool operator < (const Value
& rhs
) const
277 return (bool)lua_lessthan(state
, index
, rhs
.index
);
279 bool operator <= (const Value
& rhs
) const
281 return *this < rhs
|| *this == rhs
;
283 bool operator > (const Value
& rhs
) const
285 return !(*this <= rhs
);
287 bool operator >= (const Value
& rhs
) const
289 return !(*this < rhs
);
291 operator bool () const
293 return (bool)lua_toboolean(state
, index
);
296 Value
& operator = (const Value
& rhs
)
305 * Convert the underlying value to a C++ type.
308 template <typename T
>
309 bool get(T
& value
) const
313 value
= (T
)lua_tointeger(state
, index
);
319 bool get(float& value
) const
323 value
= (float)lua_tonumber(state
, index
);
328 bool get(double& value
) const
332 value
= (double)lua_tonumber(state
, index
);
338 bool get(bool& value
) const
342 value
= (bool)lua_toboolean(state
, index
);
348 bool get(std::string
& value
) const
353 const char* str
= lua_tolstring(state
, index
, &size
);
354 value
.assign(str
, size
);
360 template <typename T
>
361 bool get(std::vector
<T
>& array
) const
363 if (!isTable()) return false;
367 Value
value(state
, -1);
368 int realIndex
= getRealIndex();
371 for (int i
= 1; !done
; ++i
)
373 lua_rawgeti(state
, realIndex
, i
);
376 if (value
.get(v
)) array
.push_back(v
);
385 template <typename T
>
386 bool get(std::map
<std::string
,T
>& dictionary
) const
388 if (!isTable()) return false;
392 Value
key(state
, -2);
393 Value
value(state
, -1);
394 int realIndex
= getRealIndex();
397 while (lua_next(state
, realIndex
) != 0)
400 if (!key
.isNumber() && key
.get(k
))
403 if (value
.get(v
)) dictionary
[k
] = v
;
415 * Copy the value and push the copy to the stack.
418 void pushCopy() const
420 lua_pushvalue(state
, index
);
424 * Replace this value with the value at the top of the stack.
427 void replaceWithTop()
429 lua_replace(state
, index
);
434 lua_remove(state
, index
);
438 * Inserts the top-most value on the stack at position index, shifting other
444 lua_insert(state
, index
);
448 void pushMetatable() const
450 lua_getmetatable(state
, index
);
453 void pushField() const
455 lua_gettable(state
, index
);
458 void pushField(const std::string
& name
) const
460 lua_getfield(state
, index
, name
.c_str());
471 mState(luaL_newstate())
473 lua_pushlightuserdata(mState
, this);
474 lua_setfield(mState
, LUA_REGISTRYINDEX
, "_script_obj");
479 if (mIsMainThread
) lua_close(mState
);
483 static ScriptP
alloc()
485 return ScriptP(new Script
);
489 void importStandardLibraries()
491 luaL_openlibs(mState
);
494 void importFunction(const std::string
& name
, const Function
& function
)
497 lua_setglobal(mState
, name
.c_str());
501 STATUS
doString(const std::string
& commands
)
503 return (STATUS
)luaL_dostring(mState
, commands
.c_str());
506 STATUS
doFile(const std::string
& file
)
508 return (STATUS
)luaL_dofile(mState
, file
.c_str());
513 * Thread-handling methods.
516 Script
pushNewThread()
518 return Script(mState
);
523 lua_pushthread(mState
);
526 STATUS
resume(int nargs
)
528 return (STATUS
)lua_resume(mState
, nargs
);
531 STATUS
getStatus() const
533 return (STATUS
)lua_status(mState
);
536 int yield(int results
)
538 return lua_yield(mState
, results
);
541 bool isMainThread() const
543 return mIsMainThread
;
548 * Throw an error with the value at the top of the stack. This method never
549 * returns because it does a long jump. Consequently, constructed C++
550 * objects which exist on the stack between the current frame and some lua
551 * function will not be destructed. That's not a problem for objects that
552 * only exist on the stack, but any objects that allocate memory on the heap
553 * (such as containers or strings) will leak. Therefore, you should only
554 * call this method after cleaning up such objects.
564 * Get significant values.
567 Value
getGlobalTable() const
569 return Value(mState
, GLOBALS
);
572 Value
getRegistryTable() const
574 return Value(mState
, REGISTRY
);
577 Value
getEnvironmentTable() const
579 return Value(mState
, ENVIRONMENT
);
584 return Value(mState
, lua_gettop(mState
));
588 * Get the size of the stack; this is also the index of the top-most value.
593 return lua_gettop(mState
);
596 void setSize(int size
)
598 lua_settop(mState
, size
);
608 * Makes sure there is at least extra more places on the stack. Returns
609 * false if space couldn't be created. Just like with the regular Lua API,
610 * you are responsible to make sure the stack is big enough to hold whatever
611 * you want to push on it. This is usually only an issue if you're pushing
615 bool checkStack(int extra
)
617 return (bool)lua_checkstack(mState
, extra
);
622 * Concatenates the top-most n values on the stack.
627 lua_concat(mState
, n
);
632 * Push some values onto the stack.
635 template <typename T
>
638 lua_pushinteger(mState
, lua_Integer(value
));
641 void push(bool value
)
643 lua_pushboolean(mState
, int(value
));
646 void push(float value
)
648 lua_pushnumber(mState
, (lua_Number
)value
);
650 void push(double value
)
652 lua_pushnumber(mState
, (lua_Number
)value
);
655 void push(const std::string
& value
)
657 lua_pushlstring(mState
, value
.c_str(), value
.length());
659 void push(const char* value
)
661 lua_pushstring(mState
, value
);
663 void push(const char* value
, size_t length
)
665 lua_pushlstring(mState
, value
, length
);
668 void push(const Function
& function
)
670 mFunctions
.push_back(function
);
672 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
673 lua_pushcclosure(mState
, dispatchCall
, 1);
676 void push(void* data
)
678 lua_pushlightuserdata(mState
, data
);
686 void pushFromThread(Script
& thread
, int n
)
688 lua_xmove(thread
.mState
, mState
, n
);
691 STATUS
pushCode(const std::string
& filename
)
693 return (STATUS
)luaL_loadfile(mState
, filename
.c_str());
696 STATUS
pushCode(const std::string
& name
, const char* buffer
, size_t size
)
698 return (STATUS
)luaL_loadbuffer(mState
, buffer
, size
, name
.c_str());
701 void* pushNewData(size_t size
)
703 return lua_newuserdata(mState
, size
);
708 lua_newtable(mState
);
713 * Call a function on the stack. The correct procedure is to push a
714 * function onto the stack followed by nargs arguments. This method will
715 * pop them off upon return, leaving up to nresults return values (default
716 * is any number of return values, depending on the callee).
719 STATUS
call(int nargs
, int nresults
= LUA_MULTRET
)
721 return (STATUS
)lua_pcall(mState
, nargs
, nresults
, 0);
726 * Pops n values from the top of the stack.
736 * Index into the stack to get a Value.
739 Value
operator [] (int index
) const
741 return Value(mState
, index
);
746 * Getting and setting fields of a table.
749 void get(const std::string
& field
, int index
= GLOBALS
) const
751 lua_getfield(mState
, index
, field
.c_str());
754 void set(const std::string
& field
, int index
= GLOBALS
)
756 lua_setfield(mState
, index
, field
.c_str());
761 * Control over the garbage collection process.
766 lua_gc(mState
, LUA_GCCOLLECT
, 0);
771 lua_gc(mState
, LUA_GCSTOP
, 0);
774 void restartCollector()
776 lua_gc(mState
, LUA_GCRESTART
, 0);
779 int getUsedMemory() const
782 return lua_gc(mState
, LUA_GCCOUNT
, 0);
785 void collectStep(int step
)
787 lua_gc(mState
, LUA_GCSTEP
, step
);
790 void tuneCollector(int pause
, int step
)
792 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
793 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
798 struct Exception
: public Mf::Exception
800 explicit Exception(unsigned error
) :
801 Mf::Exception(error
) {}
812 Script(lua_State
* state
) :
813 mState(lua_newthread(state
)),
814 mIsMainThread(false) {}
816 static int dispatchCall(lua_State
* state
)
818 const Function
* function
= (const Function
*)lua_touserdata(state
,
819 lua_upvalueindex(1));
821 lua_getfield(state
, LUA_REGISTRYINDEX
, "_script_obj");
822 Script
* script
= (Script
*)lua_touserdata(state
, -1);
825 return (*function
)(*script
);
830 std::list
<Function
> mFunctions
;
836 #endif // _MOOF_SCRIPT_HH_
838 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.069533 seconds and 4 git commands to generate.