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