From 083228a10dffcaa77b1d0035c29013c6802befd4 Mon Sep 17 00:00:00 2001 From: "lapayo94@gmail.com" Date: Sun, 8 Jul 2012 21:01:08 +0000 Subject: Squirrel Plugins I worked a little bit on the squirrel Bindings They work now on linux and windows :) (OSX is untested, but should work also) but they are very limited at the moment. (Only made OnChat working) I also fixed some small bugs. git-svn-id: http://mc-server.googlecode.com/svn/trunk@648 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- squirrel_3_0_1_stable/_OLD_sqplus/sqplus.h | 2327 ++++++++++++++++++++++++++++ 1 file changed, 2327 insertions(+) create mode 100644 squirrel_3_0_1_stable/_OLD_sqplus/sqplus.h (limited to 'squirrel_3_0_1_stable/_OLD_sqplus/sqplus.h') diff --git a/squirrel_3_0_1_stable/_OLD_sqplus/sqplus.h b/squirrel_3_0_1_stable/_OLD_sqplus/sqplus.h new file mode 100644 index 000000000..fff1633ed --- /dev/null +++ b/squirrel_3_0_1_stable/_OLD_sqplus/sqplus.h @@ -0,0 +1,2327 @@ +// SqPlus.h +// Created by John Schultz 9/05/05, major update 10/05/05. +// Template function call design from LuaPlusCD by Joshua C. Jensen, +// inspired by luabind which was inspired by boost::python. +// Const argument, const member functions, and Mac OS-X changes by Simon Michelmore. +// DECLARE_INSTANCE_TYPE_NAME changes by Ben (Project5) from http://www.squirrel-lang.org/forums/. +// Added Kamaitati's changes 5/28/06. +// Free for any use. + +#ifndef _SQ_PLUS_H_ +#define _SQ_PLUS_H_ + +#include +#include + +#ifdef __APPLE__ + #include +#else + #include +#endif +#include +#include +#include // For INT_MAX on GCC + +#include "squirrel.h" // Include to get SQUNICODE setting from here +#ifndef _SC + #error No _SC macro - Usually defined in squirrel.h +#endif +// Provide a _sqT(...) macros also (same as _SC but easier to know its for Squirrel) +#ifndef _sqT + #define _sqT _SC +#endif + +// For backward compatibility, define _T if outside of Windows platform. +// (really, _SC() or _sqT() are better, since that leaves us free to run +// Squirrel in ASCII or wchar_t mode, regardless of the app being built). +#if !defined(_WIN32) && !defined(_WIN64) + #ifndef _T + #define _T _SC + #endif +#endif + + +// A comment about strings. We let squirrel.h determine whether to use +// char or wchar_t strings. So here we follow the define SQUNICODE. This +// opens up for using Unicode system calls on Windows while having the script +// engine in ASCII mode, or vice versa. To enable this, also the macro +// _SC("some string") is used instead of _T("some string"). +// +// To handle the case where function parameters are given in the opposite +// character mode (char if SQChar is wchar_t and vice versa), such strings +// can be converted on the fly to the other mode in the function call, if +// the define SQPLUS_AUTOCONVERT_OTHER_CHAR is set below. Buffers are +// allocated and kept around for the duration of the function call. The +// same applies to returned strings of the opposite type. + +#if defined(_MSC_VER) || defined(__BORLANDC__) + #include + #ifndef SQUNICODE + #define SCSNPRINTF _snprintf + #define SCPUTS puts + #else + #define SCSNPRINTF _snwprintf + #define SCPUTS _putws + #endif + #if defined(_MSC_VER) + #ifndef _CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE // Disable warnings around various sprintf + #endif + #pragma warning(disable: 4996) // When above does not work + #endif +#else + #ifdef SQUNICODE + #define SCSNPRINTF _snwprintf + #define SCPUTS _putws + #include // for snprintf + #else + #define SCSNPRINTF snprintf + #include // for snprintf + #define SCPUTS puts + #endif +#endif + + +#ifndef _WINDEF_ + typedef int BOOL; + typedef int INT; + typedef float FLOAT; + #define TRUE 1 + #define FALSE 0 +#endif + +#if 1 +#define SQ_CALL_RAISE_ERROR SQTrue +#else +#define SQ_CALL_RAISE_ERROR SQFalse +#endif + +#include "SquirrelObject.h" +#include "SquirrelVM.h" +#include "SquirrelBindingsUtils.h" + +// All setup defines have moved to its own file +#include "SqPlusSetup.h" + +#ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR +#define SQPLUS_AUTOCONVERT_MAX_INSTANCES 8 // In argument conversion, don't keep more than this alive +#include "SqPlusOCharBuf.h" +#endif + +#if defined(SQPLUS_SUPPORT_STD_STRING) && defined(SQUNICODE) + #ifdef _MSC_VER + #pragma message("std::string and SQChar as wchar_t is not compatible!") + #else + #warning std::string and SQChar as wchar_t is not compatible! + #endif +#endif + + +namespace SqPlus { + +template struct TypeWrapper {}; +struct SquirrelNull {}; +struct SQNoBaseClass {}; // For scripted classes with no base class (or no scripted base class) + +struct SQAnything { void * anything; }; // Needed for binding pointers to variables (cannot dereference void *). +typedef SQAnything * SQAnythingPtr; +typedef SQChar * SQCharPtr; + +// Helper struct to (sometimes) store a temporary return value as another type. +// Useful when returning const char* and other types that require temp allocation. +// For primitive types, it just maps onto itself. +template +struct Temporary { + typedef T type; +}; + +// References are tricky, but they should just be filtered out usually +template +struct SqAssignableRef { + SqAssignableRef( ) : m_pt(0) { } + void operator = (T& tr){ m_pt=&tr; } + operator T& () { return *m_pt; } + T *m_pt; +}; + +template +struct Temporary { + typedef SqAssignableRef type; +}; + + +// === Do not use directly: use one of the predefined sizes below === + +struct ScriptStringVarBase { + const unsigned char MaxLength; // Real length is MaxLength+1. + SQChar s[1]; + ScriptStringVarBase(int _MaxLength) : MaxLength(_MaxLength) {} + operator SQChar * () { return &s[0]; } + operator void * () { return (void *)&s[0]; } + const SQChar * operator = (const SQChar * _s) { + return safeStringCopy(s,_s,MaxLength); + } + // Special safe string copy where MaxLength is 1 less than true buffer length. + // strncpy() pads out nulls for the full length of the buffer specified by MaxLength. + static inline SQChar * safeStringCopy(SQChar * d,const SQChar * s,int MaxLength) { + int i=0; + while (s[i]) { + d[i] = s[i]; + i++; + if (i == MaxLength) break; + } // while + d[i] = 0; // Null terminate. + return d; + } // safeStringCopy +}; + +// === Do not use directly: use one of the predefined sizes below === + +template // MAXLENGTH is max printable characters (trailing NULL is accounted for in ScriptStringVarBase::s[1]). +struct ScriptStringVar : ScriptStringVarBase { + SQChar ps[MAXLENGTH]; + ScriptStringVar() : ScriptStringVarBase(MAXLENGTH) { + s[0] = 0; + } + ScriptStringVar(const SQChar * _s) : ScriptStringVarBase(MAXLENGTH) { + *this = _s; + } + const SQChar * operator = (const SQChar * _s) { + return safeStringCopy(s,_s,MaxLength); + } + const SQChar * operator = (const ScriptStringVar & _s) { + return safeStringCopy(s,_s.s,MaxLength); + } + bool operator == (const ScriptStringVar & _s) { + return _strcmp(s,_s.s) == 0; + } + bool compareCaseInsensitive(const ScriptStringVar & _s) { + return _stricmp(s,_s.s) == 0; + } +}; + +// === Fixed size strings for scripting === + +typedef ScriptStringVar<8> ScriptStringVar8; +typedef ScriptStringVar<16> ScriptStringVar16; +typedef ScriptStringVar<32> ScriptStringVar32; +typedef ScriptStringVar<64> ScriptStringVar64; +typedef ScriptStringVar<128> ScriptStringVar128; +typedef ScriptStringVar<256> ScriptStringVar256; + +// === Script Variable Types === + +enum ScriptVarType { + VAR_TYPE_NONE = -1, + VAR_TYPE_INT = 0, + VAR_TYPE_UINT, + VAR_TYPE_FLOAT, + VAR_TYPE_BOOL, + VAR_TYPE_CONST_STRING, + VAR_TYPE_STRING, + VAR_TYPE_USER_POINTER, + VAR_TYPE_INSTANCE, +#ifdef SQPLUS_SUPPORT_STD_STRING + VAR_TYPE_STD_STRING, +#endif +}; + +template +struct TypeInfo { + const SQChar * typeName; + enum {TypeID=VAR_TYPE_NONE, Size=0, TypeMask='?', IsInstance=0}; +}; + +// === Common Variable Types === + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("int")) {} + enum {TypeID=VAR_TYPE_INT,Size=sizeof(INT),TypeMask='i', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("uint")) {} + enum {TypeID=VAR_TYPE_UINT,Size=sizeof(unsigned), IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("float")) {} + enum {TypeID=VAR_TYPE_FLOAT,Size=sizeof(FLOAT),TypeMask='f', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("bool")) {} + enum {TypeID=VAR_TYPE_BOOL,Size=sizeof(bool),TypeMask='b', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("short")) {} + enum {TypeID=VAR_TYPE_INT,Size=sizeof(short),TypeMask='i', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("char")) {} + enum {TypeID=VAR_TYPE_INT,Size=sizeof(char),TypeMask='i', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("SQUserPointer")) {} + enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(SQUserPointer),TypeMask='u', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("SQUserPointer")) {} + enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(SQUserPointer),TypeMask='u', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(0) {} + enum {TypeID=-1,Size=0,TypeMask=' ', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("const SQChar *")) {} + enum {TypeID=VAR_TYPE_CONST_STRING,Size=sizeof(const SQChar *),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +#ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("const SQOtherChar *")) {} + enum {TypeID=VAR_TYPE_CONST_STRING,Size=sizeof(const SQOtherChar *),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; +template<> +struct Temporary { + typedef SQOthCharBuf type; +}; +template<> +struct Temporary { + typedef SQOthCharBuf type; +}; +#endif // SQPLUS_AUTOCONVERT_OTHER_CHAR + +// base case: raw pointer +template +struct TypeInfoPtrBase { + const SQChar * typeName; + TypeInfoPtrBase() : typeName(TypeInfo().typeName) {} + enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(T*),TypeMask='u'}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template +struct TypeInfoPtrBase : public TypeInfo { }; + +// Partial specialization for pointers (to access type without pointer / or instance typeinfo) +template +struct TypeInfo : public TypeInfoPtrBase::IsInstance> { }; + +// Same thing for references +template +struct TypeInfo : public TypeInfoPtrBase::IsInstance> { }; + +#ifdef SQPLUS_SUPPORT_STD_STRING +template<> +struct TypeInfo { + const SQChar *typeName; + TypeInfo() : typeName(_SC("std::string")) {} + enum {TypeID=SqPlus::VAR_TYPE_STD_STRING,Size=sizeof(std::string),TypeMask='s'}; + operator ScriptVarType() {return ScriptVarType(TypeID);} +}; +#endif + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("ScriptStringVarBase")) {} + enum {TypeID=VAR_TYPE_STRING,Size=sizeof(ScriptStringVarBase),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +// === Fixed String Variants === + +template +struct TypeInfo > { + SQChar typeName[24]; + TypeInfo() { scsprintf(typeName,_SC("ScriptStringVar<%d>"),N); } + enum {TypeID=VAR_TYPE_STRING,Size=N*sizeof(ScriptStringVar),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +#ifdef SQPLUS_SMARTPOINTER_OPT + #define SQPLUS_SMARTPOINTER_ACCESSTYPE + #include "SqPlusSmartPointer.h" +#else + enum VarAccessType {VAR_ACCESS_READ_WRITE=0,VAR_ACCESS_READ_ONLY=1<<0,VAR_ACCESS_CONSTANT=1<<1,VAR_ACCESS_STATIC=1<<2}; +#endif // SQPLUS_SMARTPOINTER_OPT + +// See VarRef and ClassType<> below: for instance assignment. +typedef void (*CopyVarFunc)(void * dst,void * src); + + +// === Class Type Helper class: returns an ID for each class type and provides base class pointer offset === + +struct ClassTypeBase { + ClassTypeBase() : m_pbase(0), m_name(0), m_offset(0), m_may_have_offset(-1) { } + // Many types cannot have offset, since "this" is the same for all base classes of + // an instance. Detect this, to avoid sum up base offsets all the time. + int MayHaveOffset( ) { + if( m_may_have_offset<0 ){ + if( m_offset ) m_may_have_offset = 1; + else m_may_have_offset = m_pbase ? m_pbase->MayHaveOffset() : 0; + } + return m_may_have_offset; + } + int GetOffsetTo( ClassTypeBase *pbase ){ + if( !m_pbase ) { /*printf("ClassTypeBase::getOffsetTo - Warning - Base type pointer is NULL!\n" );*/ return 0; } + return m_pbase==pbase ? m_offset : m_offset+m_pbase->GetOffsetTo(pbase); + } + virtual CopyVarFunc vgetCopyFunc(void) = 0; + virtual const SQChar* GetTypeName() = 0; + + ClassTypeBase *m_pbase; + const SQChar *m_name; // Name of type + int m_offset; // Adjustment of this pointer between this type and its base class + int m_may_have_offset; // Set to 0 for types that cannot possibly have offset +}; + +// This level handles instance copying in different ways +template +struct ClassTypeCopyImpl; + +// Helper struct to decide if type is copyable or not +template +struct IsCopyable { enum { value=true }; }; + +#define DECLARE_NONCOPY_TYPE_INTERN(TYPE) \ + template<> struct IsCopyable { enum { value=false }; }; + +// Macro to declare a type that should _not_ be copied using ordinary +// c++ copy expresssion: *(T*)pt1 = *(T*)pt2; +#define DECLARE_NONCOPY_TYPE(TYPE) namespace SqPlus { \ + template<> struct IsCopyable { enum { value=false }; }; \ +} + +// Base class to do copying in ordinary C++ way +template +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(T * dst,T * src) { + *dst = *src; // This works types with copy ctor / assign operator + } // copy +}; + +// Base class to do copying with memcpy +template +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(T * dst,T * src) { + memcpy(dst,src,sizeof(T)); // This works for raw data types + } // copy +}; + +// Base classes to do avoid copying altogether (void case) +template<> +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(void * dst,void * src) { } // copy +}; + +template<> +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(void * dst,void * src) { } // copy +}; + + +template +struct ClassType : public ClassTypeCopyImpl::value> { + typedef ClassTypeCopyImpl::value> ClassTypeBase; + ClassType( ) { this->m_name=stGetName(); } + + virtual CopyVarFunc vgetCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; } + virtual const SQChar* GetTypeName(){ return this->m_name; } + + template + void SetBase(TypeWrapper) { + this->m_pbase = ClassType::Get(); + T* pt = reinterpret_cast(this); + this->m_offset = ((char*)pt)-((char*)static_cast(pt)); + } + static ClassType* Get(){ static ClassType st_ct; return &st_ct; } + static ClassTypeBase* type() { return Get(); } + static CopyVarFunc getCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; } + static const SQChar* stGetName(){ return TypeInfo().typeName; } + + #ifdef SQPLUS_OVERLOAD_OPT + #define SQPLUS_OVERLOAD_RELEASE_HOOK + #include "SqPlusOverload.h" + #endif +}; + + +// === Variable references for script access === + +#define SQ_PLUS_TYPE_TABLE _SC("__SqTypes") + +struct VarRef { + // In this case 'offsetOrAddrOrConst' is simpler than using an anonymous union. + void * offsetOrAddrOrConst; // Instance member variable offset from 'this' pointer base (as size_t), or address if static variable (void *), or constant value. + ScriptVarType m_type; // Variable type (from enum above). + ClassTypeBase* instanceType; // Class type of the containing class instance (for member vars only). + ClassTypeBase* varType; // The class type of the variable itself + short m_size; // ATS: Use for short and char support. For debugging only (size of item when pointer to item is dereferenced). Could be used for variable max string buffer length. + short m_access; // VarAccessType. + + VarRef() : offsetOrAddrOrConst(0), m_type(VAR_TYPE_NONE), instanceType(0/*(SQUserPointer)-1*/), /*copyFunc(0),*/ m_size(0), m_access(VAR_ACCESS_READ_WRITE) {} + VarRef(void * _offsetOrAddrOrConst, ScriptVarType _type, ClassTypeBase* _instanceType, ClassTypeBase* _varType, int _size, VarAccessType _access) : + offsetOrAddrOrConst(_offsetOrAddrOrConst), m_type(_type), instanceType(_instanceType), varType(_varType), m_size(_size), m_access(_access) { +#ifdef SQ_SUPPORT_INSTANCE_TYPE_INFO + SquirrelObject typeTable = SquirrelVM::GetRootTable().GetValue(SQ_PLUS_TYPE_TABLE); + if (typeTable.IsNull()) { + typeTable = SquirrelVM::CreateTable(); + SquirrelObject root = SquirrelVM::GetRootTable(); + root.SetValue(SQ_PLUS_TYPE_TABLE,typeTable); + } // if + typeTable.SetValue(INT((size_t)varType),varType->GetTypeName()); +#endif // SQ_SUPPORT_INSTANCE_TYPE_INFO + } +}; + +typedef VarRef * VarRefPtr; + +// Internal use only. +inline void getVarNameTag(SQChar * buff,INT maxSize,const SQChar * scriptName) { +// assert(maxSize > 3); +#if 1 + SQChar * d = buff; + d[0] = '_'; + d[1] = 'v'; + d = &d[2]; + maxSize -= (2+1); // +1 = space for null. + int pos=0; + while (scriptName[pos] && pos < maxSize) { + d[pos] = scriptName[pos]; + pos++; + } // while + d[pos] = 0; // null terminate. +#else + SCSNPRINTF(buff,maxSize,_SC("_v%s"),scriptName); +#endif +} // getVarNameTag + +// Internal use only. +int setVarFunc(HSQUIRRELVM v); +int getVarFunc(HSQUIRRELVM v); +int setInstanceVarFunc(HSQUIRRELVM v); +int getInstanceVarFunc(HSQUIRRELVM v); + +// === BEGIN Helpers === + +inline void createTableSetGetHandlers(SquirrelObject & so) { + SquirrelObject delegate = so.GetDelegate(); + if (!delegate.Exists(_SC("_set"))) { + delegate = SquirrelVM::CreateTable(); + SquirrelVM::CreateFunction(delegate,setVarFunc,_SC("_set"),_SC("sn|b|s")); // String var name = number(int or float) or bool or string. + SquirrelVM::CreateFunction(delegate,getVarFunc,_SC("_get"),_SC("s")); // String var name. + so.SetDelegate(delegate); + } // if +} // createTableSetGetHandlers + +inline VarRefPtr createVarRef(SquirrelObject & so,const SQChar * scriptVarName) { + VarRefPtr pvr=0; + ScriptStringVar256 scriptVarTagName; getVarNameTag(scriptVarTagName,sizeof(scriptVarTagName),scriptVarName); + if (!so.GetUserData(scriptVarTagName,(SQUserPointer *)&pvr)) { + so.NewUserData(scriptVarTagName,sizeof(*pvr)); + if (!so.GetUserData(scriptVarTagName,(SQUserPointer *)&pvr)) throw SquirrelError(_SC("Could not create UserData.")); + } // if + return pvr; +} // createVarRef + +template +void validateConstantType(T constant) { + switch(TypeInfo()) { + case VAR_TYPE_INT: + case VAR_TYPE_FLOAT: + case VAR_TYPE_BOOL: + case VAR_TYPE_CONST_STRING: + break; + default: + throw SquirrelError(_SC("validateConstantType(): type must be INT, FLOAT, BOOL, or CONST CHAR *.")); + } // case +} // validateConstantType + +inline void createInstanceSetGetHandlers(SquirrelObject & so) { + if (!so.Exists(_SC("_set"))) { + SquirrelVM::CreateFunction(so,setInstanceVarFunc,_SC("_set"),_SC("sn|b|s|x")); // String var name = number(int or float) or bool or string or instance. + SquirrelVM::CreateFunction(so,getInstanceVarFunc,_SC("_get"),_SC("s")); // String var name. + } // if +} // createInstanceSetGetHandlers + +// === END Helpers === + + +// Provide an overridable way of copying / deleting objects +template +struct ObjectCloner { + static T* Clone(T* src){ return new T(src); } + static void Delete(T* dst){ if(dst) delete dst; } +}; + +// specialization for void type +//template<> inline void ClassType::copy(void *dst, void *src) {} +DECLARE_NONCOPY_TYPE_INTERN(void) + + +// === Bind a global or pre-allocated (not instance) class member variable or constant (for tables only (not classes)) === + +template +void BindVariable(SquirrelObject & so,T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { + VarRefPtr pvr = createVarRef(so,scriptVarName); + *pvr = VarRef(var,TypeInfo(),NULL,ClassType::type(),sizeof(*var),access); + createTableSetGetHandlers(so); +} // BindVariable + +// === Bind a constant by value: INT, FLOAT, BOOL, or CONST CHAR * (for tables only (not classes)) === + +template +void BindConstant(SquirrelObject & so,T constant,const SQChar * scriptVarName) { + validateConstantType(constant); + VarRefPtr pvr = createVarRef(so,scriptVarName); + struct CV { + T var; + } cv; // Cast Variable helper. + cv.var = constant; + *pvr = VarRef(*(void **)&cv,TypeInfo(),NULL,ClassType::type(),sizeof(constant),VAR_ACCESS_CONSTANT); + createTableSetGetHandlers(so); +} // BindConstant + +template +void BindVariable(T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { + SquirrelObject so = SquirrelVM::GetRootTable(); + BindVariable(so,var,scriptVarName,access); +} // BindVariable + +template +void BindConstant(T constant,const SQChar * scriptVarName) { + SquirrelObject so = SquirrelVM::GetRootTable(); + BindConstant(so,constant,scriptVarName); +} // BindConstant + +// === Register a class instance member variable or constant. var argument provides type and offset ( effectively &((ClassType *)0)->var ) === + +// classType is the type of the member variable's containing class. + template +void RegisterInstanceVariable(SquirrelObject & so,ClassTypeBase* classType,T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { + VarRef * pvr = createVarRef(so,scriptVarName); + void * offsetOrAddrOrConst = (void *)var; // var must be passed in as &obj->var, where obj = 0 (the address is the offset), or as static/global address. + *pvr = VarRef(offsetOrAddrOrConst,TypeInfo(),classType,ClassType::type(),sizeof(*var),access); + createInstanceSetGetHandlers(so); +} // RegisterInstanceVariable + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_REGISTER_VARIABLE +#include "SqPlusSmartPointer.h" +#endif + +template +void RegisterInstanceConstant(SquirrelObject & so,ClassTypeBase *classType,T constant,const SQChar * scriptVarName) { + validateConstantType(constant); + VarRef * pvr = createVarRef(so,scriptVarName); + struct CV { + T var; + size_t pad; + } cv; // Cast Variable helper. + cv.var = constant; + *pvr = VarRef(*(void **)&cv,TypeInfo(),classType,ClassType::type(),sizeof(constant),VAR_ACCESS_CONSTANT); + createInstanceSetGetHandlers(so); +} // RegisterInstanceConstant + +////////////////////////////////////////////////////////////////////////// +/////////// BEGIN Generalized Class/Struct Instance Support ////////////// +////////////////////////////////////////////////////////////////////////// + +// Was previously in SqPlus namespace +//BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar * classname,SQUserPointer ud,SQRELEASEHOOK hook); // In SquirrelBindingUtils.cpp. + +// Create native class instance and leave on stack. +//BOOL CreateConstructNativeClassInstance(HSQUIRRELVM v,const SQChar * className); + +// Create new instance, copy 'classToCopy', and store result on stack. +template +inline BOOL CreateCopyInstance(HSQUIRRELVM v, const SQChar * className,const T & classToCopy) { +#ifndef SQPLUS_DISABLE_COPY_INSTANCES + if (!CreateConstructNativeClassInstance(v,className)) { + return FALSE; + } // if + SQUserPointer up=0; + sq_getinstanceup(v,-1,&up,ClassType::type()); + if (!up) return FALSE; + T * newClass = (T *)up; + *newClass = classToCopy; // Optimized version that uses the copy constructor. + return TRUE; +#else + return FALSE; +#endif +} // CreateCopyInstance + +// Create a new copy of type 'className' and copy 'classToCopy', return result via SquirrelObject. +template +inline SquirrelObject NewClassCopy(HSQUIRRELVM v, const SQChar * className,const T & classToCopy) { + if (CreateCopyInstance(v, className,classToCopy)) { + HSQOBJECT t; + sq_getstackobj(v,-1,&t); + SquirrelObject obj(t); + sq_poptop(v); + return obj; + } else { + throw SquirrelError(_SC("NewClassCopy(): could not create class")); + } // if + return SquirrelObject(); +} // NewClassCopy + +// Return a new class copy on the stack from a varArgs function call. +template +inline int ReturnCopy(HSQUIRRELVM v,const T & classToCopy) { + SquirrelObject so(NewClassCopy(v,GetTypeName(classToCopy),classToCopy)); + return StackHandler(v).Return(so); +} // ReturnCopy + +// Katsuaki Kawachi's GetInstance<> exception change. 6/27/06 jcs + +// Get an instance of type T from the stack at idx (for function calls). +template +T * GetInstance(HSQUIRRELVM v,SQInteger idx) { + SQUserPointer up=0; + if (SQ_FAILED(sq_getinstanceup(v,idx,&up,ClassType::type()))) { + up = 0; + } + if (ExceptionOnError) { // This code block should be compiled out when ExceptionOnError is false. In any case, the compiler should not generate a test condition (include or exclude the enclosed code block). + if (!up) { + throw SquirrelError(_SC("GetInstance: Invalid argument type")); + } + } // if + return (T *)up; +} // GetInstance + + +template void Push(HSQUIRRELVM v, T* pt); +template void Push(HSQUIRRELVM v, T& t); +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix); +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix); +template T &Get(TypeWrapper, HSQUIRRELVM v, int ix); +template T *Get(TypeWrapper, HSQUIRRELVM v, int ix); + + +#ifdef SQPLUS_USE_GENERIC_HANDLERS +// With template specialization, we get Push handlers per 'precise type match' +// This adds a fallback level after that, where we can delegate the work to +// wider C-style functions that can do something for a whole class hierarchy. +// (GenPush, GenGet, GenMatch). + +// This macro allows for a a last generic cast operation before giving control +// to one of GenPush/GenMatch/GenGet. +#ifndef SQPLUS_GEN_CAST + #define SQPLUS_GEN_CAST(TYPE,value) ((TYPE*)value) +#endif + +template void Push(HSQUIRRELVM v, T* pt){ GenPush(v,SQPLUS_GEN_CAST(T,pt)); } +template void Push(HSQUIRRELVM v, T& t){ GenPush(v,SQPLUS_GEN_CAST(T,&t)); } +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return false; +} +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return false; +} +template T &Get(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return *(T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return *SQPLUS_GEN_CAST(T,0); +} +template T *Get(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return (T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return NULL; +} +#endif // SQPLUS_USE_GENERIC_HANDLERS + + +// === BEGIN Function Call Handler Prototypes === + +void Push(HSQUIRRELVM v, char value); +void Push(HSQUIRRELVM v, unsigned char value); +void Push(HSQUIRRELVM v, short value); +void Push(HSQUIRRELVM v, unsigned short value); +void Push(HSQUIRRELVM v, int value); +void Push(HSQUIRRELVM v, unsigned int value); +void Push(HSQUIRRELVM v, long value); +void Push(HSQUIRRELVM v, unsigned long value); +void Push(HSQUIRRELVM v, double value); +void Push(HSQUIRRELVM v, float value); +void Push(HSQUIRRELVM v, const SQChar *value); +void Push(HSQUIRRELVM v, SQChar *value); +void Push(HSQUIRRELVM v, const SquirrelNull &); +void Push(HSQUIRRELVM v, SQFUNCTION value); +void Push(HSQUIRRELVM v, SQAnythingPtr value); // Cast to SQAnythingPtr instead of void * if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. +void Push(HSQUIRRELVM v, SquirrelObject &so); + +#define USE_ARGUMENT_DEPENDANT_OVERLOADS +#ifdef USE_ARGUMENT_DEPENDANT_OVERLOADS +#ifdef _MSC_VER +#pragma warning(disable:4675) // Disable warning: "resolved overload was found by argument-dependent lookup" when class/struct pointers are used as function arguments. +#endif +// === BEGIN Argument Dependent Overloads === +void Push(HSQUIRRELVM v, bool value); // Pass bool as int if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. +void Push(HSQUIRRELVM v, const void *value); // Pass SQAnythingPtr instead of void * " " +void Push(HSQUIRRELVM v, const SQUserPointer &value); +// === END Argument Dependent Overloads === +#endif + +#define SQPLUS_CHECK_GET(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(_SC("sq_get*() failed (type error)")) + +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); // See Get() for HSQUIRRELVM below (v is always present). +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); // See sq_getstackobj(): always returns true. + +void Get(TypeWrapper, HSQUIRRELVM v, int); +bool Get(TypeWrapper, HSQUIRRELVM v, int idx); +char Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned char Get(TypeWrapper, HSQUIRRELVM v, int idx); +short Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned short Get(TypeWrapper, HSQUIRRELVM v, int idx); +int Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned int Get(TypeWrapper, HSQUIRRELVM v, int idx); +long Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned long Get(TypeWrapper, HSQUIRRELVM v, int idx); +float Get(TypeWrapper, HSQUIRRELVM v, int idx); +double Get(TypeWrapper, HSQUIRRELVM v, int idx); +const SQChar *Get(TypeWrapper, HSQUIRRELVM v, int idx); +SquirrelNull Get(TypeWrapper, HSQUIRRELVM v, int idx); +void *Get(TypeWrapper, HSQUIRRELVM v, int idx); +HSQUIRRELVM Get(TypeWrapper, HSQUIRRELVM v, int /*idx*/); // sq_poptop(v): remove UserData from stack so GetParamCount() matches normal behavior. +SquirrelObject Get(TypeWrapper, HSQUIRRELVM v, int idx); + +#ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR + void Push(HSQUIRRELVM v, const SQOtherChar *value); + void Push(HSQUIRRELVM v, SQOtherChar *value); + bool Match(TypeWrapper, HSQUIRRELVM v, int idx); + bool Match(TypeWrapper, HSQUIRRELVM v, int idx); + SQOthCharBuf Get(TypeWrapper, HSQUIRRELVM v, int idx); +#endif // SQPLUS_AUTOCONVERT_OTHER_CHAR + +#ifdef SQPLUS_SUPPORT_STD_STRING +void Push(HSQUIRRELVM v, const std::string& value); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +std::string Get(TypeWrapper, HSQUIRRELVM v, int idx); +#endif + +// Added jflanglois suggestion, 8/20/06. jcs +#ifdef SQPLUS_SUPPORT_SQ_STD_STRING +typedef std::basic_string sq_std_string; +void Push(HSQUIRRELVM v,const sq_std_string & value); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +sq_std_string Get(TypeWrapper, HSQUIRRELVM v, int idx); +#endif + +// Specialization to support void return type. +void GetRet(TypeWrapper, HSQUIRRELVM v,int idx); + +// GetRet() restores the stack for SquirrelFunction<>() calls. +// Hold on to a reference since return value might be temporary string/instance +template +inline RT GetRet(TypeWrapper,HSQUIRRELVM v,int idx) { + static SquirrelObject st_sq_ret; + static typename Temporary::type st_ret; + st_ret = Get(TypeWrapper(),v,idx); + st_sq_ret.AttachToStackObject(idx); + sq_pop(v,2); // restore stack after function call. + return st_ret; } + +#ifndef GCC_INLINE_WORKAROUND +# include "SqPlusFunctionCallImpl.h" +#endif // GCC_INLINE_WORKAROUND + +// === END Function Call Handlers === + + +// Helper, only implement function bodies +#define IMPLEMENT_ENUM_TYPE(TYPE) namespace SqPlus { \ + bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return Match(TypeWrapper(),v,idx); } \ + TYPE Get(TypeWrapper,HSQUIRRELVM v,int idx) { return (TYPE)Get(TypeWrapper(),v,idx); } \ + void Push(HSQUIRRELVM v,TYPE value) { sq_pushinteger(v,(int)value); } \ +} // nameSpace SqPlus + +// To register simple types (like enums) so they can be used as arguments +// (however, this does not handle enums as return values correctly, since +// we C++ gets problems with references to temporaries) +#define DECLARE_ENUM_TYPE(TYPE) IMPLEMENT_ENUM_TYPE(TYPE) \ +namespace SqPlus { \ + template<> struct TypeInfo : public TypeInfo { }; \ +} // nameSpace SqPlus + +// As above but use when function bodies should not be generated +// (for a header file). +#define PROTOS_ENUM_TYPE(TYPE) namespace SqPlus { \ + bool Match(TypeWrapper,HSQUIRRELVM v,int idx); \ + TYPE Get(TypeWrapper,HSQUIRRELVM v,int idx); \ + void Push(HSQUIRRELVM v,TYPE value); \ + template<> struct TypeInfo : public TypeInfo { }; \ +} // nameSpace SqPlus + + +// NAME and macro changes from Ben's (Project5) forum post. 2/26/06 jcs +// Kamaitati's NULL_INSTANCE support. 5/28/06 jcs + +// ATS: Splitting the macros in different parts to support custom Push implementation (covariant return type) + +#define DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + inline const SQChar * GetTypeName(const TYPE & n) { return _SC(#NAME); } \ + template<> \ + struct TypeInfo { \ + const SQChar * typeName; \ + TypeInfo() : typeName( _SC(#NAME)) {} \ + enum {TypeID=VAR_TYPE_INSTANCE,Size=sizeof(TYPE),TypeMask='x', IsInstance=1}; \ + operator ScriptVarType() { return ScriptVarType(TypeID); } \ + }; + +#define DECLARE_INSTANCE_TYPEINFO(TYPE) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,TYPE) \ +} // namespace SqPlus + +#define DECLARE_INSTANCE_TYPEINFO_NAME(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ +} // namespace SqPlus + + +#ifdef SQPLUS_SUPPORT_NULL_INSTANCES + +// Macro part shared by 'derived' macros +#define DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { \ + return (sq_gettype(v,idx)==OT_NULL) || (GetInstance(v,idx) != NULL); } \ + template<> inline TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } \ + template<> inline TYPE * Get(TypeWrapper,HSQUIRRELVM v,int idx) { \ + if (sq_gettype(v,idx)==OT_NULL) return NULL; \ + return GetInstance(v,idx); } + +// Ordinary case +#define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ + template<> inline void Push(HSQUIRRELVM v,TYPE * value) { \ + if (!value) sq_pushnull(v); \ + else if (!CreateNativeClassInstance(v,GetTypeName(*value),value,0)) \ + throw SquirrelError( _SC( "Push(): could not create INSTANCE (check registration name)")); } \ + template<> inline void Push(HSQUIRRELVM v,TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError( _SC( "Push(): could not create INSTANCE copy (check registration name)")); } \ +} // nameSpace SqPlus + +// Allows for providing custom Push handlers (protos here, impl must be provided by app) +#define DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ + template<> void Push(HSQUIRRELVM v,TYPE * value); \ + template<> void Push(HSQUIRRELVM v,TYPE & value); \ +} // nameSpace SqPlus + + +#else + +#define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + template<> inline void Push(HSQUIRRELVM v,TYPE * value) { if (!CreateNativeClassInstance(v,GetTypeName(*value),value,0)) throw SquirrelError( _SC( "Push(): could not create INSTANCE (check registration name)")); } \ + template<> inline void Push(HSQUIRRELVM v,TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError( _SC( "Push(): could not create INSTANCE copy (check registration name)")); } \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ + template<> inline TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } \ + template<> inline TYPE * Get(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx); } \ +} // nameSpace SqPlus + +#endif + +// TYPE or NAME below must match the string name used in SQClassDef<>, otherwise name lookup won't match and Squirrel will throw a "can't create instance" error. +#ifndef SQPLUS_CONST_OPT +#define DECLARE_INSTANCE_TYPE(TYPE) DECLARE_INSTANCE_TYPE_NAME_(TYPE,TYPE) +#define DECLARE_INSTANCE_TYPE_NAME(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) +#define DECLARE_INSTANCE_TYPE_CUSTOM(TYPE) DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,TYPE) +#define DECLARE_INSTANCE_TYPE_NAME_CUSTOM(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,NAME) +#else +#define SQPLUS_DECLARE_INSTANCE_TYPE_CONST +#include "SqPlusConst.h" +#endif + +#ifdef SQPLUS_OVERLOAD_OPT +#define SQPLUS_OVERLOAD_DECLARATION +#include "SqPlusOverload.h" +#endif + +// Versions of above for types that aren't copy constructable +#define DECLARE_INSTANCE_TYPEINFO_NOCOPY(TYPE) \ + DECLARE_INSTANCE_TYPEINFO(TYPE) \ + DECLARE_NONCOPY_TYPE(TYPE) + +#define DECLARE_INSTANCE_TYPEINFO_NOCOPY_NAME(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + DECLARE_NONCOPY_TYPE(TYPE) + +#define DECLARE_INSTANCE_TYPE_NOCOPY(TYPE) \ + DECLARE_INSTANCE_TYPE(TYPE) \ + DECLARE_NONCOPY_TYPE(TYPE) + +#define DECLARE_INSTANCE_TYPE_NOCOPY_NAME(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + DECLARE_NONCOPY_TYPE(TYPE) + + +////////////////////////////////////////////////////////////////////////// +//////////// END Generalized Class/Struct Instance Support /////////////// +////////////////////////////////////////////////////////////////////////// + +#ifndef SQ_SKIP_ARG_ASSERT + #define sq_argassert(arg,_index_) if (!Match(TypeWrapper(),v,_index_)) return sq_throwerror(v,_SC("Incorrect function argument")) +#else + #define sq_argassert(arg,_index_) +#endif + +// === Return value variants === + +template +struct ReturnSpecialization { + + // === Standard Function calls === + + static int Call(RT (*func)(),HSQUIRRELVM v,int /*index*/) { + RT ret = func(); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + RT ret = func( + Get(TypeWrapper(),v,index + 0) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + sq_argassert(7,index + 6); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5), + Get(TypeWrapper(),v,index + 6) + ); + Push(v,ret); + return 1; + } + + // === Member Function calls === + + +#define SQPLUS_CALL_MFUNC_RET0 +#include "SqPlusCallTemplates.h" + +#ifdef SQPLUS_CONST_OPT +#define SQPLUS_CALL_MFUNC_RET0 +#include "SqPlusConst.h" +#endif +}; + +// === No return value variants === + +template<> +struct ReturnSpecialization { + + // === Standard function calls === + + static int Call(void (*func)(),HSQUIRRELVM v,int /*index*/) { + (void)v; + func(); + return 0; + } + + template + static int Call(void (*func)(P1),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + func( + Get(TypeWrapper(),v,index + 0) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + sq_argassert(7,index + 6); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5), + Get(TypeWrapper(),v,index + 6) + ); + return 0; + } + + // === Member function calls === + + +#define SQPLUS_CALL_MFUNC_NORET +#include "SqPlusCallTemplates.h" + +#ifdef SQPLUS_CONST_OPT +#define SQPLUS_CALL_MFUNC_NORET +#include "SqPlusConst.h" +#endif + +}; + +// === STANDARD Function return value specialized call handlers === + +template +int Call(RT (*func)(),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +// === MEMBER Function return value specialized call handlers === + + +#define SQPLUS_CALL_MFUNC_RET1 +#include "SqPlusCallTemplates.h" + +#ifdef SQPLUS_CONST_OPT +#define SQPLUS_CALL_MFUNC_RET1 +#include "SqPlusConst.h" +#endif + +// === Direct Call Standard Function handler === + +template +struct DirectCallFunction { + static inline int Dispatch(HSQUIRRELVM v) { +#ifdef SQPLUS_USE_SANDBOX_VM + if( v==SquirrelVM::GetSandboxVMPtr() ){ + return sq_throwerror(v, _SC("SqPlus: Cannot exec function from sandbox VM")); + } +#endif + StackHandler sa(v); + int paramCount = sa.GetParamCount(); + Func * func = (Func *)sa.GetUserData(paramCount); + return Call(*func,v,2); + } // Dispatch +}; + +// === Direct Call Member Function handler === + +template +class DirectCallMemberFunction { +public: + static inline int Dispatch(HSQUIRRELVM v) { +#ifdef SQPLUS_USE_SANDBOX_VM + if( v==SquirrelVM::GetSandboxVMPtr() ){ + return sq_throwerror(v, _SC("SqPlus: Cannot exec function from sandbox VM")); + } +#endif + StackHandler sa(v); + int paramCount = sa.GetParamCount(); + unsigned char * ud = (unsigned char *)sa.GetUserData(paramCount); + return Call(**(Callee**)ud,*(Func*)(ud + sizeof(Callee*)),v,2); + } // Dispatch +}; + +// === Direct Call Function handlers === + +#define SQ_CLASS_OBJECT_TABLE_NAME _SC("__ot") +#define SQ_CLASS_HIER_ARRAY _SC("__ca") + +template +struct DirectCallInstanceFuncPicker { + Callee *instance; + Func *func; + DirectCallInstanceFuncPicker(HSQUIRRELVM v) { +#ifdef SQPLUS_USE_SANDBOX_VM + if( v==SquirrelVM::GetSandboxVMPtr() ){ + instance = NULL; + func = NULL; + return; + } +#endif + StackHandler sa(v); + instance = static_cast(sa.GetInstanceUp(1, 0)); + const int paramCount = sa.GetParamCount(); + func = static_cast(sa.GetUserData(paramCount)); +#ifdef SQ_USE_CLASS_INHERITANCE + SquirrelObject so(sa.GetObjectHandle(1)); // 'this' + SQUserPointer typetag; so.GetTypeTag(&typetag); + SQUserPointer calleeType = ClassType::type(); + if (typetag != calleeType) { + SquirrelObject typeTable = so.GetValue(SQ_CLASS_OBJECT_TABLE_NAME); + instance = static_cast( + // 64-bit compatible version. + typeTable.GetUserPointer(INT((size_t)ClassType::type())) + ); + } +#elif defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + SquirrelObject so(sa.GetObjectHandle(1)); // 'this' + ClassTypeBase *instType; so.GetTypeTag((SQUserPointer*)&instType); + ClassTypeBase *calleeType = ClassType::type(); + if (instType!=calleeType && instType->MayHaveOffset() ) { + // instance type is nore derived than callee, adjust pointer + int offset = instType->GetOffsetTo(calleeType); + instance = (Callee*)((char*)instance-offset); + } +#endif + } +}; + +// === Direct Call Instance Member Function handler === +template +class DirectCallInstanceMemberFunction { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + return p.instance && p.func ? + Call(*(p.instance), *(p.func), v, 2) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +// === Direct Call Instance Global Function handler === +template +class DirectCallInstanceGlobalFunction { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + return p.func ? + Call(*(p.func), v, 1) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +// === Direct Call Instance Global Function Var Args handler === +template +class DirectCallInstanceGlobalFunctionVarArgs { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + return p.func && p.instance ? + (*p.func)(p.instance,v) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +// === Direct Call Instance Member Function Variable Argument handler === +template +class DirectCallInstanceMemberFunctionVarArgs { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + sq_poptop(v); // Remove UserData from stack: so sa.GetParamCount() returns actual param count. + return p.func && p.instance ? + (p.instance->*(*p.func))(v) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_DISPATCH +#include "SqPlusSmartPointer.h" +#endif + + +// Code fragment useful for debugging new implementations. +#if 0 +HSQOBJECT ho = sa.GetObjectHandle(paramCount); +SquirrelObject so(ho); +SQObjectType sot = so.GetType(); +#endif + +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + #include "SqPlusTypeMask.h" +#endif + +// === Standard function call === + +template +inline void sq_pushdirectclosure(HSQUIRRELVM v,Func func,SQUnsignedInteger nupvalues) { + SQUserPointer up = sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + sq_newclosure(v,DirectCallFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,0,sqTypeMask::Get()); +#endif +} // sq_pushdirectclosure + +// === Fixed Class pointer call (always calls with object pointer that was registered) === + +template +inline void sq_pushdirectclosure(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(Callee*)+sizeof(func)); // Also pushed on stack. + const SQUserPointer pCallee = (SQUserPointer)&callee; + memcpy(up,&pCallee,sizeof(Callee*)); + memcpy(up + sizeof(Callee*),&func,sizeof(func)); + sq_newclosure(v,DirectCallMemberFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,0,sqTypeMask::Get()); +#endif +} // sq_pushdirectclosure + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_DIRECT_CLOSURE +#include "SqPlusSmartPointer.h" +#endif + +// === Class Instance call: class pointer retrieved from script class instance === + +template +inline void sq_pushdirectinstanceclosure(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + sq_newclosure(v,DirectCallInstanceMemberFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,0,sqTypeMask::Get()); +#endif +} // sq_pushdirectinstanceclosure + +// === Global function using this: class pointer retrieved from script class instance === + +template +inline void sq_pushdirectinstanceclosureglobal(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + // Could check that 1st arg of Func is a Callee + sq_newclosure(v,DirectCallInstanceGlobalFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + SQChar *tm = (SQChar*)sqTypeMask::Get(); + if( tm ) { + // Censor out the 1st arg, since SqPlus adds that automatically + tm[1] = _SC('x'); //tm[0]; + tm++; + } + sq_setparamscheck(v,0,tm?tm:_SC("")); +#endif +} // sq_pushdirectinstanceclosureglobal + +// === Global function using this: class pointer retrieved from script class instance === + +template +inline void sq_pushdirectinstanceclosureglobalvarargs(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + // Could check that 1st arg of Func is a Callee + sq_newclosure(v,DirectCallInstanceGlobalFunctionVarArgs::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,-1,_SC("x")); +#endif +} // sq_pushdirectinstanceclosureglobal + +// === Class Instance call: class pointer retrieved from script class instance (variable arguments) === + +template +inline void sq_pushdirectinstanceclosurevarargs(HSQUIRRELVM v,const Callee & callee,int (Callee::*func)(HSQUIRRELVM),SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + typedef int (Callee::*FuncType)(HSQUIRRELVM); + sq_newclosure(v,DirectCallInstanceMemberFunctionVarArgs::Dispatch,nupvalues+1); +} // sq_pushdirectinstanceclosurevarargs + +// === Register a STANDARD function (table or class on stack) === + +template +inline void Register(HSQUIRRELVM v,Func func,const SQChar * name) { + sq_pushstring(v,name,-1); + sq_pushdirectclosure(v,func,0); + sq_createslot(v,-3); // Stack is restored after this call (same state as before Register() call). +} // Register + +// === Register a MEMBER function (table or class on stack) === + +template +inline void Register(HSQUIRRELVM v,Callee & callee,Func func,const SQChar * name) { + sq_pushstring(v,name,-1); + sq_pushdirectclosure(v,callee,func,0); + sq_createslot(v,-3); // Stack is restored after this call (same state as before Register() call). +} // Register + +// === Register a STANDARD global function (root table) === + +template +inline void RegisterGlobal(HSQUIRRELVM v,Func func,const SQChar * name) { + sq_pushroottable(v); + Register(v,func,name); + sq_poptop(v); // Remove root table. +} // RegisterGlobal + +template +inline void RegisterGlobal(Func func,const SQChar * name) { + RegisterGlobal(SquirrelVM::GetVMPtr(),func,name); +} // RegisterGlobal + +// === Register a MEMBER global function (root table) === + +template +inline void RegisterGlobal(HSQUIRRELVM v,Callee & callee,Func func,const SQChar * name) { + sq_pushroottable(v); + Register(v,callee,func,name); + sq_poptop(v); // Remove root table. +} // RegisterGlobal + +template +inline void RegisterGlobal(Callee & callee,Func func,const SQChar * name) { + RegisterGlobal(SquirrelVM::GetVMPtr(),callee,func,name); +} // RegisterGlobal + +// === Register a STANDARD function (hso is table or class) === + +template +inline void Register(HSQUIRRELVM v,HSQOBJECT hso,Func func,const SQChar * name) { + sq_pushobject(v,hso); + Register(v,func,name); + sq_poptop(v); // Remove hso. +} // Register + +// === Register a MEMBER function (hso is table or class) === +// === Fixed Class pointer call (always calls with object pointer that was registered) === + +template +inline void Register(HSQUIRRELVM v,HSQOBJECT hso,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hso); + Register(v,callee,func,name); + sq_poptop(v); // Remove hso. +} // Register + +// === Register an INSTANCE MEMBER function === +// === Class Instance call: class pointer retrieved from script class instance === + +template +inline void RegisterInstance(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosure(v,callee,func,0); + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstance + + +// === Register an INSTANCE GLOBAL MEMBER function === +// === Class Instance call: class pointer retrieved from script class instance === +// Allows embedding global func that takes Callee as 1st arg as a member func +template +inline void RegisterInstanceGlobalFunc(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosureglobal(v,callee,func,0); + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstanceGlobaFunc + +// === Register an INSTANCE GLOBAL MEMBER WITH VAR ARGS function === +// === Class Instance call: class pointer retrieved from script class instance === +// Allows embedding global func that takes Callee as 1st arg as a member func +template +inline void RegisterInstanceGlobalFuncVarArgs(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosureglobalvarargs(v,callee,func,0); + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstanceGlobaFunc + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_REGISTER_INSTANCE +#include "SqPlusSmartPointer.h" +#endif + +#ifdef _MSC_VER +#pragma warning(disable : 4995) // Deprecated _snprintf +#endif + +// === Register an INSTANCE MEMBER function Variable Arguments === +// typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). +// All the other Squirrel type-masks are passed normally. + +template +inline void RegisterInstanceVarArgs(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,int (Callee::*func)(HSQUIRRELVM),const SQChar * name,const SQChar * typeMask=_SC("*")) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosurevarargs(v,callee,func,0); + SQChar tm[64]; + SQChar * ptm = tm; + int numParams = SQ_MATCHTYPEMASKSTRING; + if (typeMask) { + if (typeMask[0] == '*') { + ptm = 0; // Variable args: don't check parameters. +// numParams = 0; // Clear SQ_MATCHTYPEMASKSTRING (does not mean match 0 params. See sq_setparamscheck()). + } else { + if (SCSNPRINTF(tm,sizeof(tm),_SC("x%s"),typeMask) < 0) { // Must be an instance. + throw SquirrelError(_SC("RegisterInstanceVarArgs: typeMask string too long.")); + } // if + } // if + } else { // Need to check object type on stack: table, class, instance, etc. +// _snprintf(tm,sizeof(tm),"x"); // instance. + tm[0] = 'x'; + tm[1] = 0; + } // if + if (ptm) { // If ptm == 0, don't check type. + sq_setparamscheck(v,numParams,ptm); // Determine arg count from type string. + } // if +#ifdef _DEBUG + sq_setnativeclosurename(v,-1,name); // For debugging only. +#endif + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstanceVarArgs + +#ifdef _MSC_VER +#pragma warning(default : 4995) +#endif + +// === Call Squirrel Functions from C/C++ === +// No type checking is performed for Squirrel functions as Squirrel types are dynamic: +// Incoming types are passed unchanged to Squirrel functions. The parameter count is checked: an exception is thrown if mismatched. +// Return values must match the RT template argument type, else an exception can be thrown on return. + +template +struct SquirrelFunction { + HSQUIRRELVM v; + SquirrelObject object; // Table or class. + SquirrelObject func; + SquirrelFunction() : v(0) {} + SquirrelFunction(HSQUIRRELVM _v,const SquirrelObject & _object,const SquirrelObject & _func) : v(_v), object(_object), func(_func) {} + SquirrelFunction(const SquirrelObject & _object,const SquirrelObject & _func) : v(SquirrelVM::GetVMPtr()), object(_object), func(_func) {} + SquirrelFunction(const SquirrelObject & _object,const SQChar * name) { + v = SquirrelVM::GetVMPtr(); + object = _object; + func = object.GetValue(name); + } + SquirrelFunction(const SQChar * name) { + v = SquirrelVM::GetVMPtr(); + object = SquirrelVM::GetRootTable(); + func = object.GetValue(name); + } + + // Release references and reset internal objects to null. + void reset(void) { + func.Reset(); + object.Reset(); + } // Reset + +#define SQPLUS_CHECK_FNCALL(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(_SC("SquirrelFunction<> call failed")) + + RT operator()(void) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + SQPLUS_CHECK_FNCALL(sq_call(v,1,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + SQPLUS_CHECK_FNCALL(sq_call(v,2,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + SQPLUS_CHECK_FNCALL(sq_call(v,3,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + SQPLUS_CHECK_FNCALL(sq_call(v,4,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + SQPLUS_CHECK_FNCALL(sq_call(v,5,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + Push(v,p5); + SQPLUS_CHECK_FNCALL(sq_call(v,6,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + Push(v,p5); + Push(v,p6); + SQPLUS_CHECK_FNCALL(sq_call(v,7,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + Push(v,p5); + Push(v,p6); + Push(v,p7); + SQPLUS_CHECK_FNCALL(sq_call(v,8,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + +}; + +// === Class/Struct registration === + +#define SQ_DELETE_CLASS(CLASSTYPE) if (up) { CLASSTYPE * self = (CLASSTYPE *)up; delete self;} return 0 +#define SQ_DECLARE_RELEASE(CLASSTYPE) \ + static int release(SQUserPointer up,SQInteger size) { \ + SQ_DELETE_CLASS(CLASSTYPE); \ + } + +template +struct ReleaseClassPtrPtr { + static int release(SQUserPointer up,SQInteger size) { + if (up) { + T ** self = (T **)up; + delete *self; + } // if + return 0; + } // release +}; + +template +struct ReleaseClassPtr { + static int release(SQUserPointer up,SQInteger size) { + if (up) { + T * self = (T *)up; + delete self; + } // if + return 0; + } // release +}; + +BOOL CreateClass(HSQUIRRELVM v,SquirrelObject & newClass,SQUserPointer classType,const SQChar * name,const SQChar * baseName=0); + + +template +inline void PopulateAncestry(HSQUIRRELVM v, + SquirrelObject &instance, + T *newClass) +{ + // 11/2/05: Create a new table for this instance. + SquirrelObject newObjectTable = SquirrelVM::CreateTable(); + // 64-bit compatible version. + newObjectTable.SetUserPointer(INT((size_t)ClassType::type()), newClass); + instance.SetValue(SQ_CLASS_OBJECT_TABLE_NAME, newObjectTable); + + SquirrelObject classHierArray = instance.GetValue(SQ_CLASS_HIER_ARRAY); + INT count = classHierArray.Len(); + + // This will be true when more than one C/C++ class is in the hierarchy. + if (count > 1) { + --count; // Skip the most-derived class. + for (INT i = 0; i < count; i++) { + // Kamaitati's changes for C++ inheritance support. jcs 5/28/06 + SquirrelObject so = classHierArray.GetValue(i); + sq_pushobject(v,so.GetObjectHandle()); + SQUserPointer typeTag; + sq_gettypetag(v,-1,&typeTag); + newObjectTable.SetUserPointer(INT(size_t(typeTag)),newClass); + sq_poptop(v); + } + } +} + + +// Call PostConstruct() at the end of custom constructors. +template +inline int PostConstruct(HSQUIRRELVM v, T *newClass, SQRELEASEHOOK hook) +{ +#ifdef SQ_USE_CLASS_INHERITANCE + StackHandler sa(v); + HSQOBJECT ho = sa.GetObjectHandle(1); // OT_INSTANCE + SquirrelObject instance(ho); + PopulateAncestry(v, instance, newClass); +#endif // SQ_USE_CLASS_INHERITANCE + + sq_setinstanceup(v, 1, newClass); + sq_setreleasehook(v, 1, hook); + return TRUE; +} // PostConstruct + +inline int PostConstructSimple(HSQUIRRELVM v, void *newClass, SQRELEASEHOOK hook){ + sq_setinstanceup(v, 1, newClass); + sq_setreleasehook(v, 1, hook); + return TRUE; +} // PostConstructSimple + + +template +struct ConstructReleaseClass { + static int construct(HSQUIRRELVM v) { + return PostConstruct(v,new T(),release); + } // construct + SQ_DECLARE_RELEASE(T) +}; + +# ifdef SQPLUS_ENABLE_TYPEOF +template +int sq_typeof(HSQUIRRELVM v) { + sq_pushstring(v,TypeInfo().typeName,-1); + return 1; +} +# endif + +// === Helper for RegisterClassType*() === +inline void setupClassHierarchy(SquirrelObject newClass) { + // New member vars cannot be added to instances (OT_INSTANCE): additions must occur on the defining class (OT_CLASS), before any instances are instantiated. + if (!newClass.Exists(SQ_CLASS_OBJECT_TABLE_NAME)) { // Will always get table from most-derived registered class. + SquirrelObject objectTable = SquirrelVM::CreateTable(); + newClass.SetValue(SQ_CLASS_OBJECT_TABLE_NAME,objectTable); // Constructors must add their 'this' pointer indexed by type to this table. See PostConstruct() above. + // 11/2/05: This table will behave as a static global for each instance unless overwritten during construction (see PostConstruct() above). + } // if + SquirrelObject classHierArray; + if (!newClass.Exists(SQ_CLASS_HIER_ARRAY)) { // Will always get table from most-derived registered class. + classHierArray = SquirrelVM::CreateArray(0); // The only constructor called will be the most-derived class: this array contains all classes in the hierarchy to be constructed. + newClass.SetValue(SQ_CLASS_HIER_ARRAY,classHierArray); + } else { + classHierArray = newClass.GetValue(SQ_CLASS_HIER_ARRAY); + } // if + classHierArray.ArrayAppend(newClass); // Add the class to the hierarchy array. The array values will be released and replaced with UserData to free created ancestor classes. +} // setupClassHierarchy + + +template +inline SquirrelObject RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName,const SQChar * baseScriptClassName=0) { + int top = sq_gettop(v); + SquirrelObject newClass; + if (CreateClass(v,newClass,(SQUserPointer)ClassType::type(),scriptClassName,baseScriptClassName)) { + SquirrelVM::CreateFunction(newClass,&ConstructReleaseClass::construct,_SC("constructor")); +# ifdef SQ_USE_CLASS_INHERITANCE + setupClassHierarchy(newClass); +# endif +# ifdef SQPLUS_ENABLE_TYPEOF + SquirrelVM::CreateFunction(newClass,&sq_typeof,_SC("_typeof")); +# endif + } // if + sq_settop(v,top); + return newClass; +} // RegisterClassType + +template +inline SquirrelObject RegisterClassTypeNoConstructor(HSQUIRRELVM v,const SQChar * scriptClassName,const SQChar * baseScriptClassName=0) { + int top = sq_gettop(v); + SquirrelObject newClass; + if (CreateClass(v,newClass,(SQUserPointer)ClassType::type(),scriptClassName,baseScriptClassName)) { +# ifdef SQ_USE_CLASS_INHERITANCE + setupClassHierarchy(newClass); +# endif +# ifdef SQPLUS_ENABLE_TYPEOF + SquirrelVM::CreateFunction(newClass,&sq_typeof,_SC("_typeof")); +# endif + } // if + sq_settop(v,top); + return newClass; +} // RegisterClassTypeNoConstructor + + +// === Define and register a C++ class and its members for use with Squirrel === +// Constructors+destructors are automatically created. Custom constructors must use the +// standard SQFUNCTION signature if variable argument types are required (overloads). +// See testSqPlus2.cpp for examples. + +// Do not use SQClassDefBase<> directly, use SQClassDef<> or SQClassDefNoConstructor<>, below. +template +struct SQClassDefBase { + HSQUIRRELVM v; + const SQChar * name; + SquirrelObject newClass; + +#if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + const SQChar * base; + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefBase(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : v(_v), name(_name), base(_base) {InitBase();} + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefBase(const SQChar * _name=0,const SQChar * _base=0) : v(SquirrelVM::GetVMPtr()), name(_name), base(_base) {InitBase(TypeWrapper());} + template + void InitBase(TypeWrapper){ /*assert(base);*/ ClassType::Get()->SetBase(TypeWrapper()); CheckInitDefaultNames(); } + void InitBase(TypeWrapper){ /*assert(!base);*/ CheckInitDefaultNames(); } + void CheckInitDefaultNames(){ if( !name ) name=TypeInfo().typeName; if( !base ) base=TypeInfo().typeName; } +#else + SQClassDefBase(HSQUIRRELVM _v,const SQChar * _name=0) : v(_v), name(_name) { CheckInitDefaultName(); } + SQClassDefBase(const SQChar * _name=0) : v(SquirrelVM::GetVMPtr()), name(_name) { CheckInitDefaultName(); } + void CheckInitDefaultName(){ if( !name ) name=TypeInfo().typeName; } +#endif + + // Register a member function. + template + SQClassDefBase & func(Func pfunc,const SQChar * name) { + RegisterInstance(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); + return *this; + } // func + + // Register a global function as a member function (the global takes a Callee*/& as first arg). + template + SQClassDefBase & globMembFunc(Func pfunc,const SQChar * name) { + RegisterInstanceGlobalFunc(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); + return *this; + } // globMemberFunc + + // Register a global function as a member function (the global takes a Callee*/& as first arg and SQVM* as 2nd). + template + SQClassDefBase & globMembFuncVarArgs(Func pfunc,const SQChar * name) { + RegisterInstanceGlobalFuncVarArgs(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); + return *this; + } // globMemberFuncVarArgs + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_CLASS_DEF_FUNC +#include "SqPlusSmartPointer.h" +#endif + + // Register a variable-argument member function (supports variable+multiple return values). + // typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). + // All the other Squirrel type-masks are passed normally. + template + SQClassDefBase & funcVarArgs(Func pfunc,const SQChar * name,const SQChar * typeMask=_SC("*")) { + RegisterInstanceVarArgs(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name,typeMask); + return *this; + } // funcVarArgs + + // === BEGIN static-member+global function registration === + + // === This version is for static member functions only, such as custom constructors where 'this' is not yet valid === + // typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). + // All the other Squirrel type-masks are passed normally. + + template + SQClassDefBase & staticFuncVarArgs(Func pfunc,const SQChar * name,const SQChar * typeMask=_SC("*")) { + SquirrelVM::PushObject(newClass); + SquirrelVM::CreateFunction(pfunc,name,typeMask); + SquirrelVM::Pop(1); + return *this; + } // staticFuncVarArgs + + // Register a standard global function (effectively embedding a global function in TClassType's script namespace: does not need or use a 'this' pointer). + template + SQClassDefBase & staticFunc(Func pfunc,const SQChar * name) { + Register(v,newClass.GetObjectHandle(),pfunc,name); + return *this; + } // staticFunc + + // Register a function to a pre-allocated class/struct member function: will use callee's 'this' (effectively embedding a global function in TClassType's script namespace). + template + SQClassDefBase & staticFunc(Callee & callee,Func pfunc,const SQChar * name) { + Register(v,newClass.GetObjectHandle(),callee,pfunc,name); + return *this; + } // staticFunc + + // === END static+global function registration === + + // Register a member variable. + template + SQClassDefBase & var(VarType TClassType::* pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_WRITE) { + struct CV { + VarType TClassType::* var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,access); + return *this; + } // var + + // Register a member variable as a UserPointer (read only). + template + SQClassDefBase & varAsUserPointer(VarType TClassType::* pvar,const SQChar * name) { + struct CV { + VarType TClassType::* var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterInstanceVariable(newClass,ClassType::type(),*(SQAnything **)&cv,name,VAR_ACCESS_READ_ONLY); + return *this; + } // varAsUserPointer + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_CLASS_DEF_VAR +#include "SqPlusSmartPointer.h" +#endif + + template + SQClassDefBase & staticVar(VarType * pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_WRITE) { + struct CV { + VarType * var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,VarAccessType(access|VAR_ACCESS_STATIC)); + return *this; + } // staticVar + +#ifdef SQPLUS_CONST_OPT +#define SQ_REG_CONST_STATIC_VAR +#include "SqPlusConst.h" +#endif + + // Member / static member script vars (ordinary Squirrel vars) + SQClassDefBase & scriptVar( const SQChar* name, int ival, SQBool static_var=SQFalse ) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + sq_pushobject(v,newClass.GetObjectHandle()); + sq_pushstring(v,name,-1); + sq_pushinteger(v,ival); + sq_newslot(v,-3,static_var); + sq_pop(v,1); + return *this; + } + + SQClassDefBase & scriptVar( const SQChar* name, double fval, SQBool static_var=SQFalse ) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + sq_pushobject(v,newClass.GetObjectHandle()); + sq_pushstring(v,name,-1); + sq_pushfloat(v,fval); + sq_newslot(v,-3,static_var); + sq_pop(v,1); + return *this; + } + + SQClassDefBase & scriptVar( const SQChar* name, const SQChar* sval, SQBool static_var=SQFalse ) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + sq_pushobject(v,newClass.GetObjectHandle()); + sq_pushstring(v,name,-1); + sq_pushstring(v,sval,-1); + sq_newslot(v,-3,static_var); + sq_pop(v,1); + return *this; + } + + // Register a constant (read-only in script, passed by value (only INT, FLOAT, or BOOL types)). + template + SQClassDefBase & constant(ConstantType constant,const SQChar * name) { + RegisterInstanceConstant(newClass,ClassType::type(),constant,name); + return *this; + } // constant + + // Register an enum as an integer (read-only in script). + SQClassDefBase & enumInt(int constant,const SQChar * name) { + RegisterInstanceConstant(newClass,ClassType::type(),constant,name); + return *this; + } // enumInt + +#ifdef SQPLUS_OVERLOAD_OPT +#define SQPLUS_OVERLOAD_IMPLEMENTATION +#include "SqPlusOverload.h" +#endif +}; + +#ifdef SQPLUS_OVERLOAD_OPT +#define SQPLUS_OVERLOAD_FUNCTIONS +#include "SqPlusOverload.h" +#endif + +template +struct SQClassDef : public SQClassDefBase { + +#if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDef(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_v,_name,_base) { + SQClassDefBase::newClass = + RegisterClassType( SQClassDefBase::v, + SQClassDefBase::name, + SQClassDefBase::base ); + } + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDef(const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_name,_base) { + SQClassDefBase::newClass = + RegisterClassType< TClassType>( SQClassDefBase::v, + SQClassDefBase::name, + SQClassDefBase::base ); + } +#else + SQClassDef(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase(_v,_name) { + SQClassDefBase::newClass = + RegisterClassType(SQClassDefBase::v, + SQClassDefBase::name ); + } + SQClassDef(const SQChar * _name=0) : SQClassDefBase(_name) { + SQClassDefBase::newClass = + RegisterClassType(SQClassDefBase::v, + SQClassDefBase::name ); + } +#endif +}; + +template +struct SQClassDefNoConstructor : public SQClassDefBase { +#if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefNoConstructor(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_v,_name,_base) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name,SQClassDefBase::base); + } + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefNoConstructor(const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_name,_base) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name,SQClassDefBase::base); + } +#else + SQClassDefNoConstructor(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase(_v,_name) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name); + } + SQClassDefNoConstructor(const SQChar * _name=0) : SQClassDefBase(_name) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name); + } +#endif +}; + + +// === Macros for old style registration. SQClassDef registration is now easier to use (SQ_DECLARE_CLASS() is not needed) === + +#define SQ_DECLARE_CLASS(CLASSNAME) \ +static int _##CLASSNAME##_release(SQUserPointer up,SQInteger size) { \ + if (up) { \ + CLASSNAME * self = (CLASSNAME *)up; \ + delete self; \ + } \ + return 0; \ +} \ +static int _##CLASSNAME##_constructor(HSQUIRRELVM v) { \ + CLASSNAME * pc = new CLASSNAME(); \ + sq_setinstanceup(v,1,pc); \ + sq_setreleasehook(v,1,_##CLASSNAME##_release); \ + return 1; \ +} + +#define SQ_REGISTER_CLASS(CLASSNAME) \ + RegisterClassType(SquirrelVM::GetVMPtr(),_SC(#CLASSNAME),_##CLASSNAME##_constructor) + +#define SQ_REGISTER_INSTANCE(NEWSQCLASS,CCLASS,FUNCNAME) \ + RegisterInstance(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,_SC(#FUNCNAME)); + +#define SQ_REGISTER_INSTANCE_VARARGS(NEWSQCLASS,CCLASS,FUNCNAME) \ + RegisterInstanceVarArgs(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,_SC(#FUNCNAME)); + +#define SQ_REGISTER_INSTANCE_VARIABLE(NEWSQCLASS,CCLASS,VARNAME) \ + RegisterInstanceVariable(NEWSQCLASS,&((CCLASS *)0)->VARNAME,_SC(#VARNAME)); + +#if defined(USE_ARGUMENT_DEPENDANT_OVERLOADS) && defined(_MSC_VER) +#pragma warning (default:4675) +#endif + +}; // namespace SqPlus + + +// === BEGIN code suggestion from the Wiki === + +// Get any bound type from this SquirrelObject. Note that Squirrel's +// handling of references and pointers still holds here. +template +inline _ty SquirrelObject::Get(void) { + sq_pushobject(SquirrelVM::_VM,GetObjectHandle()); + _ty val = SqPlus::Get(SqPlus::TypeWrapper<_ty>(),SquirrelVM::_VM,-1); + sq_poptop(SquirrelVM::_VM); + return val; +} + +// Set any bound type to this SquirrelObject. Note that Squirrel's +// handling of references and pointers still holds here. +template +inline SquirrelObject SquirrelObject::SetByValue(_ty val) { // classes/structs should be passed by ref (below) to avoid an extra copy. + SqPlus::Push(SquirrelVM::_VM,val); + AttachToStackObject(-1); + sq_poptop(SquirrelVM::_VM); + return *this; +} + +// Set any bound type to this SquirrelObject. Note that Squirrel's +// handling of references and pointers still holds here. +template +inline SquirrelObject &SquirrelObject::Set(_ty & val) { + SqPlus::Push(SquirrelVM::_VM,val); + AttachToStackObject(-1); + sq_poptop(SquirrelVM::_VM); + return *this; +} + +// === END code suggestion from the Wiki === + +#endif //_SQ_PLUS_H_ -- cgit v1.2.3