//----------------------------------------------------------------// // userdata -> memberTable -> refTable -> interfaceTable // userdata is the object // memberTable is for ad hoc members added by the scripter // refTable is for ad hoc mambers added by the engine // interfaceTable is the 'class' table - methods and constants // __index looks in membertTable then *skips* refTable to fall back on interfaceTable void MOAILuaObject::BindToLua ( MOAILuaState& state ) { assert ( !this->mUserdata ); if ( MOAILuaRuntime::IsValid ()) { MOAILuaRuntime::Get ().RegisterObject ( state, *this ); } MOAILuaClass* type = this->GetLuaClass (); assert ( type ); // both singletons and instances may be bound to a userdata state.PushPtrUserData ( this ); // userdata // for now, singletons are just userdata with no add'l metatables // so only build the metatable stack if we're *not* a singleton if ( !type->IsSingleton ()) { // instances get the 'full stack' of metatables lua_newtable ( state ); // ref table lua_newtable ( state ); // member table type->PushInterfaceTable ( state ); // interface table this->MakeLuaBinding ( state ); } // and take a weak ref back to the userdata this->mUserdata.SetRef ( state, -1 ); assert ( !lua_isnil ( state, -1 )); // NOTE: we have to do this *after* mUserdata has been initialized as LuaRetain calls PushLuaUserdata // which in turn calls BindToLua if there is no mUserdata... if ( type->IsSingleton ()) { this->LuaRetain ( this ); // create a circular reference to 'pin' the userdata } }
//----------------------------------------------------------------// void MOAILuaObject::BindToLuaWithTable ( MOAILuaState& state ) { assert ( !this->mUserdata ); assert ( state.IsType ( -1, LUA_TTABLE )); MOAILuaClass* type = this->GetLuaClass (); assert ( type ); // create and initialize a new userdata state.PushPtrUserData ( this ); // create and initialize the private table lua_newtable ( state ); // set the ref to the private table lua_pushvalue ( state, -3 ); lua_setfield ( state, -2, LUA_MEMBER_TABLE_NAME ); // initialize the private table lua_pushcfunction ( state, MOAILuaObject::_gc ); lua_setfield ( state, -2, "__gc" ); lua_pushcfunction ( state, MOAILuaObject::_tostring ); lua_setfield ( state, -2, "__tostring" ); lua_pushcfunction ( state, MOAILuaObject::_index ); lua_setfield ( state, -2, "__index" ); lua_pushcfunction ( state, MOAILuaObject::_newindex ); lua_setfield ( state, -2, "__newindex" ); // make the interface table the instance table's meta type->PushInterfaceTable ( state ); lua_setmetatable ( state, -2 ); // grab a ref to the instance table; attach it to the userdata this->mInstanceTable = state.GetWeakRef ( -1 ); lua_setmetatable ( state, -2 ); // and take a ref back to the userdata if ( this->GetRefCount () == 0 ) { this->mUserdata.SetWeakRef ( state, -1 ); } else { this->mUserdata.SetStrongRef ( state, -1 ); } // overwrite the member table lua_replace ( state, -2 ); assert ( !lua_isnil ( state, -1 )); }
//----------------------------------------------------------------// void MOAILuaObject::BindToLua ( MOAILuaState& state ) { assert ( !this->mUserdata ); MOAILuaClass* type = this->GetLuaClass (); assert ( type ); // create and initialize a new userdata state.PushPtrUserData ( this ); // create and initialize the member table lua_newtable ( state ); lua_pushvalue ( state, -1 ); lua_setfield ( state, -2, "__index" ); lua_pushvalue ( state, -1 ); lua_setfield ( state, -2, "__newindex" ); lua_pushcfunction ( state, MOAILuaObject::_gc ); lua_setfield ( state, -2, "__gc" ); lua_pushcfunction ( state, MOAILuaObject::_tostring ); lua_setfield ( state, -2, "__tostring" ); // attach the member table to the userdata lua_pushvalue ( state, -1 ); lua_setmetatable ( state, -3 ); // grab a ref to the member table this->mMemberTable = state.GetWeakRef ( -1 ); // stack: // -1: member table // -2: userdata // create an empty ref table and attach it to the member table lua_newtable ( state ); lua_pushvalue ( state, -1 ); lua_setmetatable ( state, -3 ); // stack: // -1: ref table // -2: member table // -3: userdata // push the interface table and attach it to the ref table type->PushInterfaceTable ( state ); lua_pushvalue ( state, -1 ); lua_setmetatable ( state, -3 ); // stack: // -1: interface table // -2: ref table // -3: member table // -4: userdata // use the interface table as the ref table's __index lua_setfield ( state, -2, "__index" ); // stack: // -1: ref table // -2: member table // -3: userdata lua_pop ( state, 2 ); // stack: // -1: userdata // and take a ref back to the userdata if ( this->GetRefCount () == 0 ) { this->mUserdata.SetWeakRef ( state, -1 ); } else { this->mUserdata.SetStrongRef ( state, -1 ); } assert ( !lua_isnil ( state, -1 )); }
//----------------------------------------------------------------// int MOAILuaClass::_extendSingleton ( lua_State* L ) { MOAILuaState state ( L ); // upvalues: // 1: singleton userdata // 2: class table // set the userdata MOAILuaObject* luaData = ( MOAILuaObject* )state.GetPtrUserData ( lua_upvalueindex ( 1 )); state.PushPtrUserData ( luaData ); // clone the class table state.CloneTable ( lua_upvalueindex ( 2 )); lua_pushvalue ( state, -1 ); lua_setfield ( state, -2, "__index" ); lua_pushvalue ( state, -1 ); lua_setfield ( state, -2, "__newindex" ); // add getClassName to class table lua_pushvalue ( L, 1 ); lua_pushcclosure ( L, _getUpvalue, 1 ); lua_setfield ( L, -2, "getClassName" ); // copy the extended userdata lua_pushvalue ( L, -2 ); // copy the extended table lua_pushvalue ( L, -2 ); // push the 'extend' method with the singleton userdata and extended class table upvalues lua_pushcclosure ( L, _extendSingleton, 2 ); // set the extended 'extend' method... lua_setfield ( L, -2, "extend" ); // stack: // -1: extended class table // -2: extended userdata // call the extender if ( state.IsType ( 2, LUA_TFUNCTION )) { lua_pushvalue ( L, 2 ); lua_pushvalue ( L, -2 ); lua_pushvalue ( L, lua_upvalueindex ( 2 )); state.DebugCall ( 2, 0 ); } // stack: // -1: extended class table // -2: extended userdata // set the table as a metatable on the userdata lua_setmetatable ( L, -2 ); // and we're done cc8* classname = state.GetValue < cc8* >( 1, "" ); lua_setglobal ( state, classname ); return 0; }