1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-01-19 03:57:14 +01:00

Simplify the script function wrapper.

This commit is contained in:
Sandu Liviu Catalin 2018-07-31 17:41:46 +03:00
parent e48cb3b43c
commit 4c111d4139
2 changed files with 112 additions and 279 deletions

View File

@ -39,9 +39,7 @@
namespace Sqrat { namespace Sqrat {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Represents a function in Squirrel
/// Represents a function in Squirrel
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Function { class Function {
friend class TableBase; friend class TableBase;
@ -51,242 +49,136 @@ class Function {
private: private:
HSQUIRRELVM vm;
HSQOBJECT env, obj; HSQOBJECT env, obj;
public: public:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Default constructor (null)
/// Default constructor (null) Function() noexcept {
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Function() {
sq_resetobject(&env); sq_resetobject(&env);
sq_resetobject(&obj); sq_resetobject(&obj);
} }
// Copy constructor
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function(const Function& sf) noexcept : env(sf.env), obj(sf.obj) {
/// Copy constructor sq_addref(DefaultVM::Get_(), &env);
/// sq_addref(DefaultVM::Get_(), &obj);
/// \param sf Function to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Function(const Function& sf) : vm(sf.vm), env(sf.env), obj(sf.obj) {
sq_addref(vm, &env);
sq_addref(vm, &obj);
} }
// Move constructor
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function(Function&& sf) noexcept : env(sf.env), obj(sf.obj) {
/// Move constructor
///
/// \param sf Function to move
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Function(Function&& sf) : vm(sf.vm), env(sf.env), obj(sf.obj) {
sq_resetobject(&sf.GetEnv()); sq_resetobject(&sf.GetEnv());
sq_resetobject(&sf.GetFunc()); sq_resetobject(&sf.GetFunc());
} }
// Constructs a Function from a slot in an Object
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function(const Object& e, const SQChar* slot) : env(e.GetObject()) {
/// Constructs a Function from a slot in an Object sq_addref(DefaultVM::Get_(), &env);
///
/// \param e Object that potentially contains a Squirrel function in a slot
/// \param slot Name of the slot to look for the Squirrel function in
///
/// \remarks
/// This function MUST have its Error handled if it occurred.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Function(const Object& e, const SQChar* slot) : vm(e.GetVM()), env(e.GetObject()) {
sq_addref(vm, &env);
Object so = e.GetSlot(slot); Object so = e.GetSlot(slot);
obj = so.GetObject(); obj = so.GetObject();
sq_addref(vm, &obj); sq_addref(DefaultVM::Get_(), &obj);
#if !defined (SCRAT_NO_ERROR_CHECKING) #if !defined (SCRAT_NO_ERROR_CHECKING)
SQObjectType value_type = so.GetType(); SQObjectType value_type = so.GetType();
if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE && value_type != OT_CLASS) { if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) {
// Note that classes can also be considered functions in Squirrel // Note that classes can also be considered functions in Squirrel
SQTHROW(vm, _SC("function not found in slot")); SQTHROW(DefaultVM::Get_(), _SC("function not found in slot"));
} }
#endif #endif
} }
// Constructs a Function from a value off the stack at the specified index
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Assumes the Function environment is at index 1.
/// Constructs a Function from two Squirrel objects (one is the environment object and the other is the function object) Function(HSQUIRRELVM vm, SQInteger idx) {
/// sq_getstackobj(vm, 1, &env);
/// \param v VM that the function will exist in sq_getstackobj(vm, idx, &obj);
/// \param e Squirrel object that should represent the environment of the function sq_addref(vm, &env);
/// \param o Squirrel object that should already represent a Squirrel function sq_addref(vm, &obj);
/// #if !defined (SCRAT_NO_ERROR_CHECKING)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SQObjectType value_type = sq_gettype(vm, idx);
Function(HSQUIRRELVM v, HSQOBJECT e, HSQOBJECT o) : vm(v), env(e), obj(o) { if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) {
SQTHROW(vm, FormatTypeError(vm, idx, _SC("closure")));
}
#endif
}
// Constructs a Function from two Squirrel objects (one is the environment object and the other is the function object)
Function(HSQUIRRELVM vm, HSQOBJECT e, HSQOBJECT o) noexcept : env(e), obj(o) {
sq_addref(vm, &env); sq_addref(vm, &env);
sq_addref(vm, &obj); sq_addref(vm, &obj);
} }
// Destructor
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~Function() { ~Function() {
Release(); Release();
} }
// Copy Assignment operator
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function& operator=(const Function& sf) noexcept {
/// Assignment operator
///
/// \param sf Function to copy
///
/// \return The Function itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Function& operator=(const Function& sf) {
Release(); Release();
vm = sf.vm;
env = sf.env; env = sf.env;
obj = sf.obj; obj = sf.obj;
sq_addref(vm, &env); if (!sf.IsNull()) {
sq_addref(vm, &obj); sq_addref(DefaultVM::Get_(), &env);
sq_addref(DefaultVM::Get_(), &obj);
}
return *this; return *this;
} }
// Move Assignment operator
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function& operator=(Function&& sf) noexcept {
/// Assignment operator
///
/// \param sf Function to move
///
/// \return The Function itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Function& operator=(Function&& sf) {
Release(); Release();
vm = sf.vm;
env = sf.env; env = sf.env;
obj = sf.obj; obj = sf.obj;
sq_resetobject(&sf.GetEnv()); sq_resetobject(&sf.GetEnv());
sq_resetobject(&sf.GetFunc()); sq_resetobject(&sf.GetFunc());
return *this; return *this;
} }
// Checks whether the Function is null
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IsNull() const noexcept {
/// Checks whether the Function is null
///
/// \return True if the Function currently has a null value, otherwise false
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IsNull() {
return sq_isnull(obj); return sq_isnull(obj);
} }
// Gets the Squirrel environment object for this Function (copy)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HSQOBJECT GetEnv() const noexcept {
/// Gets the Squirrel environment object for this Function (copy)
///
/// \return Squirrel object representing the Function environment
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HSQOBJECT GetEnv() const {
return env; return env;
} }
// Gets the Squirrel environment object for this Function (reference)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HSQOBJECT& GetEnv() noexcept {
/// Gets the Squirrel environment object for this Function (reference)
///
/// \return Squirrel object representing the Function environment
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HSQOBJECT& GetEnv() {
return env; return env;
} }
// Gets the Squirrel function object for this Function (copy)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HSQOBJECT GetFunc() const noexcept {
/// Gets the Squirrel function object for this Function (copy)
///
/// \return Squirrel object representing the Function
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HSQOBJECT GetFunc() const {
return obj; return obj;
} }
// Gets the Squirrel function object for this Function (reference)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HSQOBJECT& GetFunc() noexcept {
/// Gets the Squirrel function object for this Function (reference)
///
/// \return Squirrel object representing the Function
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HSQOBJECT& GetFunc() {
return obj; return obj;
} }
// Gets the Squirrel VM for this Function
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HSQUIRRELVM & GetVM() const noexcept {
/// Gets the Squirrel VM for this Function (copy) return DefaultVM::Get_();
///
/// \return Squirrel VM associated with the Function
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HSQUIRRELVM GetVM() const {
return vm;
} }
// Sets the Function to null (removing its references to underlying Squirrel objects)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Release() noexcept {
/// Gets the Squirrel VM for this Function (reference)
///
/// \return Squirrel VM associated with the Function
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HSQUIRRELVM& GetVM() {
return vm;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Sets the Function to null (removing its references to underlying Squirrel objects)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Release() {
if(!IsNull()) { if(!IsNull()) {
sq_release(vm, &env); sq_release(DefaultVM::Get_(), &env);
sq_release(vm, &obj); sq_release(DefaultVM::Get_(), &obj);
sq_resetobject(&env); sq_resetobject(&env);
sq_resetobject(&obj); sq_resetobject(&obj);
} }
} }
// Sets the Function to null (removing its references to underlying Squirrel objects)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This doesn't call release if the reference count is 1.
/// Sets the Function to null (removing its references to underlying Squirrel objects) // Workaround for some weird squirrel behavior that generates an assert in debug mode.
/// void ReleaseGently() noexcept {
/// \remarks
/// This doesn't call release if the reference count is 1.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ReleaseGently() {
if(!IsNull()) { if(!IsNull()) {
sq_release(vm, &env); sq_release(DefaultVM::Get_(), &env);
if (sq_getrefcount(vm, &obj) > 1) if (sq_getrefcount(DefaultVM::Get_(), &obj) > 1) {
{ sq_release(DefaultVM::Get_(), &obj);
sq_release(vm, &obj);
} }
sq_resetobject(&env); sq_resetobject(&env);
sq_resetobject(&obj); sq_resetobject(&obj);
} }
} }
// Runs the Function and returns its value as a SharedPtr
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template<class R, class... Args> SharedPtr<R> Evaluate(Args &&... args) {
/// Runs the Function and returns its value as a SharedPtr
///
/// \return SharedPtr containing the return value (or null if failed)
///
/// \remarks
/// This function MUST have its Error handled if it occurred.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class R, class... Args>
SharedPtr<R> Evaluate(Args &&... args) {
static constexpr unsigned ARGC = sizeof...(Args) + 1; // + environment static constexpr unsigned ARGC = sizeof...(Args) + 1; // + environment
HSQUIRRELVM vm = DefaultVM::Get_();
SQInteger top = sq_gettop(vm); SQInteger top = sq_gettop(vm);
// Push the environment followed by the function
sq_pushobject(vm, obj); sq_pushobject(vm, obj);
sq_pushobject(vm, env); sq_pushobject(vm, env);
// Validate the funtion parameter count
#if !defined (SCRAT_NO_ERROR_CHECKING) #if !defined (SCRAT_NO_ERROR_CHECKING)
SQUnsignedInteger nparams; SQUnsignedInteger nparams;
SQUnsignedInteger nfreevars; SQUnsignedInteger nfreevars;
@ -296,8 +188,8 @@ public:
return SharedPtr<R>(); return SharedPtr<R>();
} }
#endif #endif
// Push the arguments
PushVars(vm, std::forward< Args >(args)...); PushVars(vm, std::forward<Args>(args)...);
#if !defined (SCRAT_NO_ERROR_CHECKING) #if !defined (SCRAT_NO_ERROR_CHECKING)
SQRESULT result = sq_call(vm, ARGC, true, ErrorHandling::IsEnabled()); SQRESULT result = sq_call(vm, ARGC, true, ErrorHandling::IsEnabled());
@ -316,23 +208,16 @@ public:
sq_settop(vm, top); sq_settop(vm, top);
return ret; return ret;
} }
// Runs the Function
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template< class... Args >
/// Runs the Function
///
/// \remarks
/// This function MUST have its Error handled if it occurred.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template < class... Args >
void Execute(Args &&... args) { void Execute(Args &&... args) {
static constexpr unsigned ARGC = sizeof...(Args) + 1; // + environment static constexpr unsigned ARGC = sizeof...(Args) + 1; // + environment
HSQUIRRELVM vm = DefaultVM::Get_();
SQInteger top = sq_gettop(vm); SQInteger top = sq_gettop(vm);
// Push the environment followed by the function
sq_pushobject(vm, obj); sq_pushobject(vm, obj);
sq_pushobject(vm, env); sq_pushobject(vm, env);
// Validate the funtion parameter count
#if !defined (SCRAT_NO_ERROR_CHECKING) #if !defined (SCRAT_NO_ERROR_CHECKING)
SQUnsignedInteger nparams; SQUnsignedInteger nparams;
SQUnsignedInteger nfreevars; SQUnsignedInteger nfreevars;
@ -343,7 +228,7 @@ public:
} }
#endif #endif
PushVars(vm, std::forward< Args >(args)...); PushVars(vm, std::forward<Args>(args)...);
#if !defined (SCRAT_NO_ERROR_CHECKING) #if !defined (SCRAT_NO_ERROR_CHECKING)
SQRESULT result = sq_call(vm, ARGC, false, ErrorHandling::IsEnabled()); SQRESULT result = sq_call(vm, ARGC, false, ErrorHandling::IsEnabled());
@ -359,77 +244,37 @@ public:
sq_settop(vm, top); sq_settop(vm, top);
#endif #endif
} }
// Runs the Function
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template< class... Args > void operator() (Args &&... args) {
/// Runs the Function Execute(std::forward<Args>(args)...);
///
/// \remarks
/// This function MUST have its Error handled if it occurred.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template < class... Args > void operator()(Args &&... args) {
Execute(std::forward< Args >(args)...);
} }
}; };
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Used to get and push Function instances to and from the stack as references (functions are always references in Squirrel)
/// Used to get and push Function instances to and from the stack as references (functions are always references in Squirrel) template<> struct Var<Function> {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// The actual value of get operations
template<> Function value;
struct Var<Function> { // Attempts to get the value off the stack at idx as a Function
// Assumes the Function environment is at index 1.
Function value; ///< The actual value of get operations Var(HSQUIRRELVM vm, SQInteger idx) : value(vm, idx) {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Attempts to get the value off the stack at idx as a Function
///
/// \param vm Target VM
/// \param idx Index trying to be read
///
/// \remarks
/// Assumes the Function environment is at index 1.
///
/// \remarks
/// This function MUST have its Error handled if it occurred.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Var(HSQUIRRELVM vm, SQInteger idx) {
HSQOBJECT sqEnv;
HSQOBJECT sqValue;
sq_getstackobj(vm, 1, &sqEnv);
sq_getstackobj(vm, idx, &sqValue);
value = Function(vm, sqEnv, sqValue);
#if !defined (SCRAT_NO_ERROR_CHECKING)
SQObjectType value_type = sq_gettype(vm, idx);
if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) {
SQTHROW(vm, FormatTypeError(vm, idx, _SC("closure")));
}
#endif
} }
// Called by Sqrat::PushVar to put a Function on the stack
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void push(HSQUIRRELVM vm, const Function& value) noexcept {
/// Called by Sqrat::PushVar to put a Function on the stack
///
/// \param vm Target VM
/// \param value Value to push on to the VM's stack
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void push(HSQUIRRELVM vm, const Function& value) {
sq_pushobject(vm, value.GetFunc()); sq_pushobject(vm, value.GetFunc());
} }
}; };
// Used to get and push Function instances to and from the stack as references (functions are always references in Squirrel)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template<> struct Var<Function&> : public Var<Function> {
/// Used to get and push Function instances to and from the stack as references (functions are always references in Squirrel) Var(HSQUIRRELVM vm, SQInteger idx) : Var<Function>(vm, idx)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {
template<> }
struct Var<Function&> : Var<Function> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Function>(vm, idx) {}}; };
// Used to get and push Function instances to and from the stack as references (functions are always references in Squirrel)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template<> struct Var<const Function&> : public Var<Function> {
/// Used to get and push Function instances to and from the stack as references (functions are always references in Squirrel) Var(HSQUIRRELVM vm, SQInteger idx) : Var<Function>(vm, idx)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {
template<> }
struct Var<const Function&> : Var<Function> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Function>(vm, idx) {}}; };
} }

View File

@ -202,37 +202,25 @@ class WeakPtr;
/// @endcond /// @endcond
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Helper class that defines a VM that can be used as a fallback VM in case no other one is given to a piece of code
/// Helper class that defines a VM that can be used as a fallback VM in case no other one is given to a piece of code
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class DefaultVM { class DefaultVM {
private: private:
static HSQUIRRELVM& StaticVM() noexcept {
static HSQUIRRELVM& staticVm() {
static HSQUIRRELVM vm; static HSQUIRRELVM vm;
return vm; return vm;
} }
public: public:
// Gets the default VM (copy)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static HSQUIRRELVM Get() noexcept {
/// Gets the default VM return StaticVM();
///
/// \return Default VM
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static HSQUIRRELVM Get() {
return staticVm();
} }
// Gets the default VM (reference)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static HSQUIRRELVM & Get_() noexcept {
/// Sets the default VM to a given VM return StaticVM();
/// }
/// \param vm New default VM // Sets the default VM to a given VM
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void Set(HSQUIRRELVM vm) { static void Set(HSQUIRRELVM vm) {
staticVm() = vm; StaticVM() = vm;
} }
}; };