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