2 see copyright notice in squirrel.h
4 #include "sqpcheader.h"
9 #include "sqfuncproto.h"
10 #include "sqcompiler.h"
11 #include "sqfuncstate.h"
16 #define DEREF_NO_DEREF -1
17 #define DEREF_FIELD -2
23 _deref = DEREF_NO_DEREF;
25 _class_or_delete = false;
28 bool _class_or_delete;
34 typedef sqvector<ExpState> ExpStateVec;
36 #define _exst (_expstates.top())
38 #define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
39 SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
40 _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
42 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
43 __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
44 if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
45 if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
46 _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
51 SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
54 _lex.Init(_ss(v), rg, up,ThrowError,this);
55 _sourcename = SQString::Create(_ss(v), sourcename);
56 _lineinfo = lineinfo;_raiseerror = raiseerror;
59 static void ThrowError(void *ud, const SQChar *s) {
60 SQCompiler *c = (SQCompiler *)ud;
63 void Error(const SQChar *s, ...)
65 static SQChar temp[256];
68 scvsprintf(temp, s, vl);
73 void Lex(){ _token = _lex.Lex();}
74 void PushExpState(){ _expstates.push_back(ExpState()); }
75 bool IsDerefToken(SQInteger tok)
78 case _SC('='): case _SC('('): case TK_NEWSLOT:
79 case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true;
83 ExpState PopExpState()
85 ExpState ret = _expstates.top();
86 _expstates.pop_back();
89 SQObject Expect(SQInteger tok)
93 if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
94 //ret = SQString::Create(_ss(_vm),_SC("constructor"));
98 const SQChar *etypename;
103 etypename = _SC("IDENTIFIER");
105 case TK_STRING_LITERAL:
106 etypename = _SC("STRING_LITERAL");
109 etypename = _SC("INTEGER");
112 etypename = _SC("FLOAT");
115 etypename = _lex.Tok2Str(tok);
117 Error(_SC("expected '%s'"), etypename);
119 Error(_SC("expected '%c'"), tok);
126 ret = _fs->CreateString(_lex._svalue);
128 case TK_STRING_LITERAL:
129 ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
132 ret = SQObjectPtr(_lex._nvalue);
135 ret = SQObjectPtr(_lex._fvalue);
141 bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
142 void OptionalSemicolon()
144 if(_token == _SC(';')) { Lex(); return; }
145 if(!IsEndOfStatement()) {
146 Error(_SC("end of statement expected (; or lf)"));
149 void MoveIfCurrentTargetIsLocal() {
150 SQInteger trg = _fs->TopTarget();
151 if(_fs->IsLocal(trg)) {
152 trg = _fs->PopTarget(); //no pops the target and move it
153 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
156 bool Compile(SQObjectPtr &o)
161 SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
162 funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
164 _fs->AddParameter(_fs->CreateString(_SC("this")));
165 _fs->_sourcename = _sourcename;
166 SQInteger stacksize = _fs->GetStackSize();
167 if(setjmp(_errorjmp) == 0) {
171 if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
173 CleanStack(stacksize);
174 _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
175 _fs->AddInstruction(_OP_RETURN, 0xFF);
176 _fs->SetStackSize(0);
177 o =_fs->BuildProto();
179 _fs->Dump(_funcproto(o));
183 if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
184 _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
185 _lex._currentline, _lex._currentcolumn);
187 _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
194 while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
196 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
201 _fs->AddLineInfos(_lex._currentline, _lineinfo);
203 case _SC(';'): Lex(); break;
204 case TK_IF: IfStatement(); break;
205 case TK_WHILE: WhileStatement(); break;
206 case TK_DO: DoWhileStatement(); break;
207 case TK_FOR: ForStatement(); break;
208 case TK_FOREACH: ForEachStatement(); break;
209 case TK_SWITCH: SwitchStatement(); break;
210 case TK_LOCAL: LocalDeclStatement(); break;
214 if(_token == TK_RETURN) {
220 _fs->_bgenerator = true;
223 if(!IsEndOfStatement()) {
224 SQInteger retexp = _fs->GetCurrentPos()+1;
226 if(op == _OP_RETURN && _fs->_traps > 0)
227 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
228 _fs->_returnexp = retexp;
229 _fs->AddInstruction(op, 1, _fs->PopTarget());
232 if(op == _OP_RETURN && _fs->_traps > 0)
233 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
234 _fs->_returnexp = -1;
235 _fs->AddInstruction(op, 0xFF);
239 if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
240 if(_fs->_breaktargets.top() > 0){
241 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
243 _fs->AddInstruction(_OP_JMP, 0, -1234);
244 _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
248 if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
249 if(_fs->_continuetargets.top() > 0) {
250 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
252 _fs->AddInstruction(_OP_JMP, 0, -1234);
253 _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
266 SQInteger stacksize = _fs->GetStackSize();
270 _fs->SetStackSize(stacksize);
279 _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
284 SQObject id = Expect(TK_IDENTIFIER);
286 SQObject val = ExpectScalar();
288 SQTable *enums = _table(_ss(_vm)->_consts);
289 SQObjectPtr strongid = id;
290 enums->NewSlot(strongid,SQObjectPtr(val));
301 void EmitDerefOp(SQOpcode op)
303 SQInteger val = _fs->PopTarget();
304 SQInteger key = _fs->PopTarget();
305 SQInteger src = _fs->PopTarget();
306 _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
308 void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
310 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
311 SQInteger p1 = _fs->PopTarget(); //key in OP_GET
312 _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
314 void EmitCompoundArith(SQInteger tok,bool deref)
318 case TK_MINUSEQ: oper = '-'; break;
319 case TK_PLUSEQ: oper = '+'; break;
320 case TK_MULEQ: oper = '*'; break;
321 case TK_DIVEQ: oper = '/'; break;
322 case TK_MODEQ: oper = '%'; break;
323 default: oper = 0; //shut up compiler
327 SQInteger val = _fs->PopTarget();
328 SQInteger key = _fs->PopTarget();
329 SQInteger src = _fs->PopTarget();
330 //mixes dest obj and source val in the arg1(hack?)
331 _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper);
334 Emit2ArgsOP(_OP_COMPARITHL, oper);
339 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
341 ExpState Expression(bool funcarg = false)
344 _exst._class_or_delete = false;
345 _exst._funcarg = funcarg;
356 SQInteger op = _token;
357 SQInteger ds = _exst._deref;
358 bool freevar = _exst._freevar;
359 if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression"));
364 if(freevar) Error(_SC("free variables cannot be modified"));
365 if(ds == DEREF_FIELD)
366 EmitDerefOp(_OP_NEWSLOT);
367 else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
368 Error(_SC("can't 'create' a local slot"));
370 case _SC('='): //ASSIGN
371 if(freevar) Error(_SC("free variables cannot be modified"));
372 if(ds == DEREF_FIELD)
373 EmitDerefOp(_OP_SET);
374 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
375 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
376 SQInteger p1 = _fs->TopTarget(); //key in OP_GET
377 _fs->AddInstruction(_OP_MOVE, p1, p2);
385 EmitCompoundArith(op,ds == DEREF_FIELD);
392 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
393 SQInteger jzpos = _fs->GetCurrentPos();
394 SQInteger trg = _fs->PushTarget();
396 SQInteger first_exp = _fs->PopTarget();
397 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
398 SQInteger endfirstexp = _fs->GetCurrentPos();
399 _fs->AddInstruction(_OP_JMP, 0, 0);
401 SQInteger jmppos = _fs->GetCurrentPos();
403 SQInteger second_exp = _fs->PopTarget();
404 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
405 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
406 _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
411 return PopExpState();
413 void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0)
416 SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
417 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
422 for(;;) if(_token == TK_OR) {
423 SQInteger first_exp = _fs->PopTarget();
424 SQInteger trg = _fs->PushTarget();
425 _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
426 SQInteger jpos = _fs->GetCurrentPos();
427 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
428 Lex(); LogicalOrExp();
430 SQInteger second_exp = _fs->PopTarget();
431 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
433 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
440 for(;;) switch(_token) {
442 SQInteger first_exp = _fs->PopTarget();
443 SQInteger trg = _fs->PushTarget();
444 _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
445 SQInteger jpos = _fs->GetCurrentPos();
446 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
447 Lex(); LogicalAndExp();
449 SQInteger second_exp = _fs->PopTarget();
450 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
452 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
455 case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break;
456 case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break;
464 for(;;) if(_token == _SC('|'))
465 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
471 for(;;) if(_token == _SC('^'))
472 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
478 for(;;) if(_token == _SC('&'))
479 {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);
485 for(;;) switch(_token) {
486 case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break;
487 case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
488 case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
489 case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
490 case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
491 case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;
498 for(;;) switch(_token) {
499 case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
500 case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
501 case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
508 for(;;) switch(_token) {
509 case _SC('+'): case _SC('-'):
510 BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break;
518 for(;;) switch(_token) {
519 case _SC('*'): case _SC('/'): case _SC('%'):
520 BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break;
524 //if 'pos' != -1 the previous variable is a local variable
527 SQInteger pos = Factor();
533 if(_token == TK_PARENT) {
536 Error(_SC("parent cannot be set"));
537 SQInteger src = _fs->PopTarget();
538 _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);
541 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
542 if(NeedGet()) Emit2ArgsOP(_OP_GET);
544 _exst._deref = DEREF_FIELD;
545 _exst._freevar = false;
549 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
550 Lex(); Expression(); Expect(_SC(']'));
552 if(NeedGet()) Emit2ArgsOP(_OP_GET);
553 _exst._deref = DEREF_FIELD;
554 _exst._freevar = false;
558 if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) {
559 SQInteger tok = _token; Lex();
561 Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);
562 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
563 SQInteger src = _fs->PopTarget();
564 _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);
572 if(_exst._deref != DEREF_NO_DEREF) {
574 SQInteger key = _fs->PopTarget(); //key
575 SQInteger table = _fs->PopTarget(); //table etc...
576 SQInteger closure = _fs->PushTarget();
577 SQInteger ttarget = _fs->PushTarget();
578 _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
581 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
585 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
586 _exst._deref = DEREF_NO_DEREF;
599 case TK_STRING_LITERAL: {
600 //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));
601 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
605 case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;
606 case TK_VARGV: { Lex();
610 SQInteger src = _fs->PopTarget();
611 _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src);
617 _exst._freevar = false;
621 case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
622 case TK_THIS: id = _fs->CreateString(_SC("this")); break;
623 case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
627 if((pos = _fs->GetLocalVariable(id)) == -1) {
628 //checks if is a free variable
629 if((pos = _fs->GetOuterVariable(id)) != -1) {
630 _exst._deref = _fs->PushTarget();
631 _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);
632 _exst._freevar = true;
634 else if(_fs->IsConstant(id,constant)) { //line 634
635 SQObjectPtr constval;
637 if(type(constant) == OT_TABLE) {
638 Expect('.'); constid = Expect(TK_IDENTIFIER);
639 if(!_table(constant)->Get(constid,constval)) {
641 Error(_SC("invalid constant [%s.%s]"), _stringval(id),_stringval(constid));
647 _exst._deref = _fs->PushTarget();
648 SQObjectType ctype = type(constval);
649 if(ctype == OT_INTEGER && (_integer(constval) & (~0x7FFFFFFF)) == 0) {
650 _fs->AddInstruction(_OP_LOADINT, _exst._deref,_integer(constval));
652 else if(ctype == OT_FLOAT && sizeof(SQFloat) == sizeof(SQInt32)) {
653 SQFloat f = _float(constval);
654 _fs->AddInstruction(_OP_LOADFLOAT, _exst._deref,*((SQInt32 *)&f));
657 _fs->AddInstruction(_OP_LOAD, _exst._deref, _fs->GetConstant(constval));
660 _exst._freevar = true;
664 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
665 if(NeedGet()) Emit2ArgsOP(_OP_GET);
666 _exst._deref = DEREF_FIELD;
671 _fs->PushTarget(pos);
677 case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break;
678 case TK_DOUBLE_COLON: // "::"
679 _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget());
680 _exst._deref = DEREF_FIELD;
681 _token = _SC('.'); //hack
685 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
689 if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?
690 _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);
693 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));
699 if(sizeof(SQFloat) == sizeof(SQInt32)) {
700 _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue));
703 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));
707 case TK_TRUE: case TK_FALSE:
708 _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
712 _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget());
713 SQInteger apos = _fs->GetCurrentPos(),key = 0;
715 while(_token != _SC(']')) {
717 if(_token == _SC(',')) Lex();
718 SQInteger val = _fs->PopTarget();
719 SQInteger array = _fs->TopTarget();
720 _fs->AddInstruction(_OP_APPENDARRAY, array, val);
723 _fs->SetIntructionParam(apos, 1, key);
728 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
729 Lex();ParseTableOrClass(_SC(','));
732 case TK_FUNCTION: FunctionExp(_token);break;
733 case TK_CLASS: Lex(); ClassExp();break;
734 case _SC('-'): UnaryOP(_OP_NEG); break;
735 case _SC('!'): UnaryOP(_OP_NOT); break;
736 case _SC('~'): UnaryOP(_OP_BWNOT); break;
737 case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;
738 case TK_RESUME : UnaryOP(_OP_RESUME); break;
739 case TK_CLONE : UnaryOP(_OP_CLONE); break;
741 case TK_PLUSPLUS :PrefixIncDec(_token); break;
742 case TK_DELETE : DeleteExpr(); break;
743 case TK_DELEGATE : DelegateExpr(); break;
744 case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
746 default: Error(_SC("expression expected"));
750 void UnaryOP(SQOpcode op)
752 Lex(); PrefixedExpr();
753 SQInteger src = _fs->PopTarget();
754 _fs->AddInstruction(op, _fs->PushTarget(), src);
759 case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS:
760 case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:
763 return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));
766 void FunctionCallArgs()
768 SQInteger nargs = 1;//this
769 while(_token != _SC(')')) {
771 MoveIfCurrentTargetIsLocal();
773 if(_token == _SC(',')){
775 if(_token == ')') Error(_SC("expression expected, found ')'"));
779 for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
780 SQInteger stackbase = _fs->PopTarget();
781 SQInteger closure = _fs->PopTarget();
782 _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
784 void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')
786 SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
788 while(_token != terminator) {
789 bool hasattrs = false;
790 bool isstatic = false;
791 //check if is an attribute
792 if(separator == ';') {
793 if(_token == TK_ATTR_OPEN) {
794 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();
795 ParseTableOrClass(',',TK_ATTR_CLOSE);
798 if(_token == TK_STATIC) {
805 case TK_CONSTRUCTOR:{
806 SQInteger tk = _token;
808 SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
810 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
812 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
816 Lex(); CommaExpr(); Expect(_SC(']'));
817 Expect(_SC('=')); Expression();
820 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
821 Expect(_SC('=')); Expression();
824 if(_token == separator) Lex();//optional comma/semicolon
826 SQInteger val = _fs->PopTarget();
827 SQInteger key = _fs->PopTarget();
828 SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
829 assert(hasattrs && attrs == key-1 || !hasattrs);
830 unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
831 SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
832 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
835 if(separator == _SC(',')) //hack recognizes a table from the separator
836 _fs->SetIntructionParam(tpos, 1, nkeys);
839 void LocalDeclStatement()
843 Lex(); varname = Expect(TK_IDENTIFIER);
844 if(_token == _SC('=')) {
846 SQInteger src = _fs->PopTarget();
847 SQInteger dest = _fs->PushTarget();
848 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
851 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
854 _fs->PushLocalVariable(varname);
856 } while(_token == _SC(','));
861 bool haselse = false;
862 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
863 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
864 SQInteger jnepos = _fs->GetCurrentPos();
865 SQInteger stacksize = _fs->GetStackSize();
869 if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
871 CleanStack(stacksize);
872 SQInteger endifblock = _fs->GetCurrentPos();
873 if(_token == TK_ELSE){
875 stacksize = _fs->GetStackSize();
876 _fs->AddInstruction(_OP_JMP);
877 jmppos = _fs->GetCurrentPos();
879 Statement(); OptionalSemicolon();
880 CleanStack(stacksize);
881 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
883 _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
885 void WhileStatement()
887 SQInteger jzpos, jmppos;
888 SQInteger stacksize = _fs->GetStackSize();
889 jmppos = _fs->GetCurrentPos();
890 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
892 BEGIN_BREAKBLE_BLOCK();
893 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
894 jzpos = _fs->GetCurrentPos();
895 stacksize = _fs->GetStackSize();
899 CleanStack(stacksize);
900 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
901 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
903 END_BREAKBLE_BLOCK(jmppos);
905 void DoWhileStatement()
908 SQInteger jzpos = _fs->GetCurrentPos();
909 SQInteger stacksize = _fs->GetStackSize();
910 BEGIN_BREAKBLE_BLOCK()
912 CleanStack(stacksize);
914 SQInteger continuetrg = _fs->GetCurrentPos();
915 Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
916 _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1);
917 END_BREAKBLE_BLOCK(continuetrg);
922 SQInteger stacksize = _fs->GetStackSize();
924 if(_token == TK_LOCAL) LocalDeclStatement();
925 else if(_token != _SC(';')){
931 SQInteger jmppos = _fs->GetCurrentPos();
932 SQInteger jzpos = -1;
933 if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
936 SQInteger expstart = _fs->GetCurrentPos() + 1;
937 if(_token != _SC(')')) {
943 SQInteger expend = _fs->GetCurrentPos();
944 SQInteger expsize = (expend - expstart) + 1;
945 SQInstructionVec exp;
947 for(SQInteger i = 0; i < expsize; i++)
948 exp.push_back(_fs->GetInstruction(expstart + i));
949 _fs->PopInstructions(expsize);
951 BEGIN_BREAKBLE_BLOCK()
953 SQInteger continuetrg = _fs->GetCurrentPos();
955 for(SQInteger i = 0; i < expsize; i++)
956 _fs->AddInstruction(exp[i]);
958 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
959 if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
960 CleanStack(stacksize);
962 END_BREAKBLE_BLOCK(continuetrg);
964 void ForEachStatement()
966 SQObject idxname, valname;
967 Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
968 if(_token == _SC(',')) {
970 Lex(); valname = Expect(TK_IDENTIFIER);
973 idxname = _fs->CreateString(_SC("@INDEX@"));
977 //save the stack size
978 SQInteger stacksize = _fs->GetStackSize();
979 //put the table in the stack(evaluate the table expression)
980 Expression(); Expect(_SC(')'));
981 SQInteger container = _fs->TopTarget();
982 //push the index local var
983 SQInteger indexpos = _fs->PushLocalVariable(idxname);
984 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
985 //push the value local var
986 SQInteger valuepos = _fs->PushLocalVariable(valname);
987 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
988 //push reference index
989 SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
990 _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
991 SQInteger jmppos = _fs->GetCurrentPos();
992 _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
993 SQInteger foreachpos = _fs->GetCurrentPos();
994 _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
995 //generate the statement code
996 BEGIN_BREAKBLE_BLOCK()
998 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
999 _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
1000 _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
1001 //restore the local variable stack(remove index,val and ref idx)
1002 CleanStack(stacksize);
1003 END_BREAKBLE_BLOCK(foreachpos - 1);
1005 void SwitchStatement()
1007 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1009 SQInteger expr = _fs->TopTarget();
1011 SQInteger tonextcondjmp = -1;
1012 SQInteger skipcondjmp = -1;
1013 SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
1014 _fs->_breaktargets.push_back(0);
1015 while(_token == TK_CASE) {
1016 //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one
1018 _fs->AddInstruction(_OP_JMP, 0, 0);
1019 skipcondjmp = _fs->GetCurrentPos();
1020 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1023 Lex(); Expression(); Expect(_SC(':'));
1024 SQInteger trg = _fs->PopTarget();
1025 _fs->AddInstruction(_OP_EQ, trg, trg, expr);
1026 _fs->AddInstruction(_OP_JZ, trg, 0);
1028 if(skipcondjmp != -1) {
1029 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
1031 tonextcondjmp = _fs->GetCurrentPos();
1032 SQInteger stacksize = _fs->GetStackSize();
1034 _fs->SetStackSize(stacksize);
1037 if(tonextcondjmp != -1)
1038 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1039 if(_token == TK_DEFAULT) {
1040 // _fs->AddLineInfos(_lex._currentline, _lineinfo);
1041 Lex(); Expect(_SC(':'));
1042 SQInteger stacksize = _fs->GetStackSize();
1044 _fs->SetStackSize(stacksize);
1048 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1049 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
1050 _fs->_breaktargets.pop_back();
1053 void FunctionStatement()
1056 Lex(); id = Expect(TK_IDENTIFIER);
1058 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1059 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1061 while(_token == TK_DOUBLE_COLON) {
1063 id = Expect(TK_IDENTIFIER);
1064 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1065 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1069 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1070 EmitDerefOp(_OP_NEWSLOT);
1073 void ClassStatement()
1076 Lex(); PushExpState();
1077 _exst._class_or_delete = true;
1078 _exst._funcarg = false;
1081 if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));
1082 if(es._deref == DEREF_FIELD) {
1084 EmitDerefOp(_OP_NEWSLOT);
1087 else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
1089 SQObject ExpectScalar()
1094 val._type = OT_INTEGER;
1095 val._unVal.nInteger = _lex._nvalue;
1098 val._type = OT_FLOAT;
1099 val._unVal.fFloat = _lex._fvalue;
1101 case TK_STRING_LITERAL:
1102 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
1109 val._type = OT_INTEGER;
1110 val._unVal.nInteger = -_lex._nvalue;
1113 val._type = OT_FLOAT;
1114 val._unVal.fFloat = -_lex._fvalue;
1117 Error(_SC("scalar expected : integer,float"));
1121 Error(_SC("scalar expected : integer,float or string"));
1126 void EnumStatement()
1130 SQObject id = Expect(TK_IDENTIFIER);
1133 SQObject table = _fs->CreateTable();
1135 while(_token != _SC('}')) {
1136 SQObject key = Expect(TK_IDENTIFIER);
1138 if(_token == _SC('=')) {
1140 val = ExpectScalar();
1143 val._type = OT_INTEGER;
1144 val._unVal.nInteger = nval++;
1146 _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
1147 if(_token == ',') Lex();
1149 SQTable *enums = _table(_ss(_vm)->_consts);
1150 SQObjectPtr strongid = id;
1151 /*SQObjectPtr dummy;
1152 if(enums->Get(strongid,dummy)) {
1153 dummy.Null(); strongid.Null();
1154 Error(_SC("enumeration already exists"));
1156 enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
1161 void TryCatchStatement()
1165 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
1167 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
1168 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
1169 SQInteger trappos = _fs->GetCurrentPos();
1172 _fs->AddInstruction(_OP_POPTRAP, 1, 0);
1173 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
1174 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
1175 _fs->AddInstruction(_OP_JMP, 0, 0);
1176 SQInteger jmppos = _fs->GetCurrentPos();
1177 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
1178 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
1179 SQInteger stacksize = _fs->GetStackSize();
1180 SQInteger ex_target = _fs->PushLocalVariable(exid);
1181 _fs->SetIntructionParam(trappos, 0, ex_target);
1183 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1184 CleanStack(stacksize);
1186 void FunctionExp(SQInteger ftype)
1188 Lex(); Expect(_SC('('));
1189 CreateFunction(_null_);
1190 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
1194 SQInteger base = -1;
1195 SQInteger attrs = -1;
1196 if(_token == TK_EXTENDS) {
1197 Lex(); Expression();
1198 base = _fs->TopTarget();
1200 if(_token == TK_ATTR_OPEN) {
1202 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
1203 ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
1204 attrs = _fs->TopTarget();
1207 if(attrs != -1) _fs->PopTarget();
1208 if(base != -1) _fs->PopTarget();
1209 _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);
1210 ParseTableOrClass(_SC(';'));
1217 SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();
1218 _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);
1223 Lex(); PushExpState();
1224 _exst._class_or_delete = true;
1225 _exst._funcarg = false;
1228 if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));
1229 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
1230 else Error(_SC("cannot delete a local"));
1232 void PrefixIncDec(SQInteger token)
1235 Lex(); PushExpState();
1236 _exst._class_or_delete = true;
1237 _exst._funcarg = false;
1240 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);
1242 SQInteger src = _fs->PopTarget();
1243 _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);
1246 void CreateFunction(SQObject &name)
1249 SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
1250 funcstate->_name = name;
1252 funcstate->AddParameter(_fs->CreateString(_SC("this")));
1253 funcstate->_sourcename = _sourcename;
1254 SQInteger defparams = 0;
1255 while(_token!=_SC(')')) {
1256 if(_token == TK_VARPARAMS) {
1257 if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
1258 funcstate->_varparams = true;
1260 if(_token != _SC(')')) Error(_SC("expected ')'"));
1264 paramname = Expect(TK_IDENTIFIER);
1265 funcstate->AddParameter(paramname);
1266 if(_token == _SC('=')) {
1269 funcstate->AddDefaultParam(_fs->TopTarget());
1273 if(defparams > 0) Error(_SC("expected '='"));
1275 if(_token == _SC(',')) Lex();
1276 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1280 for(SQInteger n = 0; n < defparams; n++) {
1284 if(_token == _SC(':')) {
1285 Lex(); Expect(_SC('('));
1286 while(_token != _SC(')')) {
1287 paramname = Expect(TK_IDENTIFIER);
1288 //outers are treated as implicit local variables
1289 funcstate->AddOuterValue(paramname);
1290 if(_token == _SC(',')) Lex();
1291 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1296 SQFuncState *currchunk = _fs;
1299 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
1300 funcstate->AddInstruction(_OP_RETURN, -1);
1301 funcstate->SetStackSize(0);
1302 //_fs->->_stacksize = _fs->_stacksize;
1303 SQFunctionProto *func = funcstate->BuildProto();
1305 funcstate->Dump(func);
1308 _fs->_functions.push_back(func);
1309 _fs->PopChildState();
1311 void CleanStack(SQInteger stacksize)
1313 if(_fs->GetStackSize() != stacksize)
1314 _fs->SetStackSize(stacksize);
1316 void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
1318 while(ntoresolve > 0) {
1319 SQInteger pos = funcstate->_unresolvedbreaks.back();
1320 funcstate->_unresolvedbreaks.pop_back();
1321 //set the jmp instruction
1322 funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
1326 void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
1328 while(ntoresolve > 0) {
1329 SQInteger pos = funcstate->_unresolvedcontinues.back();
1330 funcstate->_unresolvedcontinues.pop_back();
1331 //set the jmp instruction
1332 funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
1339 SQObjectPtr _sourcename;
1343 SQInteger _debugline;
1345 ExpStateVec _expstates;
1346 SQChar *compilererror;
1351 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
1353 SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
1354 return p.Compile(out);