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