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