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