2 see copyright notice in squirrel.h
4 #include "sqpcheader.h"
9 #include "sqfuncproto.h"
10 #include "sqcompiler.h"
11 #include "sqfuncstate.h"
15 #define DEREF_NO_DEREF -1
16 #define DEREF_FIELD -2
22 _deref = DEREF_NO_DEREF;
24 _class_or_delete = false;
27 bool _class_or_delete;
33 typedef sqvector<ExpState> ExpStateVec;
35 #define _exst (_expstates.top())
37 #define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
38 SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
39 _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
41 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
42 __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
43 if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
44 if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
45 _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
50 SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
53 _lex.Init(_ss(v), rg, up,ThrowError,this);
54 _sourcename = SQString::Create(_ss(v), sourcename);
55 _lineinfo = lineinfo;_raiseerror = raiseerror;
58 static void ThrowError(void *ud, const SQChar *s) {
59 SQCompiler *c = (SQCompiler *)ud;
62 void Error(const SQChar *s, ...)
64 static SQChar temp[256];
67 scvsprintf(temp, s, vl);
72 void Lex(){ _token = _lex.Lex();}
73 void PushExpState(){ _expstates.push_back(ExpState()); }
74 bool IsDerefToken(SQInteger tok)
77 case _SC('='): case _SC('('): case TK_NEWSLOT:
78 case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true;
82 ExpState PopExpState()
84 ExpState ret = _expstates.top();
85 _expstates.pop_back();
88 SQObject Expect(SQInteger tok)
92 if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
93 //ret = SQString::Create(_ss(_vm),_SC("constructor"));
97 const SQChar *etypename;
102 etypename = _SC("IDENTIFIER");
104 case TK_STRING_LITERAL:
105 etypename = _SC("STRING_LITERAL");
108 etypename = _SC("INTEGER");
111 etypename = _SC("FLOAT");
114 etypename = _lex.Tok2Str(tok);
116 Error(_SC("expected '%s'"), etypename);
118 Error(_SC("expected '%c'"), tok);
125 ret = _fs->CreateString(_lex._svalue);
127 case TK_STRING_LITERAL:
128 ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
131 ret = SQObjectPtr(_lex._nvalue);
134 ret = SQObjectPtr(_lex._fvalue);
140 bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
141 void OptionalSemicolon()
143 if(_token == _SC(';')) { Lex(); return; }
144 if(!IsEndOfStatement()) {
145 Error(_SC("end of statement expected (; or lf)"));
148 void MoveIfCurrentTargetIsLocal() {
149 SQInteger trg = _fs->TopTarget();
150 if(_fs->IsLocal(trg)) {
151 trg = _fs->PopTarget(); //no pops the target and move it
152 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
155 bool Compile(SQObjectPtr &o)
160 SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
161 funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
163 _fs->AddParameter(_fs->CreateString(_SC("this")));
164 _fs->_sourcename = _sourcename;
165 SQInteger stacksize = _fs->GetStackSize();
166 if(setjmp(_errorjmp) == 0) {
170 if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
172 CleanStack(stacksize);
173 _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
174 _fs->AddInstruction(_OP_RETURN, 0xFF);
175 _fs->SetStackSize(0);
176 o =_fs->BuildProto();
178 _fs->Dump(_funcproto(o));
182 if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
183 _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
184 _lex._currentline, _lex._currentcolumn);
186 _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
193 while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
195 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
200 _fs->AddLineInfos(_lex._currentline, _lineinfo);
202 case _SC(';'): Lex(); break;
203 case TK_IF: IfStatement(); break;
204 case TK_WHILE: WhileStatement(); break;
205 case TK_DO: DoWhileStatement(); break;
206 case TK_FOR: ForStatement(); break;
207 case TK_FOREACH: ForEachStatement(); break;
208 case TK_SWITCH: SwitchStatement(); break;
209 case TK_LOCAL: LocalDeclStatement(); break;
213 if(_token == TK_RETURN) {
219 _fs->_bgenerator = true;
222 if(!IsEndOfStatement()) {
223 SQInteger retexp = _fs->GetCurrentPos()+1;
225 if(op == _OP_RETURN && _fs->_traps > 0)
226 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
227 _fs->_returnexp = retexp;
228 _fs->AddInstruction(op, 1, _fs->PopTarget());
231 if(op == _OP_RETURN && _fs->_traps > 0)
232 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
233 _fs->_returnexp = -1;
234 _fs->AddInstruction(op, 0xFF);
238 if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
239 if(_fs->_breaktargets.top() > 0){
240 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
242 _fs->AddInstruction(_OP_JMP, 0, -1234);
243 _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
247 if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
248 if(_fs->_continuetargets.top() > 0) {
249 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
251 _fs->AddInstruction(_OP_JMP, 0, -1234);
252 _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
262 SQInteger stacksize = _fs->GetStackSize();
266 _fs->SetStackSize(stacksize);
275 _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
284 void EmitDerefOp(SQOpcode op)
286 SQInteger val = _fs->PopTarget();
287 SQInteger key = _fs->PopTarget();
288 SQInteger src = _fs->PopTarget();
289 _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
291 void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
293 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
294 SQInteger p1 = _fs->PopTarget(); //key in OP_GET
295 _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
297 void EmitCompoundArith(SQInteger tok,bool deref)
301 case TK_MINUSEQ: oper = '-'; break;
302 case TK_PLUSEQ: oper = '+'; break;
303 case TK_MULEQ: oper = '*'; break;
304 case TK_DIVEQ: oper = '/'; break;
305 case TK_MODEQ: oper = '%'; break;
306 default: oper = 0; //shut up compiler
310 SQInteger val = _fs->PopTarget();
311 SQInteger key = _fs->PopTarget();
312 SQInteger src = _fs->PopTarget();
313 //mixes dest obj and source val in the arg1(hack?)
314 _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper);
317 Emit2ArgsOP(_OP_COMPARITHL, oper);
322 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
324 ExpState Expression(bool funcarg = false)
327 _exst._class_or_delete = false;
328 _exst._funcarg = funcarg;
339 SQInteger op = _token;
340 SQInteger ds = _exst._deref;
341 bool freevar = _exst._freevar;
342 if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression"));
347 if(freevar) Error(_SC("free variables cannot be modified"));
348 if(ds == DEREF_FIELD)
349 EmitDerefOp(_OP_NEWSLOT);
350 else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
351 Error(_SC("can't 'create' a local slot"));
353 case _SC('='): //ASSIGN
354 if(freevar) Error(_SC("free variables cannot be modified"));
355 if(ds == DEREF_FIELD)
356 EmitDerefOp(_OP_SET);
357 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
358 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
359 SQInteger p1 = _fs->TopTarget(); //key in OP_GET
360 _fs->AddInstruction(_OP_MOVE, p1, p2);
368 EmitCompoundArith(op,ds == DEREF_FIELD);
375 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
376 SQInteger jzpos = _fs->GetCurrentPos();
377 SQInteger trg = _fs->PushTarget();
379 SQInteger first_exp = _fs->PopTarget();
380 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
381 SQInteger endfirstexp = _fs->GetCurrentPos();
382 _fs->AddInstruction(_OP_JMP, 0, 0);
384 SQInteger jmppos = _fs->GetCurrentPos();
386 SQInteger second_exp = _fs->PopTarget();
387 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
388 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
389 _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
394 return PopExpState();
396 void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0)
399 SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
400 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
405 for(;;) if(_token == TK_OR) {
406 SQInteger first_exp = _fs->PopTarget();
407 SQInteger trg = _fs->PushTarget();
408 _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
409 SQInteger jpos = _fs->GetCurrentPos();
410 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
411 Lex(); LogicalOrExp();
413 SQInteger second_exp = _fs->PopTarget();
414 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
416 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
423 for(;;) switch(_token) {
425 SQInteger first_exp = _fs->PopTarget();
426 SQInteger trg = _fs->PushTarget();
427 _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
428 SQInteger jpos = _fs->GetCurrentPos();
429 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
430 Lex(); LogicalAndExp();
432 SQInteger second_exp = _fs->PopTarget();
433 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
435 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
438 case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break;
439 case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break;
447 for(;;) if(_token == _SC('|'))
448 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
454 for(;;) if(_token == _SC('^'))
455 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
461 for(;;) if(_token == _SC('&'))
462 {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);
468 for(;;) switch(_token) {
469 case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break;
470 case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
471 case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
472 case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
473 case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
474 case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;
481 for(;;) switch(_token) {
482 case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
483 case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
484 case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
491 for(;;) switch(_token) {
492 case _SC('+'): case _SC('-'):
493 BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break;
501 for(;;) switch(_token) {
502 case _SC('*'): case _SC('/'): case _SC('%'):
503 BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break;
507 //if 'pos' != -1 the previous variable is a local variable
510 SQInteger pos = Factor();
516 if(_token == TK_PARENT) {
519 Error(_SC("parent cannot be set"));
520 SQInteger src = _fs->PopTarget();
521 _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);
524 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
525 if(NeedGet()) Emit2ArgsOP(_OP_GET);
527 _exst._deref = DEREF_FIELD;
528 _exst._freevar = false;
532 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
533 Lex(); Expression(); Expect(_SC(']'));
535 if(NeedGet()) Emit2ArgsOP(_OP_GET);
536 _exst._deref = DEREF_FIELD;
537 _exst._freevar = false;
541 if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) {
542 SQInteger tok = _token; Lex();
544 Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);
545 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
546 SQInteger src = _fs->PopTarget();
547 _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);
555 if(_exst._deref != DEREF_NO_DEREF) {
557 SQInteger key = _fs->PopTarget(); //key
558 SQInteger table = _fs->PopTarget(); //table etc...
559 SQInteger closure = _fs->PushTarget();
560 SQInteger ttarget = _fs->PushTarget();
561 _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
564 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
568 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
569 _exst._deref = DEREF_NO_DEREF;
582 case TK_STRING_LITERAL: {
583 //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));
584 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
588 case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;
589 case TK_VARGV: { Lex();
593 SQInteger src = _fs->PopTarget();
594 _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src);
600 _exst._freevar = false;
603 case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
604 case TK_THIS: id = _fs->CreateString(_SC("this")); break;
605 case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
609 if((pos = _fs->GetLocalVariable(id)) == -1) {
610 //checks if is a free variable
611 if((pos = _fs->GetOuterVariable(id)) != -1) {
612 _exst._deref = _fs->PushTarget();
613 _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);
614 _exst._freevar = true;
617 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
618 if(NeedGet()) Emit2ArgsOP(_OP_GET);
619 _exst._deref = DEREF_FIELD;
623 _fs->PushTarget(pos);
629 case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break;
630 case TK_DOUBLE_COLON: // "::"
631 _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget());
632 _exst._deref = DEREF_FIELD;
633 _token = _SC('.'); //hack
637 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
641 if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?
642 _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);
645 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));
651 if(sizeof(SQFloat) == sizeof(SQInt32)) {
652 _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue));
655 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));
659 case TK_TRUE: case TK_FALSE:
660 _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
664 _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget());
665 SQInteger apos = _fs->GetCurrentPos(),key = 0;
667 while(_token != _SC(']')) {
669 if(_token == _SC(',')) Lex();
670 SQInteger val = _fs->PopTarget();
671 SQInteger array = _fs->TopTarget();
672 _fs->AddInstruction(_OP_APPENDARRAY, array, val);
675 _fs->SetIntructionParam(apos, 1, key);
680 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
681 Lex();ParseTableOrClass(_SC(','));
684 case TK_FUNCTION: FunctionExp(_token);break;
685 case TK_CLASS: Lex(); ClassExp();break;
686 case _SC('-'): UnaryOP(_OP_NEG); break;
687 case _SC('!'): UnaryOP(_OP_NOT); break;
688 case _SC('~'): UnaryOP(_OP_BWNOT); break;
689 case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;
690 case TK_RESUME : UnaryOP(_OP_RESUME); break;
691 case TK_CLONE : UnaryOP(_OP_CLONE); break;
693 case TK_PLUSPLUS :PrefixIncDec(_token); break;
694 case TK_DELETE : DeleteExpr(); break;
695 case TK_DELEGATE : DelegateExpr(); break;
696 case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
698 default: Error(_SC("expression expected"));
702 void UnaryOP(SQOpcode op)
704 Lex(); PrefixedExpr();
705 SQInteger src = _fs->PopTarget();
706 _fs->AddInstruction(op, _fs->PushTarget(), src);
711 case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS:
712 case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:
715 return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));
718 void FunctionCallArgs()
720 SQInteger nargs = 1;//this
721 while(_token != _SC(')')) {
723 MoveIfCurrentTargetIsLocal();
725 if(_token == _SC(',')){
727 if(_token == ')') Error(_SC("expression expected, found ')'"));
731 for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
732 SQInteger stackbase = _fs->PopTarget();
733 SQInteger closure = _fs->PopTarget();
734 _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
736 void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')
738 SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
740 while(_token != terminator) {
741 bool hasattrs = false;
742 bool isstatic = false;
743 //check if is an attribute
744 if(separator == ';') {
745 if(_token == TK_ATTR_OPEN) {
746 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();
747 ParseTableOrClass(',',TK_ATTR_CLOSE);
750 if(_token == TK_STATIC) {
757 case TK_CONSTRUCTOR:{
758 SQInteger tk = _token;
760 SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
762 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
764 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
768 Lex(); CommaExpr(); Expect(_SC(']'));
769 Expect(_SC('=')); Expression();
772 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
773 Expect(_SC('=')); Expression();
776 if(_token == separator) Lex();//optional comma/semicolon
778 SQInteger val = _fs->PopTarget();
779 SQInteger key = _fs->PopTarget();
780 SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
781 assert(hasattrs && attrs == key-1 || !hasattrs);
782 unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
783 SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
784 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
787 if(separator == _SC(',')) //hack recognizes a table from the separator
788 _fs->SetIntructionParam(tpos, 1, nkeys);
791 void LocalDeclStatement()
795 Lex(); varname = Expect(TK_IDENTIFIER);
796 if(_token == _SC('=')) {
798 SQInteger src = _fs->PopTarget();
799 SQInteger dest = _fs->PushTarget();
800 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
803 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
806 _fs->PushLocalVariable(varname);
808 } while(_token == _SC(','));
813 bool haselse = false;
814 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
815 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
816 SQInteger jnepos = _fs->GetCurrentPos();
817 SQInteger stacksize = _fs->GetStackSize();
821 if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
823 CleanStack(stacksize);
824 SQInteger endifblock = _fs->GetCurrentPos();
825 if(_token == TK_ELSE){
827 stacksize = _fs->GetStackSize();
828 _fs->AddInstruction(_OP_JMP);
829 jmppos = _fs->GetCurrentPos();
831 Statement(); OptionalSemicolon();
832 CleanStack(stacksize);
833 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
835 _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
837 void WhileStatement()
839 SQInteger jzpos, jmppos;
840 SQInteger stacksize = _fs->GetStackSize();
841 jmppos = _fs->GetCurrentPos();
842 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
844 BEGIN_BREAKBLE_BLOCK();
845 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
846 jzpos = _fs->GetCurrentPos();
847 stacksize = _fs->GetStackSize();
851 CleanStack(stacksize);
852 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
853 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
855 END_BREAKBLE_BLOCK(jmppos);
857 void DoWhileStatement()
860 SQInteger jzpos = _fs->GetCurrentPos();
861 SQInteger stacksize = _fs->GetStackSize();
862 BEGIN_BREAKBLE_BLOCK()
864 CleanStack(stacksize);
866 SQInteger continuetrg = _fs->GetCurrentPos();
867 Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
868 _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1);
869 END_BREAKBLE_BLOCK(continuetrg);
874 SQInteger stacksize = _fs->GetStackSize();
876 if(_token == TK_LOCAL) LocalDeclStatement();
877 else if(_token != _SC(';')){
883 SQInteger jmppos = _fs->GetCurrentPos();
884 SQInteger jzpos = -1;
885 if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
888 SQInteger expstart = _fs->GetCurrentPos() + 1;
889 if(_token != _SC(')')) {
895 SQInteger expend = _fs->GetCurrentPos();
896 SQInteger expsize = (expend - expstart) + 1;
897 SQInstructionVec exp;
899 for(SQInteger i = 0; i < expsize; i++)
900 exp.push_back(_fs->GetInstruction(expstart + i));
901 _fs->PopInstructions(expsize);
903 BEGIN_BREAKBLE_BLOCK()
905 SQInteger continuetrg = _fs->GetCurrentPos();
907 for(SQInteger i = 0; i < expsize; i++)
908 _fs->AddInstruction(exp[i]);
910 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
911 if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
912 CleanStack(stacksize);
914 END_BREAKBLE_BLOCK(continuetrg);
916 void ForEachStatement()
918 SQObject idxname, valname;
919 Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
920 if(_token == _SC(',')) {
922 Lex(); valname = Expect(TK_IDENTIFIER);
925 idxname = _fs->CreateString(_SC("@INDEX@"));
929 //save the stack size
930 SQInteger stacksize = _fs->GetStackSize();
931 //put the table in the stack(evaluate the table expression)
932 Expression(); Expect(_SC(')'));
933 SQInteger container = _fs->TopTarget();
934 //push the index local var
935 SQInteger indexpos = _fs->PushLocalVariable(idxname);
936 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
937 //push the value local var
938 SQInteger valuepos = _fs->PushLocalVariable(valname);
939 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
940 //push reference index
941 SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
942 _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
943 SQInteger jmppos = _fs->GetCurrentPos();
944 _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
945 SQInteger foreachpos = _fs->GetCurrentPos();
946 _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
947 //generate the statement code
948 BEGIN_BREAKBLE_BLOCK()
950 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
951 _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
952 _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
953 //restore the local variable stack(remove index,val and ref idx)
954 CleanStack(stacksize);
955 END_BREAKBLE_BLOCK(foreachpos - 1);
957 void SwitchStatement()
959 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
961 SQInteger expr = _fs->TopTarget();
963 SQInteger tonextcondjmp = -1;
964 SQInteger skipcondjmp = -1;
965 SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
966 _fs->_breaktargets.push_back(0);
967 while(_token == TK_CASE) {
968 //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one
970 _fs->AddInstruction(_OP_JMP, 0, 0);
971 skipcondjmp = _fs->GetCurrentPos();
972 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
975 Lex(); Expression(); Expect(_SC(':'));
976 SQInteger trg = _fs->PopTarget();
977 _fs->AddInstruction(_OP_EQ, trg, trg, expr);
978 _fs->AddInstruction(_OP_JZ, trg, 0);
980 if(skipcondjmp != -1) {
981 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
983 tonextcondjmp = _fs->GetCurrentPos();
984 SQInteger stacksize = _fs->GetStackSize();
986 _fs->SetStackSize(stacksize);
989 if(tonextcondjmp != -1)
990 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
991 if(_token == TK_DEFAULT) {
992 // _fs->AddLineInfos(_lex._currentline, _lineinfo);
993 Lex(); Expect(_SC(':'));
994 SQInteger stacksize = _fs->GetStackSize();
996 _fs->SetStackSize(stacksize);
1000 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1001 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
1002 _fs->_breaktargets.pop_back();
1005 void FunctionStatement()
1008 Lex(); id = Expect(TK_IDENTIFIER);
1010 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1011 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1013 while(_token == TK_DOUBLE_COLON) {
1015 id = Expect(TK_IDENTIFIER);
1016 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1017 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1021 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1022 EmitDerefOp(_OP_NEWSLOT);
1025 void ClassStatement()
1028 Lex(); PushExpState();
1029 _exst._class_or_delete = true;
1030 _exst._funcarg = false;
1033 if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));
1034 if(es._deref == DEREF_FIELD) {
1036 EmitDerefOp(_OP_NEWSLOT);
1039 else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
1041 void TryCatchStatement()
1045 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
1047 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
1048 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
1049 SQInteger trappos = _fs->GetCurrentPos();
1052 _fs->AddInstruction(_OP_POPTRAP, 1, 0);
1053 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
1054 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
1055 _fs->AddInstruction(_OP_JMP, 0, 0);
1056 SQInteger jmppos = _fs->GetCurrentPos();
1057 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
1058 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
1059 SQInteger stacksize = _fs->GetStackSize();
1060 SQInteger ex_target = _fs->PushLocalVariable(exid);
1061 _fs->SetIntructionParam(trappos, 0, ex_target);
1063 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1064 CleanStack(stacksize);
1066 void FunctionExp(SQInteger ftype)
1068 Lex(); Expect(_SC('('));
1069 CreateFunction(_null_);
1070 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
1074 SQInteger base = -1;
1075 SQInteger attrs = -1;
1076 if(_token == TK_EXTENDS) {
1077 Lex(); Expression();
1078 base = _fs->TopTarget();
1080 if(_token == TK_ATTR_OPEN) {
1082 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
1083 ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
1084 attrs = _fs->TopTarget();
1087 if(attrs != -1) _fs->PopTarget();
1088 if(base != -1) _fs->PopTarget();
1089 _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);
1090 ParseTableOrClass(_SC(';'));
1097 SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();
1098 _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);
1103 Lex(); PushExpState();
1104 _exst._class_or_delete = true;
1105 _exst._funcarg = false;
1108 if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));
1109 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
1110 else Error(_SC("cannot delete a local"));
1112 void PrefixIncDec(SQInteger token)
1115 Lex(); PushExpState();
1116 _exst._class_or_delete = true;
1117 _exst._funcarg = false;
1120 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);
1122 SQInteger src = _fs->PopTarget();
1123 _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);
1126 void CreateFunction(SQObject &name)
1129 SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
1130 funcstate->_name = name;
1132 funcstate->AddParameter(_fs->CreateString(_SC("this")));
1133 funcstate->_sourcename = _sourcename;
1134 while(_token!=_SC(')')) {
1135 if(_token == TK_VARPARAMS) {
1136 funcstate->_varparams = true;
1138 if(_token != _SC(')')) Error(_SC("expected ')'"));
1142 paramname = Expect(TK_IDENTIFIER);
1143 funcstate->AddParameter(paramname);
1144 if(_token == _SC(',')) Lex();
1145 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1150 if(_token == _SC(':')) {
1151 Lex(); Expect(_SC('('));
1152 while(_token != _SC(')')) {
1153 paramname = Expect(TK_IDENTIFIER);
1154 //outers are treated as implicit local variables
1155 funcstate->AddOuterValue(paramname);
1156 if(_token == _SC(',')) Lex();
1157 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1162 SQFuncState *currchunk = _fs;
1165 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
1166 funcstate->AddInstruction(_OP_RETURN, -1);
1167 funcstate->SetStackSize(0);
1168 //_fs->->_stacksize = _fs->_stacksize;
1169 SQFunctionProto *func = funcstate->BuildProto();
1171 funcstate->Dump(func);
1174 _fs->_functions.push_back(func);
1175 _fs->PopChildState();
1177 void CleanStack(SQInteger stacksize)
1179 if(_fs->GetStackSize() != stacksize)
1180 _fs->SetStackSize(stacksize);
1182 void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
1184 while(ntoresolve > 0) {
1185 SQInteger pos = funcstate->_unresolvedbreaks.back();
1186 funcstate->_unresolvedbreaks.pop_back();
1187 //set the jmp instruction
1188 funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
1192 void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
1194 while(ntoresolve > 0) {
1195 SQInteger pos = funcstate->_unresolvedcontinues.back();
1196 funcstate->_unresolvedcontinues.pop_back();
1197 //set the jmp instruction
1198 funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
1205 SQObjectPtr _sourcename;
1209 SQInteger _debugline;
1211 ExpStateVec _expstates;
1212 SQChar *compilererror;
1217 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
1219 SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
1220 return p.Compile(out);