static int _as(lua_State *L) { // as of null returns null if (lua_isnil(L, 1)) { lua_pushnil(L); return 1; } // get the assembly lookup table lua_rawgeti(L, LUA_GLOBALSINDEX, LSASSEMBLYLOOKUP); // push the (interned) assembly name lua_pushvalue(L, 2); lua_gettable(L, -2); // get the Assembly* Assembly *assembly = (Assembly *)lua_topointer(L, -1); lua_pop(L, 2); lmAssert(assembly, "Object::_as - unable to get Assembly"); LSLuaState *lstate = assembly->getLuaState(); // the castType is the type we're casting to Type *castType = assembly->getTypeByOrdinal((LSTYPEID)lua_tonumber(L, 3)); lmAssert(castType, "Object::_as - unable to resolve TypeID %u", (LSTYPEID)lua_tonumber(L, 3)); // checking number -> enum coercian if (lua_isnumber(L, 1)) { if (castType->isEnum()) { lua_pushvalue(L, 1); return 1; } } bool valid = false; if (castType == lstate->numberType) { if (lua_isnumber(L, 1)) { valid = true; } } else if (castType == lstate->stringType) { if (lua_isstring(L, 1)) { valid = true; } } else if (castType == lstate->booleanType) { if (lua_isboolean(L, 1)) { valid = true; } } else if (castType == lstate->functionType) { if (lua_iscfunction(L, 1)) { valid = true; } else if (lua_isfunction(L, 1)) { valid = true; } } else { // If it's a primitive type but we expected an instance table, it is nil. valid = true; if (lua_isnumber(L, 1)) { valid = false; } else if (lua_isstring(L, 1)) { valid = false; } else if (lua_isboolean(L, 1)) { valid = false; } else if (lua_iscfunction(L, 1)) { valid = false; } else if (lua_isfunction(L, 1)) { valid = false; } if (valid) { // If we are not a primitive type (as detected previously) // we should be an instance table, if not something went horribly wrong if (!lua_istable(L, 1)) { lua_pushfstring(L, "Object._as - instance table expected but got %s", lua_typename(L, 1)); lua_error(L); } // retrieve the instance's type lua_rawgeti(L, 1, LSINDEXTYPE); Type *type = (Type *)lua_topointer(L, -1); lmAssert(type, "error getting type in Object._as"); lua_rawgeti(L, 1, LSINDEXDELETEDMANAGED); if (lua_toboolean(L, -1) == 1) { lua_pushfstring(L, "Object._as - accessing deleted managed native instance of type %s", type->getFullName().c_str()); lua_error(L); } lua_pop(L, 1); // we're the same type, so push identity and return if (castType == type) { lua_pushvalue(L, 1); return 1; } // if we're native types, C++ RTTI can be used if (type->isNative() && castType->isNative()) { // get the native user data from the instance lua_rawgeti(L, 1, LSINDEXNATIVE); assert(lua_isuserdata(L, -1)); Detail::Userdata *ptr = (Detail::Userdata *)lua_topointer(L, -1); // push the instance on the stack, possibly downcasting it NativeInterface::pushDynamicCast(L, type, castType, 1, ptr->getPointer()); return 1; } valid = type->castToType(castType) ? true : false; } } if (valid) { lua_pushvalue(L, 1); } else { lua_pushnil(L); } return 1; }