464a0c0d061d2cfaba7f1dcf0f387f253880e196
[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: oper = 0; //shut up compiler\r
307                         assert(0); break;\r
308                 };\r
309                 if(deref) {\r
310                         SQInteger val = _fs->PopTarget();\r
311                         SQInteger key = _fs->PopTarget();\r
312                         SQInteger src = _fs->PopTarget();\r
313                         //mixes dest obj and source val in the arg1(hack?)\r
314                         _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper);\r
315                 }\r
316                 else {\r
317                         Emit2ArgsOP(_OP_COMPARITHL, oper);\r
318                 }\r
319         }\r
320         void CommaExpr()\r
321         {\r
322                 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());\r
323         }\r
324         ExpState Expression(bool funcarg = false)\r
325         {\r
326                 PushExpState();\r
327                 _exst._class_or_delete = false;\r
328                 _exst._funcarg = funcarg;\r
329                 LogicalOrExp();\r
330                 switch(_token)  {\r
331                 case _SC('='):\r
332                 case TK_NEWSLOT:\r
333                 case TK_MINUSEQ:\r
334                 case TK_PLUSEQ:\r
335                 case TK_MULEQ:\r
336                 case TK_DIVEQ:\r
337                 case TK_MODEQ:\r
338                 {\r
339                                 SQInteger op = _token;\r
340                                 SQInteger ds = _exst._deref;\r
341                                 bool freevar = _exst._freevar;\r
342                                 if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression"));\r
343                                 Lex(); Expression();\r
344 \r
345                                 switch(op){\r
346                                 case TK_NEWSLOT:\r
347                                         if(freevar) Error(_SC("free variables cannot be modified"));\r
348                                         if(ds == DEREF_FIELD)\r
349                                                 EmitDerefOp(_OP_NEWSLOT);\r
350                                         else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
351                                                 Error(_SC("can't 'create' a local slot"));\r
352                                         break;\r
353                                 case _SC('='): //ASSIGN\r
354                                         if(freevar) Error(_SC("free variables cannot be modified"));\r
355                                         if(ds == DEREF_FIELD)\r
356                                                 EmitDerefOp(_OP_SET);\r
357                                         else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
358                                                 SQInteger p2 = _fs->PopTarget(); //src in OP_GET\r
359                                                 SQInteger p1 = _fs->TopTarget(); //key in OP_GET\r
360                                                 _fs->AddInstruction(_OP_MOVE, p1, p2);\r
361                                         }\r
362                                         break;\r
363                                 case TK_MINUSEQ:\r
364                                 case TK_PLUSEQ:\r
365                                 case TK_MULEQ:\r
366                                 case TK_DIVEQ:\r
367                                 case TK_MODEQ:\r
368                                         EmitCompoundArith(op,ds == DEREF_FIELD);\r
369                                         break;\r
370                                 }\r
371                         }\r
372                         break;\r
373                 case _SC('?'): {\r
374                         Lex();\r
375                         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
376                         SQInteger jzpos = _fs->GetCurrentPos();\r
377                         SQInteger trg = _fs->PushTarget();\r
378                         Expression();\r
379                         SQInteger first_exp = _fs->PopTarget();\r
380                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\r
381                         SQInteger endfirstexp = _fs->GetCurrentPos();\r
382                         _fs->AddInstruction(_OP_JMP, 0, 0);\r
383                         Expect(_SC(':'));\r
384                         SQInteger jmppos = _fs->GetCurrentPos();\r
385                         Expression();\r
386                         SQInteger second_exp = _fs->PopTarget();\r
387                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\r
388                         _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\r
389                         _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);\r
390                         _fs->SnoozeOpt();\r
391                         }\r
392                         break;\r
393                 }\r
394                 return PopExpState();\r
395         }\r
396         void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0)\r
397         {\r
398                 Lex(); (this->*f)();\r
399                 SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();\r
400                 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);\r
401         }\r
402         void LogicalOrExp()\r
403         {\r
404                 LogicalAndExp();\r
405                 for(;;) if(_token == TK_OR) {\r
406                         SQInteger first_exp = _fs->PopTarget();\r
407                         SQInteger trg = _fs->PushTarget();\r
408                         _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);\r
409                         SQInteger jpos = _fs->GetCurrentPos();\r
410                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\r
411                         Lex(); LogicalOrExp();\r
412                         _fs->SnoozeOpt();\r
413                         SQInteger second_exp = _fs->PopTarget();\r
414                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\r
415                         _fs->SnoozeOpt();\r
416                         _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));\r
417                         break;\r
418                 }else return;\r
419         }\r
420         void LogicalAndExp()\r
421         {\r
422                 BitwiseOrExp();\r
423                 for(;;) switch(_token) {\r
424                 case TK_AND: {\r
425                         SQInteger first_exp = _fs->PopTarget();\r
426                         SQInteger trg = _fs->PushTarget();\r
427                         _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);\r
428                         SQInteger jpos = _fs->GetCurrentPos();\r
429                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\r
430                         Lex(); LogicalAndExp();\r
431                         _fs->SnoozeOpt();\r
432                         SQInteger second_exp = _fs->PopTarget();\r
433                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\r
434                         _fs->SnoozeOpt();\r
435                         _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));\r
436                         break;\r
437                         }\r
438                 case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break;\r
439                 case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break;\r
440                 default:\r
441                         return;\r
442                 }\r
443         }\r
444         void BitwiseOrExp()\r
445         {\r
446                 BitwiseXorExp();\r
447                 for(;;) if(_token == _SC('|'))\r
448                 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);\r
449                 }else return;\r
450         }\r
451         void BitwiseXorExp()\r
452         {\r
453                 BitwiseAndExp();\r
454                 for(;;) if(_token == _SC('^'))\r
455                 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);\r
456                 }else return;\r
457         }\r
458         void BitwiseAndExp()\r
459         {\r
460                 CompExp();\r
461                 for(;;) if(_token == _SC('&'))\r
462                 {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);\r
463                 }else return;\r
464         }\r
465         void CompExp()\r
466         {\r
467                 ShiftExp();\r
468                 for(;;) switch(_token) {\r
469                 case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break;\r
470                 case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;\r
471                 case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;\r
472                 case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;\r
473                 case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;\r
474                 case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;\r
475                 default: return;        \r
476                 }\r
477         }\r
478         void ShiftExp()\r
479         {\r
480                 PlusExp();\r
481                 for(;;) switch(_token) {\r
482                 case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;\r
483                 case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;\r
484                 case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;\r
485                 default: return;        \r
486                 }\r
487         }\r
488         void PlusExp()\r
489         {\r
490                 MultExp();\r
491                 for(;;) switch(_token) {\r
492                 case _SC('+'): case _SC('-'):\r
493                         BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break;\r
494                 default: return;\r
495                 }\r
496         }\r
497         \r
498         void MultExp()\r
499         {\r
500                 PrefixedExpr();\r
501                 for(;;) switch(_token) {\r
502                 case _SC('*'): case _SC('/'): case _SC('%'):\r
503                         BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break;\r
504                 default: return;\r
505                 }\r
506         }\r
507         //if 'pos' != -1 the previous variable is a local variable\r
508         void PrefixedExpr()\r
509         {\r
510                 SQInteger pos = Factor();\r
511                 for(;;) {\r
512                         switch(_token) {\r
513                         case _SC('.'): {\r
514                                 pos = -1;\r
515                                 Lex(); \r
516                                 if(_token == TK_PARENT) {\r
517                                         Lex();\r
518                                         if(!NeedGet())\r
519                                                 Error(_SC("parent cannot be set"));\r
520                                         SQInteger src = _fs->PopTarget();\r
521                                         _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);\r
522                                 }\r
523                                 else {\r
524                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
525                                         if(NeedGet()) Emit2ArgsOP(_OP_GET);\r
526                                 }\r
527                                 _exst._deref = DEREF_FIELD;\r
528                                 _exst._freevar = false;\r
529                                 }\r
530                                 break;\r
531                         case _SC('['):\r
532                                 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));\r
533                                 Lex(); Expression(); Expect(_SC(']')); \r
534                                 pos = -1;\r
535                                 if(NeedGet()) Emit2ArgsOP(_OP_GET);\r
536                                 _exst._deref = DEREF_FIELD;\r
537                                 _exst._freevar = false;\r
538                                 break;\r
539                         case TK_MINUSMINUS:\r
540                         case TK_PLUSPLUS:\r
541                         if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { \r
542                                 SQInteger tok = _token; Lex();\r
543                                 if(pos < 0)\r
544                                         Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);\r
545                                 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
546                                         SQInteger src = _fs->PopTarget();\r
547                                         _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);\r
548                                 }\r
549                                 \r
550                         }\r
551                         return;\r
552                         break;  \r
553                         case _SC('('): \r
554                                 {\r
555                                 if(_exst._deref != DEREF_NO_DEREF) {\r
556                                         if(pos<0) {\r
557                                                 SQInteger key = _fs->PopTarget(); //key\r
558                                                 SQInteger table = _fs->PopTarget(); //table etc...\r
559                                                 SQInteger closure = _fs->PushTarget();\r
560                                                 SQInteger ttarget = _fs->PushTarget();\r
561                                                 _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);\r
562                                         }\r
563                                         else{\r
564                                                 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
565                                         }\r
566                                 }\r
567                                 else\r
568                                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
569                                 _exst._deref = DEREF_NO_DEREF;\r
570                                 Lex();\r
571                                 FunctionCallArgs();\r
572                                  }\r
573                                 break;\r
574                         default: return;\r
575                         }\r
576                 }\r
577         }\r
578         SQInteger Factor()\r
579         {\r
580                 switch(_token)\r
581                 {\r
582                 case TK_STRING_LITERAL: {\r
583                                 //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));\r
584                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));\r
585                                 Lex(); \r
586                         }\r
587                         break;\r
588                 case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;\r
589                 case TK_VARGV: { Lex();\r
590                         Expect(_SC('['));\r
591                         Expression();\r
592                         Expect(_SC(']'));\r
593                         SQInteger src = _fs->PopTarget();\r
594                         _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src);\r
595                                            }\r
596                         break;\r
597                 case TK_IDENTIFIER:\r
598                 case TK_CONSTRUCTOR:\r
599                 case TK_THIS:{\r
600                         _exst._freevar = false;\r
601                         SQObject id;\r
602                                 switch(_token) {\r
603                                         case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;\r
604                                         case TK_THIS: id = _fs->CreateString(_SC("this")); break;\r
605                                         case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;\r
606                                 }\r
607                                 SQInteger pos = -1;\r
608                                 Lex();\r
609                                 if((pos = _fs->GetLocalVariable(id)) == -1) {\r
610                                         //checks if is a free variable\r
611                                         if((pos = _fs->GetOuterVariable(id)) != -1) {\r
612                                                 _exst._deref = _fs->PushTarget();\r
613                                                 _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);        \r
614                                                 _exst._freevar = true;\r
615                                         } else {\r
616                                                 _fs->PushTarget(0);\r
617                                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
618                                                 if(NeedGet()) Emit2ArgsOP(_OP_GET);\r
619                                                 _exst._deref = DEREF_FIELD;\r
620                                         }\r
621                                 }\r
622                                 else{\r
623                                         _fs->PushTarget(pos);\r
624                                         _exst._deref = pos;\r
625                                 }\r
626                                 return _exst._deref;\r
627                         }\r
628                         break;\r
629                 case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break;\r
630                 case TK_DOUBLE_COLON:  // "::"\r
631                         _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget());\r
632                         _exst._deref = DEREF_FIELD;\r
633                         _token = _SC('.'); //hack\r
634                         return -1;\r
635                         break;\r
636                 case TK_NULL: \r
637                         _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\r
638                         Lex();\r
639                         break;\r
640                 case TK_INTEGER: {\r
641                         if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?\r
642                                 _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);\r
643                         }\r
644                         else {\r
645                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));\r
646                         }\r
647                         Lex();\r
648                                                  }\r
649                         break;\r
650                 case TK_FLOAT: \r
651                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));\r
652                         Lex();\r
653                         break;\r
654                 case TK_TRUE: case TK_FALSE:\r
655                         _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);\r
656                         Lex();\r
657                         break;\r
658                 case _SC('['): {\r
659                                 _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget());\r
660                                 SQInteger apos = _fs->GetCurrentPos(),key = 0;\r
661                                 Lex();\r
662                                 while(_token != _SC(']')) {\r
663                     Expression(); \r
664                                         if(_token == _SC(',')) Lex();\r
665                                         SQInteger val = _fs->PopTarget();\r
666                                         SQInteger array = _fs->TopTarget();\r
667                                         _fs->AddInstruction(_OP_APPENDARRAY, array, val);\r
668                                         key++;\r
669                                 }\r
670                                 _fs->SetIntructionParam(apos, 1, key);\r
671                                 Lex();\r
672                         }\r
673                         break;\r
674                 case _SC('{'):{\r
675                         _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());\r
676                         Lex();ParseTableOrClass(_SC(','));\r
677                                  }\r
678                         break;\r
679                 case TK_FUNCTION: FunctionExp(_token);break;\r
680                 case TK_CLASS: Lex(); ClassExp();break;\r
681                 case _SC('-'): UnaryOP(_OP_NEG); break;\r
682                 case _SC('!'): UnaryOP(_OP_NOT); break;\r
683                 case _SC('~'): UnaryOP(_OP_BWNOT); break;\r
684                 case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;\r
685                 case TK_RESUME : UnaryOP(_OP_RESUME); break;\r
686                 case TK_CLONE : UnaryOP(_OP_CLONE); break;\r
687                 case TK_MINUSMINUS : \r
688                 case TK_PLUSPLUS :PrefixIncDec(_token); break;\r
689                 case TK_DELETE : DeleteExpr(); break;\r
690                 case TK_DELEGATE : DelegateExpr(); break;\r
691                 case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));\r
692                         break;\r
693                 default: Error(_SC("expression expected"));\r
694                 }\r
695                 return -1;\r
696         }\r
697         void UnaryOP(SQOpcode op)\r
698         {\r
699                 Lex(); PrefixedExpr();\r
700                 SQInteger src = _fs->PopTarget();\r
701                 _fs->AddInstruction(op, _fs->PushTarget(), src);\r
702         }\r
703         bool NeedGet()\r
704         {\r
705                 switch(_token) {\r
706                 case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS:\r
707                 case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:\r
708                         return false;\r
709                 }\r
710                 return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));\r
711         }\r
712         \r
713         void FunctionCallArgs()\r
714         {\r
715                 SQInteger nargs = 1;//this\r
716                  while(_token != _SC(')')) {\r
717                          Expression(true);\r
718                          MoveIfCurrentTargetIsLocal();\r
719                          nargs++; \r
720                          if(_token == _SC(',')){ \r
721                                  Lex(); \r
722                                  if(_token == ')') Error(_SC("expression expected, found ')'"));\r
723                          }\r
724                  }\r
725                  Lex();\r
726                  for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();\r
727                  SQInteger stackbase = _fs->PopTarget();\r
728                  SQInteger closure = _fs->PopTarget();\r
729          _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);\r
730         }\r
731         void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')\r
732         {\r
733                 SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;\r
734                 \r
735                 while(_token != terminator) {\r
736                         bool hasattrs = false;\r
737                         bool isstatic = false;\r
738                         //check if is an attribute\r
739                         if(separator == ';') {\r
740                                 if(_token == TK_ATTR_OPEN) {\r
741                                         _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();\r
742                                         ParseTableOrClass(',',TK_ATTR_CLOSE);\r
743                                         hasattrs = true;\r
744                                 }\r
745                                 if(_token == TK_STATIC) {\r
746                                         isstatic = true;\r
747                                         Lex();\r
748                                 }\r
749                         }\r
750                         switch(_token) {\r
751                                 case TK_FUNCTION:\r
752                                 case TK_CONSTRUCTOR:{\r
753                                         SQInteger tk = _token;\r
754                                         Lex();\r
755                                         SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));\r
756                                         Expect(_SC('('));\r
757                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
758                                         CreateFunction(id);\r
759                                         _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
760                                                                   }\r
761                                                                   break;\r
762                                 case _SC('['):\r
763                                         Lex(); CommaExpr(); Expect(_SC(']'));\r
764                                         Expect(_SC('=')); Expression();\r
765                                         break;\r
766                                 default :\r
767                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
768                                         Expect(_SC('=')); Expression();\r
769                         }\r
770 \r
771                         if(_token == separator) Lex();//optional comma/semicolon\r
772                         nkeys++;\r
773                         SQInteger val = _fs->PopTarget();\r
774                         SQInteger key = _fs->PopTarget();\r
775                         SQInteger attrs = hasattrs ? _fs->PopTarget():-1;\r
776                         assert(hasattrs && attrs == key-1 || !hasattrs);\r
777                         unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);\r
778                         SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE\r
779                         _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);\r
780                         //_fs->PopTarget();\r
781                 }\r
782                 if(separator == _SC(',')) //hack recognizes a table from the separator\r
783                         _fs->SetIntructionParam(tpos, 1, nkeys);\r
784                 Lex();\r
785         }\r
786         void LocalDeclStatement()\r
787         {\r
788                 SQObject varname;\r
789                 do {\r
790                         Lex(); varname = Expect(TK_IDENTIFIER);\r
791                         if(_token == _SC('=')) {\r
792                                 Lex(); Expression();\r
793                                 SQInteger src = _fs->PopTarget();\r
794                                 SQInteger dest = _fs->PushTarget();\r
795                                 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);\r
796                         }\r
797                         else{\r
798                                 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\r
799                         }\r
800                         _fs->PopTarget();\r
801                         _fs->PushLocalVariable(varname);\r
802                 \r
803                 } while(_token == _SC(','));\r
804         }\r
805         void IfStatement()\r
806         {\r
807                 SQInteger jmppos;\r
808                 bool haselse = false;\r
809                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
810                 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
811                 SQInteger jnepos = _fs->GetCurrentPos();\r
812                 SQInteger stacksize = _fs->GetStackSize();\r
813                 \r
814                 Statement();\r
815                 //\r
816                 if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();\r
817                 \r
818                 CleanStack(stacksize);\r
819                 SQInteger endifblock = _fs->GetCurrentPos();\r
820                 if(_token == TK_ELSE){\r
821                         haselse = true;\r
822                         stacksize = _fs->GetStackSize();\r
823                         _fs->AddInstruction(_OP_JMP);\r
824                         jmppos = _fs->GetCurrentPos();\r
825                         Lex();\r
826                         Statement(); OptionalSemicolon();\r
827                         CleanStack(stacksize);\r
828                         _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\r
829                 }\r
830                 _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));\r
831         }\r
832         void WhileStatement()\r
833         {\r
834                 SQInteger jzpos, jmppos;\r
835                 SQInteger stacksize = _fs->GetStackSize();\r
836                 jmppos = _fs->GetCurrentPos();\r
837                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
838                 \r
839                 BEGIN_BREAKBLE_BLOCK();\r
840                 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
841                 jzpos = _fs->GetCurrentPos();\r
842                 stacksize = _fs->GetStackSize();\r
843                 \r
844                 Statement();\r
845                 \r
846                 CleanStack(stacksize);\r
847                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\r
848                 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\r
849                 \r
850                 END_BREAKBLE_BLOCK(jmppos);\r
851         }\r
852         void DoWhileStatement()\r
853         {\r
854                 Lex();\r
855                 SQInteger jzpos = _fs->GetCurrentPos();\r
856                 SQInteger stacksize = _fs->GetStackSize();\r
857                 BEGIN_BREAKBLE_BLOCK()\r
858                 Statement();\r
859                 CleanStack(stacksize);\r
860                 Expect(TK_WHILE);\r
861                 SQInteger continuetrg = _fs->GetCurrentPos();\r
862                 Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
863                 _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1);\r
864                 END_BREAKBLE_BLOCK(continuetrg);\r
865         }\r
866         void ForStatement()\r
867         {\r
868                 Lex();\r
869                 SQInteger stacksize = _fs->GetStackSize();\r
870                 Expect(_SC('('));\r
871                 if(_token == TK_LOCAL) LocalDeclStatement();\r
872                 else if(_token != _SC(';')){\r
873                         CommaExpr();\r
874                         _fs->PopTarget();\r
875                 }\r
876                 Expect(_SC(';'));\r
877                 _fs->SnoozeOpt();\r
878                 SQInteger jmppos = _fs->GetCurrentPos();\r
879                 SQInteger jzpos = -1;\r
880                 if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }\r
881                 Expect(_SC(';'));\r
882                 _fs->SnoozeOpt();\r
883                 SQInteger expstart = _fs->GetCurrentPos() + 1;\r
884                 if(_token != _SC(')')) {\r
885                         CommaExpr();\r
886                         _fs->PopTarget();\r
887                 }\r
888                 Expect(_SC(')'));\r
889                 _fs->SnoozeOpt();\r
890                 SQInteger expend = _fs->GetCurrentPos();\r
891                 SQInteger expsize = (expend - expstart) + 1;\r
892                 SQInstructionVec exp;\r
893                 if(expsize > 0) {\r
894                         for(SQInteger i = 0; i < expsize; i++)\r
895                                 exp.push_back(_fs->GetInstruction(expstart + i));\r
896                         _fs->PopInstructions(expsize);\r
897                 }\r
898                 BEGIN_BREAKBLE_BLOCK()\r
899                 Statement();\r
900                 SQInteger continuetrg = _fs->GetCurrentPos();\r
901                 if(expsize > 0) {\r
902                         for(SQInteger i = 0; i < expsize; i++)\r
903                                 _fs->AddInstruction(exp[i]);\r
904                 }\r
905                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);\r
906                 if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\r
907                 CleanStack(stacksize);\r
908                 \r
909                 END_BREAKBLE_BLOCK(continuetrg);\r
910         }\r
911         void ForEachStatement()\r
912         {\r
913                 SQObject idxname, valname;\r
914                 Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);\r
915                 if(_token == _SC(',')) {\r
916                         idxname = valname;\r
917                         Lex(); valname = Expect(TK_IDENTIFIER);\r
918                 }\r
919                 else{\r
920                         idxname = _fs->CreateString(_SC("@INDEX@"));\r
921                 }\r
922                 Expect(TK_IN);\r
923                 \r
924                 //save the stack size\r
925                 SQInteger stacksize = _fs->GetStackSize();\r
926                 //put the table in the stack(evaluate the table expression)\r
927                 Expression(); Expect(_SC(')'));\r
928                 SQInteger container = _fs->TopTarget();\r
929                 //push the index local var\r
930                 SQInteger indexpos = _fs->PushLocalVariable(idxname);\r
931                 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);\r
932                 //push the value local var\r
933                 SQInteger valuepos = _fs->PushLocalVariable(valname);\r
934                 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);\r
935                 //push reference index\r
936                 SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible\r
937                 _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);\r
938                 SQInteger jmppos = _fs->GetCurrentPos();\r
939                 _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);\r
940                 SQInteger foreachpos = _fs->GetCurrentPos();\r
941                 //generate the statement code\r
942                 BEGIN_BREAKBLE_BLOCK()\r
943                 Statement();\r
944                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\r
945                 _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);\r
946                 //restore the local variable stack(remove index,val and ref idx)\r
947                 CleanStack(stacksize);\r
948                 END_BREAKBLE_BLOCK(foreachpos - 1);\r
949         }\r
950         void SwitchStatement()\r
951         {\r
952                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
953                 Expect(_SC('{'));\r
954                 SQInteger expr = _fs->TopTarget();\r
955                 bool bfirst = true;\r
956                 SQInteger tonextcondjmp = -1;\r
957                 SQInteger skipcondjmp = -1;\r
958                 SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();\r
959                 _fs->_breaktargets.push_back(0);\r
960                 while(_token == TK_CASE) {\r
961                         //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one\r
962                         if(!bfirst) {\r
963                                 _fs->AddInstruction(_OP_JMP, 0, 0);\r
964                                 skipcondjmp = _fs->GetCurrentPos();\r
965                                 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\r
966                         }\r
967                         //condition\r
968                         Lex(); Expression(); Expect(_SC(':'));\r
969                         SQInteger trg = _fs->PopTarget();\r
970                         _fs->AddInstruction(_OP_EQ, trg, trg, expr);\r
971                         _fs->AddInstruction(_OP_JZ, trg, 0);\r
972                         //end condition\r
973                         if(skipcondjmp != -1) {\r
974                                 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));\r
975                         }\r
976                         tonextcondjmp = _fs->GetCurrentPos();\r
977                         SQInteger stacksize = _fs->GetStackSize();\r
978                         Statements();\r
979                         _fs->SetStackSize(stacksize);\r
980                         bfirst = false;\r
981                 }\r
982                 if(tonextcondjmp != -1)\r
983                         _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\r
984                 if(_token == TK_DEFAULT) {\r
985                 //      _fs->AddLineInfos(_lex._currentline, _lineinfo);\r
986                         Lex(); Expect(_SC(':'));\r
987                         SQInteger stacksize = _fs->GetStackSize();\r
988                         Statements();\r
989                         _fs->SetStackSize(stacksize);\r
990                 }\r
991                 Expect(_SC('}'));\r
992                 _fs->PopTarget();\r
993                 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;\r
994                 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);\r
995                 _fs->_breaktargets.pop_back();\r
996                 \r
997         }\r
998         void FunctionStatement()\r
999         {\r
1000                 SQObject id;\r
1001                 Lex(); id = Expect(TK_IDENTIFIER);\r
1002                 _fs->PushTarget(0);\r
1003                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
1004                 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);\r
1005                 \r
1006                 while(_token == TK_DOUBLE_COLON) {\r
1007                         Lex();\r
1008                         id = Expect(TK_IDENTIFIER);\r
1009                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
1010                         if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);\r
1011                 }\r
1012                 Expect(_SC('('));\r
1013                 CreateFunction(id);\r
1014                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
1015                 EmitDerefOp(_OP_NEWSLOT);\r
1016                 _fs->PopTarget();\r
1017         }\r
1018         void ClassStatement()\r
1019         {\r
1020                 ExpState es;\r
1021                 Lex(); PushExpState();\r
1022                 _exst._class_or_delete = true;\r
1023                 _exst._funcarg = false;\r
1024                 PrefixedExpr();\r
1025                 es = PopExpState();\r
1026                 if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));\r
1027                 if(es._deref == DEREF_FIELD) {\r
1028                         ClassExp();\r
1029                         EmitDerefOp(_OP_NEWSLOT);\r
1030                         _fs->PopTarget();\r
1031                 }\r
1032                 else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));\r
1033         }\r
1034         void TryCatchStatement()\r
1035         {\r
1036                 SQObject exid;\r
1037                 Lex();\r
1038                 _fs->AddInstruction(_OP_PUSHTRAP,0,0);\r
1039                 _fs->_traps++;\r
1040                 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;\r
1041                 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;\r
1042                 SQInteger trappos = _fs->GetCurrentPos();\r
1043                 Statement();\r
1044                 _fs->_traps--;\r
1045                 _fs->AddInstruction(_OP_POPTRAP, 1, 0);\r
1046                 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;\r
1047                 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;\r
1048                 _fs->AddInstruction(_OP_JMP, 0, 0);\r
1049                 SQInteger jmppos = _fs->GetCurrentPos();\r
1050                 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));\r
1051                 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));\r
1052                 SQInteger stacksize = _fs->GetStackSize();\r
1053                 SQInteger ex_target = _fs->PushLocalVariable(exid);\r
1054                 _fs->SetIntructionParam(trappos, 0, ex_target);\r
1055                 Statement();\r
1056                 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);\r
1057                 CleanStack(stacksize);\r
1058         }\r
1059         void FunctionExp(SQInteger ftype)\r
1060         {\r
1061                 Lex(); Expect(_SC('('));\r
1062                 CreateFunction(_null_);\r
1063                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);\r
1064         }\r
1065         void ClassExp()\r
1066         {\r
1067                 SQInteger base = -1;\r
1068                 SQInteger attrs = -1;\r
1069                 if(_token == TK_EXTENDS) {\r
1070                         Lex(); Expression();\r
1071                         base = _fs->TopTarget();\r
1072                 }\r
1073                 if(_token == TK_ATTR_OPEN) {\r
1074                         Lex();\r
1075                         _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());\r
1076                         ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);\r
1077                         attrs = _fs->TopTarget();\r
1078                 }\r
1079                 Expect(_SC('{'));\r
1080                 if(attrs != -1) _fs->PopTarget();\r
1081                 if(base != -1) _fs->PopTarget();\r
1082                 _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);\r
1083                 ParseTableOrClass(_SC(';'));\r
1084         }\r
1085         void DelegateExpr()\r
1086         {\r
1087                 Lex(); CommaExpr();\r
1088                 Expect(_SC(':'));\r
1089                 CommaExpr();\r
1090                 SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();\r
1091                 _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);\r
1092         }\r
1093         void DeleteExpr()\r
1094         {\r
1095                 ExpState es;\r
1096                 Lex(); PushExpState();\r
1097                 _exst._class_or_delete = true;\r
1098                 _exst._funcarg = false;\r
1099                 PrefixedExpr();\r
1100                 es = PopExpState();\r
1101                 if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));\r
1102                 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);\r
1103                 else Error(_SC("cannot delete a local"));\r
1104         }\r
1105         void PrefixIncDec(SQInteger token)\r
1106         {\r
1107                 ExpState es;\r
1108                 Lex(); PushExpState();\r
1109                 _exst._class_or_delete = true;\r
1110                 _exst._funcarg = false;\r
1111                 PrefixedExpr();\r
1112                 es = PopExpState();\r
1113                 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);\r
1114                 else {\r
1115                         SQInteger src = _fs->PopTarget();\r
1116                         _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);\r
1117                 }\r
1118         }\r
1119         void CreateFunction(SQObject &name)\r
1120         {\r
1121                 \r
1122                 SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));\r
1123                 funcstate->_name = name;\r
1124                 SQObject paramname;\r
1125                 funcstate->AddParameter(_fs->CreateString(_SC("this")));\r
1126                 funcstate->_sourcename = _sourcename;\r
1127                 while(_token!=_SC(')')) {\r
1128                         if(_token == TK_VARPARAMS) {\r
1129                                 funcstate->_varparams = true;\r
1130                                 Lex();\r
1131                                 if(_token != _SC(')')) Error(_SC("expected ')'"));\r
1132                                 break;\r
1133                         }\r
1134                         else {\r
1135                                 paramname = Expect(TK_IDENTIFIER);\r
1136                                 funcstate->AddParameter(paramname);\r
1137                                 if(_token == _SC(',')) Lex();\r
1138                                 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));\r
1139                         }\r
1140                 }\r
1141                 Expect(_SC(')'));\r
1142                 //outer values\r
1143                 if(_token == _SC(':')) {\r
1144                         Lex(); Expect(_SC('('));\r
1145                         while(_token != _SC(')')) {\r
1146                                 paramname = Expect(TK_IDENTIFIER);\r
1147                                 //outers are treated as implicit local variables\r
1148                                 funcstate->AddOuterValue(paramname);\r
1149                                 if(_token == _SC(',')) Lex();\r
1150                                 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));\r
1151                         }\r
1152                         Lex();\r
1153                 }\r
1154                 \r
1155                 SQFuncState *currchunk = _fs;\r
1156                 _fs = funcstate;\r
1157                 Statement();\r
1158                 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);\r
1159         funcstate->AddInstruction(_OP_RETURN, -1);\r
1160                 funcstate->SetStackSize(0);\r
1161                 //_fs->->_stacksize = _fs->_stacksize;\r
1162                 SQFunctionProto *func = funcstate->BuildProto();\r
1163 #ifdef _DEBUG_DUMP\r
1164                 funcstate->Dump(func);\r
1165 #endif\r
1166                 _fs = currchunk;\r
1167                 _fs->_functions.push_back(func);\r
1168                 _fs->PopChildState();\r
1169         }\r
1170         void CleanStack(SQInteger stacksize)\r
1171         {\r
1172                 if(_fs->GetStackSize() != stacksize)\r
1173                         _fs->SetStackSize(stacksize);\r
1174         }\r
1175         void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)\r
1176         {\r
1177                 while(ntoresolve > 0) {\r
1178                         SQInteger pos = funcstate->_unresolvedbreaks.back();\r
1179                         funcstate->_unresolvedbreaks.pop_back();\r
1180                         //set the jmp instruction\r
1181                         funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);\r
1182                         ntoresolve--;\r
1183                 }\r
1184         }\r
1185         void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)\r
1186         {\r
1187                 while(ntoresolve > 0) {\r
1188                         SQInteger pos = funcstate->_unresolvedcontinues.back();\r
1189                         funcstate->_unresolvedcontinues.pop_back();\r
1190                         //set the jmp instruction\r
1191                         funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);\r
1192                         ntoresolve--;\r
1193                 }\r
1194         }\r
1195 private:\r
1196         SQInteger _token;\r
1197         SQFuncState *_fs;\r
1198         SQObjectPtr _sourcename;\r
1199         SQLexer _lex;\r
1200         bool _lineinfo;\r
1201         bool _raiseerror;\r
1202         SQInteger _debugline;\r
1203         SQInteger _debugop;\r
1204         ExpStateVec _expstates;\r
1205         SQChar *compilererror;\r
1206         jmp_buf _errorjmp;\r
1207         SQVM *_vm;\r
1208 };\r
1209 \r
1210 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)\r
1211 {\r
1212         SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);\r
1213         return p.Compile(out);\r
1214 }\r