/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include "sqvm.h" #include "sqtable.h" #include "sqclass.h" #include "sqfuncproto.h" #include "sqclosure.h" SQClass::SQClass(SQSharedState *ss,SQClass *base) { _base = base; _typetag = 0; _hook = NULL; _udsize = 0; _locked = false; _constructoridx = -1; if(_base) { _constructoridx = _base->_constructoridx; _udsize = _base->_udsize; _defaultvalues.copy(base->_defaultvalues); _methods.copy(base->_methods); _COPY_VECTOR(_metamethods,base->_metamethods,MT_LAST); __ObjAddRef(_base); } _members = base?base->_members->Clone() : SQTable::Create(ss,0); __ObjAddRef(_members); INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); } void SQClass::Finalize() { _attributes.Null(); _defaultvalues.resize(0); _methods.resize(0); _NULL_SQOBJECT_VECTOR(_metamethods,MT_LAST); __ObjRelease(_members); if(_base) { __ObjRelease(_base); } } SQClass::~SQClass() { REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); Finalize(); } bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { SQObjectPtr temp; bool belongs_to_static_table = type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic; if(_locked && !belongs_to_static_table) return false; //the class already has an instance so cannot be modified if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value { _defaultvalues[_member_idx(temp)].val = val; return true; } if(belongs_to_static_table) { SQInteger mmidx; if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { _metamethods[mmidx] = val; } else { SQObjectPtr theval = val; if(_base && type(val) == OT_CLOSURE) { theval = _closure(val)->Clone(); _closure(theval)->_base = _base; __ObjAddRef(_base); //ref for the closure } if(type(temp) == OT_NULL) { bool isconstructor; SQVM::IsEqual(ss->_constructoridx, key, isconstructor); if(isconstructor) { _constructoridx = (SQInteger)_methods.size(); } SQClassMember m; m.val = theval; _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); _methods.push_back(m); } else { _methods[_member_idx(temp)].val = theval; } } return true; } SQClassMember m; m.val = val; _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size()))); _defaultvalues.push_back(m); return true; } SQInstance *SQClass::CreateInstance() { if(!_locked) Lock(); return SQInstance::Create(_opt_ss(this),this); } SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQObjectPtr oval; SQInteger idx = _members->Next(false,refpos,outkey,oval); if(idx != -1) { if(_ismethod(oval)) { outval = _methods[_member_idx(oval)].val; } else { SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val; outval = _realval(o); } } return idx; } bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) { SQObjectPtr idx; if(_members->Get(key,idx)) { if(_isfield(idx)) _defaultvalues[_member_idx(idx)].attrs = val; else _methods[_member_idx(idx)].attrs = val; return true; } return false; } bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) { SQObjectPtr idx; if(_members->Get(key,idx)) { outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs); return true; } return false; } /////////////////////////////////////////////////////////////////////// void SQInstance::Init(SQSharedState *ss) { _userpointer = NULL; _hook = NULL; __ObjAddRef(_class); _delegate = _class->_members; INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); } SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize) { _memsize = memsize; _class = c; SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger n = 0; n < nvalues; n++) { new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val); } Init(ss); } SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize) { _memsize = memsize; _class = i->_class; SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger n = 0; n < nvalues; n++) { new (&_values[n]) SQObjectPtr(i->_values[n]); } Init(ss); } void SQInstance::Finalize() { SQUnsignedInteger nvalues = _class->_defaultvalues.size(); __ObjRelease(_class); _NULL_SQOBJECT_VECTOR(_values,nvalues); //for(SQUnsignedInteger i = 0; i < nvalues; i++) { // _values[i].Null(); // } } SQInstance::~SQInstance() { REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); if(_class){ Finalize(); } //if _class is null it was already finalized by the GC } bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { if(type(_class->_metamethods[mm]) != OT_NULL) { res = _class->_metamethods[mm]; return true; } return false; } bool SQInstance::InstanceOf(SQClass *trg) { SQClass *parent = _class; while(parent != NULL) { if(parent == trg) return true; parent = parent->_base; } return false; }