The Squirrel interpreter. See http://www.squirrel-lang.org/

Dependents:   Squirrel

Revision:
0:97a4f8cc534c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/squirrel/sqcompiler.cpp	Tue Dec 16 10:20:34 2014 +0000
@@ -0,0 +1,1533 @@
+/*
+	see copyright notice in squirrel.h
+*/
+#include "sqpcheader.h"
+#ifndef NO_COMPILER
+#include <stdarg.h>
+#include <setjmp.h>
+#include "sqopcodes.h"
+#include "sqstring.h"
+#include "sqfuncproto.h"
+#include "sqcompiler.h"
+#include "sqfuncstate.h"
+#include "sqlexer.h"
+#include "sqvm.h"
+#include "sqtable.h"
+
+#define EXPR   1
+#define OBJECT 2
+#define BASE   3
+#define LOCAL  4
+#define OUTER  5
+
+struct SQExpState {
+  SQInteger  etype;       /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */
+  SQInteger  epos;        /* expr. location on stack; -1 for OBJECT and BASE */
+  bool       donot_get;   /* signal not to deref the next value */
+};
+
+#define MAX_COMPILER_ERROR_LEN 256
+
+struct SQScope {
+	SQInteger outers;
+	SQInteger stacksize;
+};
+
+#define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \
+					 _scope.outers = _fs->_outers; \
+					 _scope.stacksize = _fs->GetStackSize();
+
+#define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \
+							if(_fs->CountOuters(_scope.stacksize)) { \
+								_fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
+							} \
+						}
+
+#define END_SCOPE_NO_CLOSE() {	if(_fs->GetStackSize() != _scope.stacksize) { \
+							_fs->SetStackSize(_scope.stacksize); \
+						} \
+						_scope = __oldscope__; \
+					}
+
+#define END_SCOPE() {	SQInteger oldouters = _fs->_outers;\
+						if(_fs->GetStackSize() != _scope.stacksize) { \
+							_fs->SetStackSize(_scope.stacksize); \
+							if(oldouters != _fs->_outers) { \
+								_fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
+							} \
+						} \
+						_scope = __oldscope__; \
+					}
+
+#define BEGIN_BREAKBLE_BLOCK()	SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
+							SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
+							_fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
+
+#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
+					__ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
+					if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
+					if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
+					_fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
+
+class SQCompiler
+{
+public:
+	SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
+	{
+		_vm=v;
+		_lex.Init(_ss(v), rg, up,ThrowError,this);
+		_sourcename = SQString::Create(_ss(v), sourcename);
+		_lineinfo = lineinfo;_raiseerror = raiseerror;
+		_scope.outers = 0;
+		_scope.stacksize = 0;
+		_compilererror[0] = NULL;
+	}
+	static void ThrowError(void *ud, const SQChar *s) {
+		SQCompiler *c = (SQCompiler *)ud;
+		c->Error(s);
+	}
+	void Error(const SQChar *s, ...)
+	{
+		va_list vl;
+		va_start(vl, s);
+		scvsprintf(_compilererror, s, vl);
+		va_end(vl);
+		longjmp(_errorjmp,1);
+	}
+	void Lex(){	_token = _lex.Lex();}
+	SQObject Expect(SQInteger tok)
+	{
+		
+		if(_token != tok) {
+			if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
+				//do nothing
+			}
+			else {
+				const SQChar *etypename;
+				if(tok > 255) {
+					switch(tok)
+					{
+					case TK_IDENTIFIER:
+						etypename = _SC("IDENTIFIER");
+						break;
+					case TK_STRING_LITERAL:
+						etypename = _SC("STRING_LITERAL");
+						break;
+					case TK_INTEGER:
+						etypename = _SC("INTEGER");
+						break;
+					case TK_FLOAT:
+						etypename = _SC("FLOAT");
+						break;
+					default:
+						etypename = _lex.Tok2Str(tok);
+					}
+					Error(_SC("expected '%s'"), etypename);
+				}
+				Error(_SC("expected '%c'"), tok);
+			}
+		}
+		SQObjectPtr ret;
+		switch(tok)
+		{
+		case TK_IDENTIFIER:
+			ret = _fs->CreateString(_lex._svalue);
+			break;
+		case TK_STRING_LITERAL:
+			ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+			break;
+		case TK_INTEGER:
+			ret = SQObjectPtr(_lex._nvalue);
+			break;
+		case TK_FLOAT:
+			ret = SQObjectPtr(_lex._fvalue);
+			break;
+		}
+		Lex();
+		return ret;
+	}
+	bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
+	void OptionalSemicolon()
+	{
+		if(_token == _SC(';')) { Lex(); return; }
+		if(!IsEndOfStatement()) {
+			Error(_SC("end of statement expected (; or lf)"));
+		}
+	}
+	void MoveIfCurrentTargetIsLocal() {
+		SQInteger trg = _fs->TopTarget();
+		if(_fs->IsLocal(trg)) {
+			trg = _fs->PopTarget(); //no pops the target and move it
+			_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
+		}
+	}
+	bool Compile(SQObjectPtr &o)
+	{
+		_debugline = 1;
+		_debugop = 0;
+
+		SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
+		funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
+		_fs = &funcstate;
+		_fs->AddParameter(_fs->CreateString(_SC("this")));
+		_fs->AddParameter(_fs->CreateString(_SC("vargv")));
+		_fs->_varparams = true;
+		_fs->_sourcename = _sourcename;
+		SQInteger stacksize = _fs->GetStackSize();
+		if(setjmp(_errorjmp) == 0) {
+			Lex();
+			while(_token > 0){
+				Statement();
+				if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
+			}
+			_fs->SetStackSize(stacksize);
+			_fs->AddLineInfos(_lex._currentline, _lineinfo, true);
+			_fs->AddInstruction(_OP_RETURN, 0xFF);
+			_fs->SetStackSize(0);
+			o =_fs->BuildProto();
+#ifdef _DEBUG_DUMP
+			_fs->Dump(_funcproto(o));
+#endif
+		}
+		else {
+			if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
+				_ss(_vm)->_compilererrorhandler(_vm, _compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
+					_lex._currentline, _lex._currentcolumn);
+			}
+			_vm->_lasterror = SQString::Create(_ss(_vm), _compilererror, -1);
+			return false;
+		}
+		return true;
+	}
+	void Statements()
+	{
+		while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
+			Statement();
+			if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
+		}
+	}
+	void Statement(bool closeframe = true)
+	{
+		_fs->AddLineInfos(_lex._currentline, _lineinfo);
+		switch(_token){
+		case _SC(';'):	Lex();					break;
+		case TK_IF:		IfStatement();			break;
+		case TK_WHILE:		WhileStatement();		break;
+		case TK_DO:		DoWhileStatement();		break;
+		case TK_FOR:		ForStatement();			break;
+		case TK_FOREACH:	ForEachStatement();		break;
+		case TK_SWITCH:	SwitchStatement();		break;
+		case TK_LOCAL:		LocalDeclStatement();	break;
+		case TK_RETURN:
+		case TK_YIELD: {
+			SQOpcode op;
+			if(_token == TK_RETURN) {
+				op = _OP_RETURN;
+			}
+			else {
+				op = _OP_YIELD;
+				_fs->_bgenerator = true;
+			}
+			Lex();
+			if(!IsEndOfStatement()) {
+				SQInteger retexp = _fs->GetCurrentPos()+1;
+				CommaExpr();
+				if(op == _OP_RETURN && _fs->_traps > 0)
+					_fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
+				_fs->_returnexp = retexp;
+				_fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());
+			}
+			else{ 
+				if(op == _OP_RETURN && _fs->_traps > 0)
+					_fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
+				_fs->_returnexp = -1;
+				_fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); 
+			}
+			break;}
+		case TK_BREAK:
+			if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
+			if(_fs->_breaktargets.top() > 0){
+				_fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
+			}
+			RESOLVE_OUTERS();
+			_fs->AddInstruction(_OP_JMP, 0, -1234);
+			_fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
+			Lex();
+			break;
+		case TK_CONTINUE:
+			if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
+			if(_fs->_continuetargets.top() > 0) {
+				_fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
+			}
+			RESOLVE_OUTERS();
+			_fs->AddInstruction(_OP_JMP, 0, -1234);
+			_fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
+			Lex();
+			break;
+		case TK_FUNCTION:
+			FunctionStatement();
+			break;
+		case TK_CLASS:
+			ClassStatement();
+			break;
+		case TK_ENUM:
+			EnumStatement();
+			break;
+		case _SC('{'):{
+				BEGIN_SCOPE();
+				Lex();
+				Statements();
+				Expect(_SC('}'));
+				if(closeframe) {
+					END_SCOPE();
+				}
+				else {
+					END_SCOPE_NO_CLOSE();
+				}
+			}
+			break;
+		case TK_TRY:
+			TryCatchStatement();
+			break;
+		case TK_THROW:
+			Lex();
+			CommaExpr();
+			_fs->AddInstruction(_OP_THROW, _fs->PopTarget());
+			break;
+		case TK_CONST:
+			{
+			Lex();
+			SQObject id = Expect(TK_IDENTIFIER);
+			Expect('=');
+			SQObject val = ExpectScalar();
+			OptionalSemicolon();
+			SQTable *enums = _table(_ss(_vm)->_consts);
+			SQObjectPtr strongid = id; 
+			enums->NewSlot(strongid,SQObjectPtr(val));
+			strongid.Null();
+			}
+			break;
+		default:
+			CommaExpr();
+			_fs->DiscardTarget();
+			//_fs->PopTarget();
+			break;
+		}
+		_fs->SnoozeOpt();
+	}
+	void EmitDerefOp(SQOpcode op)
+	{
+		SQInteger val = _fs->PopTarget();
+		SQInteger key = _fs->PopTarget();
+		SQInteger src = _fs->PopTarget();
+        _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
+	}
+	void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
+	{
+		SQInteger p2 = _fs->PopTarget(); //src in OP_GET
+		SQInteger p1 = _fs->PopTarget(); //key in OP_GET
+		_fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
+	}
+	void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)
+	{
+		/* Generate code depending on the expression type */
+		switch(etype) {
+		case LOCAL:{
+			SQInteger p2 = _fs->PopTarget(); //src in OP_GET
+			SQInteger p1 = _fs->PopTarget(); //key in OP_GET
+			_fs->PushTarget(p1);
+			//EmitCompArithLocal(tok, p1, p1, p2);
+			_fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
+			_fs->SnoozeOpt();
+				   }
+			break;
+		case OBJECT:
+		case BASE:
+			{
+				SQInteger val = _fs->PopTarget();
+				SQInteger key = _fs->PopTarget();
+				SQInteger src = _fs->PopTarget();
+				/* _OP_COMPARITH mixes dest obj and source val in the arg1 */
+				_fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));
+			}
+			break;
+		case OUTER:
+			{
+				SQInteger val = _fs->TopTarget();
+				SQInteger tmp = _fs->PushTarget();
+				_fs->AddInstruction(_OP_GETOUTER,   tmp, pos);
+				_fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
+				_fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp);
+			}
+			break;
+		}
+	}
+	void CommaExpr()
+	{
+		for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
+	}
+	void Expression()
+	{
+		 SQExpState es = _es;
+		_es.etype     = EXPR;
+		_es.epos      = -1;
+		_es.donot_get = false;
+		LogicalOrExp();
+		switch(_token)  {
+		case _SC('='):
+		case TK_NEWSLOT:
+		case TK_MINUSEQ:
+		case TK_PLUSEQ:
+		case TK_MULEQ:
+		case TK_DIVEQ:
+		case TK_MODEQ:{
+			SQInteger op = _token;
+			SQInteger ds = _es.etype;
+			SQInteger pos = _es.epos;
+			if(ds == EXPR) Error(_SC("can't assign expression"));
+			else if(ds == BASE) Error(_SC("'base' cannot be modified"));
+
+			Lex(); Expression();
+
+			switch(op){
+			case TK_NEWSLOT:
+				if(ds == OBJECT || ds == BASE)
+					EmitDerefOp(_OP_NEWSLOT);
+				else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
+					Error(_SC("can't 'create' a local slot"));
+				break;
+			case _SC('='): //ASSIGN
+				switch(ds) {
+				case LOCAL:
+					{
+						SQInteger src = _fs->PopTarget();
+						SQInteger dst = _fs->TopTarget();
+						_fs->AddInstruction(_OP_MOVE, dst, src);
+					}
+					break;
+				case OBJECT:
+				case BASE:
+					EmitDerefOp(_OP_SET);
+					break;
+				case OUTER:
+					{
+						SQInteger src = _fs->PopTarget();
+						SQInteger dst = _fs->PushTarget();
+						_fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
+					}
+				}
+				break;
+			case TK_MINUSEQ:
+			case TK_PLUSEQ:
+			case TK_MULEQ:
+			case TK_DIVEQ:
+			case TK_MODEQ:
+				EmitCompoundArith(op, ds, pos);
+				break;
+			}
+			}
+			break;
+		case _SC('?'): {
+			Lex();
+			_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
+			SQInteger jzpos = _fs->GetCurrentPos();
+			SQInteger trg = _fs->PushTarget();
+			Expression();
+			SQInteger first_exp = _fs->PopTarget();
+			if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
+			SQInteger endfirstexp = _fs->GetCurrentPos();
+			_fs->AddInstruction(_OP_JMP, 0, 0);
+			Expect(_SC(':'));
+			SQInteger jmppos = _fs->GetCurrentPos();
+			Expression();
+			SQInteger second_exp = _fs->PopTarget();
+			if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
+			_fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
+			_fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
+			_fs->SnoozeOpt();
+			}
+			break;
+		}
+		_es = es;
+	}
+	template<typename T> void INVOKE_EXP(T f)
+	{
+		SQExpState es = _es;
+		_es.etype     = EXPR;
+		_es.epos      = -1;
+		_es.donot_get = false;
+		(this->*f)();
+		_es = es;
+	}
+	template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)
+	{
+		Lex(); 
+		INVOKE_EXP(f);
+		SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
+		_fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
+	}
+	void LogicalOrExp()
+	{
+		LogicalAndExp();
+		for(;;) if(_token == TK_OR) {
+			SQInteger first_exp = _fs->PopTarget();
+			SQInteger trg = _fs->PushTarget();
+			_fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
+			SQInteger jpos = _fs->GetCurrentPos();
+			if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
+			Lex(); INVOKE_EXP(&SQCompiler::LogicalOrExp);
+			_fs->SnoozeOpt();
+			SQInteger second_exp = _fs->PopTarget();
+			if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
+			_fs->SnoozeOpt();
+			_fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
+			break;
+		}else return;
+	}
+	void LogicalAndExp()
+	{
+		BitwiseOrExp();
+		for(;;) switch(_token) {
+		case TK_AND: {
+			SQInteger first_exp = _fs->PopTarget();
+			SQInteger trg = _fs->PushTarget();
+			_fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
+			SQInteger jpos = _fs->GetCurrentPos();
+			if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
+			Lex(); INVOKE_EXP(&SQCompiler::LogicalAndExp);
+			_fs->SnoozeOpt();
+			SQInteger second_exp = _fs->PopTarget();
+			if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
+			_fs->SnoozeOpt();
+			_fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
+			break;
+			}
+    
+		default:
+			return;
+		}
+	}
+	void BitwiseOrExp()
+	{
+		BitwiseXorExp();
+		for(;;) if(_token == _SC('|'))
+		{BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
+		}else return;
+	}
+	void BitwiseXorExp()
+	{
+		BitwiseAndExp();
+		for(;;) if(_token == _SC('^'))
+		{BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
+		}else return;
+	}
+	void BitwiseAndExp()
+	{
+		EqExp();
+		for(;;) if(_token == _SC('&'))
+		{BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND);
+		}else return;
+	}
+	void EqExp()
+	{
+		CompExp();
+		for(;;) switch(_token) {
+		case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break;
+		case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break;
+		case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break;
+		default: return;	
+		}
+	}
+	void CompExp()
+	{
+		ShiftExp();
+		for(;;) switch(_token) {
+		case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
+		case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
+		case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
+		case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
+		case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::ShiftExp); break;
+		case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::ShiftExp); break;
+		default: return;	
+		}
+	}
+	void ShiftExp()
+	{
+		PlusExp();
+		for(;;) switch(_token) {
+		case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
+		case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
+		case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
+		default: return;	
+		}
+	}
+	SQOpcode ChooseArithOpByToken(SQInteger tok)
+	{
+		switch(tok) {
+			case TK_PLUSEQ: case '+': return _OP_ADD;
+			case TK_MINUSEQ: case '-': return _OP_SUB;
+			case TK_MULEQ: case '*': return _OP_MUL;
+			case TK_DIVEQ: case '/': return _OP_DIV;
+			case TK_MODEQ: case '%': return _OP_MOD;
+			default: assert(0);
+		}
+		return _OP_ADD;
+	}
+	SQInteger ChooseCompArithCharByToken(SQInteger tok)
+	{
+		SQInteger oper;
+		switch(tok){
+		case TK_MINUSEQ: oper = '-'; break;
+		case TK_PLUSEQ: oper = '+'; break;
+		case TK_MULEQ: oper = '*'; break;
+		case TK_DIVEQ: oper = '/'; break;
+		case TK_MODEQ: oper = '%'; break;
+		default: oper = 0; //shut up compiler
+			assert(0); break;
+		};
+		return oper;
+	}
+	void PlusExp()
+	{
+		MultExp();
+		for(;;) switch(_token) {
+		case _SC('+'): case _SC('-'):
+			BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break;
+		default: return;
+		}
+	}
+	
+	void MultExp()
+	{
+		PrefixedExpr();
+		for(;;) switch(_token) {
+		case _SC('*'): case _SC('/'): case _SC('%'):
+			BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break;
+		default: return;
+		}
+	}
+	//if 'pos' != -1 the previous variable is a local variable
+	void PrefixedExpr()
+	{
+		SQInteger pos = Factor();
+		for(;;) {
+			switch(_token) {
+			case _SC('.'):
+				pos = -1;
+				Lex(); 
+
+				_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
+				if(_es.etype==BASE) {
+					Emit2ArgsOP(_OP_GET);
+					pos = _fs->TopTarget();
+					_es.etype = EXPR;
+					_es.epos   = pos;
+				}
+				else {
+					if(NeedGet()) {
+						Emit2ArgsOP(_OP_GET);
+					}
+					_es.etype = OBJECT;
+				}
+				break;
+			case _SC('['):
+				if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
+				Lex(); Expression(); Expect(_SC(']')); 
+				pos = -1;
+				if(_es.etype==BASE) {
+					Emit2ArgsOP(_OP_GET);
+					pos = _fs->TopTarget();
+					_es.etype = EXPR;
+					_es.epos   = pos;
+				}
+				else {
+					if(NeedGet()) {
+						Emit2ArgsOP(_OP_GET);
+					}
+					_es.etype = OBJECT;
+				}
+				break;
+			case TK_MINUSMINUS:
+			case TK_PLUSPLUS:
+				{
+					if(IsEndOfStatement()) return;
+					SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
+					Lex();
+					switch(_es.etype)
+					{
+						case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
+						case OBJECT:
+						case BASE:
+							Emit2ArgsOP(_OP_PINC, diff);
+							break;
+						case LOCAL: {
+							SQInteger src = _fs->PopTarget();
+							_fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);
+									}
+							break;
+						case OUTER: {
+							SQInteger tmp1 = _fs->PushTarget();
+							SQInteger tmp2 = _fs->PushTarget();
+							_fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);
+							_fs->AddInstruction(_OP_PINCL,    tmp1, tmp2, 0, diff);
+							_fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);
+							_fs->PopTarget();
+						}
+					}
+				}
+				return;
+				break;	
+			case _SC('('): 
+				switch(_es.etype) {
+					case OBJECT: {
+						SQInteger key     = _fs->PopTarget();  /* location of the key */
+						SQInteger table   = _fs->PopTarget();  /* location of the object */
+						SQInteger closure = _fs->PushTarget(); /* location for the closure */
+						SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */
+						_fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
+						}
+						break;
+					case BASE:
+						//Emit2ArgsOP(_OP_GET);
+						_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
+						break;
+					case OUTER:
+						_fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);
+						_fs->AddInstruction(_OP_MOVE,     _fs->PushTarget(), 0);
+						break;
+					default:
+						_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
+				}
+				_es.etype = EXPR;
+				Lex();
+				FunctionCallArgs();
+				break;
+			default: return;
+			}
+		}
+	}
+	SQInteger Factor()
+	{
+		_es.etype = EXPR;
+		switch(_token)
+		{
+		case TK_STRING_LITERAL:
+			_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
+			Lex(); 
+			break;
+		case TK_BASE:
+			Lex();
+			_fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());
+			_es.etype  = BASE;
+			_es.epos   = _fs->TopTarget();
+			return (_es.epos);
+			break;
+		case TK_IDENTIFIER:
+		case TK_CONSTRUCTOR:
+		case TK_THIS:{
+				SQObject id;
+				SQObject constant;
+
+				switch(_token) {
+					case TK_IDENTIFIER:  id = _fs->CreateString(_lex._svalue);       break;
+					case TK_THIS:        id = _fs->CreateString(_SC("this"));        break;
+					case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
+				}
+
+				SQInteger pos = -1;
+				Lex();
+				if((pos = _fs->GetLocalVariable(id)) != -1) {
+					/* Handle a local variable (includes 'this') */
+					_fs->PushTarget(pos);
+					_es.etype  = LOCAL;
+					_es.epos   = pos;
+				}
+
+				else if((pos = _fs->GetOuterVariable(id)) != -1) {
+					/* Handle a free var */
+					if(NeedGet()) {
+						_es.epos  = _fs->PushTarget();
+						_fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);	
+						/* _es.etype = EXPR; already default value */
+					}
+					else {
+						_es.etype = OUTER;
+						_es.epos  = pos;
+					}
+				}
+
+				else if(_fs->IsConstant(id, constant)) {
+					/* Handle named constant */
+					SQObjectPtr constval;
+					SQObject    constid;
+					if(type(constant) == OT_TABLE) {
+						Expect('.');
+						constid = Expect(TK_IDENTIFIER);
+						if(!_table(constant)->Get(constid, constval)) {
+							constval.Null();
+							Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));
+						}
+					}
+					else {
+						constval = constant;
+					}
+					_es.epos = _fs->PushTarget();
+
+					/* generate direct or literal function depending on size */
+					SQObjectType ctype = type(constval);
+					switch(ctype) {
+						case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;
+						case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;
+						default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;
+					}
+					_es.etype = EXPR;
+				}
+				else {
+					/* Handle a non-local variable, aka a field. Push the 'this' pointer on
+					* the virtual stack (always found in offset 0, so no instruction needs to
+					* be generated), and push the key next. Generate an _OP_LOAD instruction
+					* for the latter. If we are not using the variable as a dref expr, generate
+					* the _OP_GET instruction.
+					*/
+					_fs->PushTarget(0);
+					_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
+					if(NeedGet()) {
+						Emit2ArgsOP(_OP_GET);
+					}
+					_es.etype = OBJECT;
+				}
+				return _es.epos;
+			}
+			break;
+		case TK_DOUBLE_COLON:  // "::"
+			_fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());
+			_es.etype = OBJECT;
+			_token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/
+			_es.epos = -1;
+			return _es.epos;
+			break;
+		case TK_NULL: 
+			_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
+			Lex();
+			break;
+		case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex();	break;
+		case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;
+		case TK_TRUE: case TK_FALSE:
+			_fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
+			Lex();
+			break;
+		case _SC('['): {
+				_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);
+				SQInteger apos = _fs->GetCurrentPos(),key = 0;
+				Lex();
+				while(_token != _SC(']')) {
+                    Expression(); 
+					if(_token == _SC(',')) Lex();
+					SQInteger val = _fs->PopTarget();
+					SQInteger array = _fs->TopTarget();
+					_fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);
+					key++;
+				}
+				_fs->SetIntructionParam(apos, 1, key);
+				Lex();
+			}
+			break;
+		case _SC('{'):
+			_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
+			Lex();ParseTableOrClass(_SC(','),_SC('}'));
+			break;
+		case TK_FUNCTION: FunctionExp(_token);break;
+		case _SC('@'): FunctionExp(_token,true);break;
+		case TK_CLASS: Lex(); ClassExp();break;
+		case _SC('-'): 
+			Lex(); 
+			switch(_token) {
+			case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;
+			case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;
+			default: UnaryOP(_OP_NEG);
+			}
+			break;
+		case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;
+		case _SC('~'): 
+			Lex(); 
+			if(_token == TK_INTEGER)  { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }
+			UnaryOP(_OP_BWNOT); 
+			break;
+		case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;
+		case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;
+		case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;
+		case TK_MINUSMINUS : 
+		case TK_PLUSPLUS :PrefixIncDec(_token); break;
+		case TK_DELETE : DeleteExpr(); break;
+		case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
+			break;
+		default: Error(_SC("expression expected"));
+		}
+		return -1;
+	}
+	void EmitLoadConstInt(SQInteger value,SQInteger target)
+	{
+		if(target < 0) {
+			target = _fs->PushTarget();
+		}
+		if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits?
+			_fs->AddInstruction(_OP_LOADINT, target,value);
+		}
+		else {
+			_fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
+		}
+	}
+	void EmitLoadConstFloat(SQFloat value,SQInteger target)
+	{
+		if(target < 0) {
+			target = _fs->PushTarget();
+		}
+		if(sizeof(SQFloat) == sizeof(SQInt32)) {
+			_fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value));
+		}
+		else {
+			_fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
+		}
+	}
+	void UnaryOP(SQOpcode op)
+	{
+		PrefixedExpr();
+		SQInteger src = _fs->PopTarget();
+		_fs->AddInstruction(op, _fs->PushTarget(), src);
+	}
+	bool NeedGet()
+	{
+		switch(_token) {
+		case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:
+	    case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS:
+			return false;
+		}
+		return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
+	}
+	void FunctionCallArgs()
+	{
+		SQInteger nargs = 1;//this
+		 while(_token != _SC(')')) {
+			 Expression();
+			 MoveIfCurrentTargetIsLocal();
+			 nargs++; 
+			 if(_token == _SC(',')){ 
+				 Lex(); 
+				 if(_token == ')') Error(_SC("expression expected, found ')'"));
+			 }
+		 }
+		 Lex();
+		 for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
+		 SQInteger stackbase = _fs->PopTarget();
+		 SQInteger closure = _fs->PopTarget();
+         _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
+	}
+	void ParseTableOrClass(SQInteger separator,SQInteger terminator)
+	{
+		SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
+		while(_token != terminator) {
+			bool hasattrs = false;
+			bool isstatic = false;
+			//check if is an attribute
+			if(separator == ';') {
+				if(_token == TK_ATTR_OPEN) {
+					_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();
+					ParseTableOrClass(',',TK_ATTR_CLOSE);
+					hasattrs = true;
+				}
+				if(_token == TK_STATIC) {
+					isstatic = true;
+					Lex();
+				}
+			}
+			switch(_token) {
+			case TK_FUNCTION:
+			case TK_CONSTRUCTOR:{
+				SQInteger tk = _token;
+				Lex();
+				SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
+				Expect(_SC('('));
+				_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
+				CreateFunction(id);
+				_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
+								}
+								break;
+			case _SC('['):
+				Lex(); CommaExpr(); Expect(_SC(']'));
+				Expect(_SC('=')); Expression();
+				break;
+			case TK_STRING_LITERAL: //JSON
+				if(separator == ',') { //only works for tables
+					_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));
+					Expect(_SC(':')); Expression();
+					break;
+				}
+			default :
+				_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
+				Expect(_SC('=')); Expression();
+			}
+			if(_token == separator) Lex();//optional comma/semicolon
+			nkeys++;
+			SQInteger val = _fs->PopTarget();
+			SQInteger key = _fs->PopTarget();
+			SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
+			assert((hasattrs && (attrs == key-1)) || !hasattrs);
+			unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
+			SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
+			if(separator == _SC(',')) { //hack recognizes a table from the separator
+				_fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);
+			}
+			else {
+				_fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember
+			}
+		}
+		if(separator == _SC(',')) //hack recognizes a table from the separator
+			_fs->SetIntructionParam(tpos, 1, nkeys);
+		Lex();
+	}
+	void LocalDeclStatement()
+	{
+		SQObject varname;
+		Lex();
+		if( _token == TK_FUNCTION) {
+			Lex();
+			varname = Expect(TK_IDENTIFIER);
+			Expect(_SC('('));
+			CreateFunction(varname,false);
+			_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
+			_fs->PopTarget();
+			_fs->PushLocalVariable(varname);
+			return;
+		}
+
+		do {
+			varname = Expect(TK_IDENTIFIER);
+			if(_token == _SC('=')) {
+				Lex(); Expression();
+				SQInteger src = _fs->PopTarget();
+				SQInteger dest = _fs->PushTarget();
+				if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
+			}
+			else{
+				_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
+			}
+			_fs->PopTarget();
+			_fs->PushLocalVariable(varname);
+			if(_token == _SC(',')) Lex(); else break;
+		} while(1);
+	}
+	void IfStatement()
+    {
+        SQInteger jmppos;
+        bool haselse = false;
+        Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
+        _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
+        SQInteger jnepos = _fs->GetCurrentPos();
+        BEGIN_SCOPE();
+        
+        Statement();
+        //
+        if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
+        
+        END_SCOPE();
+        SQInteger endifblock = _fs->GetCurrentPos();
+        if(_token == TK_ELSE){
+            haselse = true;
+            BEGIN_SCOPE();
+            _fs->AddInstruction(_OP_JMP);
+            jmppos = _fs->GetCurrentPos();
+            Lex();
+            Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
+            END_SCOPE();
+            _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
+        }
+        _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
+    }
+	void WhileStatement()
+	{
+		SQInteger jzpos, jmppos;
+		jmppos = _fs->GetCurrentPos();
+		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
+		
+		BEGIN_BREAKBLE_BLOCK();
+		_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
+		jzpos = _fs->GetCurrentPos();
+		BEGIN_SCOPE();
+		
+		Statement();
+		
+		END_SCOPE();
+		_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
+		_fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
+		
+		END_BREAKBLE_BLOCK(jmppos);
+	}
+	void DoWhileStatement()
+	{
+		Lex();
+		SQInteger jmptrg = _fs->GetCurrentPos();
+		BEGIN_BREAKBLE_BLOCK()
+		BEGIN_SCOPE();
+		Statement();
+		END_SCOPE();
+		Expect(TK_WHILE);
+		SQInteger continuetrg = _fs->GetCurrentPos();
+		Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
+		_fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
+		_fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
+		END_BREAKBLE_BLOCK(continuetrg);
+	}
+	void ForStatement()
+	{
+		Lex();
+		BEGIN_SCOPE();
+		Expect(_SC('('));
+		if(_token == TK_LOCAL) LocalDeclStatement();
+		else if(_token != _SC(';')){
+			CommaExpr();
+			_fs->PopTarget();
+		}
+		Expect(_SC(';'));
+		_fs->SnoozeOpt();
+		SQInteger jmppos = _fs->GetCurrentPos();
+		SQInteger jzpos = -1;
+		if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
+		Expect(_SC(';'));
+		_fs->SnoozeOpt();
+		SQInteger expstart = _fs->GetCurrentPos() + 1;
+		if(_token != _SC(')')) {
+			CommaExpr();
+			_fs->PopTarget();
+		}
+		Expect(_SC(')'));
+		_fs->SnoozeOpt();
+		SQInteger expend = _fs->GetCurrentPos();
+		SQInteger expsize = (expend - expstart) + 1;
+		SQInstructionVec exp;
+		if(expsize > 0) {
+			for(SQInteger i = 0; i < expsize; i++)
+				exp.push_back(_fs->GetInstruction(expstart + i));
+			_fs->PopInstructions(expsize);
+		}
+		BEGIN_BREAKBLE_BLOCK()
+		Statement();
+		SQInteger continuetrg = _fs->GetCurrentPos();
+		if(expsize > 0) {
+			for(SQInteger i = 0; i < expsize; i++)
+				_fs->AddInstruction(exp[i]);
+		}
+		_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
+		if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
+		END_SCOPE();
+		
+		END_BREAKBLE_BLOCK(continuetrg);
+	}
+	void ForEachStatement()
+	{
+		SQObject idxname, valname;
+		Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
+		if(_token == _SC(',')) {
+			idxname = valname;
+			Lex(); valname = Expect(TK_IDENTIFIER);
+		}
+		else{
+			idxname = _fs->CreateString(_SC("@INDEX@"));
+		}
+		Expect(TK_IN);
+		
+		//save the stack size
+		BEGIN_SCOPE();
+		//put the table in the stack(evaluate the table expression)
+		Expression(); Expect(_SC(')'));
+		SQInteger container = _fs->TopTarget();
+		//push the index local var
+		SQInteger indexpos = _fs->PushLocalVariable(idxname);
+		_fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
+		//push the value local var
+		SQInteger valuepos = _fs->PushLocalVariable(valname);
+		_fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
+		//push reference index
+		SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
+		_fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
+		SQInteger jmppos = _fs->GetCurrentPos();
+		_fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
+		SQInteger foreachpos = _fs->GetCurrentPos();
+		_fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
+		//generate the statement code
+		BEGIN_BREAKBLE_BLOCK()
+		Statement();
+		_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
+		_fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
+		_fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
+		END_BREAKBLE_BLOCK(foreachpos - 1);
+		//restore the local variable stack(remove index,val and ref idx)
+		_fs->PopTarget();
+		END_SCOPE();
+	}
+	void SwitchStatement()
+	{
+		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
+		Expect(_SC('{'));
+		SQInteger expr = _fs->TopTarget();
+		bool bfirst = true;
+		SQInteger tonextcondjmp = -1;
+		SQInteger skipcondjmp = -1;
+		SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
+		_fs->_breaktargets.push_back(0);
+		while(_token == TK_CASE) {
+			if(!bfirst) {
+				_fs->AddInstruction(_OP_JMP, 0, 0);
+				skipcondjmp = _fs->GetCurrentPos();
+				_fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
+			}
+			//condition
+			Lex(); Expression(); Expect(_SC(':'));
+			SQInteger trg = _fs->PopTarget();
+			SQInteger eqtarget = trg;
+			bool local = _fs->IsLocal(trg);
+			if(local) {
+				eqtarget = _fs->PushTarget(); //we need to allocate a extra reg
+			}
+			_fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);
+			_fs->AddInstruction(_OP_JZ, eqtarget, 0);
+			if(local) {
+				_fs->PopTarget();
+			}
+			
+			//end condition
+			if(skipcondjmp != -1) {
+				_fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
+			}
+			tonextcondjmp = _fs->GetCurrentPos();
+			BEGIN_SCOPE();
+			Statements();
+			END_SCOPE();
+			bfirst = false;
+		}
+		if(tonextcondjmp != -1)
+			_fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
+		if(_token == TK_DEFAULT) {
+			Lex(); Expect(_SC(':'));
+			BEGIN_SCOPE();
+			Statements();
+			END_SCOPE();
+		}
+		Expect(_SC('}'));
+		_fs->PopTarget();
+		__nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
+		if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
+		_fs->_breaktargets.pop_back();
+	}
+	void FunctionStatement()
+	{
+		SQObject id;
+		Lex(); id = Expect(TK_IDENTIFIER);
+		_fs->PushTarget(0);
+		_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
+		if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
+		
+		while(_token == TK_DOUBLE_COLON) {
+			Lex();
+			id = Expect(TK_IDENTIFIER);
+			_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
+			if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
+		}
+		Expect(_SC('('));
+		CreateFunction(id);
+		_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
+		EmitDerefOp(_OP_NEWSLOT);
+		_fs->PopTarget();
+	}
+	void ClassStatement()
+	{
+		SQExpState es;
+		Lex();
+		es = _es;
+		_es.donot_get = true;
+		PrefixedExpr();
+		if(_es.etype == EXPR) {
+			Error(_SC("invalid class name"));
+		}
+		else if(_es.etype == OBJECT || _es.etype == BASE) {
+			ClassExp();
+			EmitDerefOp(_OP_NEWSLOT);
+			_fs->PopTarget();
+		}
+		else {
+			Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
+		}
+		_es = es;
+	}
+	SQObject ExpectScalar()
+	{
+		SQObject val;
+		val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x
+		switch(_token) {
+			case TK_INTEGER:
+				val._type = OT_INTEGER;
+				val._unVal.nInteger = _lex._nvalue;
+				break;
+			case TK_FLOAT:
+				val._type = OT_FLOAT;
+				val._unVal.fFloat = _lex._fvalue;
+				break;
+			case TK_STRING_LITERAL:
+				val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+				break;
+			case TK_TRUE:
+			case TK_FALSE:
+				val._type = OT_BOOL;
+				val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;
+				break;
+			case '-':
+				Lex();
+				switch(_token)
+				{
+				case TK_INTEGER:
+					val._type = OT_INTEGER;
+					val._unVal.nInteger = -_lex._nvalue;
+				break;
+				case TK_FLOAT:
+					val._type = OT_FLOAT;
+					val._unVal.fFloat = -_lex._fvalue;
+				break;
+				default:
+					Error(_SC("scalar expected : integer,float"));
+				}
+				break;
+			default:
+				Error(_SC("scalar expected : integer,float or string"));
+		}
+		Lex();
+		return val;
+	}
+	void EnumStatement()
+	{
+		Lex(); 
+		SQObject id = Expect(TK_IDENTIFIER);
+		Expect(_SC('{'));
+		
+		SQObject table = _fs->CreateTable();
+		SQInteger nval = 0;
+		while(_token != _SC('}')) {
+			SQObject key = Expect(TK_IDENTIFIER);
+			SQObject val;
+			if(_token == _SC('=')) {
+				Lex();
+				val = ExpectScalar();
+			}
+			else {
+				val._type = OT_INTEGER;
+				val._unVal.nInteger = nval++;
+			}
+			_table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
+			if(_token == ',') Lex();
+		}
+		SQTable *enums = _table(_ss(_vm)->_consts);
+		SQObjectPtr strongid = id; 
+		enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
+		strongid.Null();
+		Lex();
+	}
+	void TryCatchStatement()
+	{
+		SQObject exid;
+		Lex();
+		_fs->AddInstruction(_OP_PUSHTRAP,0,0);
+		_fs->_traps++;
+		if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
+		if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
+		SQInteger trappos = _fs->GetCurrentPos();
+		{
+			BEGIN_SCOPE();
+			Statement();
+			END_SCOPE();
+		}
+		_fs->_traps--;
+		_fs->AddInstruction(_OP_POPTRAP, 1, 0);
+		if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
+		if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
+		_fs->AddInstruction(_OP_JMP, 0, 0);
+		SQInteger jmppos = _fs->GetCurrentPos();
+		_fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
+		Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
+		{
+			BEGIN_SCOPE();
+			SQInteger ex_target = _fs->PushLocalVariable(exid);
+			_fs->SetIntructionParam(trappos, 0, ex_target);
+			Statement();
+			_fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
+			END_SCOPE();
+		}
+	}
+	void FunctionExp(SQInteger ftype,bool lambda = false)
+	{
+		Lex(); Expect(_SC('('));
+		SQObjectPtr dummy;
+		CreateFunction(dummy,lambda);
+		_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
+	}
+	void ClassExp()
+	{
+		SQInteger base = -1;
+		SQInteger attrs = -1;
+		if(_token == TK_EXTENDS) {
+			Lex(); Expression();
+			base = _fs->TopTarget();
+		}
+		if(_token == TK_ATTR_OPEN) {
+			Lex();
+			_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
+			ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
+			attrs = _fs->TopTarget();
+		}
+		Expect(_SC('{'));
+		if(attrs != -1) _fs->PopTarget();
+		if(base != -1) _fs->PopTarget();
+		_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);
+		ParseTableOrClass(_SC(';'),_SC('}'));
+	}
+	void DeleteExpr()
+	{
+		SQExpState es;
+		Lex();
+		es = _es;
+		_es.donot_get = true;
+		PrefixedExpr();
+		if(_es.etype==EXPR) Error(_SC("can't delete an expression"));
+		if(_es.etype==OBJECT || _es.etype==BASE) {
+			Emit2ArgsOP(_OP_DELETE);
+		}
+		else {
+			Error(_SC("cannot delete an (outer) local"));
+		}
+		_es = es;
+	}
+	void PrefixIncDec(SQInteger token)
+	{
+		SQExpState  es;
+		SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
+		Lex();
+		es = _es;
+		_es.donot_get = true;
+		PrefixedExpr();
+		if(_es.etype==EXPR) {
+			Error(_SC("can't '++' or '--' an expression"));
+		}
+		else if(_es.etype==OBJECT || _es.etype==BASE) {
+			Emit2ArgsOP(_OP_INC, diff);
+		}
+		else if(_es.etype==LOCAL) {
+			SQInteger src = _fs->TopTarget();
+			_fs->AddInstruction(_OP_INCL, src, src, 0, diff);
+			
+		}
+		else if(_es.etype==OUTER) {
+			SQInteger tmp = _fs->PushTarget();
+			_fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);
+			_fs->AddInstruction(_OP_INCL,     tmp, tmp, 0, diff);
+			_fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);
+		}
+		_es = es;
+	}
+	void CreateFunction(SQObject &name,bool lambda = false)
+	{
+		SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
+		funcstate->_name = name;
+		SQObject paramname;
+		funcstate->AddParameter(_fs->CreateString(_SC("this")));
+		funcstate->_sourcename = _sourcename;
+		SQInteger defparams = 0;
+		while(_token!=_SC(')')) {
+			if(_token == TK_VARPARAMS) {
+				if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
+				funcstate->AddParameter(_fs->CreateString(_SC("vargv")));
+				funcstate->_varparams = true;
+				Lex();
+				if(_token != _SC(')')) Error(_SC("expected ')'"));
+				break;
+			}
+			else {
+				paramname = Expect(TK_IDENTIFIER);
+				funcstate->AddParameter(paramname);
+				if(_token == _SC('=')) { 
+					Lex();
+					Expression();
+					funcstate->AddDefaultParam(_fs->TopTarget());
+					defparams++;
+				}
+				else {
+					if(defparams > 0) Error(_SC("expected '='"));
+				}
+				if(_token == _SC(',')) Lex();
+				else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
+			}
+		}
+		Expect(_SC(')'));
+		for(SQInteger n = 0; n < defparams; n++) {
+			_fs->PopTarget();
+		}
+				
+		SQFuncState *currchunk = _fs;
+		_fs = funcstate;
+		if(lambda) { 
+			Expression(); 
+			_fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}
+		else { 
+			Statement(false); 
+		}
+		funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
+        funcstate->AddInstruction(_OP_RETURN, -1);
+		funcstate->SetStackSize(0);
+
+		SQFunctionProto *func = funcstate->BuildProto();
+#ifdef _DEBUG_DUMP
+		funcstate->Dump(func);
+#endif
+		_fs = currchunk;
+		_fs->_functions.push_back(func);
+		_fs->PopChildState();
+	}
+	void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
+	{
+		while(ntoresolve > 0) {
+			SQInteger pos = funcstate->_unresolvedbreaks.back();
+			funcstate->_unresolvedbreaks.pop_back();
+			//set the jmp instruction
+			funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
+			ntoresolve--;
+		}
+	}
+	void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
+	{
+		while(ntoresolve > 0) {
+			SQInteger pos = funcstate->_unresolvedcontinues.back();
+			funcstate->_unresolvedcontinues.pop_back();
+			//set the jmp instruction
+			funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
+			ntoresolve--;
+		}
+	}
+private:
+	SQInteger _token;
+	SQFuncState *_fs;
+	SQObjectPtr _sourcename;
+	SQLexer _lex;
+	bool _lineinfo;
+	bool _raiseerror;
+	SQInteger _debugline;
+	SQInteger _debugop;
+	SQExpState   _es;
+	SQScope _scope;
+	SQChar _compilererror[MAX_COMPILER_ERROR_LEN];
+	jmp_buf _errorjmp;
+	SQVM *_vm;
+};
+
+bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
+{
+	SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
+	return p.Compile(out);
+}
+
+#endif