// // SqratMemberMethods: Member Methods // // // Copyright (c) 2009 Brandon Jones // Copyright 2011 Li-Cheng (Andy) Tai // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // #pragma once #include #include "sqratTypes.h" namespace Sqrat { /// @cond DEV // // Squirrel Member Functions // template struct SqMemberProxy { template static SQInteger Run(HSQUIRRELVM vm) { ArgFwd{}.Call(vm, 2, [](HSQUIRRELVM vm, A... a) { typedef R(C::*M)(A...); C* inst = Var(vm, 1).value; M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; R ret = (inst->*method)(std::forward< A >(a)...); PushVar(vm, ret); }); return 1; } template static SQInteger RunC(HSQUIRRELVM vm) { ArgFwd{}.Call(vm, 2, [](HSQUIRRELVM vm, A... a) { typedef R(C::*M)(A...) const; C* inst = Var(vm, 1).value; M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; R ret = (inst->*method)(std::forward< A >(a)...); PushVar(vm, ret); }); return 1; } }; // // reference return specialization // template struct SqMemberProxy { template static SQInteger Run(HSQUIRRELVM vm) { ArgFwd{}.Call(vm, 2, [](HSQUIRRELVM vm, A... a) { typedef R&(C::*M)(A...); C* inst = Var(vm, 1).value; M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; R& ret = (inst->*method)(std::forward< A >(a)...); PushVarR(vm, ret); }); return 1; } template static SQInteger RunC(HSQUIRRELVM vm) { ArgFwd{}.Call(vm, 2, [](HSQUIRRELVM vm, A... a) { typedef R&(C::*M)(A...) const; C* inst = Var(vm, 1).value; M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; R& ret = (inst->*method)(std::forward< A >(a)...); PushVarR(vm, ret); }); return 1; } }; // // void return specialization // template struct SqMemberProxy { template static SQInteger Run(HSQUIRRELVM vm) { ArgFwd{}.Call(vm, 2, [](HSQUIRRELVM vm, A... a) { typedef void(C::*M)(A...); C* inst = Var(vm, 1).value; M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; (inst->*method)(std::forward< A >(a)...); }); return 0; } template static SQInteger RunC(HSQUIRRELVM vm) { ArgFwd{}.Call(vm, 2, [](HSQUIRRELVM vm, A... a) { typedef void(C::*M)(A...) const; C* inst = Var(vm, 1).value; M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; (inst->*method)(std::forward< A >(a)...); }); return 0; } }; template struct SqMemberParamCheck { static inline bool Invalid(SQInteger top, SQInteger count) { return top != count; } }; template<> struct SqMemberParamCheck { static inline bool Invalid(SQInteger top, SQInteger count) { return top < count; } }; // // Squirrel Member Functions // template struct SqMember { // Function proxy template static SQFUNCTION GetProxy() { return +[](HSQUIRRELVM vm) -> SQInteger { #if !defined (SCRAT_NO_ERROR_CHECKING) if (!SQRAT_CONST_CONDITION(overloaded) && SqGlobalParamCheck< ArgFwd::HASOPT >::Invalid(sq_gettop(vm), 2 + sizeof...(A))) { return sq_throwerror(vm, _SC("wrong number of parameters")); } #endif try { return SqMemberProxy:: template Run(vm); } catch (const std::exception& e) { return sq_throwerror(vm, e.what()); } catch (...) { return sq_throwerror(vm, _SC("unknown exception occured")); } SQ_UNREACHABLE }; } // Function proxy template static SQFUNCTION GetProxyC() { return +[](HSQUIRRELVM vm) -> SQInteger { #if !defined (SCRAT_NO_ERROR_CHECKING) if (!SQRAT_CONST_CONDITION(overloaded) && SqGlobalParamCheck< ArgFwd::HASOPT >::Invalid(sq_gettop(vm), 2 + sizeof...(A))) { return sq_throwerror(vm, _SC("wrong number of parameters")); } #endif try { return SqMemberProxy::template RunC(vm); } catch (const std::exception& e) { return sq_throwerror(vm, e.what()); } catch (...) { return sq_throwerror(vm, _SC("unknown exception occured")); } SQ_UNREACHABLE }; } }; // // reference return specialization // template struct SqMember { // Function proxy template static SQFUNCTION GetProxy() { return +[](HSQUIRRELVM vm) -> SQInteger { #if !defined (SCRAT_NO_ERROR_CHECKING) if (!SQRAT_CONST_CONDITION(overloaded) && SqGlobalParamCheck< ArgFwd::HASOPT >::Invalid(sq_gettop(vm), 2 + sizeof...(A))) { return sq_throwerror(vm, _SC("wrong number of parameters")); } #endif try { return SqMemberProxy::template Run(vm); } catch (const std::exception& e) { return sq_throwerror(vm, e.what()); } catch (...) { return sq_throwerror(vm, _SC("unknown exception occured")); } SQ_UNREACHABLE }; } // Function proxy template static SQFUNCTION GetProxyC() { return +[](HSQUIRRELVM vm) -> SQInteger { #if !defined (SCRAT_NO_ERROR_CHECKING) if (!SQRAT_CONST_CONDITION(overloaded) && SqGlobalParamCheck< ArgFwd::HASOPT >::Invalid(sq_gettop(vm), 2 + sizeof...(A))) { return sq_throwerror(vm, _SC("wrong number of parameters")); } #endif try { return SqMemberProxy::template RunC(vm); } catch (const std::exception& e) { return sq_throwerror(vm, e.what()); } catch (...) { return sq_throwerror(vm, _SC("unknown exception occured")); } SQ_UNREACHABLE }; } }; // // void return specialization // template struct SqMember { // Function proxy template static SQFUNCTION GetProxy() { return +[](HSQUIRRELVM vm) -> SQInteger { #if !defined (SCRAT_NO_ERROR_CHECKING) if (!SQRAT_CONST_CONDITION(overloaded) && SqGlobalParamCheck< ArgFwd::HASOPT >::Invalid(sq_gettop(vm), 2 + sizeof...(A))) { return sq_throwerror(vm, _SC("wrong number of parameters")); } #endif try { return SqMemberProxy::template Run(vm); } catch (const std::exception& e) { return sq_throwerror(vm, e.what()); } catch (...) { return sq_throwerror(vm, _SC("unknown exception occured")); } SQ_UNREACHABLE }; } // Function proxy template static SQFUNCTION GetProxyC() { return +[](HSQUIRRELVM vm) -> SQInteger { #if !defined (SCRAT_NO_ERROR_CHECKING) if (!SQRAT_CONST_CONDITION(overloaded) && SqGlobalParamCheck< ArgFwd::HASOPT >::Invalid(sq_gettop(vm), 2 + sizeof...(A))) { return sq_throwerror(vm, _SC("wrong number of parameters")); } #endif try { return SqMemberProxy::template RunC(vm); } catch (const std::exception& e) { return sq_throwerror(vm, e.what()); } catch (...) { return sq_throwerror(vm, _SC("unknown exception occured")); } SQ_UNREACHABLE }; } }; // Member Function Resolver template SQFUNCTION SqMemberFunc(R (C::* /*method*/)(A...)) { return SqMember::template GetProxy(); } // Member Function Resolver template SQFUNCTION SqMemberFunc(R (C::* /*method*/)(A...) const) { return SqMember::template GetProxyC(); } // Member Function Resolver template SQFUNCTION SqMemberFunc(R& (C::* /*method*/)(A...)) { return SqMember::template GetProxy(); } // Member Function Resolver template SQFUNCTION SqMemberFunc(R& (C::* /*method*/)(A...) const) { return SqMember::template GetProxyC(); } // // Variable Get // template inline SQInteger sqDefaultGet(HSQUIRRELVM vm) { C* ptr; SQTRY() ptr = Var(vm, 1).value; SQCATCH_NOEXCEPT(vm) { SQCLEAR(vm); // clear the previous error return sq_throwerror(vm, SQWHAT_NOEXCEPT(vm)); } SQCATCH(vm) { return sq_throwerror(vm, SQWHAT(vm)); } typedef V C::*M; M* memberPtr = nullptr; sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, nullptr); // Get Member... M member = *memberPtr; PushVarR(vm, ptr->*member); return 1; } template inline SQInteger sqStaticGet(HSQUIRRELVM vm) { typedef V *M; M* memberPtr = nullptr; sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, nullptr); // Get Member... M member = *memberPtr; PushVarR(vm, *member); return 1; } inline SQInteger sqVarGet(HSQUIRRELVM vm) { // Find the get method in the get table sq_push(vm, 2); #if !defined (SCRAT_NO_ERROR_CHECKING) if (SQ_FAILED(sq_rawget(vm, -2))) { #if (SQUIRREL_VERSION_NUMBER>= 200) && (SQUIRREL_VERSION_NUMBER < 300) // Squirrel 2.x return sq_throwerror(vm, _SC("member variable not found")); #else // Squirrel 3.x sq_pushnull(vm); return sq_throwobject(vm); #endif } #else sq_rawget(vm, -2); #endif // push 'this' sq_push(vm, 1); // Call the getter #if !defined (SCRAT_NO_ERROR_CHECKING) SQRESULT result = sq_call(vm, 1, true, ErrorHandling::IsEnabled()); if (SQ_FAILED(result)) { return sq_throwerror(vm, LastErrorString(vm).c_str()); } #else sq_call(vm, 1, true, ErrorHandling::IsEnabled()); #endif return 1; } // // Variable Set // template inline SQInteger sqDefaultSet(HSQUIRRELVM vm) { C* ptr; SQTRY() ptr = Var(vm, 1).value; SQCATCH_NOEXCEPT(vm) { SQCLEAR(vm); // clear the previous error return sq_throwerror(vm, SQWHAT_NOEXCEPT(vm)); } SQCATCH(vm) { return sq_throwerror(vm, SQWHAT(vm)); } typedef V C::*M; M* memberPtr = nullptr; sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, nullptr); // Get Member... M member = *memberPtr; SQTRY() if (is_pointer::value || is_reference::value) { ptr->*member = Var(vm, 2).value; } else { ptr->*member = Var(vm, 2).value; } SQCATCH_NOEXCEPT(vm) { return sq_throwerror(vm, SQWHAT_NOEXCEPT(vm)); } SQCATCH(vm) { return sq_throwerror(vm, SQWHAT(vm)); } return 0; } template inline SQInteger sqStaticSet(HSQUIRRELVM vm) { typedef V *M; M* memberPtr = nullptr; sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, nullptr); // Get Member... M member = *memberPtr; SQTRY() if (is_pointer::value || is_reference::value) { *member = Var(vm, 2).value; } else { *member = Var(vm, 2).value; } SQCATCH_NOEXCEPT(vm) { return sq_throwerror(vm, SQWHAT_NOEXCEPT(vm)); } SQCATCH(vm) { return sq_throwerror(vm, SQWHAT(vm)); } return 0; } inline SQInteger sqVarSet(HSQUIRRELVM vm) { // Find the set method in the set table sq_push(vm, 2); #if !defined (SCRAT_NO_ERROR_CHECKING) if (SQ_FAILED(sq_rawget(vm, -2))) { #if (SQUIRREL_VERSION_NUMBER>= 200) && (SQUIRREL_VERSION_NUMBER < 300) // Squirrel 2.x return sq_throwerror(vm, _SC("member variable not found")); #else // Squirrel 3.x sq_pushnull(vm); return sq_throwobject(vm); #endif } #else sq_rawget(vm, -2); #endif // push 'this' sq_push(vm, 1); sq_push(vm, 3); // Call the setter #if !defined (SCRAT_NO_ERROR_CHECKING) SQRESULT result = sq_call(vm, 2, false, ErrorHandling::IsEnabled()); if (SQ_FAILED(result)) { return sq_throwerror(vm, LastErrorString(vm).c_str()); } #else sq_call(vm, 2, false, ErrorHandling::IsEnabled()); #endif return 0; } /// @endcond }