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