#pragma once #include "reflection/Function.h" #include "script/LuaAtomicClasses.h" #include "script/LuaEnum.h" #include "script/ThreadRef.h" #include "script/LuaInstanceBridge.h" #include "rbx/make_shared.h" #include "rbx/DenseHash.h" #include "util/ProtectedString.h" #include "util/PhysicalProperties.h" namespace RBX { // Utility function that expands a variant to a strongly-typed value template R withVariantValue(const Reflection::Variant& value, F f) { if (value.isType()) return f(); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType< shared_ptr >()) return f(value.cast >()); if (const Reflection::EnumDescriptor* desc = Reflection::EnumDescriptor::lookupDescriptor(value.type())) { const Reflection::EnumDescriptor::Item* item = desc->lookup(value); if (item == NULL) throw RBX::runtime_error("Invalid value for enum %s", desc->name.c_str()); return f(*item); } if (value.isType()) return f(value.cast()); if (value.isType >()) return f(value.cast >()); if (value.isType >()) return f(value.cast >()); if (value.isType >()) return f(value.cast >()); if (value.isType >()) return f(value.cast >()); if (value.isType >()) return f(value.cast >()); if (value.isType< shared_ptr >()) return f(value.cast< shared_ptr >()); if (value.isType< shared_ptr >()) return f(value.cast< shared_ptr >()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if( value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(*value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); if (value.isType()) return f(value.cast()); RBXASSERT(0); return f(); } namespace Lua { class LuaArguments : public Reflection::FunctionDescriptor::Arguments { typedef DenseHashMap TablesCollection; static bool getRec(lua_State *L, int luaIndex, Reflection::Variant& value, bool treatNilAsMissing, TablesCollection* visitedTables = NULL); const int offset; lua_State * const L; public: LuaArguments(lua_State *L, int offset):L(L),offset(offset) {} virtual size_t size() const { return lua_gettop(L) - 1; } // Gets all arguments from the stack and puts them into the ValueArray static shared_ptr getValues(lua_State* L) { int argCount = lua_gettop(L); shared_ptr args(rbx::make_shared(argCount)); for (int i = 0; ivalues.at(i); bool success = RBX::Lua::LuaArguments::get(L, i+1, v, false); RBXASSERT(success); } return args; } static int pushTuple(const Reflection::Tuple& arguments, lua_State* L) { return pushValues(arguments.values, L); } // pushes all the values from the ValueArray onto the stack static int pushValues(const Reflection::ValueArray& arguments, lua_State* L) { int argCount = 0; Reflection::ValueArray::const_iterator end = arguments.end(); for (Reflection::ValueArray::const_iterator iter = arguments.begin(); iter != end; ++iter) { argCount += push(*iter, L); } return argCount; } ////////////////////////////////////// // Implemenent virtual functions // // Place the value for the requested parameter in "value". // // index: 1-based index into the argument list // value: the value to set. If index >= size(), then value is unchanged /*implement*/ bool getVariant(int index, Reflection::Variant& value) const { const int luaIndex = index + offset; RBXASSERT(luaIndex>0); return get(L, luaIndex, value, true); } /*implement*/ bool getLong(int index, long& value) const { // All numbers in Lua are double, so just call the double version of get double v; if (getDouble(index, v)) { value = G3D::iRound(v); return true; } return false; } /*implement*/ bool getDouble(int index, double& value) const; /*implement*/ bool getObject(int index, shared_ptr& value) const; /*implement*/ bool getBool(int index, bool& value) const; /*implement*/ bool getString(int index, std::string& value) const; /*implement*/ bool getVector3(int index, Vector3& value) const; /*implement*/ bool getRegion3(int index, Region3& value) const; /*implement*/ bool getVector3int16(int index, Vector3int16& value) const; /*implement*/ bool getRegion3int16(int index, Region3int16& value) const; /*implement*/ bool getRect(int index, Rect2D& value) const; /*implement*/ bool getPhysicalProperties(int index, PhysicalProperties& value) const; /*implement*/ bool getEnum(int index, const Reflection::EnumDescriptor& desc, int& value) const; // ////////////////////////////////////// // Gets a value from the Lua stack. Returns false if no value is found static bool get(lua_State *L, int luaIndex, Reflection::Variant& value, bool treatNilAsMissing); template static int pushArray(_InIt _First, _InIt _Last, lua_State * const L) { lua_createtable(L, _Last - _First, 0); unsigned int i = 0; while (_First!=_Last) { int count = push(*_First, L); RBXASSERT(count == 1); // If not 1, then what do we do? lua_rawseti(L, -2, ++i); ++_First; } return 1; } static int push(const Reflection::Variant& value, lua_State * const L); static int pushReturnValue(const Reflection::Variant& value, lua_State * const L); static shared_ptr convertToReturnValues(const Reflection::Variant& value); }; }}