0001
0002
0003
0004 #include "pspcheader.h"
0005 #ifndef NO_COMPILER
0006 #include <stdarg.h>
0007 #include <setjmp.h>
0008 #include "psopcodes.h"
0009 #include "psstring.h"
0010 #include "psfuncproto.h"
0011 #include "pscompiler.h"
0012 #include "psfuncstate.h"
0013 #include "pslexer.h"
0014 #include "psvm.h"
0015 #include "pstable.h"
0016
0017 #define EXPR 1
0018 #define OBJECT 2
0019 #define BASE 3
0020 #define LOCAL 4
0021 #define OUTER 5
0022
0023 struct PSExpState {
0024 PSInteger etype;
0025 PSInteger epos;
0026 bool donot_get;
0027 };
0028
0029 #define MAX_COMPILER_ERROR_LEN 256
0030
0031 struct PSScope {
0032 PSInteger outers;
0033 PSInteger stacksize;
0034 };
0035
0036 #define BEGIN_SCOPE() PSScope __oldscope__ = _scope; \
0037 _scope.outers = _fs->_outers; \
0038 _scope.stacksize = _fs->GetStackSize();
0039
0040 #define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \
0041 if(_fs->CountOuters(_scope.stacksize)) { \
0042 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
0043 } \
0044 }
0045
0046 #define END_SCOPE_NO_CLOSE() { if(_fs->GetStackSize() != _scope.stacksize) { \
0047 _fs->SetStackSize(_scope.stacksize); \
0048 } \
0049 _scope = __oldscope__; \
0050 }
0051
0052 #define END_SCOPE() { PSInteger oldouters = _fs->_outers;\
0053 if(_fs->GetStackSize() != _scope.stacksize) { \
0054 _fs->SetStackSize(_scope.stacksize); \
0055 if(oldouters != _fs->_outers) { \
0056 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
0057 } \
0058 } \
0059 _scope = __oldscope__; \
0060 }
0061
0062 #define BEGIN_BREAKBLE_BLOCK() PSInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
0063 PSInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
0064 _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
0065
0066 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
0067 __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
0068 if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
0069 if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
0070 _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
0071
0072 class PSCompiler
0073 {
0074 public:
0075 PSCompiler(PSVM *v, PSLEXREADFUNC rg, PSUserPointer up, const PSChar* sourcename, bool raiseerror, bool lineinfo)
0076 {
0077 _vm=v;
0078 _lex.Init(_ss(v), rg, up,ThrowError,this);
0079 _sourcename = PSString::Create(_ss(v), sourcename);
0080 _lineinfo = lineinfo;_raiseerror = raiseerror;
0081 _scope.outers = 0;
0082 _scope.stacksize = 0;
0083 _compilererror[0] = _SC('\0');
0084 }
0085 static void ThrowError(void *ud, const PSChar *s) {
0086 PSCompiler *c = (PSCompiler *)ud;
0087 c->Error(s);
0088 }
0089 void Error(const PSChar *s, ...)
0090 {
0091 va_list vl;
0092 va_start(vl, s);
0093 scvsprintf(_compilererror, MAX_COMPILER_ERROR_LEN, s, vl);
0094 va_end(vl);
0095 longjmp(_errorjmp,1);
0096 }
0097 void Lex(){ _token = _lex.Lex();}
0098 PSObject Expect(PSInteger tok)
0099 {
0100
0101 if(_token != tok) {
0102 if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
0103
0104 }
0105 else {
0106 const PSChar *etypename;
0107 if(tok > 255) {
0108 switch(tok)
0109 {
0110 case TK_IDENTIFIER:
0111 etypename = _SC("IDENTIFIER");
0112 break;
0113 case TK_STRING_LITERAL:
0114 etypename = _SC("STRING_LITERAL");
0115 break;
0116 case TK_INTEGER:
0117 etypename = _SC("INTEGER");
0118 break;
0119 case TK_FLOAT:
0120 etypename = _SC("FLOAT");
0121 break;
0122 default:
0123 etypename = _lex.Tok2Str(tok);
0124 }
0125 Error(_SC("expected '%s'"), etypename);
0126 }
0127 Error(_SC("expected '%c'"), tok);
0128 }
0129 }
0130 PSObjectPtr ret;
0131 switch(tok)
0132 {
0133 case TK_IDENTIFIER:
0134 ret = _fs->CreateString(_lex._svalue);
0135 break;
0136 case TK_STRING_LITERAL:
0137 ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
0138 break;
0139 case TK_INTEGER:
0140 ret = PSObjectPtr(_lex._nvalue);
0141 break;
0142 case TK_FLOAT:
0143 ret = PSObjectPtr(_lex._fvalue);
0144 break;
0145 }
0146 Lex();
0147 return ret;
0148 }
0149 bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == PSCRIPT_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
0150 void OptionalSemicolon()
0151 {
0152 if(_token == _SC(';')) { Lex(); return; }
0153 if(!IsEndOfStatement()) {
0154 Error(_SC("end of statement expected (; or lf)"));
0155 }
0156 }
0157 void MoveIfCurrentTargetIsLocal() {
0158 PSInteger trg = _fs->TopTarget();
0159 if(_fs->IsLocal(trg)) {
0160 trg = _fs->PopTarget();
0161 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
0162 }
0163 }
0164 bool Compile(PSObjectPtr &o)
0165 {
0166 _debugline = 1;
0167 _debugop = 0;
0168
0169 PSFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
0170 funcstate._name = PSString::Create(_ss(_vm), _SC("main"));
0171 _fs = &funcstate;
0172 _fs->AddParameter(_fs->CreateString(_SC("this")));
0173 _fs->AddParameter(_fs->CreateString(_SC("vargv")));
0174 _fs->_varparams = true;
0175 _fs->_sourcename = _sourcename;
0176 PSInteger stacksize = _fs->GetStackSize();
0177 if(setjmp(_errorjmp) == 0) {
0178 Lex();
0179 while(_token > 0){
0180 Statement();
0181 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
0182 }
0183 _fs->SetStackSize(stacksize);
0184 _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
0185 _fs->AddInstruction(_OP_RETURN, 0xFF);
0186 _fs->SetStackSize(0);
0187 o =_fs->BuildProto();
0188 #ifdef _DEBUG_DUMP
0189 _fs->Dump(_funcproto(o));
0190 #endif
0191 }
0192 else {
0193 if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
0194 _ss(_vm)->_compilererrorhandler(_vm, _compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
0195 _lex._currentline, _lex._currentcolumn);
0196 }
0197 _vm->_lasterror = PSString::Create(_ss(_vm), _compilererror, -1);
0198 return false;
0199 }
0200 return true;
0201 }
0202 void Statements()
0203 {
0204 while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
0205 Statement();
0206 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
0207 }
0208 }
0209 void Statement(bool closeframe = true)
0210 {
0211 _fs->AddLineInfos(_lex._currentline, _lineinfo);
0212 switch(_token){
0213 case _SC(';'): Lex(); break;
0214 case TK_IF: IfStatement(); break;
0215 case TK_WHILE: WhileStatement(); break;
0216 case TK_DO: DoWhileStatement(); break;
0217 case TK_FOR: ForStatement(); break;
0218 case TK_FOREACH: ForEachStatement(); break;
0219 case TK_SWITCH: SwitchStatement(); break;
0220 case TK_LOCAL: LocalDeclStatement(); break;
0221 case TK_RETURN:
0222 case TK_YIELD: {
0223 PSOpcode op;
0224 if(_token == TK_RETURN) {
0225 op = _OP_RETURN;
0226 }
0227 else {
0228 op = _OP_YIELD;
0229 _fs->_bgenerator = true;
0230 }
0231 Lex();
0232 if(!IsEndOfStatement()) {
0233 PSInteger retexp = _fs->GetCurrentPos()+1;
0234 CommaExpr();
0235 if(op == _OP_RETURN && _fs->_traps > 0)
0236 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
0237 _fs->_returnexp = retexp;
0238 _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());
0239 }
0240 else{
0241 if(op == _OP_RETURN && _fs->_traps > 0)
0242 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
0243 _fs->_returnexp = -1;
0244 _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize());
0245 }
0246 break;}
0247 case TK_BREAK:
0248 if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
0249 if(_fs->_breaktargets.top() > 0){
0250 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
0251 }
0252 RESOLVE_OUTERS();
0253 _fs->AddInstruction(_OP_JMP, 0, -1234);
0254 _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
0255 Lex();
0256 break;
0257 case TK_CONTINUE:
0258 if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
0259 if(_fs->_continuetargets.top() > 0) {
0260 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
0261 }
0262 RESOLVE_OUTERS();
0263 _fs->AddInstruction(_OP_JMP, 0, -1234);
0264 _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
0265 Lex();
0266 break;
0267 case TK_FUNCTION:
0268 FunctionStatement();
0269 break;
0270 case TK_CLASS:
0271 ClassStatement();
0272 break;
0273 case TK_ENUM:
0274 EnumStatement();
0275 break;
0276 case _SC('{'):{
0277 BEGIN_SCOPE();
0278 Lex();
0279 Statements();
0280 Expect(_SC('}'));
0281 if(closeframe) {
0282 END_SCOPE();
0283 }
0284 else {
0285 END_SCOPE_NO_CLOSE();
0286 }
0287 }
0288 break;
0289 case TK_TRY:
0290 TryCatchStatement();
0291 break;
0292 case TK_THROW:
0293 Lex();
0294 CommaExpr();
0295 _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
0296 break;
0297 case TK_CONST:
0298 {
0299 Lex();
0300 PSObject id = Expect(TK_IDENTIFIER);
0301 Expect('=');
0302 PSObject val = ExpectScalar();
0303 OptionalSemicolon();
0304 PSTable *enums = _table(_ss(_vm)->_consts);
0305 PSObjectPtr strongid = id;
0306 enums->NewSlot(strongid,PSObjectPtr(val));
0307 strongid.Null();
0308 }
0309 break;
0310 default:
0311 CommaExpr();
0312 _fs->DiscardTarget();
0313
0314 break;
0315 }
0316 _fs->SnoozeOpt();
0317 }
0318 void EmitDerefOp(PSOpcode op)
0319 {
0320 PSInteger val = _fs->PopTarget();
0321 PSInteger key = _fs->PopTarget();
0322 PSInteger src = _fs->PopTarget();
0323 _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
0324 }
0325 void Emit2ArgsOP(PSOpcode op, PSInteger p3 = 0)
0326 {
0327 PSInteger p2 = _fs->PopTarget();
0328 PSInteger p1 = _fs->PopTarget();
0329 _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
0330 }
0331 void EmitCompoundArith(PSInteger tok, PSInteger etype, PSInteger pos)
0332 {
0333
0334 switch(etype) {
0335 case LOCAL:{
0336 PSInteger p2 = _fs->PopTarget();
0337 PSInteger p1 = _fs->PopTarget();
0338 _fs->PushTarget(p1);
0339
0340 _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
0341 _fs->SnoozeOpt();
0342 }
0343 break;
0344 case OBJECT:
0345 case BASE:
0346 {
0347 PSInteger val = _fs->PopTarget();
0348 PSInteger key = _fs->PopTarget();
0349 PSInteger src = _fs->PopTarget();
0350
0351 _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));
0352 }
0353 break;
0354 case OUTER:
0355 {
0356 PSInteger val = _fs->TopTarget();
0357 PSInteger tmp = _fs->PushTarget();
0358 _fs->AddInstruction(_OP_GETOUTER, tmp, pos);
0359 _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
0360 _fs->PopTarget();
0361 _fs->PopTarget();
0362 _fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp);
0363 }
0364 break;
0365 }
0366 }
0367 void CommaExpr()
0368 {
0369 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
0370 }
0371 void Expression()
0372 {
0373 PSExpState es = _es;
0374 _es.etype = EXPR;
0375 _es.epos = -1;
0376 _es.donot_get = false;
0377 LogicalOrExp();
0378 switch(_token) {
0379 case _SC('='):
0380 case TK_NEWSLOT:
0381 case TK_MINUSEQ:
0382 case TK_PLUSEQ:
0383 case TK_MULEQ:
0384 case TK_DIVEQ:
0385 case TK_MODEQ:{
0386 PSInteger op = _token;
0387 PSInteger ds = _es.etype;
0388 PSInteger pos = _es.epos;
0389 if(ds == EXPR) Error(_SC("can't assign expression"));
0390 else if(ds == BASE) Error(_SC("'base' cannot be modified"));
0391 Lex(); Expression();
0392
0393 switch(op){
0394 case TK_NEWSLOT:
0395 if(ds == OBJECT || ds == BASE)
0396 EmitDerefOp(_OP_NEWSLOT);
0397 else
0398 Error(_SC("can't 'create' a local slot"));
0399 break;
0400 case _SC('='):
0401 switch(ds) {
0402 case LOCAL:
0403 {
0404 PSInteger src = _fs->PopTarget();
0405 PSInteger dst = _fs->TopTarget();
0406 _fs->AddInstruction(_OP_MOVE, dst, src);
0407 }
0408 break;
0409 case OBJECT:
0410 case BASE:
0411 EmitDerefOp(_OP_SET);
0412 break;
0413 case OUTER:
0414 {
0415 PSInteger src = _fs->PopTarget();
0416 PSInteger dst = _fs->PushTarget();
0417 _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
0418 }
0419 }
0420 break;
0421 case TK_MINUSEQ:
0422 case TK_PLUSEQ:
0423 case TK_MULEQ:
0424 case TK_DIVEQ:
0425 case TK_MODEQ:
0426 EmitCompoundArith(op, ds, pos);
0427 break;
0428 }
0429 }
0430 break;
0431 case _SC('?'): {
0432 Lex();
0433 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
0434 PSInteger jzpos = _fs->GetCurrentPos();
0435 PSInteger trg = _fs->PushTarget();
0436 Expression();
0437 PSInteger first_exp = _fs->PopTarget();
0438 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
0439 PSInteger endfirstexp = _fs->GetCurrentPos();
0440 _fs->AddInstruction(_OP_JMP, 0, 0);
0441 Expect(_SC(':'));
0442 PSInteger jmppos = _fs->GetCurrentPos();
0443 Expression();
0444 PSInteger second_exp = _fs->PopTarget();
0445 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
0446 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
0447 _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
0448 _fs->SnoozeOpt();
0449 }
0450 break;
0451 }
0452 _es = es;
0453 }
0454 template<typename T> void INVOKE_EXP(T f)
0455 {
0456 PSExpState es = _es;
0457 _es.etype = EXPR;
0458 _es.epos = -1;
0459 _es.donot_get = false;
0460 (this->*f)();
0461 _es = es;
0462 }
0463 template<typename T> void BIN_EXP(PSOpcode op, T f,PSInteger op3 = 0)
0464 {
0465 Lex();
0466 INVOKE_EXP(f);
0467 PSInteger op1 = _fs->PopTarget();PSInteger op2 = _fs->PopTarget();
0468 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
0469 }
0470 void LogicalOrExp()
0471 {
0472 LogicalAndExp();
0473 for(;;) if(_token == TK_OR) {
0474 PSInteger first_exp = _fs->PopTarget();
0475 PSInteger trg = _fs->PushTarget();
0476 _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
0477 PSInteger jpos = _fs->GetCurrentPos();
0478 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
0479 Lex(); INVOKE_EXP(&PSCompiler::LogicalOrExp);
0480 _fs->SnoozeOpt();
0481 PSInteger second_exp = _fs->PopTarget();
0482 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
0483 _fs->SnoozeOpt();
0484 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
0485 break;
0486 }else return;
0487 }
0488 void LogicalAndExp()
0489 {
0490 BitwiseOrExp();
0491 for(;;) switch(_token) {
0492 case TK_AND: {
0493 PSInteger first_exp = _fs->PopTarget();
0494 PSInteger trg = _fs->PushTarget();
0495 _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
0496 PSInteger jpos = _fs->GetCurrentPos();
0497 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
0498 Lex(); INVOKE_EXP(&PSCompiler::LogicalAndExp);
0499 _fs->SnoozeOpt();
0500 PSInteger second_exp = _fs->PopTarget();
0501 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
0502 _fs->SnoozeOpt();
0503 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
0504 break;
0505 }
0506
0507 default:
0508 return;
0509 }
0510 }
0511 void BitwiseOrExp()
0512 {
0513 BitwiseXorExp();
0514 for(;;) if(_token == _SC('|'))
0515 {BIN_EXP(_OP_BITW, &PSCompiler::BitwiseXorExp,BW_OR);
0516 }else return;
0517 }
0518 void BitwiseXorExp()
0519 {
0520 BitwiseAndExp();
0521 for(;;) if(_token == _SC('^'))
0522 {BIN_EXP(_OP_BITW, &PSCompiler::BitwiseAndExp,BW_XOR);
0523 }else return;
0524 }
0525 void BitwiseAndExp()
0526 {
0527 EqExp();
0528 for(;;) if(_token == _SC('&'))
0529 {BIN_EXP(_OP_BITW, &PSCompiler::EqExp,BW_AND);
0530 }else return;
0531 }
0532 void EqExp()
0533 {
0534 CompExp();
0535 for(;;) switch(_token) {
0536 case TK_EQ: BIN_EXP(_OP_EQ, &PSCompiler::CompExp); break;
0537 case TK_NE: BIN_EXP(_OP_NE, &PSCompiler::CompExp); break;
0538 case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &PSCompiler::CompExp,CMP_3W); break;
0539 default: return;
0540 }
0541 }
0542 void CompExp()
0543 {
0544 ShiftExp();
0545 for(;;) switch(_token) {
0546 case _SC('>'): BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_G); break;
0547 case _SC('<'): BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_L); break;
0548 case TK_GE: BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_GE); break;
0549 case TK_LE: BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_LE); break;
0550 case TK_IN: BIN_EXP(_OP_EXISTS, &PSCompiler::ShiftExp); break;
0551 case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &PSCompiler::ShiftExp); break;
0552 default: return;
0553 }
0554 }
0555 void ShiftExp()
0556 {
0557 PlusExp();
0558 for(;;) switch(_token) {
0559 case TK_USHIFTR: BIN_EXP(_OP_BITW, &PSCompiler::PlusExp,BW_USHIFTR); break;
0560 case TK_SHIFTL: BIN_EXP(_OP_BITW, &PSCompiler::PlusExp,BW_SHIFTL); break;
0561 case TK_SHIFTR: BIN_EXP(_OP_BITW, &PSCompiler::PlusExp,BW_SHIFTR); break;
0562 default: return;
0563 }
0564 }
0565 PSOpcode ChooseArithOpByToken(PSInteger tok)
0566 {
0567 switch(tok) {
0568 case TK_PLUSEQ: case '+': return _OP_ADD;
0569 case TK_MINUSEQ: case '-': return _OP_SUB;
0570 case TK_MULEQ: case '*': return _OP_MUL;
0571 case TK_DIVEQ: case '/': return _OP_DIV;
0572 case TK_MODEQ: case '%': return _OP_MOD;
0573 default: assert(0);
0574 }
0575 return _OP_ADD;
0576 }
0577 PSInteger ChooseCompArithCharByToken(PSInteger tok)
0578 {
0579 PSInteger oper;
0580 switch(tok){
0581 case TK_MINUSEQ: oper = '-'; break;
0582 case TK_PLUSEQ: oper = '+'; break;
0583 case TK_MULEQ: oper = '*'; break;
0584 case TK_DIVEQ: oper = '/'; break;
0585 case TK_MODEQ: oper = '%'; break;
0586 default: oper = 0;
0587 assert(0); break;
0588 };
0589 return oper;
0590 }
0591 void PlusExp()
0592 {
0593 MultExp();
0594 for(;;) switch(_token) {
0595 case _SC('+'): case _SC('-'):
0596 BIN_EXP(ChooseArithOpByToken(_token), &PSCompiler::MultExp); break;
0597 default: return;
0598 }
0599 }
0600
0601 void MultExp()
0602 {
0603 PrefixedExpr();
0604 for(;;) switch(_token) {
0605 case _SC('*'): case _SC('/'): case _SC('%'):
0606 BIN_EXP(ChooseArithOpByToken(_token), &PSCompiler::PrefixedExpr); break;
0607 default: return;
0608 }
0609 }
0610
0611 void PrefixedExpr()
0612 {
0613 PSInteger pos = Factor();
0614 for(;;) {
0615 switch(_token) {
0616 case _SC('.'):
0617 pos = -1;
0618 Lex();
0619
0620 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
0621 if(_es.etype==BASE) {
0622 Emit2ArgsOP(_OP_GET);
0623 pos = _fs->TopTarget();
0624 _es.etype = EXPR;
0625 _es.epos = pos;
0626 }
0627 else {
0628 if(NeedGet()) {
0629 Emit2ArgsOP(_OP_GET);
0630 }
0631 _es.etype = OBJECT;
0632 }
0633 break;
0634 case _SC('['):
0635 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
0636 Lex(); Expression(); Expect(_SC(']'));
0637 pos = -1;
0638 if(_es.etype==BASE) {
0639 Emit2ArgsOP(_OP_GET);
0640 pos = _fs->TopTarget();
0641 _es.etype = EXPR;
0642 _es.epos = pos;
0643 }
0644 else {
0645 if(NeedGet()) {
0646 Emit2ArgsOP(_OP_GET);
0647 }
0648 _es.etype = OBJECT;
0649 }
0650 break;
0651 case TK_MINUSMINUS:
0652 case TK_PLUSPLUS:
0653 {
0654 if(IsEndOfStatement()) return;
0655 PSInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
0656 Lex();
0657 switch(_es.etype)
0658 {
0659 case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
0660 case OBJECT:
0661 case BASE:
0662 if(_es.donot_get == true) { Error(_SC("can't '++' or '--' an expression")); break; }
0663 Emit2ArgsOP(_OP_PINC, diff);
0664 break;
0665 case LOCAL: {
0666 PSInteger src = _fs->PopTarget();
0667 _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);
0668 }
0669 break;
0670 case OUTER: {
0671 PSInteger tmp1 = _fs->PushTarget();
0672 PSInteger tmp2 = _fs->PushTarget();
0673 _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);
0674 _fs->AddInstruction(_OP_PINCL, tmp1, tmp2, 0, diff);
0675 _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);
0676 _fs->PopTarget();
0677 }
0678 }
0679 }
0680 return;
0681 break;
0682 case _SC('('):
0683 switch(_es.etype) {
0684 case OBJECT: {
0685 PSInteger key = _fs->PopTarget();
0686 PSInteger table = _fs->PopTarget();
0687 PSInteger closure = _fs->PushTarget();
0688 PSInteger ttarget = _fs->PushTarget();
0689 _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
0690 }
0691 break;
0692 case BASE:
0693
0694 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
0695 break;
0696 case OUTER:
0697 _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);
0698 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
0699 break;
0700 default:
0701 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
0702 }
0703 _es.etype = EXPR;
0704 Lex();
0705 FunctionCallArgs();
0706 break;
0707 default: return;
0708 }
0709 }
0710 }
0711 PSInteger Factor()
0712 {
0713
0714 switch(_token)
0715 {
0716 case TK_STRING_LITERAL:
0717 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
0718 Lex();
0719 break;
0720 case TK_BASE:
0721 Lex();
0722 _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());
0723 _es.etype = BASE;
0724 _es.epos = _fs->TopTarget();
0725 return (_es.epos);
0726 break;
0727 case TK_IDENTIFIER:
0728 case TK_CONSTRUCTOR:
0729 case TK_THIS:{
0730 PSObject id;
0731 PSObject constant;
0732
0733 switch(_token) {
0734 case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
0735 case TK_THIS: id = _fs->CreateString(_SC("this"),4); break;
0736 case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor"),11); break;
0737 }
0738
0739 PSInteger pos = -1;
0740 Lex();
0741 if((pos = _fs->GetLocalVariable(id)) != -1) {
0742
0743 _fs->PushTarget(pos);
0744 _es.etype = LOCAL;
0745 _es.epos = pos;
0746 }
0747
0748 else if((pos = _fs->GetOuterVariable(id)) != -1) {
0749
0750 if(NeedGet()) {
0751 _es.epos = _fs->PushTarget();
0752 _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);
0753
0754 }
0755 else {
0756 _es.etype = OUTER;
0757 _es.epos = pos;
0758 }
0759 }
0760
0761 else if(_fs->IsConstant(id, constant)) {
0762
0763 PSObjectPtr constval;
0764 PSObject constid;
0765 if(type(constant) == OT_TABLE) {
0766 Expect('.');
0767 constid = Expect(TK_IDENTIFIER);
0768 if(!_table(constant)->Get(constid, constval)) {
0769 constval.Null();
0770 Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));
0771 }
0772 }
0773 else {
0774 constval = constant;
0775 }
0776 _es.epos = _fs->PushTarget();
0777
0778
0779 PSObjectType ctype = type(constval);
0780 switch(ctype) {
0781 case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;
0782 case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;
0783 case OT_BOOL: _fs->AddInstruction(_OP_LOADBOOL, _es.epos, _integer(constval)); break;
0784 default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;
0785 }
0786 _es.etype = EXPR;
0787 }
0788 else {
0789
0790
0791
0792
0793
0794
0795 _fs->PushTarget(0);
0796 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
0797 if(NeedGet()) {
0798 Emit2ArgsOP(_OP_GET);
0799 }
0800 _es.etype = OBJECT;
0801 }
0802 return _es.epos;
0803 }
0804 break;
0805 case TK_DOUBLE_COLON:
0806 _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());
0807 _es.etype = OBJECT;
0808 _token = _SC('.');
0809 _es.epos = -1;
0810 return _es.epos;
0811 break;
0812 case TK_NULL:
0813 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
0814 Lex();
0815 break;
0816 case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex(); break;
0817 case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;
0818 case TK_TRUE: case TK_FALSE:
0819 _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
0820 Lex();
0821 break;
0822 case _SC('['): {
0823 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);
0824 PSInteger apos = _fs->GetCurrentPos(),key = 0;
0825 Lex();
0826 while(_token != _SC(']')) {
0827 Expression();
0828 if(_token == _SC(',')) Lex();
0829 PSInteger val = _fs->PopTarget();
0830 PSInteger array = _fs->TopTarget();
0831 _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);
0832 key++;
0833 }
0834 _fs->SetIntructionParam(apos, 1, key);
0835 Lex();
0836 }
0837 break;
0838 case _SC('{'):
0839 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
0840 Lex();ParseTableOrClass(_SC(','),_SC('}'));
0841 break;
0842 case TK_FUNCTION: FunctionExp(_token);break;
0843 case _SC('@'): FunctionExp(_token,true);break;
0844 case TK_CLASS: Lex(); ClassExp();break;
0845 case _SC('-'):
0846 Lex();
0847 switch(_token) {
0848 case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;
0849 case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;
0850 default: UnaryOP(_OP_NEG);
0851 }
0852 break;
0853 case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;
0854 case _SC('~'):
0855 Lex();
0856 if(_token == TK_INTEGER) { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }
0857 UnaryOP(_OP_BWNOT);
0858 break;
0859 case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;
0860 case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;
0861 case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;
0862 case TK_MINUSMINUS :
0863 case TK_PLUSPLUS :PrefixIncDec(_token); break;
0864 case TK_DELETE : DeleteExpr(); break;
0865 case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
0866 break;
0867 case TK___LINE__: EmitLoadConstInt(_lex._currentline,-1); Lex(); break;
0868 case TK___FILE__: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename)); Lex(); break;
0869 default: Error(_SC("expression expected"));
0870 }
0871 _es.etype = EXPR;
0872 return -1;
0873 }
0874 void EmitLoadConstInt(PSInteger value,PSInteger target)
0875 {
0876 if(target < 0) {
0877 target = _fs->PushTarget();
0878 }
0879 if(value <= INT_MAX && value > INT_MIN) {
0880 _fs->AddInstruction(_OP_LOADINT, target,value);
0881 }
0882 else {
0883 _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
0884 }
0885 }
0886 void EmitLoadConstFloat(PSFloat value,PSInteger target)
0887 {
0888 if(target < 0) {
0889 target = _fs->PushTarget();
0890 }
0891 if(sizeof(PSFloat) == sizeof(PSInt32)) {
0892 _fs->AddInstruction(_OP_LOADFLOAT, target,*((PSInt32 *)&value));
0893 }
0894 else {
0895 _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
0896 }
0897 }
0898 void UnaryOP(PSOpcode op)
0899 {
0900 PrefixedExpr();
0901 PSInteger src = _fs->PopTarget();
0902 _fs->AddInstruction(op, _fs->PushTarget(), src);
0903 }
0904 bool NeedGet()
0905 {
0906 switch(_token) {
0907 case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:
0908 case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ:
0909 return false;
0910 case TK_PLUSPLUS: case TK_MINUSMINUS:
0911 if (!IsEndOfStatement()) {
0912 return false;
0913 }
0914 break;
0915 }
0916 return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
0917 }
0918 void FunctionCallArgs()
0919 {
0920 PSInteger nargs = 1;
0921 while(_token != _SC(')')) {
0922 Expression();
0923 MoveIfCurrentTargetIsLocal();
0924 nargs++;
0925 if(_token == _SC(',')){
0926 Lex();
0927 if(_token == ')') Error(_SC("expression expected, found ')'"));
0928 }
0929 }
0930 Lex();
0931 for(PSInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
0932 PSInteger stackbase = _fs->PopTarget();
0933 PSInteger closure = _fs->PopTarget();
0934 _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
0935 }
0936 void ParseTableOrClass(PSInteger separator,PSInteger terminator)
0937 {
0938 PSInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
0939 while(_token != terminator) {
0940 bool hasattrs = false;
0941 bool isstatic = false;
0942
0943 if(separator == ';') {
0944 if(_token == TK_ATTR_OPEN) {
0945 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();
0946 ParseTableOrClass(',',TK_ATTR_CLOSE);
0947 hasattrs = true;
0948 }
0949 if(_token == TK_STATIC) {
0950 isstatic = true;
0951 Lex();
0952 }
0953 }
0954 switch(_token) {
0955 case TK_FUNCTION:
0956 case TK_CONSTRUCTOR:{
0957 PSInteger tk = _token;
0958 Lex();
0959 PSObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
0960 Expect(_SC('('));
0961 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
0962 CreateFunction(id);
0963 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
0964 }
0965 break;
0966 case _SC('['):
0967 Lex(); CommaExpr(); Expect(_SC(']'));
0968 Expect(_SC('=')); Expression();
0969 break;
0970 case TK_STRING_LITERAL:
0971 if(separator == ',') {
0972 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));
0973 Expect(_SC(':')); Expression();
0974 break;
0975 }
0976 default :
0977 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
0978 Expect(_SC('=')); Expression();
0979 }
0980 if(_token == separator) Lex();
0981 nkeys++;
0982 PSInteger val = _fs->PopTarget();
0983 PSInteger key = _fs->PopTarget();
0984 PSInteger attrs = hasattrs ? _fs->PopTarget():-1;
0985 ((void)attrs);
0986 assert((hasattrs && (attrs == key-1)) || !hasattrs);
0987 unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
0988 PSInteger table = _fs->TopTarget();
0989 if(separator == _SC(',')) {
0990 _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);
0991 }
0992 else {
0993 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
0994 }
0995 }
0996 if(separator == _SC(','))
0997 _fs->SetIntructionParam(tpos, 1, nkeys);
0998 Lex();
0999 }
1000 void LocalDeclStatement()
1001 {
1002 PSObject varname;
1003 Lex();
1004 if( _token == TK_FUNCTION) {
1005 Lex();
1006 varname = Expect(TK_IDENTIFIER);
1007 Expect(_SC('('));
1008 CreateFunction(varname,false);
1009 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1010 _fs->PopTarget();
1011 _fs->PushLocalVariable(varname);
1012 return;
1013 }
1014
1015 do {
1016 varname = Expect(TK_IDENTIFIER);
1017 if(_token == _SC('=')) {
1018 Lex(); Expression();
1019 PSInteger src = _fs->PopTarget();
1020 PSInteger dest = _fs->PushTarget();
1021 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
1022 }
1023 else{
1024 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
1025 }
1026 _fs->PopTarget();
1027 _fs->PushLocalVariable(varname);
1028 if(_token == _SC(',')) Lex(); else break;
1029 } while(1);
1030 }
1031 void IfBlock()
1032 {
1033 if (_token == _SC('{'))
1034 {
1035 BEGIN_SCOPE();
1036 Lex();
1037 Statements();
1038 Expect(_SC('}'));
1039 if (true) {
1040 END_SCOPE();
1041 }
1042 else {
1043 END_SCOPE_NO_CLOSE();
1044 }
1045 }
1046 else {
1047
1048 Statement();
1049 if (_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
1050
1051 }
1052 }
1053 void IfStatement()
1054 {
1055 PSInteger jmppos;
1056 bool haselse = false;
1057 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1058 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
1059 PSInteger jnepos = _fs->GetCurrentPos();
1060
1061
1062
1063 IfBlock();
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077 PSInteger endifblock = _fs->GetCurrentPos();
1078 if(_token == TK_ELSE){
1079 haselse = true;
1080
1081 _fs->AddInstruction(_OP_JMP);
1082 jmppos = _fs->GetCurrentPos();
1083 Lex();
1084
1085 IfBlock();
1086
1087 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
1088 }
1089 _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
1090 }
1091 void WhileStatement()
1092 {
1093 PSInteger jzpos, jmppos;
1094 jmppos = _fs->GetCurrentPos();
1095 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1096
1097 BEGIN_BREAKBLE_BLOCK();
1098 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
1099 jzpos = _fs->GetCurrentPos();
1100 BEGIN_SCOPE();
1101
1102 Statement();
1103
1104 END_SCOPE();
1105 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
1106 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
1107
1108 END_BREAKBLE_BLOCK(jmppos);
1109 }
1110 void DoWhileStatement()
1111 {
1112 Lex();
1113 PSInteger jmptrg = _fs->GetCurrentPos();
1114 BEGIN_BREAKBLE_BLOCK()
1115 BEGIN_SCOPE();
1116 Statement();
1117 END_SCOPE();
1118 Expect(TK_WHILE);
1119 PSInteger continuetrg = _fs->GetCurrentPos();
1120 Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1121 _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
1122 _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
1123 END_BREAKBLE_BLOCK(continuetrg);
1124 }
1125 void ForStatement()
1126 {
1127 Lex();
1128 BEGIN_SCOPE();
1129 Expect(_SC('('));
1130 if(_token == TK_LOCAL) LocalDeclStatement();
1131 else if(_token != _SC(';')){
1132 CommaExpr();
1133 _fs->PopTarget();
1134 }
1135 Expect(_SC(';'));
1136 _fs->SnoozeOpt();
1137 PSInteger jmppos = _fs->GetCurrentPos();
1138 PSInteger jzpos = -1;
1139 if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
1140 Expect(_SC(';'));
1141 _fs->SnoozeOpt();
1142 PSInteger expstart = _fs->GetCurrentPos() + 1;
1143 if(_token != _SC(')')) {
1144 CommaExpr();
1145 _fs->PopTarget();
1146 }
1147 Expect(_SC(')'));
1148 _fs->SnoozeOpt();
1149 PSInteger expend = _fs->GetCurrentPos();
1150 PSInteger expsize = (expend - expstart) + 1;
1151 PSInstructionVec exp;
1152 if(expsize > 0) {
1153 for(PSInteger i = 0; i < expsize; i++)
1154 exp.push_back(_fs->GetInstruction(expstart + i));
1155 _fs->PopInstructions(expsize);
1156 }
1157 BEGIN_BREAKBLE_BLOCK()
1158 Statement();
1159 PSInteger continuetrg = _fs->GetCurrentPos();
1160 if(expsize > 0) {
1161 for(PSInteger i = 0; i < expsize; i++)
1162 _fs->AddInstruction(exp[i]);
1163 }
1164 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
1165 if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
1166 END_SCOPE();
1167
1168 END_BREAKBLE_BLOCK(continuetrg);
1169 }
1170 void ForEachStatement()
1171 {
1172 PSObject idxname, valname;
1173 Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
1174 if(_token == _SC(',')) {
1175 idxname = valname;
1176 Lex(); valname = Expect(TK_IDENTIFIER);
1177 }
1178 else{
1179 idxname = _fs->CreateString(_SC("@INDEX@"));
1180 }
1181 Expect(TK_IN);
1182
1183
1184 BEGIN_SCOPE();
1185
1186 Expression(); Expect(_SC(')'));
1187 PSInteger container = _fs->TopTarget();
1188
1189 PSInteger indexpos = _fs->PushLocalVariable(idxname);
1190 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
1191
1192 PSInteger valuepos = _fs->PushLocalVariable(valname);
1193 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
1194
1195 PSInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@")));
1196 _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
1197 PSInteger jmppos = _fs->GetCurrentPos();
1198 _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
1199 PSInteger foreachpos = _fs->GetCurrentPos();
1200 _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
1201
1202 BEGIN_BREAKBLE_BLOCK()
1203 Statement();
1204 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
1205 _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
1206 _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
1207 END_BREAKBLE_BLOCK(foreachpos - 1);
1208
1209 _fs->PopTarget();
1210 END_SCOPE();
1211 }
1212 void SwitchStatement()
1213 {
1214 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1215 Expect(_SC('{'));
1216 PSInteger expr = _fs->TopTarget();
1217 bool bfirst = true;
1218 PSInteger tonextcondjmp = -1;
1219 PSInteger skipcondjmp = -1;
1220 PSInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
1221 _fs->_breaktargets.push_back(0);
1222 while(_token == TK_CASE) {
1223 if(!bfirst) {
1224 _fs->AddInstruction(_OP_JMP, 0, 0);
1225 skipcondjmp = _fs->GetCurrentPos();
1226 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1227 }
1228
1229 Lex(); Expression(); Expect(_SC(':'));
1230 PSInteger trg = _fs->PopTarget();
1231 PSInteger eqtarget = trg;
1232 bool local = _fs->IsLocal(trg);
1233 if(local) {
1234 eqtarget = _fs->PushTarget();
1235 }
1236 _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);
1237 _fs->AddInstruction(_OP_JZ, eqtarget, 0);
1238 if(local) {
1239 _fs->PopTarget();
1240 }
1241
1242
1243 if(skipcondjmp != -1) {
1244 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
1245 }
1246 tonextcondjmp = _fs->GetCurrentPos();
1247 BEGIN_SCOPE();
1248 Statements();
1249 END_SCOPE();
1250 bfirst = false;
1251 }
1252 if(tonextcondjmp != -1)
1253 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1254 if(_token == TK_DEFAULT) {
1255 Lex(); Expect(_SC(':'));
1256 BEGIN_SCOPE();
1257 Statements();
1258 END_SCOPE();
1259 }
1260 Expect(_SC('}'));
1261 _fs->PopTarget();
1262 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1263 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
1264 _fs->_breaktargets.pop_back();
1265 }
1266 void FunctionStatement()
1267 {
1268 PSObject id;
1269 Lex(); id = Expect(TK_IDENTIFIER);
1270 _fs->PushTarget(0);
1271 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1272 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1273
1274 while(_token == TK_DOUBLE_COLON) {
1275 Lex();
1276 id = Expect(TK_IDENTIFIER);
1277 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1278 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1279 }
1280 Expect(_SC('('));
1281 CreateFunction(id);
1282 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1283 EmitDerefOp(_OP_NEWSLOT);
1284 _fs->PopTarget();
1285 }
1286 void ClassStatement()
1287 {
1288 PSExpState es;
1289 Lex();
1290 es = _es;
1291 _es.donot_get = true;
1292 PrefixedExpr();
1293 if(_es.etype == EXPR) {
1294 Error(_SC("invalid class name"));
1295 }
1296 else if(_es.etype == OBJECT || _es.etype == BASE) {
1297 ClassExp();
1298 EmitDerefOp(_OP_NEWSLOT);
1299 _fs->PopTarget();
1300 }
1301 else {
1302 Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
1303 }
1304 _es = es;
1305 }
1306 PSObject ExpectScalar()
1307 {
1308 PSObject val;
1309 val._type = OT_NULL; val._unVal.nInteger = 0;
1310 switch(_token) {
1311 case TK_INTEGER:
1312 val._type = OT_INTEGER;
1313 val._unVal.nInteger = _lex._nvalue;
1314 break;
1315 case TK_FLOAT:
1316 val._type = OT_FLOAT;
1317 val._unVal.fFloat = _lex._fvalue;
1318 break;
1319 case TK_STRING_LITERAL:
1320 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
1321 break;
1322 case TK_TRUE:
1323 case TK_FALSE:
1324 val._type = OT_BOOL;
1325 val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;
1326 break;
1327 case '-':
1328 Lex();
1329 switch(_token)
1330 {
1331 case TK_INTEGER:
1332 val._type = OT_INTEGER;
1333 val._unVal.nInteger = -_lex._nvalue;
1334 break;
1335 case TK_FLOAT:
1336 val._type = OT_FLOAT;
1337 val._unVal.fFloat = -_lex._fvalue;
1338 break;
1339 default:
1340 Error(_SC("scalar expected : integer,float"));
1341 }
1342 break;
1343 default:
1344 Error(_SC("scalar expected : integer,float or string"));
1345 }
1346 Lex();
1347 return val;
1348 }
1349 void EnumStatement()
1350 {
1351 Lex();
1352 PSObject id = Expect(TK_IDENTIFIER);
1353 Expect(_SC('{'));
1354
1355 PSObject table = _fs->CreateTable();
1356 PSInteger nval = 0;
1357 while(_token != _SC('}')) {
1358 PSObject key = Expect(TK_IDENTIFIER);
1359 PSObject val;
1360 if(_token == _SC('=')) {
1361 Lex();
1362 val = ExpectScalar();
1363 }
1364 else {
1365 val._type = OT_INTEGER;
1366 val._unVal.nInteger = nval++;
1367 }
1368 _table(table)->NewSlot(PSObjectPtr(key),PSObjectPtr(val));
1369 if(_token == ',') Lex();
1370 }
1371 PSTable *enums = _table(_ss(_vm)->_consts);
1372 PSObjectPtr strongid = id;
1373 enums->NewSlot(PSObjectPtr(strongid),PSObjectPtr(table));
1374 strongid.Null();
1375 Lex();
1376 }
1377 void TryCatchStatement()
1378 {
1379 PSObject exid;
1380 Lex();
1381 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
1382 _fs->_traps++;
1383 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
1384 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
1385 PSInteger trappos = _fs->GetCurrentPos();
1386 {
1387 BEGIN_SCOPE();
1388 Statement();
1389 END_SCOPE();
1390 }
1391 _fs->_traps--;
1392 _fs->AddInstruction(_OP_POPTRAP, 1, 0);
1393 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
1394 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
1395 _fs->AddInstruction(_OP_JMP, 0, 0);
1396 PSInteger jmppos = _fs->GetCurrentPos();
1397 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
1398 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
1399 {
1400 BEGIN_SCOPE();
1401 PSInteger ex_target = _fs->PushLocalVariable(exid);
1402 _fs->SetIntructionParam(trappos, 0, ex_target);
1403 Statement();
1404 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1405 END_SCOPE();
1406 }
1407 }
1408 void FunctionExp(PSInteger ftype,bool lambda = false)
1409 {
1410 Lex(); Expect(_SC('('));
1411 PSObjectPtr dummy;
1412 CreateFunction(dummy,lambda);
1413 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
1414 }
1415 void ClassExp()
1416 {
1417 PSInteger base = -1;
1418 PSInteger attrs = -1;
1419 if(_token == TK_EXTENDS) {
1420 Lex(); Expression();
1421 base = _fs->TopTarget();
1422 }
1423 if(_token == TK_ATTR_OPEN) {
1424 Lex();
1425 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
1426 ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
1427 attrs = _fs->TopTarget();
1428 }
1429 Expect(_SC('{'));
1430 if(attrs != -1) _fs->PopTarget();
1431 if(base != -1) _fs->PopTarget();
1432 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);
1433 ParseTableOrClass(_SC(';'),_SC('}'));
1434 }
1435 void DeleteExpr()
1436 {
1437 PSExpState es;
1438 Lex();
1439 es = _es;
1440 _es.donot_get = true;
1441 PrefixedExpr();
1442 if(_es.etype==EXPR) Error(_SC("can't delete an expression"));
1443 if(_es.etype==OBJECT || _es.etype==BASE) {
1444 Emit2ArgsOP(_OP_DELETE);
1445 }
1446 else {
1447 Error(_SC("cannot delete an (outer) local"));
1448 }
1449 _es = es;
1450 }
1451 void PrefixIncDec(PSInteger token)
1452 {
1453 PSExpState es;
1454 PSInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
1455 Lex();
1456 es = _es;
1457 _es.donot_get = true;
1458 PrefixedExpr();
1459 if(_es.etype==EXPR) {
1460 Error(_SC("can't '++' or '--' an expression"));
1461 }
1462 else if(_es.etype==OBJECT || _es.etype==BASE) {
1463 Emit2ArgsOP(_OP_INC, diff);
1464 }
1465 else if(_es.etype==LOCAL) {
1466 PSInteger src = _fs->TopTarget();
1467 _fs->AddInstruction(_OP_INCL, src, src, 0, diff);
1468
1469 }
1470 else if(_es.etype==OUTER) {
1471 PSInteger tmp = _fs->PushTarget();
1472 _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);
1473 _fs->AddInstruction(_OP_INCL, tmp, tmp, 0, diff);
1474 _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);
1475 }
1476 _es = es;
1477 }
1478 void CreateFunction(PSObject &name,bool lambda = false)
1479 {
1480 PSFuncState *funcstate = _fs->PushChildState(_ss(_vm));
1481 funcstate->_name = name;
1482 PSObject paramname;
1483 funcstate->AddParameter(_fs->CreateString(_SC("this")));
1484 funcstate->_sourcename = _sourcename;
1485 PSInteger defparams = 0;
1486 while(_token!=_SC(')')) {
1487 if(_token == TK_VARPARAMS) {
1488 if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
1489 funcstate->AddParameter(_fs->CreateString(_SC("vargv")));
1490 funcstate->_varparams = true;
1491 Lex();
1492 if(_token != _SC(')')) Error(_SC("expected ')'"));
1493 break;
1494 }
1495 else {
1496 paramname = Expect(TK_IDENTIFIER);
1497 funcstate->AddParameter(paramname);
1498 if(_token == _SC('=')) {
1499 Lex();
1500 Expression();
1501 funcstate->AddDefaultParam(_fs->TopTarget());
1502 defparams++;
1503 }
1504 else {
1505 if(defparams > 0) Error(_SC("expected '='"));
1506 }
1507 if(_token == _SC(',')) Lex();
1508 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1509 }
1510 }
1511 Expect(_SC(')'));
1512 for(PSInteger n = 0; n < defparams; n++) {
1513 _fs->PopTarget();
1514 }
1515
1516 PSFuncState *currchunk = _fs;
1517 _fs = funcstate;
1518 if(lambda) {
1519 Expression();
1520 _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}
1521 else {
1522 Statement(false);
1523 }
1524 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
1525 funcstate->AddInstruction(_OP_RETURN, -1);
1526 funcstate->SetStackSize(0);
1527
1528 PSFunctionProto *func = funcstate->BuildProto();
1529 #ifdef _DEBUG_DUMP
1530 funcstate->Dump(func);
1531 #endif
1532 _fs = currchunk;
1533 _fs->_functions.push_back(func);
1534 _fs->PopChildState();
1535 }
1536 void ResolveBreaks(PSFuncState *funcstate, PSInteger ntoresolve)
1537 {
1538 while(ntoresolve > 0) {
1539 PSInteger pos = funcstate->_unresolvedbreaks.back();
1540 funcstate->_unresolvedbreaks.pop_back();
1541
1542 funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
1543 ntoresolve--;
1544 }
1545 }
1546 void ResolveContinues(PSFuncState *funcstate, PSInteger ntoresolve, PSInteger targetpos)
1547 {
1548 while(ntoresolve > 0) {
1549 PSInteger pos = funcstate->_unresolvedcontinues.back();
1550 funcstate->_unresolvedcontinues.pop_back();
1551
1552 funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
1553 ntoresolve--;
1554 }
1555 }
1556 private:
1557 PSInteger _token;
1558 PSFuncState *_fs;
1559 PSObjectPtr _sourcename;
1560 PSLexer _lex;
1561 bool _lineinfo;
1562 bool _raiseerror;
1563 PSInteger _debugline;
1564 PSInteger _debugop;
1565 PSExpState _es;
1566 PSScope _scope;
1567 PSChar _compilererror[MAX_COMPILER_ERROR_LEN];
1568 jmp_buf _errorjmp;
1569 PSVM *_vm;
1570 };
1571
1572 bool Compile(PSVM *vm,PSLEXREADFUNC rg, PSUserPointer up, const PSChar *sourcename, PSObjectPtr &out, bool raiseerror, bool lineinfo)
1573 {
1574 PSCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
1575 return p.Compile(out);
1576 }
1577
1578 #endif