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