1 /*
2 	see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include <stdarg.h>
6 #include <setjmp.h>
7 #include "sqopcodes.h"
8 #include "sqstring.h"
9 #include "sqfuncproto.h"
10 #include "sqcompiler.h"
11 #include "sqfuncstate.h"
12 #include "sqlexer.h"
13 #include "sqvm.h"
14 #include "sqtable.h"
15 
16 #define DEREF_NO_DEREF	-1
17 #define DEREF_FIELD		-2
18 
19 struct ExpState
20 {
ExpStateExpState21 	ExpState()
22 	{
23 		_deref = DEREF_NO_DEREF;
24 		_freevar = false;
25 		_class_or_delete = false;
26 		_funcarg = false;
27 	}
28 	bool _class_or_delete;
29 	bool _funcarg;
30 	bool _freevar;
31 	SQInteger _deref;
32 };
33 
34 typedef sqvector<ExpState> ExpStateVec;
35 
36 #define _exst (_expstates.top())
37 
38 #define BEGIN_BREAKBLE_BLOCK()	SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
39 							SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
40 							_fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
41 
42 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
43 					__ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
44 					if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
45 					if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
46 					_fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
47 
48 class SQCompiler
49 {
50 public:
SQCompiler(SQVM * v,SQLEXREADFUNC rg,SQUserPointer up,const SQChar * sourcename,bool raiseerror,bool lineinfo)51 	SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
52 	{
53 		_vm=v;
54 		_lex.Init(_ss(v), rg, up,ThrowError,this);
55 		_sourcename = SQString::Create(_ss(v), sourcename);
56 		_lineinfo = lineinfo;_raiseerror = raiseerror;
57 		compilererror = NULL;
58 	}
ThrowError(void * ud,const SQChar * s)59 	static void ThrowError(void *ud, const SQChar *s) {
60 		SQCompiler *c = (SQCompiler *)ud;
61 		c->Error(s);
62 	}
Error(const SQChar * s,...)63 	void Error(const SQChar *s, ...)
64 	{
65 		static SQChar temp[256];
66 		va_list vl;
67 		va_start(vl, s);
68 		scvsprintf(temp, s, vl);
69 		va_end(vl);
70 		compilererror = temp;
71 		longjmp(_errorjmp,1);
72 	}
Lex()73 	void Lex(){	_token = _lex.Lex();}
PushExpState()74 	void PushExpState(){ _expstates.push_back(ExpState()); }
IsDerefToken(SQInteger tok)75 	bool IsDerefToken(SQInteger tok)
76 	{
77 		switch(tok){
78 		case _SC('='): case _SC('('): case TK_NEWSLOT:
79 		case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true;
80 		}
81 		return false;
82 	}
PopExpState()83 	ExpState PopExpState()
84 	{
85 		ExpState ret = _expstates.top();
86 		_expstates.pop_back();
87 		return ret;
88 	}
Expect(SQInteger tok)89 	SQObject Expect(SQInteger tok)
90 	{
91 
92 		if(_token != tok) {
93 			if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
94 				//ret = SQString::Create(_ss(_vm),_SC("constructor"));
95 				//do nothing
96 			}
97 			else {
98 				const SQChar *etypename;
99 				if(tok > 255) {
100 					switch(tok)
101 					{
102 					case TK_IDENTIFIER:
103 						etypename = _SC("IDENTIFIER");
104 						break;
105 					case TK_STRING_LITERAL:
106 						etypename = _SC("STRING_LITERAL");
107 						break;
108 					case TK_INTEGER:
109 						etypename = _SC("INTEGER");
110 						break;
111 					case TK_FLOAT:
112 						etypename = _SC("FLOAT");
113 						break;
114 					default:
115 						etypename = _lex.Tok2Str(tok);
116 					}
117 					Error(_SC("expected '%s'"), etypename);
118 				}
119 				Error(_SC("expected '%c'"), tok);
120 			}
121 		}
122 		SQObjectPtr ret;
123 		switch(tok)
124 		{
125 		case TK_IDENTIFIER:
126 			ret = _fs->CreateString(_lex._svalue);
127 			break;
128 		case TK_STRING_LITERAL:
129 			ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
130 			break;
131 		case TK_INTEGER:
132 			ret = SQObjectPtr(_lex._nvalue);
133 			break;
134 		case TK_FLOAT:
135 			ret = SQObjectPtr(_lex._fvalue);
136 			break;
137 		}
138 		Lex();
139 		return ret;
140 	}
IsEndOfStatement()141 	bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
OptionalSemicolon()142 	void OptionalSemicolon()
143 	{
144 		if(_token == _SC(';')) { Lex(); return; }
145 		if(!IsEndOfStatement()) {
146 			Error(_SC("end of statement expected (; or lf)"));
147 		}
148 	}
MoveIfCurrentTargetIsLocal()149 	void MoveIfCurrentTargetIsLocal() {
150 		SQInteger trg = _fs->TopTarget();
151 		if(_fs->IsLocal(trg)) {
152 			trg = _fs->PopTarget(); //no pops the target and move it
153 			_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
154 		}
155 	}
Compile(SQObjectPtr & o)156 	bool Compile(SQObjectPtr &o)
157 	{
158 		_debugline = 1;
159 		_debugop = 0;
160 
161 		SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
162 		funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
163 		_fs = &funcstate;
164 		_fs->AddParameter(_fs->CreateString(_SC("this")));
165 		_fs->_sourcename = _sourcename;
166 		SQInteger stacksize = _fs->GetStackSize();
167 		if(setjmp(_errorjmp) == 0) {
168 			Lex();
169 			while(_token > 0){
170 				Statement();
171 				if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
172 			}
173 			CleanStack(stacksize);
174 			_fs->AddLineInfos(_lex._currentline, _lineinfo, true);
175 			_fs->AddInstruction(_OP_RETURN, 0xFF);
176 			_fs->SetStackSize(0);
177 			o =_fs->BuildProto();
178 #ifdef _DEBUG_DUMP
179 			_fs->Dump(_funcproto(o));
180 #endif
181 		}
182 		else {
183 			if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
184 				_ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
185 					_lex._currentline, _lex._currentcolumn);
186 			}
187 			_vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
188 			return false;
189 		}
190 		return true;
191 	}
Statements()192 	void Statements()
193 	{
194 		while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
195 			Statement();
196 			if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
197 		}
198 	}
Statement()199 	void Statement()
200 	{
201 		_fs->AddLineInfos(_lex._currentline, _lineinfo);
202 		switch(_token){
203 		case _SC(';'):	Lex();					break;
204 		case TK_IF:		IfStatement();			break;
205 		case TK_WHILE:		WhileStatement();		break;
206 		case TK_DO:		DoWhileStatement();		break;
207 		case TK_FOR:		ForStatement();			break;
208 		case TK_FOREACH:	ForEachStatement();		break;
209 		case TK_SWITCH:	SwitchStatement();		break;
210 		case TK_LOCAL:		LocalDeclStatement();	break;
211 		case TK_RETURN:
212 		case TK_YIELD: {
213 			SQOpcode op;
214 			if(_token == TK_RETURN) {
215 				op = _OP_RETURN;
216 
217 			}
218 			else {
219 				op = _OP_YIELD;
220 				_fs->_bgenerator = true;
221 			}
222 			Lex();
223 			if(!IsEndOfStatement()) {
224 				SQInteger retexp = _fs->GetCurrentPos()+1;
225 				CommaExpr();
226 				if(op == _OP_RETURN && _fs->_traps > 0)
227 					_fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
228 				_fs->_returnexp = retexp;
229 				_fs->AddInstruction(op, 1, _fs->PopTarget());
230 			}
231 			else{
232 				if(op == _OP_RETURN && _fs->_traps > 0)
233 					_fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
234 				_fs->_returnexp = -1;
235 				_fs->AddInstruction(op, 0xFF);
236 			}
237 			break;}
238 		case TK_BREAK:
239 			if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
240 			if(_fs->_breaktargets.top() > 0){
241 				_fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
242 			}
243 			_fs->AddInstruction(_OP_JMP, 0, -1234);
244 			_fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
245 			Lex();
246 			break;
247 		case TK_CONTINUE:
248 			if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
249 			if(_fs->_continuetargets.top() > 0) {
250 				_fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
251 			}
252 			_fs->AddInstruction(_OP_JMP, 0, -1234);
253 			_fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
254 			Lex();
255 			break;
256 		case TK_FUNCTION:
257 			FunctionStatement();
258 			break;
259 		case TK_CLASS:
260 			ClassStatement();
261 			break;
262 		case TK_ENUM:
263 			EnumStatement();
264 			break;
265 		case _SC('{'):{
266 				SQInteger stacksize = _fs->GetStackSize();
267 				Lex();
268 				Statements();
269 				Expect(_SC('}'));
270 				_fs->SetStackSize(stacksize);
271 			}
272 			break;
273 		case TK_TRY:
274 			TryCatchStatement();
275 			break;
276 		case TK_THROW:
277 			Lex();
278 			CommaExpr();
279 			_fs->AddInstruction(_OP_THROW, _fs->PopTarget());
280 			break;
281 		case TK_CONST:
282 			{
283 			Lex();
284 			SQObject id = Expect(TK_IDENTIFIER);
285 			Expect('=');
286 			SQObject val = ExpectScalar();
287 			OptionalSemicolon();
288 			SQTable *enums = _table(_ss(_vm)->_consts);
289 			SQObjectPtr strongid = id;
290 			enums->NewSlot(strongid,SQObjectPtr(val));
291 			strongid.Null();
292 			}
293 			break;
294 		default:
295 			CommaExpr();
296 			_fs->PopTarget();
297 			break;
298 		}
299 		_fs->SnoozeOpt();
300 	}
EmitDerefOp(SQOpcode op)301 	void EmitDerefOp(SQOpcode op)
302 	{
303 		SQInteger val = _fs->PopTarget();
304 		SQInteger key = _fs->PopTarget();
305 		SQInteger src = _fs->PopTarget();
306         _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
307 	}
Emit2ArgsOP(SQOpcode op,SQInteger p3=0)308 	void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
309 	{
310 		SQInteger p2 = _fs->PopTarget(); //src in OP_GET
311 		SQInteger p1 = _fs->PopTarget(); //key in OP_GET
312 		_fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
313 	}
EmitCompoundArith(SQInteger tok,bool deref)314 	void EmitCompoundArith(SQInteger tok,bool deref)
315 	{
316 		SQInteger oper;
317 		switch(tok){
318 		case TK_MINUSEQ: oper = '-'; break;
319 		case TK_PLUSEQ: oper = '+'; break;
320 		case TK_MULEQ: oper = '*'; break;
321 		case TK_DIVEQ: oper = '/'; break;
322 		case TK_MODEQ: oper = '%'; break;
323 		default: oper = 0; //shut up compiler
324 			assert(0); break;
325 		};
326 		if(deref) {
327 			SQInteger val = _fs->PopTarget();
328 			SQInteger key = _fs->PopTarget();
329 			SQInteger src = _fs->PopTarget();
330 			//mixes dest obj and source val in the arg1(hack?)
331 			_fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper);
332 		}
333 		else {
334 			Emit2ArgsOP(_OP_COMPARITHL, oper);
335 		}
336 	}
CommaExpr()337 	void CommaExpr()
338 	{
339 		for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
340 	}
Expression(bool funcarg=false)341 	ExpState Expression(bool funcarg = false)
342 	{
343 		PushExpState();
344 		_exst._class_or_delete = false;
345 		_exst._funcarg = funcarg;
346 		LogicalOrExp();
347 		switch(_token)  {
348 		case _SC('='):
349 		case TK_NEWSLOT:
350 		case TK_MINUSEQ:
351 		case TK_PLUSEQ:
352 		case TK_MULEQ:
353 		case TK_DIVEQ:
354 		case TK_MODEQ:
355 		{
356 				SQInteger op = _token;
357 				SQInteger ds = _exst._deref;
358 				bool freevar = _exst._freevar;
359 				if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression"));
360 				Lex(); Expression();
361 
362 				switch(op){
363 				case TK_NEWSLOT:
364 					if(freevar) Error(_SC("free variables cannot be modified"));
365 					if(ds == DEREF_FIELD)
366 						EmitDerefOp(_OP_NEWSLOT);
367 					else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
368 						Error(_SC("can't 'create' a local slot"));
369 					break;
370 				case _SC('='): //ASSIGN
371 					if(freevar) Error(_SC("free variables cannot be modified"));
372 					if(ds == DEREF_FIELD)
373 						EmitDerefOp(_OP_SET);
374 					else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
375 						SQInteger p2 = _fs->PopTarget(); //src in OP_GET
376 						SQInteger p1 = _fs->TopTarget(); //key in OP_GET
377 						_fs->AddInstruction(_OP_MOVE, p1, p2);
378 					}
379 					break;
380 				case TK_MINUSEQ:
381 				case TK_PLUSEQ:
382 				case TK_MULEQ:
383 				case TK_DIVEQ:
384 				case TK_MODEQ:
385 					EmitCompoundArith(op,ds == DEREF_FIELD);
386 					break;
387 				}
388 			}
389 			break;
390 		case _SC('?'): {
391 			Lex();
392 			_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
393 			SQInteger jzpos = _fs->GetCurrentPos();
394 			SQInteger trg = _fs->PushTarget();
395 			Expression();
396 			SQInteger first_exp = _fs->PopTarget();
397 			if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
398 			SQInteger endfirstexp = _fs->GetCurrentPos();
399 			_fs->AddInstruction(_OP_JMP, 0, 0);
400 			Expect(_SC(':'));
401 			SQInteger jmppos = _fs->GetCurrentPos();
402 			Expression();
403 			SQInteger second_exp = _fs->PopTarget();
404 			if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
405 			_fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
406 			_fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
407 			_fs->SnoozeOpt();
408 			}
409 			break;
410 		}
411 		return PopExpState();
412 	}
BIN_EXP(SQOpcode op,void (SQCompiler::* f)(void),SQInteger op3=0)413 	void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0)
414 	{
415 		Lex(); (this->*f)();
416 		SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
417 		_fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
418 	}
LogicalOrExp()419 	void LogicalOrExp()
420 	{
421 		LogicalAndExp();
422 		for(;;) if(_token == TK_OR) {
423 			SQInteger first_exp = _fs->PopTarget();
424 			SQInteger trg = _fs->PushTarget();
425 			_fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
426 			SQInteger jpos = _fs->GetCurrentPos();
427 			if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
428 			Lex(); LogicalOrExp();
429 			_fs->SnoozeOpt();
430 			SQInteger second_exp = _fs->PopTarget();
431 			if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
432 			_fs->SnoozeOpt();
433 			_fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
434 			break;
435 		}else return;
436 	}
LogicalAndExp()437 	void LogicalAndExp()
438 	{
439 		BitwiseOrExp();
440 		for(;;) switch(_token) {
441 		case TK_AND: {
442 			SQInteger first_exp = _fs->PopTarget();
443 			SQInteger trg = _fs->PushTarget();
444 			_fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
445 			SQInteger jpos = _fs->GetCurrentPos();
446 			if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
447 			Lex(); LogicalAndExp();
448 			_fs->SnoozeOpt();
449 			SQInteger second_exp = _fs->PopTarget();
450 			if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
451 			_fs->SnoozeOpt();
452 			_fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
453 			break;
454 			}
455 		case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break;
456 		case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break;
457 		default:
458 			return;
459 		}
460 	}
BitwiseOrExp()461 	void BitwiseOrExp()
462 	{
463 		BitwiseXorExp();
464 		for(;;) if(_token == _SC('|'))
465 		{BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
466 		}else return;
467 	}
BitwiseXorExp()468 	void BitwiseXorExp()
469 	{
470 		BitwiseAndExp();
471 		for(;;) if(_token == _SC('^'))
472 		{BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
473 		}else return;
474 	}
BitwiseAndExp()475 	void BitwiseAndExp()
476 	{
477 		CompExp();
478 		for(;;) if(_token == _SC('&'))
479 		{BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);
480 		}else return;
481 	}
CompExp()482 	void CompExp()
483 	{
484 		ShiftExp();
485 		for(;;) switch(_token) {
486 		case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break;
487 		case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
488 		case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
489 		case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
490 		case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
491 		case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;
492 		default: return;
493 		}
494 	}
ShiftExp()495 	void ShiftExp()
496 	{
497 		PlusExp();
498 		for(;;) switch(_token) {
499 		case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
500 		case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
501 		case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
502 		default: return;
503 		}
504 	}
PlusExp()505 	void PlusExp()
506 	{
507 		MultExp();
508 		for(;;) switch(_token) {
509 		case _SC('+'): case _SC('-'):
510 			BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break;
511 		default: return;
512 		}
513 	}
514 
MultExp()515 	void MultExp()
516 	{
517 		PrefixedExpr();
518 		for(;;) switch(_token) {
519 		case _SC('*'): case _SC('/'): case _SC('%'):
520 			BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break;
521 		default: return;
522 		}
523 	}
524 	//if 'pos' != -1 the previous variable is a local variable
PrefixedExpr()525 	void PrefixedExpr()
526 	{
527 		SQInteger pos = Factor();
528 		for(;;) {
529 			switch(_token) {
530 			case _SC('.'): {
531 				pos = -1;
532 				Lex();
533 				if(_token == TK_PARENT) {
534 					Lex();
535 					if(!NeedGet())
536 						Error(_SC("parent cannot be set"));
537 					SQInteger src = _fs->PopTarget();
538 					_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);
539 				}
540 				else {
541 					_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
542 					if(NeedGet()) Emit2ArgsOP(_OP_GET);
543 				}
544 				_exst._deref = DEREF_FIELD;
545 				_exst._freevar = false;
546 				}
547 				break;
548 			case _SC('['):
549 				if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
550 				Lex(); Expression(); Expect(_SC(']'));
551 				pos = -1;
552 				if(NeedGet()) Emit2ArgsOP(_OP_GET);
553 				_exst._deref = DEREF_FIELD;
554 				_exst._freevar = false;
555 				break;
556 			case TK_MINUSMINUS:
557 			case TK_PLUSPLUS:
558 			if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) {
559 				SQInteger tok = _token; Lex();
560 				if(pos < 0)
561 					Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);
562 				else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
563 					SQInteger src = _fs->PopTarget();
564 					_fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);
565 				}
566 
567 			}
568 			return;
569 			break;
570 			case _SC('('):
571 				{
572 				if(_exst._deref != DEREF_NO_DEREF) {
573 					if(pos<0) {
574 						SQInteger key = _fs->PopTarget(); //key
575 						SQInteger table = _fs->PopTarget(); //table etc...
576 						SQInteger closure = _fs->PushTarget();
577 						SQInteger ttarget = _fs->PushTarget();
578 						_fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
579 					}
580 					else{
581 						_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
582 					}
583 				}
584 				else
585 					_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
586 				_exst._deref = DEREF_NO_DEREF;
587 				Lex();
588 				FunctionCallArgs();
589 				 }
590 				break;
591 			default: return;
592 			}
593 		}
594 	}
Factor()595 	SQInteger Factor()
596 	{
597 		_exst._deref = DEREF_NO_DEREF;
598 		switch(_token)
599 		{
600 		case TK_STRING_LITERAL: {
601 				//SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));
602 				_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
603 				Lex();
604 			}
605 			break;
606 		case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;
607 		case TK_VARGV: { Lex();
608 			Expect(_SC('['));
609 			Expression();
610 			Expect(_SC(']'));
611 			SQInteger src = _fs->PopTarget();
612 			_fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src);
613 					   }
614 			break;
615 		case TK_IDENTIFIER:
616 		case TK_CONSTRUCTOR:
617 		case TK_THIS:{
618 			_exst._freevar = false;
619 			SQObject id;
620 			SQObject constant;
621 				switch(_token) {
622 					case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
623 					case TK_THIS: id = _fs->CreateString(_SC("this")); break;
624 					case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
625 				}
626 				SQInteger pos = -1;
627 				Lex();
628 				if((pos = _fs->GetLocalVariable(id)) == -1) {
629 					//checks if is a free variable
630 					if((pos = _fs->GetOuterVariable(id)) != -1) {
631 						_exst._deref = _fs->PushTarget();
632 						_fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);
633 						_exst._freevar = true;
634 					}
635 					else if(_fs->IsConstant(id,constant)) { //line 634
636 						SQObjectPtr constval;
637 						SQObject constid;
638 						if(type(constant) == OT_TABLE) {
639 							Expect('.'); constid = Expect(TK_IDENTIFIER);
640 							if(!_table(constant)->Get(constid,constval)) {
641 								constval.Null();
642 								Error(_SC("invalid constant [%s.%s]"), _stringval(id),_stringval(constid));
643 							}
644 						}
645 						else {
646 							constval = constant;
647 						}
648 						_exst._deref = _fs->PushTarget();
649 						SQObjectType ctype = type(constval);
650 						if(ctype == OT_INTEGER && (_integer(constval) & (~0x7FFFFFFF)) == 0) {
651 							_fs->AddInstruction(_OP_LOADINT, _exst._deref,_integer(constval));
652 						}
653 						else if(ctype == OT_FLOAT && sizeof(SQFloat) == sizeof(SQInt32)) {
654 							SQFloat f = _float(constval);
655 							_fs->AddInstruction(_OP_LOADFLOAT, _exst._deref,*((SQInt32 *)&f));
656 						}
657 						else {
658 							_fs->AddInstruction(_OP_LOAD, _exst._deref, _fs->GetConstant(constval));
659 						}
660 
661 						_exst._freevar = true;
662 					}
663 					else {
664 						_fs->PushTarget(0);
665 						_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
666 						if(NeedGet()) Emit2ArgsOP(_OP_GET);
667 						_exst._deref = DEREF_FIELD;
668 					}
669 				}
670 
671 				else{
672 					_fs->PushTarget(pos);
673 					_exst._deref = pos;
674 				}
675 				return _exst._deref;
676 			}
677 			break;
678 		case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break;
679 		case TK_DOUBLE_COLON:  // "::"
680 			_fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget());
681 			_exst._deref = DEREF_FIELD;
682 			_token = _SC('.'); //hack
683 			return -1;
684 			break;
685 		case TK_NULL:
686 			_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
687 			Lex();
688 			break;
689 		case TK_INTEGER: {
690 			if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?
691 				_fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);
692 			}
693 			else {
694 				_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));
695 			}
696 			Lex();
697 						 }
698 			break;
699 		case TK_FLOAT:
700 			if(sizeof(SQFloat) == sizeof(SQInt32)) {
701 				_fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue));
702 			}
703 			else {
704 				_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));
705 			}
706 			Lex();
707 			break;
708 		case TK_TRUE: case TK_FALSE:
709 			_fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
710 			Lex();
711 			break;
712 		case _SC('['): {
713 				_fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget());
714 				SQInteger apos = _fs->GetCurrentPos(),key = 0;
715 				Lex();
716 				while(_token != _SC(']')) {
717                     Expression();
718 					if(_token == _SC(',')) Lex();
719 					SQInteger val = _fs->PopTarget();
720 					SQInteger array = _fs->TopTarget();
721 					_fs->AddInstruction(_OP_APPENDARRAY, array, val);
722 					key++;
723 				}
724 				_fs->SetIntructionParam(apos, 1, key);
725 				Lex();
726 			}
727 			break;
728 		case _SC('{'):{
729 			_fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
730 			Lex();ParseTableOrClass(_SC(','));
731 				 }
732 			break;
733 		case TK_FUNCTION: FunctionExp(_token);break;
734 		case TK_CLASS: Lex(); ClassExp();break;
735 		case _SC('-'): UnaryOP(_OP_NEG); break;
736 		case _SC('!'): UnaryOP(_OP_NOT); break;
737 		case _SC('~'): UnaryOP(_OP_BWNOT); break;
738 		case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;
739 		case TK_RESUME : UnaryOP(_OP_RESUME); break;
740 		case TK_CLONE : UnaryOP(_OP_CLONE); break;
741 		case TK_MINUSMINUS :
742 		case TK_PLUSPLUS :PrefixIncDec(_token); break;
743 		case TK_DELETE : DeleteExpr(); break;
744 		case TK_DELEGATE : DelegateExpr(); break;
745 		case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
746 			break;
747 		default: Error(_SC("expression expected"));
748 		}
749 		return -1;
750 	}
UnaryOP(SQOpcode op)751 	void UnaryOP(SQOpcode op)
752 	{
753 		Lex(); PrefixedExpr();
754 		SQInteger src = _fs->PopTarget();
755 		_fs->AddInstruction(op, _fs->PushTarget(), src);
756 	}
NeedGet()757 	bool NeedGet()
758 	{
759 		switch(_token) {
760 		case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS:
761 		case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:
762 			return false;
763 		}
764 		return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));
765 	}
766 
FunctionCallArgs()767 	void FunctionCallArgs()
768 	{
769 		SQInteger nargs = 1;//this
770 		 while(_token != _SC(')')) {
771 			 Expression(true);
772 			 MoveIfCurrentTargetIsLocal();
773 			 nargs++;
774 			 if(_token == _SC(',')){
775 				 Lex();
776 				 if(_token == ')') Error(_SC("expression expected, found ')'"));
777 			 }
778 		 }
779 		 Lex();
780 		 for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
781 		 SQInteger stackbase = _fs->PopTarget();
782 		 SQInteger closure = _fs->PopTarget();
783          _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
784 	}
ParseTableOrClass(SQInteger separator,SQInteger terminator='}')785 	void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')
786 	{
787 		SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
788 
789 		while(_token != terminator) {
790 			bool hasattrs = false;
791 			bool isstatic = false;
792 			//check if is an attribute
793 			if(separator == ';') {
794 				if(_token == TK_ATTR_OPEN) {
795 					_fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();
796 					ParseTableOrClass(',',TK_ATTR_CLOSE);
797 					hasattrs = true;
798 				}
799 				if(_token == TK_STATIC) {
800 					isstatic = true;
801 					Lex();
802 				}
803 			}
804 			switch(_token) {
805 				case TK_FUNCTION:
806 				case TK_CONSTRUCTOR:{
807 					SQInteger tk = _token;
808 					Lex();
809 					SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
810 					Expect(_SC('('));
811 					_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
812 					CreateFunction(id);
813 					_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
814 								  }
815 								  break;
816 				case _SC('['):
817 					Lex(); CommaExpr(); Expect(_SC(']'));
818 					Expect(_SC('=')); Expression();
819 					break;
820 				default :
821 					_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
822 					Expect(_SC('=')); Expression();
823 			}
824 
825 			if(_token == separator) Lex();//optional comma/semicolon
826 			nkeys++;
827 			SQInteger val = _fs->PopTarget();
828 			SQInteger key = _fs->PopTarget();
829 			SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
830 			// C::B patch: Eliminate compiler warnings
831 			assert((hasattrs && (attrs == key-1)) || !hasattrs);
832 			// C::B patch: Eliminate compiler warnings
833 			int flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
834 			SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
835 			_fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
836 			//_fs->PopTarget();
837 		}
838 		if(separator == _SC(',')) //hack recognizes a table from the separator
839 			_fs->SetIntructionParam(tpos, 1, nkeys);
840 		Lex();
841 	}
LocalDeclStatement()842 	void LocalDeclStatement()
843 	{
844 		SQObject varname;
845 		do {
846 			Lex(); varname = Expect(TK_IDENTIFIER);
847 			if(_token == _SC('=')) {
848 				Lex(); Expression();
849 				SQInteger src = _fs->PopTarget();
850 				SQInteger dest = _fs->PushTarget();
851 				if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
852 			}
853 			else{
854 				_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
855 			}
856 			_fs->PopTarget();
857 			_fs->PushLocalVariable(varname);
858 
859 		} while(_token == _SC(','));
860 	}
IfStatement()861 	void IfStatement()
862 	{
863 		SQInteger jmppos;
864 		bool haselse = false;
865 		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
866 		_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
867 		SQInteger jnepos = _fs->GetCurrentPos();
868 		SQInteger stacksize = _fs->GetStackSize();
869 
870 		Statement();
871 		//
872 		if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
873 
874 		CleanStack(stacksize);
875 		SQInteger endifblock = _fs->GetCurrentPos();
876 		if(_token == TK_ELSE){
877 			haselse = true;
878 			stacksize = _fs->GetStackSize();
879 			_fs->AddInstruction(_OP_JMP);
880 			jmppos = _fs->GetCurrentPos();
881 			Lex();
882 			Statement(); OptionalSemicolon();
883 			CleanStack(stacksize);
884 			_fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
885 		}
886 		_fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
887 	}
WhileStatement()888 	void WhileStatement()
889 	{
890 		SQInteger jzpos, jmppos;
891 		SQInteger stacksize = _fs->GetStackSize();
892 		jmppos = _fs->GetCurrentPos();
893 		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
894 
895 		BEGIN_BREAKBLE_BLOCK();
896 		_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
897 		jzpos = _fs->GetCurrentPos();
898 		stacksize = _fs->GetStackSize();
899 
900 		Statement();
901 
902 		CleanStack(stacksize);
903 		_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
904 		_fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
905 
906 		END_BREAKBLE_BLOCK(jmppos);
907 	}
DoWhileStatement()908 	void DoWhileStatement()
909 	{
910 		Lex();
911 		SQInteger jzpos = _fs->GetCurrentPos();
912 		SQInteger stacksize = _fs->GetStackSize();
913 		BEGIN_BREAKBLE_BLOCK()
914 		Statement();
915 		CleanStack(stacksize);
916 		Expect(TK_WHILE);
917 		SQInteger continuetrg = _fs->GetCurrentPos();
918 		Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
919 		_fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1);
920 		END_BREAKBLE_BLOCK(continuetrg);
921 	}
ForStatement()922 	void ForStatement()
923 	{
924 		Lex();
925 		SQInteger stacksize = _fs->GetStackSize();
926 		Expect(_SC('('));
927 		if(_token == TK_LOCAL) LocalDeclStatement();
928 		else if(_token != _SC(';')){
929 			CommaExpr();
930 			_fs->PopTarget();
931 		}
932 		Expect(_SC(';'));
933 		_fs->SnoozeOpt();
934 		SQInteger jmppos = _fs->GetCurrentPos();
935 		SQInteger jzpos = -1;
936 		if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
937 		Expect(_SC(';'));
938 		_fs->SnoozeOpt();
939 		SQInteger expstart = _fs->GetCurrentPos() + 1;
940 		if(_token != _SC(')')) {
941 			CommaExpr();
942 			_fs->PopTarget();
943 		}
944 		Expect(_SC(')'));
945 		_fs->SnoozeOpt();
946 		SQInteger expend = _fs->GetCurrentPos();
947 		SQInteger expsize = (expend - expstart) + 1;
948 		SQInstructionVec exp;
949 		if(expsize > 0) {
950 			for(SQInteger i = 0; i < expsize; i++)
951 				exp.push_back(_fs->GetInstruction(expstart + i));
952 			_fs->PopInstructions(expsize);
953 		}
954 		BEGIN_BREAKBLE_BLOCK()
955 		Statement();
956 		SQInteger continuetrg = _fs->GetCurrentPos();
957 		if(expsize > 0) {
958 			for(SQInteger i = 0; i < expsize; i++)
959 				_fs->AddInstruction(exp[i]);
960 		}
961 		_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
962 		if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
963 		CleanStack(stacksize);
964 
965 		END_BREAKBLE_BLOCK(continuetrg);
966 	}
ForEachStatement()967 	void ForEachStatement()
968 	{
969 		SQObject idxname, valname;
970 		Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
971 		if(_token == _SC(',')) {
972 			idxname = valname;
973 			Lex(); valname = Expect(TK_IDENTIFIER);
974 		}
975 		else{
976 			idxname = _fs->CreateString(_SC("@INDEX@"));
977 		}
978 		Expect(TK_IN);
979 
980 		//save the stack size
981 		SQInteger stacksize = _fs->GetStackSize();
982 		//put the table in the stack(evaluate the table expression)
983 		Expression(); Expect(_SC(')'));
984 		SQInteger container = _fs->TopTarget();
985 		//push the index local var
986 		SQInteger indexpos = _fs->PushLocalVariable(idxname);
987 		_fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
988 		//push the value local var
989 		SQInteger valuepos = _fs->PushLocalVariable(valname);
990 		_fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
991 		//push reference index
992 		SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
993 		_fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
994 		SQInteger jmppos = _fs->GetCurrentPos();
995 		_fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
996 		SQInteger foreachpos = _fs->GetCurrentPos();
997 		_fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
998 		//generate the statement code
999 		BEGIN_BREAKBLE_BLOCK()
1000 		Statement();
1001 		_fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
1002 		_fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
1003 		_fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
1004 		//restore the local variable stack(remove index,val and ref idx)
1005 		CleanStack(stacksize);
1006 		END_BREAKBLE_BLOCK(foreachpos - 1);
1007 	}
SwitchStatement()1008 	void SwitchStatement()
1009 	{
1010 		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1011 		Expect(_SC('{'));
1012 		SQInteger expr = _fs->TopTarget();
1013 		bool bfirst = true;
1014 		SQInteger tonextcondjmp = -1;
1015 		SQInteger skipcondjmp = -1;
1016 		SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
1017 		_fs->_breaktargets.push_back(0);
1018 		while(_token == TK_CASE) {
1019 			//_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one
1020 			if(!bfirst) {
1021 				_fs->AddInstruction(_OP_JMP, 0, 0);
1022 				skipcondjmp = _fs->GetCurrentPos();
1023 				_fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1024 			}
1025 			//condition
1026 			Lex(); Expression(); Expect(_SC(':'));
1027 			SQInteger trg = _fs->PopTarget();
1028 			_fs->AddInstruction(_OP_EQ, trg, trg, expr);
1029 			_fs->AddInstruction(_OP_JZ, trg, 0);
1030 			//end condition
1031 			if(skipcondjmp != -1) {
1032 				_fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
1033 			}
1034 			tonextcondjmp = _fs->GetCurrentPos();
1035 			SQInteger stacksize = _fs->GetStackSize();
1036 			Statements();
1037 			_fs->SetStackSize(stacksize);
1038 			bfirst = false;
1039 		}
1040 		if(tonextcondjmp != -1)
1041 			_fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1042 		if(_token == TK_DEFAULT) {
1043 		//	_fs->AddLineInfos(_lex._currentline, _lineinfo);
1044 			Lex(); Expect(_SC(':'));
1045 			SQInteger stacksize = _fs->GetStackSize();
1046 			Statements();
1047 			_fs->SetStackSize(stacksize);
1048 		}
1049 		Expect(_SC('}'));
1050 		_fs->PopTarget();
1051 		__nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1052 		if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
1053 		_fs->_breaktargets.pop_back();
1054 
1055 	}
FunctionStatement()1056 	void FunctionStatement()
1057 	{
1058 		SQObject id;
1059 		Lex(); id = Expect(TK_IDENTIFIER);
1060 		_fs->PushTarget(0);
1061 		_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1062 		if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1063 
1064 		while(_token == TK_DOUBLE_COLON) {
1065 			Lex();
1066 			id = Expect(TK_IDENTIFIER);
1067 			_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1068 			if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1069 		}
1070 		Expect(_SC('('));
1071 		CreateFunction(id);
1072 		_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1073 		EmitDerefOp(_OP_NEWSLOT);
1074 		_fs->PopTarget();
1075 	}
ClassStatement()1076 	void ClassStatement()
1077 	{
1078 		ExpState es;
1079 		Lex(); PushExpState();
1080 		_exst._class_or_delete = true;
1081 		_exst._funcarg = false;
1082 		PrefixedExpr();
1083 		es = PopExpState();
1084 		if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));
1085 		if(es._deref == DEREF_FIELD) {
1086 			ClassExp();
1087 			EmitDerefOp(_OP_NEWSLOT);
1088 			_fs->PopTarget();
1089 		}
1090 		else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
1091 	}
ExpectScalar()1092 	SQObject ExpectScalar()
1093 	{
1094 		SQObject val;
1095 		switch(_token) {
1096 			case TK_INTEGER:
1097 				val._type = OT_INTEGER;
1098 				val._unVal.nInteger = _lex._nvalue;
1099 				break;
1100 			case TK_FLOAT:
1101 				val._type = OT_FLOAT;
1102 				val._unVal.fFloat = _lex._fvalue;
1103 				break;
1104 			case TK_STRING_LITERAL:
1105 				val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
1106 				break;
1107 			case '-':
1108 				Lex();
1109 				switch(_token)
1110 				{
1111 				case TK_INTEGER:
1112 					val._type = OT_INTEGER;
1113 					val._unVal.nInteger = -_lex._nvalue;
1114 				break;
1115 				case TK_FLOAT:
1116 					val._type = OT_FLOAT;
1117 					val._unVal.fFloat = -_lex._fvalue;
1118 				break;
1119 				default:
1120 					Error(_SC("scalar expected : integer,float"));
1121 				}
1122 				break;
1123 			default:
1124 			Error(_SC("scalar expected : integer,float or string"));
1125 		}
1126 		Lex();
1127 		return val;
1128 	}
EnumStatement()1129 	void EnumStatement()
1130 	{
1131 
1132 		Lex();
1133 		SQObject id = Expect(TK_IDENTIFIER);
1134 		Expect(_SC('{'));
1135 
1136 		SQObject table = _fs->CreateTable();
1137 		SQInteger nval = 0;
1138 		while(_token != _SC('}')) {
1139 			SQObject key = Expect(TK_IDENTIFIER);
1140 			SQObject val;
1141 			if(_token == _SC('=')) {
1142 				Lex();
1143 				val = ExpectScalar();
1144 			}
1145 			else {
1146 				val._type = OT_INTEGER;
1147 				val._unVal.nInteger = nval++;
1148 			}
1149 			_table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
1150 			if(_token == ',') Lex();
1151 		}
1152 		SQTable *enums = _table(_ss(_vm)->_consts);
1153 		SQObjectPtr strongid = id;
1154 		/*SQObjectPtr dummy;
1155 		if(enums->Get(strongid,dummy)) {
1156 			dummy.Null(); strongid.Null();
1157 			Error(_SC("enumeration already exists"));
1158 		}*/
1159 		enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
1160 		strongid.Null();
1161 		Lex();
1162 
1163 	}
TryCatchStatement()1164 	void TryCatchStatement()
1165 	{
1166 		SQObject exid;
1167 		Lex();
1168 		_fs->AddInstruction(_OP_PUSHTRAP,0,0);
1169 		_fs->_traps++;
1170 		if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
1171 		if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
1172 		SQInteger trappos = _fs->GetCurrentPos();
1173 		Statement();
1174 		_fs->_traps--;
1175 		_fs->AddInstruction(_OP_POPTRAP, 1, 0);
1176 		if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
1177 		if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
1178 		_fs->AddInstruction(_OP_JMP, 0, 0);
1179 		SQInteger jmppos = _fs->GetCurrentPos();
1180 		_fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
1181 		Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
1182 		SQInteger stacksize = _fs->GetStackSize();
1183 		SQInteger ex_target = _fs->PushLocalVariable(exid);
1184 		_fs->SetIntructionParam(trappos, 0, ex_target);
1185 		Statement();
1186 		_fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1187 		CleanStack(stacksize);
1188 	}
FunctionExp(SQInteger ftype)1189 	void FunctionExp(SQInteger ftype)
1190 	{
1191 		Lex(); Expect(_SC('('));
1192 		CreateFunction(_null_);
1193 		_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
1194 	}
ClassExp()1195 	void ClassExp()
1196 	{
1197 		SQInteger base = -1;
1198 		SQInteger attrs = -1;
1199 		if(_token == TK_EXTENDS) {
1200 			Lex(); Expression();
1201 			base = _fs->TopTarget();
1202 		}
1203 		if(_token == TK_ATTR_OPEN) {
1204 			Lex();
1205 			_fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
1206 			ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
1207 			attrs = _fs->TopTarget();
1208 		}
1209 		Expect(_SC('{'));
1210 		if(attrs != -1) _fs->PopTarget();
1211 		if(base != -1) _fs->PopTarget();
1212 		_fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);
1213 		ParseTableOrClass(_SC(';'));
1214 	}
DelegateExpr()1215 	void DelegateExpr()
1216 	{
1217 		Lex(); CommaExpr();
1218 		Expect(_SC(':'));
1219 		CommaExpr();
1220 		SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();
1221 		_fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);
1222 	}
DeleteExpr()1223 	void DeleteExpr()
1224 	{
1225 		ExpState es;
1226 		Lex(); PushExpState();
1227 		_exst._class_or_delete = true;
1228 		_exst._funcarg = false;
1229 		PrefixedExpr();
1230 		es = PopExpState();
1231 		if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));
1232 		if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
1233 		else Error(_SC("cannot delete a local"));
1234 	}
PrefixIncDec(SQInteger token)1235 	void PrefixIncDec(SQInteger token)
1236 	{
1237 		ExpState es;
1238 		Lex(); PushExpState();
1239 		_exst._class_or_delete = true;
1240 		_exst._funcarg = false;
1241 		PrefixedExpr();
1242 		es = PopExpState();
1243 		if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);
1244 		else {
1245 			SQInteger src = _fs->PopTarget();
1246 			_fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);
1247 		}
1248 	}
CreateFunction(SQObject & name)1249 	void CreateFunction(SQObject &name)
1250 	{
1251 
1252 		SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
1253 		funcstate->_name = name;
1254 		SQObject paramname;
1255 		funcstate->AddParameter(_fs->CreateString(_SC("this")));
1256 		funcstate->_sourcename = _sourcename;
1257 		SQInteger defparams = 0;
1258 		while(_token!=_SC(')')) {
1259 			if(_token == TK_VARPARAMS) {
1260 				if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
1261 				funcstate->_varparams = true;
1262 				Lex();
1263 				if(_token != _SC(')')) Error(_SC("expected ')'"));
1264 				break;
1265 			}
1266 			else {
1267 				paramname = Expect(TK_IDENTIFIER);
1268 				funcstate->AddParameter(paramname);
1269 				if(_token == _SC('=')) {
1270 					Lex();
1271 					Expression();
1272 					funcstate->AddDefaultParam(_fs->TopTarget());
1273 					defparams++;
1274 				}
1275 				else {
1276 					if(defparams > 0) Error(_SC("expected '='"));
1277 				}
1278 				if(_token == _SC(',')) Lex();
1279 				else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1280 			}
1281 		}
1282 		Expect(_SC(')'));
1283 		for(SQInteger n = 0; n < defparams; n++) {
1284 			_fs->PopTarget();
1285 		}
1286 		//outer values
1287 		if(_token == _SC(':')) {
1288 			Lex(); Expect(_SC('('));
1289 			while(_token != _SC(')')) {
1290 				paramname = Expect(TK_IDENTIFIER);
1291 				//outers are treated as implicit local variables
1292 				funcstate->AddOuterValue(paramname);
1293 				if(_token == _SC(',')) Lex();
1294 				else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1295 			}
1296 			Lex();
1297 		}
1298 
1299 		SQFuncState *currchunk = _fs;
1300 		_fs = funcstate;
1301 		Statement();
1302 		funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
1303         funcstate->AddInstruction(_OP_RETURN, -1);
1304 		funcstate->SetStackSize(0);
1305 		//_fs->->_stacksize = _fs->_stacksize;
1306 		SQFunctionProto *func = funcstate->BuildProto();
1307 #ifdef _DEBUG_DUMP
1308 		funcstate->Dump(func);
1309 #endif
1310 		_fs = currchunk;
1311 		_fs->_functions.push_back(func);
1312 		_fs->PopChildState();
1313 	}
CleanStack(SQInteger stacksize)1314 	void CleanStack(SQInteger stacksize)
1315 	{
1316 		if(_fs->GetStackSize() != stacksize)
1317 			_fs->SetStackSize(stacksize);
1318 	}
ResolveBreaks(SQFuncState * funcstate,SQInteger ntoresolve)1319 	void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
1320 	{
1321 		while(ntoresolve > 0) {
1322 			SQInteger pos = funcstate->_unresolvedbreaks.back();
1323 			funcstate->_unresolvedbreaks.pop_back();
1324 			//set the jmp instruction
1325 			funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
1326 			ntoresolve--;
1327 		}
1328 	}
ResolveContinues(SQFuncState * funcstate,SQInteger ntoresolve,SQInteger targetpos)1329 	void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
1330 	{
1331 		while(ntoresolve > 0) {
1332 			SQInteger pos = funcstate->_unresolvedcontinues.back();
1333 			funcstate->_unresolvedcontinues.pop_back();
1334 			//set the jmp instruction
1335 			funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
1336 			ntoresolve--;
1337 		}
1338 	}
1339 private:
1340 	SQInteger _token;
1341 	SQFuncState *_fs;
1342 	SQObjectPtr _sourcename;
1343 	SQLexer _lex;
1344 	bool _lineinfo;
1345 	bool _raiseerror;
1346 	SQInteger _debugline;
1347 	SQInteger _debugop;
1348 	ExpStateVec _expstates;
1349 	SQChar *compilererror;
1350 	jmp_buf _errorjmp;
1351 	SQVM *_vm;
1352 };
1353 
Compile(SQVM * vm,SQLEXREADFUNC rg,SQUserPointer up,const SQChar * sourcename,SQObjectPtr & out,bool raiseerror,bool lineinfo)1354 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
1355 {
1356 	SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
1357 	return p.Compile(out);
1358 }
1359