1 /*
2 see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include "sqvm.h"
6 #include "sqtable.h"
7 #include "sqclass.h"
8 #include "sqclosure.h"
9
SQClass(SQSharedState * ss,SQClass * base)10 SQClass::SQClass(SQSharedState *ss,SQClass *base)
11 {
12 _base = base;
13 _typetag = 0;
14 _hook = NULL;
15 _udsize = 0;
16 _metamethods.resize(MT_LAST); //size it to max size
17 if(_base) {
18 _defaultvalues.copy(base->_defaultvalues);
19 _methods.copy(base->_methods);
20 _metamethods.copy(base->_metamethods);
21 __ObjAddRef(_base);
22 }
23 _members = base?base->_members->Clone() : SQTable::Create(ss,0);
24 __ObjAddRef(_members);
25 _locked = false;
26 INIT_CHAIN();
27 ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);
28 }
29
Finalize()30 void SQClass::Finalize() {
31 _attributes = _null_;
32 _defaultvalues.resize(0);
33 _methods.resize(0);
34 _metamethods.resize(0);
35 __ObjRelease(_members);
36 if(_base) {
37 __ObjRelease(_base);
38 }
39 }
40
~SQClass()41 SQClass::~SQClass()
42 {
43 REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);
44 Finalize();
45 }
46
NewSlot(SQSharedState * ss,const SQObjectPtr & key,const SQObjectPtr & val,bool bstatic)47 bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)
48 {
49 SQObjectPtr temp;
50 if(_locked)
51 return false; //the class already has an instance so cannot be modified
52 if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value
53 {
54 _defaultvalues[_member_idx(temp)].val = val;
55 return true;
56 }
57 if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic) {
58 SQInteger mmidx;
59 if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) &&
60 (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) {
61 _metamethods[mmidx] = val;
62 }
63 else {
64 if(type(temp) == OT_NULL) {
65 SQClassMember m;
66 m.val = val;
67 _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size())));
68 _methods.push_back(m);
69 }
70 else {
71 _methods[_member_idx(temp)].val = val;
72 }
73 }
74 return true;
75 }
76 SQClassMember m;
77 m.val = val;
78 _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size())));
79 _defaultvalues.push_back(m);
80 return true;
81 }
82
CreateInstance()83 SQInstance *SQClass::CreateInstance()
84 {
85 if(!_locked) Lock();
86 return SQInstance::Create(_opt_ss(this),this);
87 }
88
Next(const SQObjectPtr & refpos,SQObjectPtr & outkey,SQObjectPtr & outval)89 SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
90 {
91 SQObjectPtr oval;
92 SQInteger idx = _members->Next(false,refpos,outkey,oval);
93 if(idx != -1) {
94 if(_ismethod(oval)) {
95 outval = _methods[_member_idx(oval)].val;
96 }
97 else {
98 SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val;
99 outval = _realval(o);
100 }
101 }
102 return idx;
103 }
104
SetAttributes(const SQObjectPtr & key,const SQObjectPtr & val)105 bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val)
106 {
107 SQObjectPtr idx;
108 if(_members->Get(key,idx)) {
109 if(_isfield(idx))
110 _defaultvalues[_member_idx(idx)].attrs = val;
111 else
112 _methods[_member_idx(idx)].attrs = val;
113 return true;
114 }
115 return false;
116 }
117
GetAttributes(const SQObjectPtr & key,SQObjectPtr & outval)118 bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval)
119 {
120 SQObjectPtr idx;
121 if(_members->Get(key,idx)) {
122 outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs);
123 return true;
124 }
125 return false;
126 }
127
128 ///////////////////////////////////////////////////////////////////////
Init(SQSharedState * ss)129 void SQInstance::Init(SQSharedState *ss)
130 {
131 _userpointer = NULL;
132 _hook = NULL;
133 __ObjAddRef(_class);
134 _delegate = _class->_members;
135 INIT_CHAIN();
136 ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);
137 }
138
SQInstance(SQSharedState * ss,SQClass * c,SQInteger memsize)139 SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize)
140 {
141 _memsize = memsize;
142 _class = c;
143 SQUnsignedInteger nvalues = _class->_defaultvalues.size();
144 for(SQUnsignedInteger n = 0; n < nvalues; n++) {
145 new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val);
146 }
147 Init(ss);
148 }
149
SQInstance(SQSharedState * ss,SQInstance * i,SQInteger memsize)150 SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize)
151 {
152 _memsize = memsize;
153 _class = i->_class;
154 SQUnsignedInteger nvalues = _class->_defaultvalues.size();
155 for(SQUnsignedInteger n = 0; n < nvalues; n++) {
156 new (&_values[n]) SQObjectPtr(i->_values[n]);
157 }
158 Init(ss);
159 }
160
Finalize()161 void SQInstance::Finalize()
162 {
163 SQUnsignedInteger nvalues = _class->_defaultvalues.size();
164 __ObjRelease(_class);
165 for(SQUnsignedInteger i = 0; i < nvalues; i++) {
166 _values[i] = _null_;
167 }
168 }
169
~SQInstance()170 SQInstance::~SQInstance()
171 {
172 REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);
173 if(_class){ Finalize(); } //if _class is null it was already finalized by the GC
174 }
175
176 // C::B patch: Make the compiler happy by commenting unused variables
GetMetaMethod(SQVM *,SQMetaMethod mm,SQObjectPtr & res)177 bool SQInstance::GetMetaMethod(SQVM * /*v*/,SQMetaMethod mm,SQObjectPtr &res)
178 {
179 if(type(_class->_metamethods[mm]) != OT_NULL) {
180 res = _class->_metamethods[mm];
181 return true;
182 }
183 return false;
184 }
185
InstanceOf(SQClass * trg)186 bool SQInstance::InstanceOf(SQClass *trg)
187 {
188 SQClass *parent = _class;
189 while(parent != NULL) {
190 if(parent == trg)
191 return true;
192 parent = parent->_base;
193 }
194 return false;
195 }
196