restore trunk
[supertux.git] / src / squirrel / squirrel / sqcompiler.cpp
1 /*
2         see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include <stdarg.h>
6 #include <setjmp.h>
7 #include "sqopcodes.h"
8 #include "sqstring.h"
9 #include "sqfuncproto.h"
10 #include "sqcompiler.h"
11 #include "sqfuncstate.h"
12 #include "sqlexer.h"
13 #include "sqvm.h"
14
15 #define DEREF_NO_DEREF  -1
16 #define DEREF_FIELD             -2
17
18 struct ExpState
19 {
20         ExpState()
21         {
22                 _deref = DEREF_NO_DEREF;
23                 _freevar = false;
24                 _class_or_delete = false;
25                 _funcarg = false;
26         }
27         bool _class_or_delete;
28         bool _funcarg;
29         bool _freevar;
30         SQInteger _deref;
31 };
32
33 typedef sqvector<ExpState> ExpStateVec;
34
35 #define _exst (_expstates.top())
36
37 #define BEGIN_BREAKBLE_BLOCK()  SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
38                                                         SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
39                                                         _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
40
41 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
42                                         __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
43                                         if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
44                                         if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
45                                         _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
46
47 class SQCompiler
48 {
49 public:
50         SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
51         {
52                 _vm=v;
53                 _lex.Init(_ss(v), rg, up,ThrowError,this);
54                 _sourcename = SQString::Create(_ss(v), sourcename);
55                 _lineinfo = lineinfo;_raiseerror = raiseerror;
56                 compilererror = NULL;
57         }
58         static void ThrowError(void *ud, const SQChar *s) {
59                 SQCompiler *c = (SQCompiler *)ud;
60                 c->Error(s);
61         }
62         void Error(const SQChar *s, ...)
63         {
64                 static SQChar temp[256];
65                 va_list vl;
66                 va_start(vl, s);
67                 scvsprintf(temp, s, vl);
68                 va_end(vl);
69                 compilererror = temp;
70                 longjmp(_errorjmp,1);
71         }
72         void Lex(){     _token = _lex.Lex();}
73         void PushExpState(){ _expstates.push_back(ExpState()); }
74         bool IsDerefToken(SQInteger tok)
75         {
76                 switch(tok){
77                 case _SC('='): case _SC('('): case TK_NEWSLOT:
78                 case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true;
79                 }
80                 return false;
81         }
82         ExpState PopExpState()
83         {
84                 ExpState ret = _expstates.top();
85                 _expstates.pop_back();
86                 return ret;
87         }
88         SQObject Expect(SQInteger tok)
89         {
90                 
91                 if(_token != tok) {
92                         if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
93                                 //ret = SQString::Create(_ss(_vm),_SC("constructor"));
94                                 //do nothing
95                         }
96                         else {
97                                 const SQChar *etypename;
98                                 if(tok > 255) {
99                                         switch(tok)
100                                         {
101                                         case TK_IDENTIFIER:
102                                                 etypename = _SC("IDENTIFIER");
103                                                 break;
104                                         case TK_STRING_LITERAL:
105                                                 etypename = _SC("STRING_LITERAL");
106                                                 break;
107                                         case TK_INTEGER:
108                                                 etypename = _SC("INTEGER");
109                                                 break;
110                                         case TK_FLOAT:
111                                                 etypename = _SC("FLOAT");
112                                                 break;
113                                         default:
114                                                 etypename = _lex.Tok2Str(tok);
115                                         }
116                                         Error(_SC("expected '%s'"), etypename);
117                                 }
118                                 Error(_SC("expected '%c'"), tok);
119                         }
120                 }
121                 SQObjectPtr ret;
122                 switch(tok)
123                 {
124                 case TK_IDENTIFIER:
125                         ret = _fs->CreateString(_lex._svalue);
126                         break;
127                 case TK_STRING_LITERAL:
128                         ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
129                         break;
130                 case TK_INTEGER:
131                         ret = SQObjectPtr(_lex._nvalue);
132                         break;
133                 case TK_FLOAT:
134                         ret = SQObjectPtr(_lex._fvalue);
135                         break;
136                 }
137                 Lex();
138                 return ret;
139         }
140         bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
141         void OptionalSemicolon()
142         {
143                 if(_token == _SC(';')) { Lex(); return; }
144                 if(!IsEndOfStatement()) {
145                         Error(_SC("end of statement expected (; or lf)"));
146                 }
147         }
148         void MoveIfCurrentTargetIsLocal() {
149                 SQInteger trg = _fs->TopTarget();
150                 if(_fs->IsLocal(trg)) {
151                         trg = _fs->PopTarget(); //no pops the target and move it
152                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
153                 }
154         }
155         bool Compile(SQObjectPtr &o)
156         {
157                 _debugline = 1;
158                 _debugop = 0;
159
160                 SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
161                 funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
162                 _fs = &funcstate;
163                 _fs->AddParameter(_fs->CreateString(_SC("this")));
164                 _fs->_sourcename = _sourcename;
165                 SQInteger stacksize = _fs->GetStackSize();
166                 if(setjmp(_errorjmp) == 0) {
167                         Lex();
168                         while(_token > 0){
169                                 Statement();
170                                 if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
171                         }
172                         CleanStack(stacksize);
173                         _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
174                         _fs->AddInstruction(_OP_RETURN, 0xFF);
175                         _fs->SetStackSize(0);
176                         o =_fs->BuildProto();
177 #ifdef _DEBUG_DUMP
178                         _fs->Dump(_funcproto(o));
179 #endif
180                 }
181                 else {
182                         if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
183                                 _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
184                                         _lex._currentline, _lex._currentcolumn);
185                         }
186                         _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
187                         return false;
188                 }
189                 return true;
190         }
191         void Statements()
192         {
193                 while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
194                         Statement();
195                         if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
196                 }
197         }
198         void Statement()
199         {
200                 _fs->AddLineInfos(_lex._currentline, _lineinfo);
201                 switch(_token){
202                 case _SC(';'):  Lex();                                  break;
203                 case TK_IF:             IfStatement();                  break;
204                 case TK_WHILE:          WhileStatement();               break;
205                 case TK_DO:             DoWhileStatement();             break;
206                 case TK_FOR:            ForStatement();                 break;
207                 case TK_FOREACH:        ForEachStatement();             break;
208                 case TK_SWITCH: SwitchStatement();              break;
209                 case TK_LOCAL:          LocalDeclStatement();   break;
210                 case TK_RETURN:
211                 case TK_YIELD: {
212                         SQOpcode op;
213                         if(_token == TK_RETURN) {
214                                 op = _OP_RETURN;
215                                 
216                         }
217                         else {
218                                 op = _OP_YIELD;
219                                 _fs->_bgenerator = true;
220                         }
221                         Lex();
222                         if(!IsEndOfStatement()) {
223                                 SQInteger retexp = _fs->GetCurrentPos()+1;
224                                 CommaExpr();
225                                 if(op == _OP_RETURN && _fs->_traps > 0)
226                                         _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
227                                 _fs->_returnexp = retexp;
228                                 _fs->AddInstruction(op, 1, _fs->PopTarget());
229                         }
230                         else{ 
231                                 if(op == _OP_RETURN && _fs->_traps > 0)
232                                         _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
233                                 _fs->_returnexp = -1;
234                                 _fs->AddInstruction(op, 0xFF); 
235                         }
236                         break;}
237                 case TK_BREAK:
238                         if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
239                         if(_fs->_breaktargets.top() > 0){
240                                 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
241                         }
242                         _fs->AddInstruction(_OP_JMP, 0, -1234);
243                         _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
244                         Lex();
245                         break;
246                 case TK_CONTINUE:
247                         if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
248                         if(_fs->_continuetargets.top() > 0) {
249                                 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
250                         }
251                         _fs->AddInstruction(_OP_JMP, 0, -1234);
252                         _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
253                         Lex();
254                         break;
255                 case TK_FUNCTION:
256                         FunctionStatement();
257                         break;
258                 case TK_CLASS:
259                         ClassStatement();
260                         break;
261                 case _SC('{'):{
262                                 SQInteger stacksize = _fs->GetStackSize();
263                                 Lex();
264                                 Statements();
265                                 Expect(_SC('}'));
266                                 _fs->SetStackSize(stacksize);
267                         }
268                         break;
269                 case TK_TRY:
270                         TryCatchStatement();
271                         break;
272                 case TK_THROW:
273                         Lex();
274                         CommaExpr();
275                         _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
276                         break;
277                 default:
278                         CommaExpr();
279                         _fs->PopTarget();
280                         break;
281                 }
282                 _fs->SnoozeOpt();
283         }
284         void EmitDerefOp(SQOpcode op)
285         {
286                 SQInteger val = _fs->PopTarget();
287                 SQInteger key = _fs->PopTarget();
288                 SQInteger src = _fs->PopTarget();
289         _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
290         }
291         void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
292         {
293                 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
294                 SQInteger p1 = _fs->PopTarget(); //key in OP_GET
295                 _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
296         }
297         void EmitCompoundArith(SQInteger tok,bool deref)
298         {
299                 SQInteger oper;
300                 switch(tok){
301                 case TK_MINUSEQ: oper = '-'; break;
302                 case TK_PLUSEQ: oper = '+'; break;
303                 case TK_MULEQ: oper = '*'; break;
304                 case TK_DIVEQ: oper = '/'; break;
305                 case TK_MODEQ: oper = '%'; break;
306                 default: oper = 0; //shut up compiler
307                         assert(0); break;
308                 };
309                 if(deref) {
310                         SQInteger val = _fs->PopTarget();
311                         SQInteger key = _fs->PopTarget();
312                         SQInteger src = _fs->PopTarget();
313                         //mixes dest obj and source val in the arg1(hack?)
314                         _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper);
315                 }
316                 else {
317                         Emit2ArgsOP(_OP_COMPARITHL, oper);
318                 }
319         }
320         void CommaExpr()
321         {
322                 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
323         }
324         ExpState Expression(bool funcarg = false)
325         {
326                 PushExpState();
327                 _exst._class_or_delete = false;
328                 _exst._funcarg = funcarg;
329                 LogicalOrExp();
330                 switch(_token)  {
331                 case _SC('='):
332                 case TK_NEWSLOT:
333                 case TK_MINUSEQ:
334                 case TK_PLUSEQ:
335                 case TK_MULEQ:
336                 case TK_DIVEQ:
337                 case TK_MODEQ:
338                 {
339                                 SQInteger op = _token;
340                                 SQInteger ds = _exst._deref;
341                                 bool freevar = _exst._freevar;
342                                 if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression"));
343                                 Lex(); Expression();
344
345                                 switch(op){
346                                 case TK_NEWSLOT:
347                                         if(freevar) Error(_SC("free variables cannot be modified"));
348                                         if(ds == DEREF_FIELD)
349                                                 EmitDerefOp(_OP_NEWSLOT);
350                                         else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
351                                                 Error(_SC("can't 'create' a local slot"));
352                                         break;
353                                 case _SC('='): //ASSIGN
354                                         if(freevar) Error(_SC("free variables cannot be modified"));
355                                         if(ds == DEREF_FIELD)
356                                                 EmitDerefOp(_OP_SET);
357                                         else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
358                                                 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
359                                                 SQInteger p1 = _fs->TopTarget(); //key in OP_GET
360                                                 _fs->AddInstruction(_OP_MOVE, p1, p2);
361                                         }
362                                         break;
363                                 case TK_MINUSEQ:
364                                 case TK_PLUSEQ:
365                                 case TK_MULEQ:
366                                 case TK_DIVEQ:
367                                 case TK_MODEQ:
368                                         EmitCompoundArith(op,ds == DEREF_FIELD);
369                                         break;
370                                 }
371                         }
372                         break;
373                 case _SC('?'): {
374                         Lex();
375                         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
376                         SQInteger jzpos = _fs->GetCurrentPos();
377                         SQInteger trg = _fs->PushTarget();
378                         Expression();
379                         SQInteger first_exp = _fs->PopTarget();
380                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
381                         SQInteger endfirstexp = _fs->GetCurrentPos();
382                         _fs->AddInstruction(_OP_JMP, 0, 0);
383                         Expect(_SC(':'));
384                         SQInteger jmppos = _fs->GetCurrentPos();
385                         Expression();
386                         SQInteger second_exp = _fs->PopTarget();
387                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
388                         _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
389                         _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
390                         _fs->SnoozeOpt();
391                         }
392                         break;
393                 }
394                 return PopExpState();
395         }
396         void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0)
397         {
398                 Lex(); (this->*f)();
399                 SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
400                 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
401         }
402         void LogicalOrExp()
403         {
404                 LogicalAndExp();
405                 for(;;) if(_token == TK_OR) {
406                         SQInteger first_exp = _fs->PopTarget();
407                         SQInteger trg = _fs->PushTarget();
408                         _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
409                         SQInteger jpos = _fs->GetCurrentPos();
410                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
411                         Lex(); LogicalOrExp();
412                         _fs->SnoozeOpt();
413                         SQInteger second_exp = _fs->PopTarget();
414                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
415                         _fs->SnoozeOpt();
416                         _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
417                         break;
418                 }else return;
419         }
420         void LogicalAndExp()
421         {
422                 BitwiseOrExp();
423                 for(;;) switch(_token) {
424                 case TK_AND: {
425                         SQInteger first_exp = _fs->PopTarget();
426                         SQInteger trg = _fs->PushTarget();
427                         _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
428                         SQInteger jpos = _fs->GetCurrentPos();
429                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
430                         Lex(); LogicalAndExp();
431                         _fs->SnoozeOpt();
432                         SQInteger second_exp = _fs->PopTarget();
433                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
434                         _fs->SnoozeOpt();
435                         _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
436                         break;
437                         }
438                 case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break;
439                 case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break;
440                 default:
441                         return;
442                 }
443         }
444         void BitwiseOrExp()
445         {
446                 BitwiseXorExp();
447                 for(;;) if(_token == _SC('|'))
448                 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
449                 }else return;
450         }
451         void BitwiseXorExp()
452         {
453                 BitwiseAndExp();
454                 for(;;) if(_token == _SC('^'))
455                 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
456                 }else return;
457         }
458         void BitwiseAndExp()
459         {
460                 CompExp();
461                 for(;;) if(_token == _SC('&'))
462                 {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);
463                 }else return;
464         }
465         void CompExp()
466         {
467                 ShiftExp();
468                 for(;;) switch(_token) {
469                 case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break;
470                 case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
471                 case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
472                 case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
473                 case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
474                 case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;
475                 default: return;        
476                 }
477         }
478         void ShiftExp()
479         {
480                 PlusExp();
481                 for(;;) switch(_token) {
482                 case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
483                 case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
484                 case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
485                 default: return;        
486                 }
487         }
488         void PlusExp()
489         {
490                 MultExp();
491                 for(;;) switch(_token) {
492                 case _SC('+'): case _SC('-'):
493                         BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break;
494                 default: return;
495                 }
496         }
497         
498         void MultExp()
499         {
500                 PrefixedExpr();
501                 for(;;) switch(_token) {
502                 case _SC('*'): case _SC('/'): case _SC('%'):
503                         BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break;
504                 default: return;
505                 }
506         }
507         //if 'pos' != -1 the previous variable is a local variable
508         void PrefixedExpr()
509         {
510                 SQInteger pos = Factor();
511                 for(;;) {
512                         switch(_token) {
513                         case _SC('.'): {
514                                 pos = -1;
515                                 Lex(); 
516                                 if(_token == TK_PARENT) {
517                                         Lex();
518                                         if(!NeedGet())
519                                                 Error(_SC("parent cannot be set"));
520                                         SQInteger src = _fs->PopTarget();
521                                         _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);
522                                 }
523                                 else {
524                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
525                                         if(NeedGet()) Emit2ArgsOP(_OP_GET);
526                                 }
527                                 _exst._deref = DEREF_FIELD;
528                                 _exst._freevar = false;
529                                 }
530                                 break;
531                         case _SC('['):
532                                 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
533                                 Lex(); Expression(); Expect(_SC(']')); 
534                                 pos = -1;
535                                 if(NeedGet()) Emit2ArgsOP(_OP_GET);
536                                 _exst._deref = DEREF_FIELD;
537                                 _exst._freevar = false;
538                                 break;
539                         case TK_MINUSMINUS:
540                         case TK_PLUSPLUS:
541                         if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { 
542                                 SQInteger tok = _token; Lex();
543                                 if(pos < 0)
544                                         Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);
545                                 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
546                                         SQInteger src = _fs->PopTarget();
547                                         _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);
548                                 }
549                                 
550                         }
551                         return;
552                         break;  
553                         case _SC('('): 
554                                 {
555                                 if(_exst._deref != DEREF_NO_DEREF) {
556                                         if(pos<0) {
557                                                 SQInteger key = _fs->PopTarget(); //key
558                                                 SQInteger table = _fs->PopTarget(); //table etc...
559                                                 SQInteger closure = _fs->PushTarget();
560                                                 SQInteger ttarget = _fs->PushTarget();
561                                                 _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
562                                         }
563                                         else{
564                                                 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
565                                         }
566                                 }
567                                 else
568                                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
569                                 _exst._deref = DEREF_NO_DEREF;
570                                 Lex();
571                                 FunctionCallArgs();
572                                  }
573                                 break;
574                         default: return;
575                         }
576                 }
577         }
578         SQInteger Factor()
579         {
580                 switch(_token)
581                 {
582                 case TK_STRING_LITERAL: {
583                                 //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));
584                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
585                                 Lex(); 
586                         }
587                         break;
588                 case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;
589                 case TK_VARGV: { Lex();
590                         Expect(_SC('['));
591                         Expression();
592                         Expect(_SC(']'));
593                         SQInteger src = _fs->PopTarget();
594                         _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src);
595                                            }
596                         break;
597                 case TK_IDENTIFIER:
598                 case TK_CONSTRUCTOR:
599                 case TK_THIS:{
600                         _exst._freevar = false;
601                         SQObject id;
602                                 switch(_token) {
603                                         case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
604                                         case TK_THIS: id = _fs->CreateString(_SC("this")); break;
605                                         case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
606                                 }
607                                 SQInteger pos = -1;
608                                 Lex();
609                                 if((pos = _fs->GetLocalVariable(id)) == -1) {
610                                         //checks if is a free variable
611                                         if((pos = _fs->GetOuterVariable(id)) != -1) {
612                                                 _exst._deref = _fs->PushTarget();
613                                                 _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);        
614                                                 _exst._freevar = true;
615                                         } else {
616                                                 _fs->PushTarget(0);
617                                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
618                                                 if(NeedGet()) Emit2ArgsOP(_OP_GET);
619                                                 _exst._deref = DEREF_FIELD;
620                                         }
621                                 }
622                                 else{
623                                         _fs->PushTarget(pos);
624                                         _exst._deref = pos;
625                                 }
626                                 return _exst._deref;
627                         }
628                         break;
629                 case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break;
630                 case TK_DOUBLE_COLON:  // "::"
631                         _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget());
632                         _exst._deref = DEREF_FIELD;
633                         _token = _SC('.'); //hack
634                         return -1;
635                         break;
636                 case TK_NULL: 
637                         _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
638                         Lex();
639                         break;
640                 case TK_INTEGER: {
641                         if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?
642                                 _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);
643                         }
644                         else {
645                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));
646                         }
647                         Lex();
648                                                  }
649                         break;
650                 case TK_FLOAT:
651                         if(sizeof(SQFloat) == sizeof(SQInt32)) {
652                                 _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue));
653                         }
654                         else {
655                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));
656                         }
657                         Lex();
658                         break;
659                 case TK_TRUE: case TK_FALSE:
660                         _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
661                         Lex();
662                         break;
663                 case _SC('['): {
664                                 _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget());
665                                 SQInteger apos = _fs->GetCurrentPos(),key = 0;
666                                 Lex();
667                                 while(_token != _SC(']')) {
668                     Expression(); 
669                                         if(_token == _SC(',')) Lex();
670                                         SQInteger val = _fs->PopTarget();
671                                         SQInteger array = _fs->TopTarget();
672                                         _fs->AddInstruction(_OP_APPENDARRAY, array, val);
673                                         key++;
674                                 }
675                                 _fs->SetIntructionParam(apos, 1, key);
676                                 Lex();
677                         }
678                         break;
679                 case _SC('{'):{
680                         _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
681                         Lex();ParseTableOrClass(_SC(','));
682                                  }
683                         break;
684                 case TK_FUNCTION: FunctionExp(_token);break;
685                 case TK_CLASS: Lex(); ClassExp();break;
686                 case _SC('-'): UnaryOP(_OP_NEG); break;
687                 case _SC('!'): UnaryOP(_OP_NOT); break;
688                 case _SC('~'): UnaryOP(_OP_BWNOT); break;
689                 case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;
690                 case TK_RESUME : UnaryOP(_OP_RESUME); break;
691                 case TK_CLONE : UnaryOP(_OP_CLONE); break;
692                 case TK_MINUSMINUS : 
693                 case TK_PLUSPLUS :PrefixIncDec(_token); break;
694                 case TK_DELETE : DeleteExpr(); break;
695                 case TK_DELEGATE : DelegateExpr(); break;
696                 case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
697                         break;
698                 default: Error(_SC("expression expected"));
699                 }
700                 return -1;
701         }
702         void UnaryOP(SQOpcode op)
703         {
704                 Lex(); PrefixedExpr();
705                 SQInteger src = _fs->PopTarget();
706                 _fs->AddInstruction(op, _fs->PushTarget(), src);
707         }
708         bool NeedGet()
709         {
710                 switch(_token) {
711                 case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS:
712                 case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:
713                         return false;
714                 }
715                 return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));
716         }
717         
718         void FunctionCallArgs()
719         {
720                 SQInteger nargs = 1;//this
721                  while(_token != _SC(')')) {
722                          Expression(true);
723                          MoveIfCurrentTargetIsLocal();
724                          nargs++; 
725                          if(_token == _SC(',')){ 
726                                  Lex(); 
727                                  if(_token == ')') Error(_SC("expression expected, found ')'"));
728                          }
729                  }
730                  Lex();
731                  for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
732                  SQInteger stackbase = _fs->PopTarget();
733                  SQInteger closure = _fs->PopTarget();
734          _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
735         }
736         void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')
737         {
738                 SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
739                 
740                 while(_token != terminator) {
741                         bool hasattrs = false;
742                         bool isstatic = false;
743                         //check if is an attribute
744                         if(separator == ';') {
745                                 if(_token == TK_ATTR_OPEN) {
746                                         _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();
747                                         ParseTableOrClass(',',TK_ATTR_CLOSE);
748                                         hasattrs = true;
749                                 }
750                                 if(_token == TK_STATIC) {
751                                         isstatic = true;
752                                         Lex();
753                                 }
754                         }
755                         switch(_token) {
756                                 case TK_FUNCTION:
757                                 case TK_CONSTRUCTOR:{
758                                         SQInteger tk = _token;
759                                         Lex();
760                                         SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
761                                         Expect(_SC('('));
762                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
763                                         CreateFunction(id);
764                                         _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
765                                                                   }
766                                                                   break;
767                                 case _SC('['):
768                                         Lex(); CommaExpr(); Expect(_SC(']'));
769                                         Expect(_SC('=')); Expression();
770                                         break;
771                                 default :
772                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
773                                         Expect(_SC('=')); Expression();
774                         }
775
776                         if(_token == separator) Lex();//optional comma/semicolon
777                         nkeys++;
778                         SQInteger val = _fs->PopTarget();
779                         SQInteger key = _fs->PopTarget();
780                         SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
781                         assert(hasattrs && attrs == key-1 || !hasattrs);
782                         unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
783                         SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
784                         _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
785                         //_fs->PopTarget();
786                 }
787                 if(separator == _SC(',')) //hack recognizes a table from the separator
788                         _fs->SetIntructionParam(tpos, 1, nkeys);
789                 Lex();
790         }
791         void LocalDeclStatement()
792         {
793                 SQObject varname;
794                 do {
795                         Lex(); varname = Expect(TK_IDENTIFIER);
796                         if(_token == _SC('=')) {
797                                 Lex(); Expression();
798                                 SQInteger src = _fs->PopTarget();
799                                 SQInteger dest = _fs->PushTarget();
800                                 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
801                         }
802                         else{
803                                 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
804                         }
805                         _fs->PopTarget();
806                         _fs->PushLocalVariable(varname);
807                 
808                 } while(_token == _SC(','));
809         }
810         void IfStatement()
811         {
812                 SQInteger jmppos;
813                 bool haselse = false;
814                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
815                 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
816                 SQInteger jnepos = _fs->GetCurrentPos();
817                 SQInteger stacksize = _fs->GetStackSize();
818                 
819                 Statement();
820                 //
821                 if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
822                 
823                 CleanStack(stacksize);
824                 SQInteger endifblock = _fs->GetCurrentPos();
825                 if(_token == TK_ELSE){
826                         haselse = true;
827                         stacksize = _fs->GetStackSize();
828                         _fs->AddInstruction(_OP_JMP);
829                         jmppos = _fs->GetCurrentPos();
830                         Lex();
831                         Statement(); OptionalSemicolon();
832                         CleanStack(stacksize);
833                         _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
834                 }
835                 _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
836         }
837         void WhileStatement()
838         {
839                 SQInteger jzpos, jmppos;
840                 SQInteger stacksize = _fs->GetStackSize();
841                 jmppos = _fs->GetCurrentPos();
842                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
843                 
844                 BEGIN_BREAKBLE_BLOCK();
845                 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
846                 jzpos = _fs->GetCurrentPos();
847                 stacksize = _fs->GetStackSize();
848                 
849                 Statement();
850                 
851                 CleanStack(stacksize);
852                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
853                 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
854                 
855                 END_BREAKBLE_BLOCK(jmppos);
856         }
857         void DoWhileStatement()
858         {
859                 Lex();
860                 SQInteger jzpos = _fs->GetCurrentPos();
861                 SQInteger stacksize = _fs->GetStackSize();
862                 BEGIN_BREAKBLE_BLOCK()
863                 Statement();
864                 CleanStack(stacksize);
865                 Expect(TK_WHILE);
866                 SQInteger continuetrg = _fs->GetCurrentPos();
867                 Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
868                 _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1);
869                 END_BREAKBLE_BLOCK(continuetrg);
870         }
871         void ForStatement()
872         {
873                 Lex();
874                 SQInteger stacksize = _fs->GetStackSize();
875                 Expect(_SC('('));
876                 if(_token == TK_LOCAL) LocalDeclStatement();
877                 else if(_token != _SC(';')){
878                         CommaExpr();
879                         _fs->PopTarget();
880                 }
881                 Expect(_SC(';'));
882                 _fs->SnoozeOpt();
883                 SQInteger jmppos = _fs->GetCurrentPos();
884                 SQInteger jzpos = -1;
885                 if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
886                 Expect(_SC(';'));
887                 _fs->SnoozeOpt();
888                 SQInteger expstart = _fs->GetCurrentPos() + 1;
889                 if(_token != _SC(')')) {
890                         CommaExpr();
891                         _fs->PopTarget();
892                 }
893                 Expect(_SC(')'));
894                 _fs->SnoozeOpt();
895                 SQInteger expend = _fs->GetCurrentPos();
896                 SQInteger expsize = (expend - expstart) + 1;
897                 SQInstructionVec exp;
898                 if(expsize > 0) {
899                         for(SQInteger i = 0; i < expsize; i++)
900                                 exp.push_back(_fs->GetInstruction(expstart + i));
901                         _fs->PopInstructions(expsize);
902                 }
903                 BEGIN_BREAKBLE_BLOCK()
904                 Statement();
905                 SQInteger continuetrg = _fs->GetCurrentPos();
906                 if(expsize > 0) {
907                         for(SQInteger i = 0; i < expsize; i++)
908                                 _fs->AddInstruction(exp[i]);
909                 }
910                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
911                 if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
912                 CleanStack(stacksize);
913                 
914                 END_BREAKBLE_BLOCK(continuetrg);
915         }
916         void ForEachStatement()
917         {
918                 SQObject idxname, valname;
919                 Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
920                 if(_token == _SC(',')) {
921                         idxname = valname;
922                         Lex(); valname = Expect(TK_IDENTIFIER);
923                 }
924                 else{
925                         idxname = _fs->CreateString(_SC("@INDEX@"));
926                 }
927                 Expect(TK_IN);
928                 
929                 //save the stack size
930                 SQInteger stacksize = _fs->GetStackSize();
931                 //put the table in the stack(evaluate the table expression)
932                 Expression(); Expect(_SC(')'));
933                 SQInteger container = _fs->TopTarget();
934                 //push the index local var
935                 SQInteger indexpos = _fs->PushLocalVariable(idxname);
936                 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
937                 //push the value local var
938                 SQInteger valuepos = _fs->PushLocalVariable(valname);
939                 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
940                 //push reference index
941                 SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
942                 _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
943                 SQInteger jmppos = _fs->GetCurrentPos();
944                 _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
945                 SQInteger foreachpos = _fs->GetCurrentPos();
946                 _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
947                 //generate the statement code
948                 BEGIN_BREAKBLE_BLOCK()
949                 Statement();
950                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
951                 _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
952                 _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
953                 //restore the local variable stack(remove index,val and ref idx)
954                 CleanStack(stacksize);
955                 END_BREAKBLE_BLOCK(foreachpos - 1);
956         }
957         void SwitchStatement()
958         {
959                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
960                 Expect(_SC('{'));
961                 SQInteger expr = _fs->TopTarget();
962                 bool bfirst = true;
963                 SQInteger tonextcondjmp = -1;
964                 SQInteger skipcondjmp = -1;
965                 SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
966                 _fs->_breaktargets.push_back(0);
967                 while(_token == TK_CASE) {
968                         //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one
969                         if(!bfirst) {
970                                 _fs->AddInstruction(_OP_JMP, 0, 0);
971                                 skipcondjmp = _fs->GetCurrentPos();
972                                 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
973                         }
974                         //condition
975                         Lex(); Expression(); Expect(_SC(':'));
976                         SQInteger trg = _fs->PopTarget();
977                         _fs->AddInstruction(_OP_EQ, trg, trg, expr);
978                         _fs->AddInstruction(_OP_JZ, trg, 0);
979                         //end condition
980                         if(skipcondjmp != -1) {
981                                 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
982                         }
983                         tonextcondjmp = _fs->GetCurrentPos();
984                         SQInteger stacksize = _fs->GetStackSize();
985                         Statements();
986                         _fs->SetStackSize(stacksize);
987                         bfirst = false;
988                 }
989                 if(tonextcondjmp != -1)
990                         _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
991                 if(_token == TK_DEFAULT) {
992                 //      _fs->AddLineInfos(_lex._currentline, _lineinfo);
993                         Lex(); Expect(_SC(':'));
994                         SQInteger stacksize = _fs->GetStackSize();
995                         Statements();
996                         _fs->SetStackSize(stacksize);
997                 }
998                 Expect(_SC('}'));
999                 _fs->PopTarget();
1000                 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1001                 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
1002                 _fs->_breaktargets.pop_back();
1003                 
1004         }
1005         void FunctionStatement()
1006         {
1007                 SQObject id;
1008                 Lex(); id = Expect(TK_IDENTIFIER);
1009                 _fs->PushTarget(0);
1010                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1011                 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1012                 
1013                 while(_token == TK_DOUBLE_COLON) {
1014                         Lex();
1015                         id = Expect(TK_IDENTIFIER);
1016                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1017                         if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1018                 }
1019                 Expect(_SC('('));
1020                 CreateFunction(id);
1021                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1022                 EmitDerefOp(_OP_NEWSLOT);
1023                 _fs->PopTarget();
1024         }
1025         void ClassStatement()
1026         {
1027                 ExpState es;
1028                 Lex(); PushExpState();
1029                 _exst._class_or_delete = true;
1030                 _exst._funcarg = false;
1031                 PrefixedExpr();
1032                 es = PopExpState();
1033                 if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));
1034                 if(es._deref == DEREF_FIELD) {
1035                         ClassExp();
1036                         EmitDerefOp(_OP_NEWSLOT);
1037                         _fs->PopTarget();
1038                 }
1039                 else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
1040         }
1041         void TryCatchStatement()
1042         {
1043                 SQObject exid;
1044                 Lex();
1045                 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
1046                 _fs->_traps++;
1047                 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
1048                 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
1049                 SQInteger trappos = _fs->GetCurrentPos();
1050                 Statement();
1051                 _fs->_traps--;
1052                 _fs->AddInstruction(_OP_POPTRAP, 1, 0);
1053                 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
1054                 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
1055                 _fs->AddInstruction(_OP_JMP, 0, 0);
1056                 SQInteger jmppos = _fs->GetCurrentPos();
1057                 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
1058                 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
1059                 SQInteger stacksize = _fs->GetStackSize();
1060                 SQInteger ex_target = _fs->PushLocalVariable(exid);
1061                 _fs->SetIntructionParam(trappos, 0, ex_target);
1062                 Statement();
1063                 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1064                 CleanStack(stacksize);
1065         }
1066         void FunctionExp(SQInteger ftype)
1067         {
1068                 Lex(); Expect(_SC('('));
1069                 CreateFunction(_null_);
1070                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
1071         }
1072         void ClassExp()
1073         {
1074                 SQInteger base = -1;
1075                 SQInteger attrs = -1;
1076                 if(_token == TK_EXTENDS) {
1077                         Lex(); Expression();
1078                         base = _fs->TopTarget();
1079                 }
1080                 if(_token == TK_ATTR_OPEN) {
1081                         Lex();
1082                         _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
1083                         ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
1084                         attrs = _fs->TopTarget();
1085                 }
1086                 Expect(_SC('{'));
1087                 if(attrs != -1) _fs->PopTarget();
1088                 if(base != -1) _fs->PopTarget();
1089                 _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);
1090                 ParseTableOrClass(_SC(';'));
1091         }
1092         void DelegateExpr()
1093         {
1094                 Lex(); CommaExpr();
1095                 Expect(_SC(':'));
1096                 CommaExpr();
1097                 SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();
1098                 _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);
1099         }
1100         void DeleteExpr()
1101         {
1102                 ExpState es;
1103                 Lex(); PushExpState();
1104                 _exst._class_or_delete = true;
1105                 _exst._funcarg = false;
1106                 PrefixedExpr();
1107                 es = PopExpState();
1108                 if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));
1109                 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
1110                 else Error(_SC("cannot delete a local"));
1111         }
1112         void PrefixIncDec(SQInteger token)
1113         {
1114                 ExpState es;
1115                 Lex(); PushExpState();
1116                 _exst._class_or_delete = true;
1117                 _exst._funcarg = false;
1118                 PrefixedExpr();
1119                 es = PopExpState();
1120                 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);
1121                 else {
1122                         SQInteger src = _fs->PopTarget();
1123                         _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);
1124                 }
1125         }
1126         void CreateFunction(SQObject &name)
1127         {
1128                 
1129                 SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
1130                 funcstate->_name = name;
1131                 SQObject paramname;
1132                 funcstate->AddParameter(_fs->CreateString(_SC("this")));
1133                 funcstate->_sourcename = _sourcename;
1134                 while(_token!=_SC(')')) {
1135                         if(_token == TK_VARPARAMS) {
1136                                 funcstate->_varparams = true;
1137                                 Lex();
1138                                 if(_token != _SC(')')) Error(_SC("expected ')'"));
1139                                 break;
1140                         }
1141                         else {
1142                                 paramname = Expect(TK_IDENTIFIER);
1143                                 funcstate->AddParameter(paramname);
1144                                 if(_token == _SC(',')) Lex();
1145                                 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1146                         }
1147                 }
1148                 Expect(_SC(')'));
1149                 //outer values
1150                 if(_token == _SC(':')) {
1151                         Lex(); Expect(_SC('('));
1152                         while(_token != _SC(')')) {
1153                                 paramname = Expect(TK_IDENTIFIER);
1154                                 //outers are treated as implicit local variables
1155                                 funcstate->AddOuterValue(paramname);
1156                                 if(_token == _SC(',')) Lex();
1157                                 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1158                         }
1159                         Lex();
1160                 }
1161                 
1162                 SQFuncState *currchunk = _fs;
1163                 _fs = funcstate;
1164                 Statement();
1165                 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
1166         funcstate->AddInstruction(_OP_RETURN, -1);
1167                 funcstate->SetStackSize(0);
1168                 //_fs->->_stacksize = _fs->_stacksize;
1169                 SQFunctionProto *func = funcstate->BuildProto();
1170 #ifdef _DEBUG_DUMP
1171                 funcstate->Dump(func);
1172 #endif
1173                 _fs = currchunk;
1174                 _fs->_functions.push_back(func);
1175                 _fs->PopChildState();
1176         }
1177         void CleanStack(SQInteger stacksize)
1178         {
1179                 if(_fs->GetStackSize() != stacksize)
1180                         _fs->SetStackSize(stacksize);
1181         }
1182         void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
1183         {
1184                 while(ntoresolve > 0) {
1185                         SQInteger pos = funcstate->_unresolvedbreaks.back();
1186                         funcstate->_unresolvedbreaks.pop_back();
1187                         //set the jmp instruction
1188                         funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
1189                         ntoresolve--;
1190                 }
1191         }
1192         void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
1193         {
1194                 while(ntoresolve > 0) {
1195                         SQInteger pos = funcstate->_unresolvedcontinues.back();
1196                         funcstate->_unresolvedcontinues.pop_back();
1197                         //set the jmp instruction
1198                         funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
1199                         ntoresolve--;
1200                 }
1201         }
1202 private:
1203         SQInteger _token;
1204         SQFuncState *_fs;
1205         SQObjectPtr _sourcename;
1206         SQLexer _lex;
1207         bool _lineinfo;
1208         bool _raiseerror;
1209         SQInteger _debugline;
1210         SQInteger _debugop;
1211         ExpStateVec _expstates;
1212         SQChar *compilererror;
1213         jmp_buf _errorjmp;
1214         SQVM *_vm;
1215 };
1216
1217 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
1218 {
1219         SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
1220         return p.Compile(out);
1221 }