restored some lost changes
[supertux.git] / src / squirrel / squirrel / sqobject.cpp
1 /*
2         see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include "sqvm.h"
6 #include "sqstring.h"
7 #include "sqarray.h"
8 #include "sqtable.h"
9 #include "squserdata.h"
10 #include "sqfuncproto.h"
11 #include "sqclass.h"
12 #include "sqclosure.h"
13
14 SQString *SQString::Create(SQSharedState *ss,const SQChar *s,int len)
15 {
16         SQString *str=ADD_STRING(ss,s,len);
17         str->_sharedstate=ss;
18         return str;
19 }
20
21 void SQString::Release()
22 {
23         REMOVE_STRING(_sharedstate,this);
24 }
25
26 unsigned int TranslateIndex(const SQObjectPtr &idx)
27 {
28         switch(type(idx)){
29                 case OT_NULL:
30                         return 0;
31                 case OT_INTEGER:
32                         return (unsigned int)_integer(idx);
33                 default:
34                         break;
35         }
36         assert(0);
37         return 0;
38 }
39
40 bool SQDelegable::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) {
41         if(_delegate) {
42                 return _delegate->Get((*_ss(this)->_metamethods)[mm],res);
43         }
44         return false;
45 }
46
47 bool SQGenerator::Yield(SQVM *v)
48 {
49         if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator"));  return false;}
50         if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; }
51         int size = v->_top-v->_stackbase;
52         _ci=*v->ci;
53         _stack.resize(size);
54         for(int n =0; n<size; n++) {
55                 _stack._vals[n] = v->_stack[v->_stackbase+n];
56                 v->_stack[v->_stackbase+n] = _null_;
57         }
58         int nvargs = v->ci->_vargs.size;
59         int vargsbase = v->ci->_vargs.base;
60         for(int j = nvargs - 1; j >= 0; j--) {
61                 _vargsstack.push_back(v->_vargsstack[vargsbase+j]);
62         }
63         _ci._generator=_null_;
64         for(int i=0;i<_ci._etraps;i++) {
65                 _etraps.push_back(v->_etraps.top());
66                 v->_etraps.pop_back();
67         }
68         _state=eSuspended;
69         return true;
70 }
71
72 bool SQGenerator::Resume(SQVM *v,int target)
73 {
74         int size=_stack.size();
75         if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; }
76         if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; }
77         int prevtop=v->_top-v->_stackbase;
78         PUSH_CALLINFO(v,_ci);
79         int oldstackbase=v->_stackbase;
80         v->_stackbase=v->_top;
81         v->ci->_target=target;
82         v->ci->_generator=SQObjectPtr(this);
83         v->ci->_vargs.size = _vargsstack.size();
84         
85         for(int i=0;i<_ci._etraps;i++) {
86                 v->_etraps.push_back(_etraps.top());
87                 _etraps.pop_back();
88         }
89         for(int n =0; n<size; n++) {
90                 v->_stack[v->_stackbase+n] = _stack._vals[n];
91                 _stack._vals[0] = _null_;
92         }
93         while(_vargsstack.size()) {
94                 v->_vargsstack.push_back(_vargsstack.back());
95                 _vargsstack.pop_back();
96         }
97         v->ci->_vargs.base = v->_vargsstack.size() - v->ci->_vargs.size;
98         v->_top=v->_stackbase+size;
99         v->ci->_prevtop=prevtop;
100         v->ci->_prevstkbase=v->_stackbase-oldstackbase;
101         _state=eRunning;
102         return true;
103 }
104
105 void SQArray::Extend(const SQArray *a){
106         int xlen;
107         if((xlen=a->Size()))
108                 for(int i=0;i<xlen;i++)
109                         Append(a->_values[i]);
110 }
111
112 const SQChar* SQFunctionProto::GetLocal(SQVM *vm,unsigned int stackbase,unsigned int nseq,unsigned int nop)
113 {
114         unsigned int nvars=_localvarinfos.size();
115         const SQChar *res=NULL; 
116         if(nvars>=nseq){
117                 for(unsigned int i=0;i<nvars;i++){
118                         if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop)
119                         {
120                                 if(nseq==0){
121                                         vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]);
122                                         res=_stringval(_localvarinfos[i]._name);
123                                         break;
124                                 }
125                                 nseq--;
126                         }
127                 }
128         }
129         return res;
130 }
131
132 int SQFunctionProto::GetLine(SQInstruction *curr)
133 {
134         int op=(curr-_instructions._vals);
135         int line=_lineinfos[0]._line;
136         for(unsigned int i=1;i<_lineinfos.size();i++){
137                 if(_lineinfos[i]._op>=op)
138                         return line;
139                 line=_lineinfos[i]._line;
140         }
141         return line;
142 }
143
144 //#define _ERROR_TRAP() error_trap:
145 #define _CHECK_IO(exp)  { if(!exp)return false; }
146 bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,int size)
147 {
148         if(write(up,dest,size) != size) {
149                 v->Raise_Error(_SC("io error (write function failure)"));
150                 return false;
151         }
152         return true;
153 }
154
155 bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,int size)
156 {
157         if(size && read(up,dest,size) != size) {
158                 v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated"));
159                 return false;
160         }
161         return true;
162 }
163
164 bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,int tag)
165 {
166         return SafeWrite(v,write,up,&tag,sizeof(tag));
167 }
168
169 bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,int tag)
170 {
171         int t;
172         _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t)));
173         if(t != tag){
174                 v->Raise_Error(_SC("invalid or corrupted closure stream"));
175                 return false;
176         }
177         return true;
178 }
179
180 bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o)
181 {
182         _CHECK_IO(SafeWrite(v,write,up,&type(o),sizeof(SQObjectType)));
183         switch(type(o)){
184         case OT_STRING:
185                 _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));
186                 _CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len)));
187                 break;
188         case OT_INTEGER:
189                 _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break;
190         case OT_FLOAT:
191                 _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break;
192         case OT_NULL:
193                 break;
194         default:
195                 v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o));
196                 return false;
197         }
198         return true;
199 }
200
201 bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)
202 {
203         SQObjectType t;
204         _CHECK_IO(SafeRead(v,read,up,&t,sizeof(SQObjectType)));
205         switch(t){
206         case OT_STRING:{
207                 int len;
208                 _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));
209                 _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len)));
210                 o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);
211                                    }
212                 break;
213         case OT_INTEGER:{
214                 SQInteger i;
215                 _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break;
216                                         }
217         case OT_FLOAT:{
218                 SQFloat f;
219                 _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break;
220                                   }
221         case OT_NULL:
222                 o=_null_;
223                 break;
224         default:
225                 v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t));
226                 return false;
227         }
228         return true;
229 }
230
231 bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)
232 {
233         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD));
234         _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar)));
235         _CHECK_IO(_funcproto(_function)->Save(v,up,write));
236         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL));
237         return true;
238 }
239
240 bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read)
241 {
242         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD));
243         _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar)));
244         _CHECK_IO(_funcproto(_function)->Load(v,up,read));
245         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL));
246         return true;
247 }
248
249 bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)
250 {
251         int i,nsize=_literals.size();
252         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
253         _CHECK_IO(WriteObject(v,up,write,_sourcename));
254         _CHECK_IO(WriteObject(v,up,write,_name));
255         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
256         _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize)));
257         for(i=0;i<nsize;i++){
258                 _CHECK_IO(WriteObject(v,up,write,_literals[i]));
259         }
260         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
261         nsize=_parameters.size();
262         _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize)));
263         for(i=0;i<nsize;i++){
264                 _CHECK_IO(WriteObject(v,up,write,_parameters[i]));
265         }
266         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
267         nsize=_outervalues.size();
268         _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize)));
269         for(i=0;i<nsize;i++){
270                 _CHECK_IO(SafeWrite(v,write,up,&_outervalues[i]._type,sizeof(unsigned int)));
271                 _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._src));
272                 _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._name));
273         }
274         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
275         nsize=_localvarinfos.size();
276         _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize)));
277         for(i=0;i<nsize;i++){
278                 SQLocalVarInfo &lvi=_localvarinfos[i];
279                 _CHECK_IO(WriteObject(v,up,write,lvi._name));
280                 _CHECK_IO(SafeWrite(v,write,up,&lvi._pos,sizeof(unsigned int)));
281                 _CHECK_IO(SafeWrite(v,write,up,&lvi._start_op,sizeof(unsigned int)));
282                 _CHECK_IO(SafeWrite(v,write,up,&lvi._end_op,sizeof(unsigned int)));
283         }
284         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
285         nsize=_lineinfos.size();
286         _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize)));
287         _CHECK_IO(SafeWrite(v,write,up,&_lineinfos[0],sizeof(SQLineInfo)*nsize));
288         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
289         nsize=_instructions.size();
290         _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize)));
291         _CHECK_IO(SafeWrite(v,write,up,&_instructions[0],sizeof(SQInstruction)*nsize));
292         _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
293         nsize=_functions.size();
294         _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize)));
295         for(i=0;i<nsize;i++){
296                 _CHECK_IO(_funcproto(_functions[i])->Save(v,up,write));
297         }
298         _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize)));
299         _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator)));
300         _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams)));
301         return true;
302 }
303
304 bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read)
305 {
306         int i, nsize = _literals.size();
307         SQObjectPtr o;
308         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
309         _CHECK_IO(ReadObject(v, up, read, _sourcename));
310         _CHECK_IO(ReadObject(v, up, read, _name));
311         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
312         _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize)));
313         for(i = 0;i < nsize; i++){
314                 _CHECK_IO(ReadObject(v, up, read, o));
315                 _literals.push_back(o);
316         }
317         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
318         _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize)));
319         for(i = 0; i < nsize; i++){
320                 _CHECK_IO(ReadObject(v, up, read, o));
321                 _parameters.push_back(o);
322         }
323         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
324         _CHECK_IO(SafeRead(v,read,up,&nsize,sizeof(nsize)));
325         for(i = 0; i < nsize; i++){
326                 unsigned int type;
327                 SQObjectPtr name;
328                 _CHECK_IO(SafeRead(v,read,up, &type, sizeof(unsigned int)));
329                 _CHECK_IO(ReadObject(v, up, read, o));
330                 _CHECK_IO(ReadObject(v, up, read, name));
331                 _outervalues.push_back(SQOuterVar(name,o, (SQOuterType)type));
332         }
333         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
334         _CHECK_IO(SafeRead(v,read,up,&nsize, sizeof(nsize)));
335         for(i = 0; i < nsize; i++){
336                 SQLocalVarInfo lvi;
337                 _CHECK_IO(ReadObject(v, up, read, lvi._name));
338                 _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(unsigned int)));
339                 _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(unsigned int)));
340                 _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(unsigned int)));
341                 _localvarinfos.push_back(lvi);
342         }
343         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
344         _CHECK_IO(SafeRead(v,read,up, &nsize,sizeof(nsize)));
345         _lineinfos.resize(nsize);
346         _CHECK_IO(SafeRead(v,read,up, &_lineinfos[0], sizeof(SQLineInfo)*nsize));
347         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
348         _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize)));
349         _instructions.resize(nsize);
350         _CHECK_IO(SafeRead(v,read,up, &_instructions[0], sizeof(SQInstruction)*nsize));
351         _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
352         _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize)));
353         for(i = 0; i < nsize; i++){
354                 o = SQFunctionProto::Create();
355                 _CHECK_IO(_funcproto(o)->Load(v, up, read));
356                 _functions.push_back(o);
357         }
358         _CHECK_IO(SafeRead(v,read,up, &_stacksize, sizeof(_stacksize)));
359         _CHECK_IO(SafeRead(v,read,up, &_bgenerator, sizeof(_bgenerator)));
360         _CHECK_IO(SafeRead(v,read,up, &_varparams, sizeof(_varparams)));
361         return true;
362 }
363
364 #ifndef NO_GARBAGE_COLLECTOR
365
366 #define START_MARK()    if(!(_uiRef&MARK_FLAG)){ \
367                 _uiRef|=MARK_FLAG;
368
369 #define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \
370                 AddToChain(chain, this); }
371
372 void SQVM::Mark(SQCollectable **chain)
373 {
374         START_MARK()
375                 SQSharedState::MarkObject(_lasterror,chain);
376                 SQSharedState::MarkObject(_errorhandler,chain);
377                 SQSharedState::MarkObject(_debughook,chain);
378                 SQSharedState::MarkObject(_roottable, chain);
379                 SQSharedState::MarkObject(temp_reg, chain);
380                 for(unsigned int i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);
381                 for(unsigned int j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain);
382         END_MARK()
383 }
384
385 void SQArray::Mark(SQCollectable **chain)
386 {
387         START_MARK()
388                 int len = _values.size();
389                 for(int i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain);
390         END_MARK()
391 }
392 void SQTable::Mark(SQCollectable **chain)
393 {
394         START_MARK()
395                 if(_delegate) _delegate->Mark(chain);
396                 int len = _numofnodes;
397                 for(int i = 0; i < len; i++){
398                         SQSharedState::MarkObject(_nodes[i].key, chain);
399                         SQSharedState::MarkObject(_nodes[i].val, chain);
400                 }
401         END_MARK()
402 }
403
404 void SQClass::Mark(SQCollectable **chain)
405 {
406         START_MARK()
407                 _members->Mark(chain);
408                 if(_base) _base->Mark(chain);
409                 SQSharedState::MarkObject(_attributes, chain);
410                 for(unsigned int i =0; i< _defaultvalues.size(); i++) {
411                         SQSharedState::MarkObject(_defaultvalues[i].val, chain);
412                         SQSharedState::MarkObject(_defaultvalues[i].attrs, chain);
413                 }
414                 for(unsigned int j =0; j< _methods.size(); j++) {
415                         SQSharedState::MarkObject(_methods[j].val, chain);
416                         SQSharedState::MarkObject(_methods[j].attrs, chain);
417                 }
418                 for(unsigned int k =0; k< _metamethods.size(); k++) {
419                         SQSharedState::MarkObject(_metamethods[k], chain);
420                 }
421         END_MARK()
422 }
423
424 void SQInstance::Mark(SQCollectable **chain)
425 {
426         START_MARK()
427                 _class->Mark(chain);
428                 for(unsigned int i =0; i< _values.size(); i++) {
429                         SQSharedState::MarkObject(_values[i], chain);
430                 }
431         END_MARK()
432 }
433
434 void SQGenerator::Mark(SQCollectable **chain)
435 {
436         START_MARK()
437                 for(unsigned int i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);
438                 for(unsigned int j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain);
439                 SQSharedState::MarkObject(_closure, chain);
440         END_MARK()
441 }
442
443 void SQClosure::Mark(SQCollectable **chain)
444 {
445         START_MARK()
446                 for(unsigned int i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain);
447         END_MARK()
448 }
449
450 void SQNativeClosure::Mark(SQCollectable **chain)
451 {
452         START_MARK()
453                 for(unsigned int i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain);
454         END_MARK()
455 }
456
457 void SQUserData::Mark(SQCollectable **chain){
458         START_MARK()
459                 if(_delegate) _delegate->Mark(chain);
460         END_MARK()
461 }
462
463 void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; }
464
465 #endif
466