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