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