![]() |
Show Changes |
![]() |
|
![]() |
Recent Changes |
![]() |
Subscriptions |
![]() |
Lost and Found |
![]() |
Find References |
![]() |
Rename |
![]() |
Administration Page |
![]() |
Topic Locks |
| Search |
History
| 7/5/2007 6:48:36 AM |
| -220.211.116.217 |
| 5/30/2007 12:38:59 PM |
| -125.72.28.38 |
| 5/28/2007 6:49:52 AM |
| -69.136.148.27 |
| 7/13/2006 9:51:28 PM |
| -71.225.31.29 |
| 7/12/2006 12:04:48 PM |
| -71.224.62.52 |
![]() |
List all versions |
To expose the bug:
#include <string>
#include <sqplus.h>
class Base
{
public:
Base() {}
virtual ~Base() {}
static void Bind()
{
SqPlus::SQClassDef<Base>(_T("Base")).
func(&Base::GetBaseId,"getBaseId");
}
std::string GetBaseId() { return "Base"; }
};
DECLARE_INSTANCE_TYPE(Base);
class Derived : public Base
{
public:
Derived() : Base() {}
virtual ~Derived() {}
static void Bind()
{
SqPlus::SQClassDef<Derived>(_T("Derived"),_T("Base")).
staticFunc( &Derived::GetNativeCreated, "getNativeCreated" );
func( &Derived::GetDerivedId, "getDerivedId");
}
std::string GetDerivedId() { return "Derived"; }
static Derived* GetNativeCreated() { return instance; }
private:
static Derived* instance;
};
Derived* Derived::instance = new Derived();
DECLARE_INSTANCE_TYPE(Derived);
int _tmain(int argc, _TCHAR* argv[])
{
printf("Initialize Squirrel\n");
SquirrelVM::Init();
printf("Binding classes to squirrel\n");
Base::Bind();
Derived::Bind();
try
{
SquirrelObject script = SquirrelVM::CompileBuffer(_T(
" \
local shouldWork = Derived(); \
print(\"Base id is \" + shouldWork.getBaseId()); \
local shouldFail = shouldWork.getNativeCreated(); \
print(\"Base id is \" + shouldFail.getBaseId()); \
"
));
SquirrelVM::RunScript(script);
}
catch(SquirrelError& error)
{
printf("Error: %s\n",std::string(error.desc).c_str());
}
}
To fix it:
In sqplus.h add this after #define SQ_ANCESTOR_CLASS_INDEX T("_ci")
#define SQ_CLASS_HEIRARCHY_TABLE _T("__ch")
inline void PopulateAncestry(HSQUIRRELVM v, SquirrelObject& instance, SQUserPointer up) {
int oldtop = sq_gettop(v);
SquirrelObject objectTable = SquirrelVM::CreateTable();
instance.SetValue(SQ_CLASS_OBJECT_TABLE_NAME,objectTable);
SquirrelObject root = SquirrelVM::GetRootTable();
if (root.Exists(SQ_CLASS_HEIRARCHY_TABLE))
{
SquirrelObject classHeirarchyTable = root.GetValue(SQ_CLASS_HEIRARCHY_TABLE);
SQUserPointer myTypeTag;
if(instance.GetTypeTag(&myTypeTag))
{
SquirrelObject classHierArray = classHeirarchyTable.GetValue(INT(size_t(myTypeTag)));
if(OT_ARRAY == classHierArray.GetType())
{
INT count = classHierArray.Len();
for (INT i=0; i < count; i++) {
SquirrelObject so = classHierArray.GetValue(i);
sq_pushobject(v,so.GetObjectHandle());
SQUserPointer typeTag;
sq_gettypetag(v,-1,&typeTag);
objectTable.SetUserPointer(INT(size_t(typeTag)),up);
sq_poptop(v);
} // for
}
}
}
sq_settop(v,oldtop);
}
Replace the PostConstruct function with this
template<typename T>
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_setinstanceup(v,1,newClass);
sq_setreleasehook(v,1,hook);
return 1;
} // PostConstruct
replace the RegisterClassType function with
template<typename T>
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<T>::type(),scriptClassName,baseScriptClassName)) {
SquirrelVM::CreateFunction(newClass,&ConstructReleaseClass<T>::construct,_T("constructor"));
#ifdef SQ_USE_CLASS_INHERITANCE
// <NOTE> 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 root = SquirrelVM::GetRootTable();
SquirrelObject classHeirarchyTable;
if (!root.Exists(SQ_CLASS_HEIRARCHY_TABLE))
{
classHeirarchyTable = SquirrelVM::CreateTable();
root.SetValue(SQ_CLASS_HEIRARCHY_TABLE,classHeirarchyTable);
}
else
{
classHeirarchyTable = root.GetValue(SQ_CLASS_HEIRARCHY_TABLE);
}
if(0 != baseScriptClassName)
{
if(root.Exists(baseScriptClassName))
{
SquirrelObject baseClass = root.GetValue(baseScriptClassName);
SQUserPointer baseType;
if(baseClass.GetTypeTag(&baseType))
{
SquirrelObject classHierArray = classHeirarchyTable.GetValue((INT(size_t(baseType))));
if(OT_ARRAY == classHierArray.GetType())
{
SquirrelObject newArray = classHierArray.Clone();
newArray.ArrayAppend(newClass);
classHeirarchyTable.SetValue((INT(size_t(ClassType<T>::type()))),newArray);
}
}
}
}
else
{
SquirrelObject newArray = SquirrelVM::CreateArray(0);
newArray.ArrayAppend(newClass);
classHeirarchyTable.SetValue((INT(size_t(ClassType<T>::type()))),newArray);
}
#endif
} // if
sq_settop(v,top);
return newClass;
} // RegisterClassType
In SquirrelBindingsUtils.h replace CreateNativeClassInstance with this
BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar *classname,SQUserPointer ud,SQRELEASEHOOK hook)
{
int oldtop = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v,classname,-1);
if(SQ_FAILED(sq_rawget(v,-2))){ // Get the class (created with sq_newclass()).
sq_settop(v,oldtop);
return FALSE;
}
//sq_pushroottable(v);
if(SQ_FAILED(sq_createinstance(v,-1))) {
sq_settop(v,oldtop);
return FALSE;
}
#ifdef SQ_USE_CLASS_INHERITANCE
HSQOBJECT ho;
sq_getstackobj(v,-1,&ho); // OT_INSTANCE
SquirrelObject instance(ho);
SqPlus::PopulateAncestry(v,instance,ud);
#endif
sq_remove(v,-3); //removes the root table
sq_remove(v,-2); //removes the class
if(SQ_FAILED(sq_setinstanceup(v,-1,ud))) {
sq_settop(v,oldtop);
return FALSE;
}
sq_setreleasehook(v,-1,hook);
return TRUE;
}