Lua_icxx  1.02 (Aug 2011)
LuaObjRef.cpp
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