|
Lua_icxx
1.02 (Aug 2011)
|
00001 /* 00002 This file is part of the Lua_icxx library. 00003 Copyright 2010 (c) by Oliver Schoenborn. 00004 License terms in LICENSE.txt. 00005 */ 00006 00007 00008 #include "LuaObjRef.h" 00009 #include "LuaFuncRef.h" 00010 #include "LuaTableRef.h" 00011 #include "LuaStackCleaner.h" 00012 00013 00014 LuaObjRef::LuaObjRef( const std::string& id ) 00015 : mLua(NULL), mID(id), mErrCode(LUA_NO_LUA) 00016 { 00017 assert( mRegKey.isNil() ); 00018 } 00019 00020 00021 LuaObjRef::LuaObjRef( lua_State* lua, int stackPos ) 00022 : mLua(lua), mRegKey(lua, stackPos), mErrCode(LUA_ERR_NONE) 00023 { 00024 assert(stackPos != 0); 00025 } 00026 00027 00028 LuaObjRef::LuaObjRef( const LuaTempResult::Item& resultItem ) 00029 : mLua(resultItem.mLua), mRegKey(mLua, resultItem.mStackPos) 00030 , mErrCode(resultItem.mErrCode) 00031 { 00032 } 00033 00034 00035 LuaObjRef::LuaObjRef( const LuaTempResult& result ) 00036 : mLua(result.getLuaState()), mRegKey(mLua, result.getStackPos(1)) 00037 , mErrCode( (LuaErrCode)result.getErrCode() ) 00038 { 00039 } 00040 00041 00042 void 00043 LuaObjRef::resetRef( const LuaTempResult::Item& resultItem ) 00044 { 00045 mLua = resultItem.mLua; 00046 mRegKey.reset(mLua, resultItem.mStackPos); 00047 mErrCode = resultItem.mErrCode; 00048 } 00049 00050 00051 /* Creates a __metatable field in this object's metatable, such that Lua code will 00052 not be able to change this object's metatable (only C++ can). 00053 Returns false if no metatable (nothing to protect); true otherwise. 00054 */ 00055 bool 00056 LuaObjRef::setMetaProtected( bool val ) 00057 { 00058 assert(mLua); 00059 const LuaStackCleaner s(mLua); 00060 pushObj(); 00061 // if we don't have a metatable, nothing to do 00062 assert( lua_checkstack(mLua, 2) ); 00063 if ( lua_getmetatable(mLua, -1) == 0 ) 00064 { 00065 assert( s.willPop(1) ); 00066 return false; 00067 } 00068 00069 if (val) 00070 lua_pushstring(mLua, "protected!"); 00071 else 00072 lua_pushnil(mLua); 00073 lua_setfield(mLua, -2, "__metatable"); 00074 assert( s.willPop(2) ); 00075 00076 return true; 00077 } 00078 00079 00080 // Sets (or replaces existing, if there is one) this object's metatable 00081 void 00082 LuaObjRef::setMetaTable( const LuaTableRef& metatable) 00083 { 00084 assert(mLua); 00085 const LuaStackCleaner s(mLua); 00086 pushObj(); 00087 metatable.pushObj(); 00088 lua_setmetatable(mLua, -2); 00089 assert( s.willPop(1) ); 00090 } 00091 00092 00093 // Gets this object's metatable, or nil if it has none 00094 LuaTempResult 00095 LuaObjRef::getMetaTable() const 00096 { 00097 assert(mLua); 00098 const int prevStackTop = lua_gettop(mLua); 00099 pushObj(); 00100 if ( lua_getmetatable(mLua, -1) != 0 ) 00101 lua_remove(mLua, -2); 00102 else 00103 { 00104 lua_pop(mLua, 1); 00105 lua_pushnil(mLua); 00106 } 00107 assert(lua_gettop(mLua) == prevStackTop + 1 ); 00108 return LuaTempResult(mLua, prevStackTop); 00109 } 00110 00111 00112 // Returns true if this object has a metatable, false otherwise 00113 bool 00114 LuaObjRef::hasMetaTable() const 00115 { 00116 assert(mLua); 00117 const LuaStackCleaner s(mLua); 00118 pushObj(); 00119 return lua_getmetatable(mLua, -1) != 0; 00120 } 00121 00122 00123 void 00124 LuaObjRef::setMetaMethod( MetaMethod id, const LuaFuncRef& func ) 00125 { 00126 assert(mLua); 00127 const LuaStackCleaner s(mLua); 00128 pushObj(); 00129 if ( lua_getmetatable(mLua, -1) == 0 ) 00130 { 00131 // no metatable; create one 00132 lua_newtable(mLua); 00133 } 00134 00135 func.pushObj(); 00136 lua_setfield(mLua, -2, getMetaMethodFromID(id)); 00137 assert( s.willPop(2) ); 00138 } 00139 00140 00141 const char* 00142 LuaObjRef::getMetaMethodFromID( MetaMethod id ) 00143 { 00144 switch (id) 00145 { 00146 case MM_ADD: return "__add"; 00147 case MM_SUBTRACT: return "__sub"; 00148 case MM_MULTIPLY: return "__mul"; 00149 case MM_DIVIDE: return "__div"; 00150 case MM_UNARY_MINUS: 00151 case MM_NEGATE: return "__unm"; 00152 case MM_CONCATENATE: return "__concat"; 00153 00154 case MM_EQUAL: return "__eq"; 00155 case MM_LESS_THAN: return "__lt"; 00156 case MM_LESS_OR_EQUAL: return "__le"; 00157 00158 case MM_TOSTRING: return "__tostring"; 00159 case MM_INDEX: 00160 case MM_FIELD: return "__index"; 00161 case MM_NEW_INDEX: 00162 case MM_NEW_FIELD: return "__newindex"; 00163 } 00164 assert(false); 00165 return ""; 00166 } 00167 00168 00169 bool 00170 LuaObjRef::hasMetaBase() const 00171 { 00172 assert(mLua); 00173 // get metatable 00174 const LuaStackCleaner s(mLua); 00175 pushObj(); 00176 lua_getmetatable(mLua, -1); 00177 00178 // if nil, done; 00179 if ( lua_isnil(mLua, -1) ) 00180 { 00181 assert( s.willPop(2) ); 00182 return false; 00183 } 00184 00185 // if field "__index" exists, answer is "true" 00186 lua_getfield(mLua, -2, "__index"); 00187 const bool hasBase = lua_isnil( mLua, -1 ); 00188 00189 // cleanup 00190 assert( s.willPop(3) ); 00191 return hasBase; 00192 } 00193 00194 00195 void 00196 LuaObjRef::setMetaBase( const LuaTableRef& baseTable) 00197 { 00198 assert(mLua); 00199 const LuaStackCleaner s(mLua); 00200 00201 // get metatable 00202 pushObj(); 00203 if ( lua_getmetatable(mLua, -1) == 0 ) 00204 // if nil, create a table and set as metatable 00205 { 00206 assert( lua_checkstack(mLua, 2) ); 00207 lua_newtable(mLua); 00208 lua_pushvalue(mLua, -1); // copy it 00209 lua_setmetatable(mLua, -3); 00210 } 00211 00212 // set field "__index" to baseTable 00213 baseTable.pushObj(); 00214 lua_setfield(mLua, -2, "__index"); 00215 00216 // pop as required 00217 assert( s.willPop(2) ); 00218 } 00219 00220 00221 std::string 00222 LuaObjRef::getErrMsg() 00223 const 00224 { 00225 if (! mErrCode) 00226 return ""; 00227 00228 if (mErrCode == LUA_NO_LUA) 00229 return "No Lua interpreter"; 00230 00231 LuaStackCleaner s(mLua); 00232 mRegKey.pushObj(); 00233 return getObjFromStack<std::string>(mLua); 00234 } 00235