see copyright notice in squirrel.h\r
*/\r
#include "sqpcheader.h"\r
+#ifndef NO_COMPILER\r
#include <stdarg.h>\r
#include <setjmp.h>\r
#include "sqopcodes.h"\r
#include "sqvm.h"\r
#include "sqtable.h"\r
\r
-#define DEREF_NO_DEREF -1\r
-#define DEREF_FIELD -2\r
+#define EXPR 1\r
+#define OBJECT 2\r
+#define BASE 3\r
+#define LOCAL 4\r
+#define OUTER 5\r
\r
-struct ExpState\r
-{\r
- ExpState()\r
- {\r
- _deref = DEREF_NO_DEREF;\r
- _freevar = false;\r
- _class_or_delete = false;\r
- _funcarg = false;\r
- }\r
- bool _class_or_delete;\r
- bool _funcarg;\r
- bool _freevar;\r
- SQInteger _deref;\r
+struct SQExpState {\r
+ SQInteger etype; /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */\r
+ SQInteger epos; /* expr. location on stack; -1 for OBJECT and BASE */\r
+ bool donot_get; /* signal not to deref the next value */\r
+};\r
+\r
+struct SQScope {\r
+ SQInteger outers;\r
+ SQInteger stacksize;\r
};\r
\r
-typedef sqvector<ExpState> ExpStateVec;\r
+#define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \\r
+ _scope.outers = _fs->_outers; \\r
+ _scope.stacksize = _fs->GetStackSize();\r
+\r
+#define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \\r
+ if(_fs->CountOuters(_scope.stacksize)) { \\r
+ _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \\r
+ } \\r
+ }\r
\r
-#define _exst (_expstates.top())\r
+#define END_SCOPE_NO_CLOSE() { if(_fs->GetStackSize() != _scope.stacksize) { \\r
+ _fs->SetStackSize(_scope.stacksize); \\r
+ } \\r
+ _scope = __oldscope__; \\r
+ }\r
+\r
+#define END_SCOPE() { SQInteger oldouters = _fs->_outers;\\r
+ if(_fs->GetStackSize() != _scope.stacksize) { \\r
+ _fs->SetStackSize(_scope.stacksize); \\r
+ if(oldouters != _fs->_outers) { \\r
+ _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \\r
+ } \\r
+ } \\r
+ _scope = __oldscope__; \\r
+ }\r
\r
#define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \\r
SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \\r
_lex.Init(_ss(v), rg, up,ThrowError,this);\r
_sourcename = SQString::Create(_ss(v), sourcename);\r
_lineinfo = lineinfo;_raiseerror = raiseerror;\r
+ _scope.outers = 0;\r
+ _scope.stacksize = 0;\r
compilererror = NULL;\r
}\r
static void ThrowError(void *ud, const SQChar *s) {\r
longjmp(_errorjmp,1);\r
}\r
void Lex(){ _token = _lex.Lex();}\r
- void PushExpState(){ _expstates.push_back(ExpState()); }\r
- bool IsDerefToken(SQInteger tok)\r
- {\r
- switch(tok){\r
- case _SC('='): case _SC('('): case TK_NEWSLOT:\r
- case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true;\r
- }\r
- return false;\r
- }\r
- ExpState PopExpState()\r
- {\r
- ExpState ret = _expstates.top();\r
- _expstates.pop_back();\r
- return ret;\r
- }\r
SQObject Expect(SQInteger tok)\r
{\r
\r
if(_token != tok) {\r
if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {\r
- //ret = SQString::Create(_ss(_vm),_SC("constructor"));\r
//do nothing\r
}\r
else {\r
funcstate._name = SQString::Create(_ss(_vm), _SC("main"));\r
_fs = &funcstate;\r
_fs->AddParameter(_fs->CreateString(_SC("this")));\r
+ _fs->AddParameter(_fs->CreateString(_SC("vargv")));\r
+ _fs->_varparams = true;\r
_fs->_sourcename = _sourcename;\r
SQInteger stacksize = _fs->GetStackSize();\r
if(setjmp(_errorjmp) == 0) {\r
Lex();\r
while(_token > 0){\r
Statement();\r
- if(_lex._prevtoken != _SC('}')) OptionalSemicolon();\r
+ if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();\r
}\r
- CleanStack(stacksize);\r
+ _fs->SetStackSize(stacksize);\r
_fs->AddLineInfos(_lex._currentline, _lineinfo, true);\r
_fs->AddInstruction(_OP_RETURN, 0xFF);\r
_fs->SetStackSize(0);\r
if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();\r
}\r
}\r
- void Statement()\r
+ void Statement(bool closeframe = true)\r
{\r
_fs->AddLineInfos(_lex._currentline, _lineinfo);\r
switch(_token){\r
SQOpcode op;\r
if(_token == TK_RETURN) {\r
op = _OP_RETURN;\r
- \r
}\r
else {\r
op = _OP_YIELD;\r
if(op == _OP_RETURN && _fs->_traps > 0)\r
_fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);\r
_fs->_returnexp = retexp;\r
- _fs->AddInstruction(op, 1, _fs->PopTarget());\r
+ _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());\r
}\r
else{ \r
if(op == _OP_RETURN && _fs->_traps > 0)\r
_fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);\r
_fs->_returnexp = -1;\r
- _fs->AddInstruction(op, 0xFF); \r
+ _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); \r
}\r
break;}\r
case TK_BREAK:\r
if(_fs->_breaktargets.top() > 0){\r
_fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);\r
}\r
+ RESOLVE_OUTERS();\r
_fs->AddInstruction(_OP_JMP, 0, -1234);\r
_fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());\r
Lex();\r
if(_fs->_continuetargets.top() > 0) {\r
_fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);\r
}\r
+ RESOLVE_OUTERS();\r
_fs->AddInstruction(_OP_JMP, 0, -1234);\r
_fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());\r
Lex();\r
EnumStatement();\r
break;\r
case _SC('{'):{\r
- SQInteger stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
Lex();\r
Statements();\r
Expect(_SC('}'));\r
- _fs->SetStackSize(stacksize);\r
+ if(closeframe) {\r
+ END_SCOPE();\r
+ }\r
+ else {\r
+ END_SCOPE_NO_CLOSE();\r
+ }\r
}\r
break;\r
case TK_TRY:\r
break;\r
default:\r
CommaExpr();\r
- _fs->PopTarget();\r
+ _fs->DiscardTarget();\r
+ //_fs->PopTarget();\r
break;\r
}\r
_fs->SnoozeOpt();\r
SQInteger p1 = _fs->PopTarget(); //key in OP_GET\r
_fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);\r
}\r
- void EmitCompoundArith(SQInteger tok,bool deref)\r
+ void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)\r
{\r
- SQInteger oper;\r
- switch(tok){\r
- case TK_MINUSEQ: oper = '-'; break;\r
- case TK_PLUSEQ: oper = '+'; break;\r
- case TK_MULEQ: oper = '*'; break;\r
- case TK_DIVEQ: oper = '/'; break;\r
- case TK_MODEQ: oper = '%'; break;\r
- default: oper = 0; //shut up compiler\r
- assert(0); break;\r
- };\r
- if(deref) {\r
- SQInteger val = _fs->PopTarget();\r
- SQInteger key = _fs->PopTarget();\r
- SQInteger src = _fs->PopTarget();\r
- //mixes dest obj and source val in the arg1(hack?)\r
- _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper);\r
- }\r
- else {\r
- Emit2ArgsOP(_OP_COMPARITHL, oper);\r
+ /* Generate code depending on the expression type */\r
+ switch(etype) {\r
+ case LOCAL:{\r
+ SQInteger p2 = _fs->PopTarget(); //src in OP_GET\r
+ SQInteger p1 = _fs->PopTarget(); //key in OP_GET\r
+ _fs->PushTarget(p1);\r
+ //EmitCompArithLocal(tok, p1, p1, p2);\r
+ _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);\r
+ }\r
+ break;\r
+ case OBJECT:\r
+ case BASE:\r
+ {\r
+ SQInteger val = _fs->PopTarget();\r
+ SQInteger key = _fs->PopTarget();\r
+ SQInteger src = _fs->PopTarget();\r
+ /* _OP_COMPARITH mixes dest obj and source val in the arg1 */\r
+ _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));\r
+ }\r
+ break;\r
+ case OUTER:\r
+ {\r
+ SQInteger val = _fs->TopTarget();\r
+ SQInteger tmp = _fs->PushTarget();\r
+ _fs->AddInstruction(_OP_GETOUTER, tmp, pos);\r
+ _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);\r
+ _fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp);\r
+ }\r
+ break;\r
}\r
}\r
void CommaExpr()\r
{\r
for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());\r
}\r
- ExpState Expression(bool funcarg = false)\r
+ void Expression()\r
{\r
- PushExpState();\r
- _exst._class_or_delete = false;\r
- _exst._funcarg = funcarg;\r
+ SQExpState es = _es;\r
+ _es.etype = EXPR;\r
+ _es.epos = -1;\r
+ _es.donot_get = false;\r
LogicalOrExp();\r
switch(_token) {\r
case _SC('='):\r
case TK_PLUSEQ:\r
case TK_MULEQ:\r
case TK_DIVEQ:\r
- case TK_MODEQ:\r
- {\r
- SQInteger op = _token;\r
- SQInteger ds = _exst._deref;\r
- bool freevar = _exst._freevar;\r
- if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression"));\r
- Lex(); Expression();\r
+ case TK_MODEQ:{\r
+ SQInteger op = _token;\r
+ SQInteger ds = _es.etype;\r
+ SQInteger pos = _es.epos;\r
+ if(ds == EXPR) Error(_SC("can't assign expression"));\r
+ Lex(); Expression();\r
\r
- switch(op){\r
- case TK_NEWSLOT:\r
- if(freevar) Error(_SC("free variables cannot be modified"));\r
- if(ds == DEREF_FIELD)\r
- EmitDerefOp(_OP_NEWSLOT);\r
- else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
- Error(_SC("can't 'create' a local slot"));\r
- break;\r
- case _SC('='): //ASSIGN\r
- if(freevar) Error(_SC("free variables cannot be modified"));\r
- if(ds == DEREF_FIELD)\r
- EmitDerefOp(_OP_SET);\r
- else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
- SQInteger p2 = _fs->PopTarget(); //src in OP_GET\r
- SQInteger p1 = _fs->TopTarget(); //key in OP_GET\r
- _fs->AddInstruction(_OP_MOVE, p1, p2);\r
+ switch(op){\r
+ case TK_NEWSLOT:\r
+ if(ds == OBJECT || ds == BASE)\r
+ EmitDerefOp(_OP_NEWSLOT);\r
+ else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
+ Error(_SC("can't 'create' a local slot"));\r
+ break;\r
+ case _SC('='): //ASSIGN\r
+ switch(ds) {\r
+ case LOCAL:\r
+ {\r
+ SQInteger src = _fs->PopTarget();\r
+ SQInteger dst = _fs->TopTarget();\r
+ _fs->AddInstruction(_OP_MOVE, dst, src);\r
}\r
break;\r
- case TK_MINUSEQ:\r
- case TK_PLUSEQ:\r
- case TK_MULEQ:\r
- case TK_DIVEQ:\r
- case TK_MODEQ:\r
- EmitCompoundArith(op,ds == DEREF_FIELD);\r
+ case OBJECT:\r
+ case BASE:\r
+ EmitDerefOp(_OP_SET);\r
break;\r
+ case OUTER:\r
+ {\r
+ SQInteger src = _fs->PopTarget();\r
+ SQInteger dst = _fs->PushTarget();\r
+ _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);\r
+ }\r
}\r
+ break;\r
+ case TK_MINUSEQ:\r
+ case TK_PLUSEQ:\r
+ case TK_MULEQ:\r
+ case TK_DIVEQ:\r
+ case TK_MODEQ:\r
+ EmitCompoundArith(op, ds, pos);\r
+ break;\r
+ }\r
}\r
break;\r
case _SC('?'): {\r
}\r
break;\r
}\r
- return PopExpState();\r
+ _es = es;\r
}\r
- void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0)\r
+ template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)\r
{\r
Lex(); (this->*f)();\r
SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();\r
}\r
void BitwiseAndExp()\r
{\r
- CompExp();\r
+ EqExp();\r
for(;;) if(_token == _SC('&'))\r
- {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);\r
+ {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND);\r
}else return;\r
}\r
+ void EqExp()\r
+ {\r
+ CompExp();\r
+ for(;;) switch(_token) {\r
+ case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break;\r
+ case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break;\r
+ case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break;\r
+ default: return; \r
+ }\r
+ }\r
void CompExp()\r
{\r
ShiftExp();\r
for(;;) switch(_token) {\r
- case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break;\r
case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;\r
case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;\r
case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;\r
case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;\r
- case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;\r
default: return; \r
}\r
}\r
default: return; \r
}\r
}\r
+ SQOpcode ChooseArithOpByToken(SQInteger tok)\r
+ {\r
+ switch(tok) {\r
+ case TK_PLUSEQ: case '+': return _OP_ADD;\r
+ case TK_MINUSEQ: case '-': return _OP_SUB;\r
+ case TK_MULEQ: case '*': return _OP_MUL;\r
+ case TK_DIVEQ: case '/': return _OP_DIV;\r
+ case TK_MODEQ: case '%': return _OP_MOD;\r
+ default: assert(0);\r
+ }\r
+ return _OP_ADD;\r
+ }\r
+ SQInteger ChooseCompArithCharByToken(SQInteger tok)\r
+ {\r
+ SQInteger oper;\r
+ switch(tok){\r
+ case TK_MINUSEQ: oper = '-'; break;\r
+ case TK_PLUSEQ: oper = '+'; break;\r
+ case TK_MULEQ: oper = '*'; break;\r
+ case TK_DIVEQ: oper = '/'; break;\r
+ case TK_MODEQ: oper = '%'; break;\r
+ default: oper = 0; //shut up compiler\r
+ assert(0); break;\r
+ };\r
+ return oper;\r
+ }\r
void PlusExp()\r
{\r
MultExp();\r
for(;;) switch(_token) {\r
case _SC('+'): case _SC('-'):\r
- BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break;\r
+ BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break;\r
default: return;\r
}\r
}\r
PrefixedExpr();\r
for(;;) switch(_token) {\r
case _SC('*'): case _SC('/'): case _SC('%'):\r
- BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break;\r
+ BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break;\r
default: return;\r
}\r
}\r
void PrefixedExpr()\r
{\r
SQInteger pos = Factor();\r
- \r
for(;;) {\r
switch(_token) {\r
- case _SC('.'): {\r
+ case _SC('.'):\r
pos = -1;\r
Lex(); \r
- if(_token == TK_PARENT) {\r
- Lex();\r
- if(!NeedGet())\r
- Error(_SC("parent cannot be set"));\r
- SQInteger src = _fs->PopTarget();\r
- _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);\r
+\r
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
+ if(_es.etype==BASE) {\r
+ Emit2ArgsOP(_OP_GET);\r
+ pos = _fs->TopTarget();\r
+ _es.etype = EXPR;\r
+ _es.epos = pos;\r
}\r
else {\r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
- if(NeedGet()) Emit2ArgsOP(_OP_GET);\r
- }\r
- _exst._deref = DEREF_FIELD;\r
- _exst._freevar = false;\r
+ if(NeedGet()) {\r
+ Emit2ArgsOP(_OP_GET);\r
+ }\r
+ _es.etype = OBJECT;\r
}\r
break;\r
case _SC('['):\r
if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));\r
Lex(); Expression(); Expect(_SC(']')); \r
pos = -1;\r
- if(NeedGet()) Emit2ArgsOP(_OP_GET);\r
- _exst._deref = DEREF_FIELD;\r
- _exst._freevar = false;\r
+ if(_es.etype==BASE) {\r
+ Emit2ArgsOP(_OP_GET);\r
+ pos = _fs->TopTarget();\r
+ _es.etype = EXPR;\r
+ _es.epos = pos;\r
+ }\r
+ else {\r
+ if(NeedGet()) {\r
+ Emit2ArgsOP(_OP_GET);\r
+ }\r
+ _es.etype = OBJECT;\r
+ }\r
break;\r
case TK_MINUSMINUS:\r
case TK_PLUSPLUS:\r
- if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { \r
- SQInteger tok = _token; Lex();\r
- if(pos < 0)\r
- Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);\r
- else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
- SQInteger src = _fs->PopTarget();\r
- _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);\r
+ {\r
+ if(IsEndOfStatement()) return;\r
+ SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;\r
+ Lex();\r
+ switch(_es.etype)\r
+ {\r
+ case EXPR: Error(_SC("can't '++' or '--' an expression")); break;\r
+ case OBJECT:\r
+ case BASE:\r
+ Emit2ArgsOP(_OP_PINC, diff);\r
+ break;\r
+ case LOCAL: {\r
+ SQInteger src = _fs->PopTarget();\r
+ _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);\r
+ }\r
+ break;\r
+ case OUTER: {\r
+ SQInteger tmp1 = _fs->PushTarget();\r
+ SQInteger tmp2 = _fs->PushTarget();\r
+ _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);\r
+ _fs->AddInstruction(_OP_PINCL, tmp1, tmp2, 0, diff);\r
+ _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);\r
+ _fs->PopTarget();\r
+ }\r
+ }\r
}\r
- \r
- }\r
- return;\r
- break; \r
+ return;\r
+ break; \r
case _SC('('): \r
- {\r
- if(_exst._deref != DEREF_NO_DEREF) {\r
- if(pos<0) {\r
- SQInteger key = _fs->PopTarget(); //key\r
- SQInteger table = _fs->PopTarget(); //table etc...\r
- SQInteger closure = _fs->PushTarget();\r
- SQInteger ttarget = _fs->PushTarget();\r
+ switch(_es.etype) {\r
+ case OBJECT: {\r
+ SQInteger key = _fs->PopTarget(); /* location of the key */\r
+ SQInteger table = _fs->PopTarget(); /* location of the object */\r
+ SQInteger closure = _fs->PushTarget(); /* location for the closure */\r
+ SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */\r
_fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);\r
- }\r
- else{\r
+ }\r
+ break;\r
+ case BASE:\r
+ //Emit2ArgsOP(_OP_GET);\r
+ _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
+ break;\r
+ case OUTER:\r
+ _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);\r
+ _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
+ break;\r
+ default:\r
_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
- }\r
}\r
- else\r
- _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
- _exst._deref = DEREF_NO_DEREF;\r
+ _es.etype = EXPR;\r
Lex();\r
FunctionCallArgs();\r
- }\r
break;\r
default: return;\r
}\r
}\r
SQInteger Factor()\r
{\r
- _exst._deref = DEREF_NO_DEREF;\r
+ _es.etype = EXPR;\r
switch(_token)\r
{\r
- case TK_STRING_LITERAL: {\r
- //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));\r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));\r
- Lex(); \r
- }\r
+ case TK_STRING_LITERAL:\r
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));\r
+ Lex(); \r
break;\r
- case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;\r
- case TK_VARGV: { Lex();\r
- Expect(_SC('['));\r
- Expression();\r
- Expect(_SC(']'));\r
- SQInteger src = _fs->PopTarget();\r
- _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src);\r
- }\r
+ case TK_BASE:\r
+ Lex();\r
+ _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());\r
+ _es.etype = BASE;\r
+ _es.epos = _fs->TopTarget();\r
+ return (_es.epos);\r
break;\r
case TK_IDENTIFIER:\r
case TK_CONSTRUCTOR:\r
case TK_THIS:{\r
- _exst._freevar = false;\r
- SQObject id;\r
- SQObject constant;\r
+ SQObject id;\r
+ SQObject constant;\r
+\r
switch(_token) {\r
- case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;\r
- case TK_THIS: id = _fs->CreateString(_SC("this")); break;\r
+ case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;\r
+ case TK_THIS: id = _fs->CreateString(_SC("this")); break;\r
case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;\r
}\r
+\r
SQInteger pos = -1;\r
Lex();\r
- if((pos = _fs->GetLocalVariable(id)) == -1) {\r
- //checks if is a free variable\r
- if((pos = _fs->GetOuterVariable(id)) != -1) {\r
- _exst._deref = _fs->PushTarget();\r
- _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos); \r
- _exst._freevar = true;\r
+ if((pos = _fs->GetLocalVariable(id)) != -1) {\r
+ /* Handle a local variable (includes 'this') */\r
+ _fs->PushTarget(pos);\r
+ _es.etype = LOCAL;\r
+ _es.epos = pos;\r
+ }\r
+\r
+ else if((pos = _fs->GetOuterVariable(id)) != -1) {\r
+ /* Handle a free var */\r
+ if(NeedGet()) {\r
+ _es.epos = _fs->PushTarget();\r
+ _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos); \r
+ /* _es.etype = EXPR; already default value */\r
}\r
- else if(_fs->IsConstant(id,constant)) { //line 634\r
- SQObjectPtr constval;\r
- SQObject constid;\r
- if(type(constant) == OT_TABLE) {\r
- Expect('.'); constid = Expect(TK_IDENTIFIER);\r
- if(!_table(constant)->Get(constid,constval)) {\r
- constval.Null();\r
- Error(_SC("invalid constant [%s.%s]"), _stringval(id),_stringval(constid));\r
- }\r
- }\r
- else {\r
- constval = constant;\r
- }\r
- _exst._deref = _fs->PushTarget();\r
- SQObjectType ctype = type(constval);\r
- if(ctype == OT_INTEGER && (_integer(constval) & (~0x7FFFFFFF)) == 0) {\r
- _fs->AddInstruction(_OP_LOADINT, _exst._deref,_integer(constval));\r
- }\r
- else if(ctype == OT_FLOAT && sizeof(SQFloat) == sizeof(SQInt32)) {\r
- SQFloat f = _float(constval);\r
- _fs->AddInstruction(_OP_LOADFLOAT, _exst._deref,*((SQInt32 *)&f));\r
- }\r
- else {\r
- _fs->AddInstruction(_OP_LOAD, _exst._deref, _fs->GetConstant(constval));\r
- }\r
+ else {\r
+ _es.etype = OUTER;\r
+ _es.epos = pos;\r
+ }\r
+ }\r
\r
- _exst._freevar = true;\r
+ else if(_fs->IsConstant(id, constant)) {\r
+ /* Handle named constant */\r
+ SQObjectPtr constval;\r
+ SQObject constid;\r
+ if(type(constant) == OT_TABLE) {\r
+ Expect('.');\r
+ constid = Expect(TK_IDENTIFIER);\r
+ if(!_table(constant)->Get(constid, constval)) {\r
+ constval.Null();\r
+ Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));\r
+ }\r
}\r
else {\r
- _fs->PushTarget(0);\r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
- if(NeedGet()) Emit2ArgsOP(_OP_GET);\r
- _exst._deref = DEREF_FIELD;\r
+ constval = constant;\r
+ }\r
+ _es.epos = _fs->PushTarget();\r
+\r
+ /* generate direct or literal function depending on size */\r
+ SQObjectType ctype = type(constval);\r
+ switch(ctype) {\r
+ case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;\r
+ case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;\r
+ default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;\r
}\r
+ _es.etype = EXPR;\r
}\r
- \r
- else{\r
- _fs->PushTarget(pos);\r
- _exst._deref = pos;\r
+ else {\r
+ /* Handle a non-local variable, aka a field. Push the 'this' pointer on\r
+ * the virtual stack (always found in offset 0, so no instruction needs to\r
+ * be generated), and push the key next. Generate an _OP_LOAD instruction\r
+ * for the latter. If we are not using the variable as a dref expr, generate\r
+ * the _OP_GET instruction.\r
+ */\r
+ _fs->PushTarget(0);\r
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
+ if(NeedGet()) {\r
+ Emit2ArgsOP(_OP_GET);\r
+ }\r
+ _es.etype = OBJECT;\r
}\r
- return _exst._deref;\r
+ return _es.epos;\r
}\r
break;\r
- case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break;\r
case TK_DOUBLE_COLON: // "::"\r
- _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget());\r
- _exst._deref = DEREF_FIELD;\r
- _token = _SC('.'); //hack\r
- return -1;\r
+ _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());\r
+ _es.etype = OBJECT;\r
+ _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/\r
+ _es.epos = -1;\r
+ return _es.epos;\r
break;\r
case TK_NULL: \r
_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\r
Lex();\r
break;\r
- case TK_INTEGER: {\r
- if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?\r
- _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);\r
- }\r
- else {\r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));\r
- }\r
- Lex();\r
- }\r
- break;\r
- case TK_FLOAT:\r
- if(sizeof(SQFloat) == sizeof(SQInt32)) {\r
- _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue));\r
- }\r
- else {\r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));\r
- }\r
- Lex();\r
- break;\r
+ case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex(); break;\r
+ case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;\r
case TK_TRUE: case TK_FALSE:\r
_fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);\r
Lex();\r
break;\r
case _SC('['): {\r
- _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget());\r
+ _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);\r
SQInteger apos = _fs->GetCurrentPos(),key = 0;\r
Lex();\r
while(_token != _SC(']')) {\r
if(_token == _SC(',')) Lex();\r
SQInteger val = _fs->PopTarget();\r
SQInteger array = _fs->TopTarget();\r
- _fs->AddInstruction(_OP_APPENDARRAY, array, val);\r
+ _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);\r
key++;\r
}\r
_fs->SetIntructionParam(apos, 1, key);\r
Lex();\r
}\r
break;\r
- case _SC('{'):{\r
- _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());\r
- Lex();ParseTableOrClass(_SC(','));\r
- }\r
+ case _SC('{'):\r
+ _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);\r
+ Lex();ParseTableOrClass(_SC(','),_SC('}'));\r
break;\r
case TK_FUNCTION: FunctionExp(_token);break;\r
+ case _SC('@'): FunctionExp(_token,true);break;\r
case TK_CLASS: Lex(); ClassExp();break;\r
- case _SC('-'): UnaryOP(_OP_NEG); break;\r
- case _SC('!'): UnaryOP(_OP_NOT); break;\r
- case _SC('~'): UnaryOP(_OP_BWNOT); break;\r
- case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;\r
- case TK_RESUME : UnaryOP(_OP_RESUME); break;\r
- case TK_CLONE : UnaryOP(_OP_CLONE); break;\r
+ case _SC('-'): \r
+ Lex(); \r
+ switch(_token) {\r
+ case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;\r
+ case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;\r
+ default: UnaryOP(_OP_NEG);\r
+ }\r
+ break;\r
+ case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;\r
+ case _SC('~'): \r
+ Lex(); \r
+ if(_token == TK_INTEGER) { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }\r
+ UnaryOP(_OP_BWNOT); \r
+ break;\r
+ case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;\r
+ case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;\r
+ case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;\r
case TK_MINUSMINUS : \r
case TK_PLUSPLUS :PrefixIncDec(_token); break;\r
case TK_DELETE : DeleteExpr(); break;\r
- case TK_DELEGATE : DelegateExpr(); break;\r
case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));\r
break;\r
default: Error(_SC("expression expected"));\r
}\r
return -1;\r
}\r
+ void EmitLoadConstInt(SQInteger value,SQInteger target)\r
+ {\r
+ if(target < 0) {\r
+ target = _fs->PushTarget();\r
+ }\r
+ if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits?\r
+ _fs->AddInstruction(_OP_LOADINT, target,value);\r
+ }\r
+ else {\r
+ _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\r
+ }\r
+ }\r
+ void EmitLoadConstFloat(SQFloat value,SQInteger target)\r
+ {\r
+ if(target < 0) {\r
+ target = _fs->PushTarget();\r
+ }\r
+ if(sizeof(SQFloat) == sizeof(SQInt32)) {\r
+ _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value));\r
+ }\r
+ else {\r
+ _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\r
+ }\r
+ }\r
void UnaryOP(SQOpcode op)\r
{\r
- Lex(); PrefixedExpr();\r
+ PrefixedExpr();\r
SQInteger src = _fs->PopTarget();\r
_fs->AddInstruction(op, _fs->PushTarget(), src);\r
}\r
bool NeedGet()\r
{\r
switch(_token) {\r
- case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS:\r
- case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:\r
+ case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:\r
+ case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS:\r
return false;\r
}\r
- return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));\r
+ return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));\r
}\r
- \r
void FunctionCallArgs()\r
{\r
SQInteger nargs = 1;//this\r
while(_token != _SC(')')) {\r
- Expression(true);\r
+ Expression();\r
MoveIfCurrentTargetIsLocal();\r
nargs++; \r
if(_token == _SC(',')){ \r
SQInteger closure = _fs->PopTarget();\r
_fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);\r
}\r
- void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')\r
+ void ParseTableOrClass(SQInteger separator,SQInteger terminator)\r
{\r
SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;\r
- \r
while(_token != terminator) {\r
bool hasattrs = false;\r
bool isstatic = false;\r
//check if is an attribute\r
if(separator == ';') {\r
if(_token == TK_ATTR_OPEN) {\r
- _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();\r
+ _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();\r
ParseTableOrClass(',',TK_ATTR_CLOSE);\r
hasattrs = true;\r
}\r
}\r
}\r
switch(_token) {\r
- case TK_FUNCTION:\r
- case TK_CONSTRUCTOR:{\r
- SQInteger tk = _token;\r
- Lex();\r
- SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));\r
- Expect(_SC('('));\r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
- CreateFunction(id);\r
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
- }\r
- break;\r
- case _SC('['):\r
- Lex(); CommaExpr(); Expect(_SC(']'));\r
- Expect(_SC('=')); Expression();\r
+ case TK_FUNCTION:\r
+ case TK_CONSTRUCTOR:{\r
+ SQInteger tk = _token;\r
+ Lex();\r
+ SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));\r
+ Expect(_SC('('));\r
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
+ CreateFunction(id);\r
+ _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
+ }\r
+ break;\r
+ case _SC('['):\r
+ Lex(); CommaExpr(); Expect(_SC(']'));\r
+ Expect(_SC('=')); Expression();\r
+ break;\r
+ case TK_STRING_LITERAL: //JSON\r
+ if(separator == ',') { //only works for tables\r
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));\r
+ Expect(_SC(':')); Expression();\r
break;\r
- default :\r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
- Expect(_SC('=')); Expression();\r
+ }\r
+ default :\r
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
+ Expect(_SC('=')); Expression();\r
}\r
-\r
if(_token == separator) Lex();//optional comma/semicolon\r
nkeys++;\r
SQInteger val = _fs->PopTarget();\r
SQInteger key = _fs->PopTarget();\r
SQInteger attrs = hasattrs ? _fs->PopTarget():-1;\r
- assert(hasattrs && attrs == key-1 || !hasattrs);\r
+ assert((hasattrs && (attrs == key-1)) || !hasattrs);\r
unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);\r
SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE\r
- _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);\r
- //_fs->PopTarget();\r
+ if(separator == _SC(',')) { //hack recognizes a table from the separator\r
+ _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);\r
+ }\r
+ else {\r
+ _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember\r
+ }\r
}\r
if(separator == _SC(',')) //hack recognizes a table from the separator\r
_fs->SetIntructionParam(tpos, 1, nkeys);\r
void LocalDeclStatement()\r
{\r
SQObject varname;\r
+ Lex();\r
+ if( _token == TK_FUNCTION) {\r
+ Lex();\r
+ varname = Expect(TK_IDENTIFIER);\r
+ Expect(_SC('('));\r
+ CreateFunction(varname,false);\r
+ _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
+ _fs->PopTarget();\r
+ _fs->PushLocalVariable(varname);\r
+ return;\r
+ }\r
+\r
do {\r
- Lex(); varname = Expect(TK_IDENTIFIER);\r
+ varname = Expect(TK_IDENTIFIER);\r
if(_token == _SC('=')) {\r
Lex(); Expression();\r
SQInteger src = _fs->PopTarget();\r
}\r
_fs->PopTarget();\r
_fs->PushLocalVariable(varname);\r
- \r
- } while(_token == _SC(','));\r
+ if(_token == _SC(',')) Lex(); else break;\r
+ } while(1);\r
}\r
void IfStatement()\r
{\r
Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
_fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
SQInteger jnepos = _fs->GetCurrentPos();\r
- SQInteger stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
\r
Statement();\r
//\r
if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();\r
\r
- CleanStack(stacksize);\r
+ END_SCOPE();\r
SQInteger endifblock = _fs->GetCurrentPos();\r
if(_token == TK_ELSE){\r
haselse = true;\r
- stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
_fs->AddInstruction(_OP_JMP);\r
jmppos = _fs->GetCurrentPos();\r
Lex();\r
Statement(); OptionalSemicolon();\r
- CleanStack(stacksize);\r
+ END_SCOPE();\r
_fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\r
}\r
_fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));\r
void WhileStatement()\r
{\r
SQInteger jzpos, jmppos;\r
- SQInteger stacksize = _fs->GetStackSize();\r
jmppos = _fs->GetCurrentPos();\r
Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
\r
BEGIN_BREAKBLE_BLOCK();\r
_fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
jzpos = _fs->GetCurrentPos();\r
- stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
\r
Statement();\r
\r
- CleanStack(stacksize);\r
+ END_SCOPE();\r
_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\r
_fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\r
\r
void DoWhileStatement()\r
{\r
Lex();\r
- SQInteger jzpos = _fs->GetCurrentPos();\r
- SQInteger stacksize = _fs->GetStackSize();\r
+ SQInteger jmptrg = _fs->GetCurrentPos();\r
BEGIN_BREAKBLE_BLOCK()\r
+ BEGIN_SCOPE();\r
Statement();\r
- CleanStack(stacksize);\r
+ END_SCOPE();\r
Expect(TK_WHILE);\r
SQInteger continuetrg = _fs->GetCurrentPos();\r
Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
- _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1);\r
+ _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);\r
+ _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);\r
END_BREAKBLE_BLOCK(continuetrg);\r
}\r
void ForStatement()\r
{\r
Lex();\r
- SQInteger stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
Expect(_SC('('));\r
if(_token == TK_LOCAL) LocalDeclStatement();\r
else if(_token != _SC(';')){\r
}\r
_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);\r
if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\r
- CleanStack(stacksize);\r
+ END_SCOPE();\r
\r
END_BREAKBLE_BLOCK(continuetrg);\r
}\r
Expect(TK_IN);\r
\r
//save the stack size\r
- SQInteger stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
//put the table in the stack(evaluate the table expression)\r
Expression(); Expect(_SC(')'));\r
SQInteger container = _fs->TopTarget();\r
_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\r
_fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);\r
_fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);\r
- //restore the local variable stack(remove index,val and ref idx)\r
- CleanStack(stacksize);\r
END_BREAKBLE_BLOCK(foreachpos - 1);\r
+ //restore the local variable stack(remove index,val and ref idx)\r
+ _fs->PopTarget();\r
+ END_SCOPE();\r
}\r
void SwitchStatement()\r
{\r
SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();\r
_fs->_breaktargets.push_back(0);\r
while(_token == TK_CASE) {\r
- //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one\r
if(!bfirst) {\r
_fs->AddInstruction(_OP_JMP, 0, 0);\r
skipcondjmp = _fs->GetCurrentPos();\r
_fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));\r
}\r
tonextcondjmp = _fs->GetCurrentPos();\r
- SQInteger stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
Statements();\r
- _fs->SetStackSize(stacksize);\r
+ END_SCOPE();\r
bfirst = false;\r
}\r
if(tonextcondjmp != -1)\r
_fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\r
if(_token == TK_DEFAULT) {\r
- // _fs->AddLineInfos(_lex._currentline, _lineinfo);\r
Lex(); Expect(_SC(':'));\r
- SQInteger stacksize = _fs->GetStackSize();\r
+ BEGIN_SCOPE();\r
Statements();\r
- _fs->SetStackSize(stacksize);\r
+ END_SCOPE();\r
}\r
Expect(_SC('}'));\r
_fs->PopTarget();\r
__nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;\r
if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);\r
_fs->_breaktargets.pop_back();\r
- \r
}\r
void FunctionStatement()\r
{\r
}\r
void ClassStatement()\r
{\r
- ExpState es;\r
- Lex(); PushExpState();\r
- _exst._class_or_delete = true;\r
- _exst._funcarg = false;\r
+ SQExpState es;\r
+ Lex();\r
+ es = _es;\r
+ _es.donot_get = true;\r
PrefixedExpr();\r
- es = PopExpState();\r
- if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));\r
- if(es._deref == DEREF_FIELD) {\r
+ if(_es.etype == EXPR) {\r
+ Error(_SC("invalid class name"));\r
+ }\r
+ else if(_es.etype == OBJECT || _es.etype == BASE) {\r
ClassExp();\r
EmitDerefOp(_OP_NEWSLOT);\r
_fs->PopTarget();\r
}\r
- else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));\r
+ else {\r
+ Error(_SC("cannot create a class in a local with the syntax(class <local>)"));\r
+ }\r
+ _es = es;\r
}\r
SQObject ExpectScalar()\r
{\r
SQObject val;\r
+ val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x\r
switch(_token) {\r
case TK_INTEGER:\r
val._type = OT_INTEGER;\r
}\r
break;\r
default:\r
- Error(_SC("scalar expected : integer,float or string"));\r
+ Error(_SC("scalar expected : integer,float or string"));\r
}\r
Lex();\r
return val;\r
}\r
void EnumStatement()\r
{\r
- \r
Lex(); \r
SQObject id = Expect(TK_IDENTIFIER);\r
Expect(_SC('{'));\r
}\r
SQTable *enums = _table(_ss(_vm)->_consts);\r
SQObjectPtr strongid = id; \r
- /*SQObjectPtr dummy;\r
- if(enums->Get(strongid,dummy)) {\r
- dummy.Null(); strongid.Null();\r
- Error(_SC("enumeration already exists"));\r
- }*/\r
enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));\r
strongid.Null();\r
Lex();\r
- \r
}\r
void TryCatchStatement()\r
{\r
if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;\r
if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;\r
SQInteger trappos = _fs->GetCurrentPos();\r
- Statement();\r
+ {\r
+ BEGIN_SCOPE();\r
+ Statement();\r
+ END_SCOPE();\r
+ }\r
_fs->_traps--;\r
_fs->AddInstruction(_OP_POPTRAP, 1, 0);\r
if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;\r
SQInteger jmppos = _fs->GetCurrentPos();\r
_fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));\r
Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));\r
- SQInteger stacksize = _fs->GetStackSize();\r
- SQInteger ex_target = _fs->PushLocalVariable(exid);\r
- _fs->SetIntructionParam(trappos, 0, ex_target);\r
- Statement();\r
- _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);\r
- CleanStack(stacksize);\r
+ {\r
+ BEGIN_SCOPE();\r
+ SQInteger ex_target = _fs->PushLocalVariable(exid);\r
+ _fs->SetIntructionParam(trappos, 0, ex_target);\r
+ Statement();\r
+ _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);\r
+ END_SCOPE();\r
+ }\r
}\r
- void FunctionExp(SQInteger ftype)\r
+ void FunctionExp(SQInteger ftype,bool lambda = false)\r
{\r
Lex(); Expect(_SC('('));\r
- CreateFunction(_null_);\r
+ SQObjectPtr dummy;\r
+ CreateFunction(dummy,lambda);\r
_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);\r
}\r
void ClassExp()\r
}\r
if(_token == TK_ATTR_OPEN) {\r
Lex();\r
- _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());\r
+ _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);\r
ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);\r
attrs = _fs->TopTarget();\r
}\r
Expect(_SC('{'));\r
if(attrs != -1) _fs->PopTarget();\r
if(base != -1) _fs->PopTarget();\r
- _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);\r
- ParseTableOrClass(_SC(';'));\r
- }\r
- void DelegateExpr()\r
- {\r
- Lex(); CommaExpr();\r
- Expect(_SC(':'));\r
- CommaExpr();\r
- SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();\r
- _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);\r
+ _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);\r
+ ParseTableOrClass(_SC(';'),_SC('}'));\r
}\r
void DeleteExpr()\r
{\r
- ExpState es;\r
- Lex(); PushExpState();\r
- _exst._class_or_delete = true;\r
- _exst._funcarg = false;\r
+ SQExpState es;\r
+ Lex();\r
+ es = _es;\r
+ _es.donot_get = true;\r
PrefixedExpr();\r
- es = PopExpState();\r
- if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));\r
- if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);\r
- else Error(_SC("cannot delete a local"));\r
+ if(_es.etype==EXPR) Error(_SC("can't delete an expression"));\r
+ if(_es.etype==OBJECT || _es.etype==BASE) {\r
+ Emit2ArgsOP(_OP_DELETE);\r
+ }\r
+ else {\r
+ Error(_SC("cannot delete an (outer) local"));\r
+ }\r
+ _es = es;\r
}\r
void PrefixIncDec(SQInteger token)\r
{\r
- ExpState es;\r
- Lex(); PushExpState();\r
- _exst._class_or_delete = true;\r
- _exst._funcarg = false;\r
+ SQExpState es;\r
+ SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;\r
+ Lex();\r
+ es = _es;\r
+ _es.donot_get = true;\r
PrefixedExpr();\r
- es = PopExpState();\r
- if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);\r
- else {\r
- SQInteger src = _fs->PopTarget();\r
- _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);\r
+ if(_es.etype==EXPR) {\r
+ Error(_SC("can't '++' or '--' an expression"));\r
+ }\r
+ else if(_es.etype==OBJECT || _es.etype==BASE) {\r
+ Emit2ArgsOP(_OP_INC, diff);\r
+ }\r
+ else if(_es.etype==LOCAL) {\r
+ SQInteger src = _fs->TopTarget();\r
+ _fs->AddInstruction(_OP_INCL, src, src, 0, diff);\r
+ \r
+ }\r
+ else if(_es.etype==OUTER) {\r
+ SQInteger tmp = _fs->PushTarget();\r
+ _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);\r
+ _fs->AddInstruction(_OP_INCL, tmp, tmp, 0, diff);\r
+ _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);\r
}\r
+ _es = es;\r
}\r
- void CreateFunction(SQObject &name)\r
+ void CreateFunction(SQObject &name,bool lambda = false)\r
{\r
- \r
SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));\r
funcstate->_name = name;\r
SQObject paramname;\r
while(_token!=_SC(')')) {\r
if(_token == TK_VARPARAMS) {\r
if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));\r
+ funcstate->AddParameter(_fs->CreateString(_SC("vargv")));\r
funcstate->_varparams = true;\r
Lex();\r
if(_token != _SC(')')) Error(_SC("expected ')'"));\r
for(SQInteger n = 0; n < defparams; n++) {\r
_fs->PopTarget();\r
}\r
- //outer values\r
- if(_token == _SC(':')) {\r
- Lex(); Expect(_SC('('));\r
- while(_token != _SC(')')) {\r
- paramname = Expect(TK_IDENTIFIER);\r
- //outers are treated as implicit local variables\r
- funcstate->AddOuterValue(paramname);\r
- if(_token == _SC(',')) Lex();\r
- else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));\r
- }\r
- Lex();\r
- }\r
- \r
+ \r
SQFuncState *currchunk = _fs;\r
_fs = funcstate;\r
- Statement();\r
+ if(lambda) { \r
+ Expression(); \r
+ _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}\r
+ else { \r
+ Statement(false); \r
+ }\r
funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);\r
funcstate->AddInstruction(_OP_RETURN, -1);\r
funcstate->SetStackSize(0);\r
- //_fs->->_stacksize = _fs->_stacksize;\r
+\r
SQFunctionProto *func = funcstate->BuildProto();\r
#ifdef _DEBUG_DUMP\r
funcstate->Dump(func);\r
_fs->_functions.push_back(func);\r
_fs->PopChildState();\r
}\r
- void CleanStack(SQInteger stacksize)\r
- {\r
- if(_fs->GetStackSize() != stacksize)\r
- _fs->SetStackSize(stacksize);\r
- }\r
void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)\r
{\r
while(ntoresolve > 0) {\r
bool _raiseerror;\r
SQInteger _debugline;\r
SQInteger _debugop;\r
- ExpStateVec _expstates;\r
+ SQExpState _es;\r
+ SQScope _scope;\r
SQChar *compilererror;\r
jmp_buf _errorjmp;\r
SQVM *_vm;\r
SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);\r
return p.Compile(out);\r
}\r
+\r
+#endif\r