5 #ifndef VOX_NO_COMPILER
11 #include "funcproto.hpp"
12 #include "compiler.hpp"
13 #include "funcstate.hpp"
26 VXInteger etype
; /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */
27 VXInteger epos
; /* expr. location on stack; -1 for OBJECT and BASE */
28 bool donot_get
; /* signal not to deref the next value */
36 #define BEGIN_VXCOPE() \
37 VXScope __oldscope__ = _scope; \
38 _scope.outers = _fs->_outers; \
39 _scope.stacksize = _fs->GetStackSize();
41 #define RESOLVE_OUTERS() \
42 if(_fs->GetStackSize() != _scope.stacksize) \
44 if(_fs->CountOuters(_scope.stacksize)) \
46 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
50 #define END_VXCOPE_NO_CLOSE() \
52 if(_fs->GetStackSize() != _scope.stacksize) \
54 _fs->SetStackSize(_scope.stacksize); \
56 _scope = __oldscope__; \
59 #define END_VXCOPE() \
61 VXInteger oldouters = _fs->_outers; \
62 if(_fs->GetStackSize() != _scope.stacksize) \
64 _fs->SetStackSize(_scope.stacksize); \
65 if(oldouters != _fs->_outers) \
67 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
70 _scope = __oldscope__; \
73 #define BEGIN_BREAKBLE_BLOCK() \
74 VXInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); \
75 VXInteger __ncontinues__ = _fs->_unresolvedcontinues.size(); \
76 _fs->_breaktargets.push_back(0); \
77 _fs->_continuetargets.push_back(0);
79 #define END_BREAKBLE_BLOCK(continue_target) \
81 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; \
82 __ncontinues__ = _fs->_unresolvedcontinues.size() - __ncontinues__; \
85 ResolveContinues(_fs,__ncontinues__,continue_target); \
89 ResolveBreaks(_fs,__nbreaks__); \
91 _fs->_breaktargets.pop_back(); \
92 _fs->_continuetargets.pop_back(); \
98 VXCompiler(VXState
*v
,
101 const char* sourcename
,
106 _lex
.Init(_ss(v
), rg
, up
, HandleError
,this);
107 _sourcename
= VXStringObj::Create(_ss(v
), sourcename
);
108 _lineinfo
= lineinfo
;_raiseerror
= raiseerror
;
110 _scope
.stacksize
= 0;
111 compilererror
= NULL
;
114 static void HandleError(void *ud
, const char *s
)
116 VXCompiler
*c
= (VXCompiler
*)ud
;
120 void Error(const char *s
, ...)
122 static char temp
[256];
125 vsprintf(temp
, s
, vl
);
127 compilererror
= temp
;
128 longjmp(_errorjmp
,1);
136 VXRawObj
Expect(VXInteger tok
)
140 if(_token
== TK_CONSTRUCTOR
&& tok
== TK_IDENTIFIER
)
146 const char *etypename
;
152 etypename
= "IDENTIFIER";
154 case TK_STRING_LITERAL
:
155 etypename
= "STRING_LITERAL";
158 etypename
= "INTEGER";
164 etypename
= _lex
.Tok2Str(tok
);
166 Error("expected '%s'", etypename
);
168 Error("expected '%c'", tok
);
175 ret
= _fs
->CreateString(_lex
._svalue
);
177 case TK_STRING_LITERAL
:
178 ret
= _fs
->CreateString(_lex
._svalue
,_lex
._longstr
.size()-1);
181 ret
= VXObject(_lex
._nvalue
);
184 ret
= VXObject(_lex
._fvalue
);
190 bool IsEndOfStatement()
193 (_lex
._prevtoken
== '\n') ||
194 (_token
== VOX_EOB
) ||
199 void OptionalSemicolon()
206 if(!IsEndOfStatement())
208 Error("end of statement expected (';' or EOL)");
211 void MoveIfCurrentTargetIsLocal()
213 VXInteger trg
= _fs
->TopTarget();
214 if(_fs
->IsLocal(trg
))
216 trg
= _fs
->PopTarget(); //no pops the target and move it
217 _fs
->AddInstruction(_OP_MOVE
, _fs
->PushTarget(), trg
);
220 bool Compile(VXObject
&o
)
225 VXFuncState
funcstate(_ss(_vm
), NULL
, HandleError
,this);
226 funcstate
._name
= VXStringObj::Create(_ss(_vm
), NAMES_MAINFUNC
);
228 _fs
->AddParameter(_fs
->CreateString(NAMES_TK_THISVAR
));
229 _fs
->AddParameter(_fs
->CreateString(NAMES_VARGV
));
230 _fs
->_varparams
= true;
231 _fs
->_sourcename
= _sourcename
;
232 VXInteger stacksize
= _fs
->GetStackSize();
233 if(setjmp(_errorjmp
) == 0)
239 if(_lex
._prevtoken
!= '}' && _lex
._prevtoken
!= ';')
244 _fs
->SetStackSize(stacksize
);
245 _fs
->AddLineInfos(_lex
._currentline
, _lineinfo
, true);
246 _fs
->AddInstruction(_OP_RETURN
, 0xFF);
247 _fs
->SetStackSize(0);
248 o
=_fs
->BuildProto();
250 _fs
->Dump(_funcproto(o
));
255 if(_raiseerror
&& _ss(_vm
)->_compilererrorhandler
)
257 _ss(_vm
)->_compilererrorhandler(
260 type(_sourcename
)==VX_OT_STRING
?_stringval(_sourcename
):"unknown",
262 _lex
._currentcolumn
);
264 _vm
->_lasterror
= VXStringObj::Create(_ss(_vm
), compilererror
, -1);
272 while(_token
!= '}' && _token
!= TK_DEFAULT
&& _token
!= TK_CASE
)
275 if(_lex
._prevtoken
!= '}' && _lex
._prevtoken
!= ';')
282 void Statement(bool closeframe
= true)
284 _fs
->AddLineInfos(_lex
._currentline
, _lineinfo
);
316 LocalDeclStatement();
323 if(_token
== TK_RETURN
)
330 _fs
->_bgenerator
= true;
333 if(!IsEndOfStatement())
335 VXInteger retexp
= _fs
->GetCurrentPos()+1;
337 if(op
== _OP_RETURN
&& _fs
->_traps
> 0)
339 _fs
->AddInstruction(_OP_POPTRAP
, _fs
->_traps
, 0);
341 _fs
->_returnexp
= retexp
;
342 _fs
->AddInstruction(op
, 1, _fs
->PopTarget(),_fs
->GetStackSize());
346 if(op
== _OP_RETURN
&& _fs
->_traps
> 0)
347 _fs
->AddInstruction(_OP_POPTRAP
, _fs
->_traps
,0);
348 _fs
->_returnexp
= -1;
349 _fs
->AddInstruction(op
, 0xFF,0,_fs
->GetStackSize());
355 if(_fs
->_breaktargets
.size() <= 0)
357 Error("'break' has to be in a loop block");
359 if(_fs
->_breaktargets
.top() > 0)
361 _fs
->AddInstruction(_OP_POPTRAP
, _fs
->_breaktargets
.top(), 0);
364 _fs
->AddInstruction(_OP_JMP
, 0, -1234);
365 _fs
->_unresolvedbreaks
.push_back(_fs
->GetCurrentPos());
370 if(_fs
->_continuetargets
.size() <= 0)
372 Error("'continue' has to be in a loop block");
374 if(_fs
->_continuetargets
.top() > 0)
376 _fs
->AddInstruction(_OP_POPTRAP
, _fs
->_continuetargets
.top(), 0);
379 _fs
->AddInstruction(_OP_JMP
, 0, -1234);
380 _fs
->_unresolvedcontinues
.push_back(_fs
->GetCurrentPos());
408 END_VXCOPE_NO_CLOSE();
420 _fs
->AddInstruction(_OP_THROW
, _fs
->PopTarget());
426 VXRawObj id
= Expect(TK_IDENTIFIER
);
428 VXRawObj val
= ExpectScalar();
430 VXTableObj
*enums
= _table(_ss(_vm
)->_consts
);
431 VXObject strongid
= id
;
432 enums
->NewSlot(strongid
,VXObject(val
));
439 _fs
->DiscardTarget();
446 void EmitDerefOp(VXOpcode op
)
448 VXInteger val
= _fs
->PopTarget();
449 VXInteger key
= _fs
->PopTarget();
450 VXInteger src
= _fs
->PopTarget();
451 _fs
->AddInstruction(op
,_fs
->PushTarget(),src
,key
,val
);
454 void Emit2ArgsOP(VXOpcode op
, VXInteger p3
= 0)
456 VXInteger p2
= _fs
->PopTarget(); //src in OP_GET
457 VXInteger p1
= _fs
->PopTarget(); //key in OP_GET
458 _fs
->AddInstruction(op
,_fs
->PushTarget(), p1
, p2
, p3
);
461 void EmitCompoundArith(VXInteger tok
, VXInteger etype
, VXInteger pos
)
463 /* Generate code depending on the expression type */
468 VXInteger p2
= _fs
->PopTarget(); //src in OP_GET
469 VXInteger p1
= _fs
->PopTarget(); //key in OP_GET
471 //EmitCompArithLocal(tok, p1, p1, p2);
472 _fs
->AddInstruction(ChooseArithOpByToken(tok
),p1
, p2
, p1
, 0);
478 VXInteger val
= _fs
->PopTarget();
479 VXInteger key
= _fs
->PopTarget();
480 VXInteger src
= _fs
->PopTarget();
481 /* _OP_COMPARITH mixes dest obj and source val in the arg1 */
487 ChooseCompArithCharByToken(tok
));
492 VXInteger val
= _fs
->TopTarget();
493 VXInteger tmp
= _fs
->PushTarget();
494 _fs
->AddInstruction(_OP_GETOUTER
, tmp
, pos
);
495 _fs
->AddInstruction(ChooseArithOpByToken(tok
), tmp
, val
, tmp
, 0);
496 _fs
->AddInstruction(_OP_SETOUTER
, tmp
, pos
, tmp
);
504 for(Expression();_token
== ',';_fs
->PopTarget(), Lex(), CommaExpr());
512 _es
.donot_get
= false;
524 VXInteger op
= _token
;
525 VXInteger ds
= _es
.etype
;
526 VXInteger pos
= _es
.epos
;
529 Error("can't assign expression");
536 if(ds
== OBJECT
|| ds
== BASE
)
538 EmitDerefOp(_OP_NEWSLOT
);
540 //if _derefstate != DEREF_NO_DEREF &&
541 // DEREF_FIELD so is the index of a local
544 //Error("can't \"create\" a local slot");
545 Error("can't use variable as slot that was previously declared local");
553 VXInteger src
= _fs
->PopTarget();
554 VXInteger dst
= _fs
->TopTarget();
555 _fs
->AddInstruction(_OP_MOVE
, dst
, src
);
560 EmitDerefOp(_OP_SET
);
564 VXInteger src
= _fs
->PopTarget();
565 VXInteger dst
= _fs
->PushTarget();
566 _fs
->AddInstruction(_OP_SETOUTER
, dst
, pos
, src
);
575 EmitCompoundArith(op
, ds
, pos
);
583 _fs
->AddInstruction(_OP_JZ
, _fs
->PopTarget());
584 VXInteger jzpos
= _fs
->GetCurrentPos();
585 VXInteger trg
= _fs
->PushTarget();
587 VXInteger first_exp
= _fs
->PopTarget();
590 _fs
->AddInstruction(_OP_MOVE
, trg
, first_exp
);
592 VXInteger endfirstexp
= _fs
->GetCurrentPos();
593 _fs
->AddInstruction(_OP_JMP
, 0, 0);
595 VXInteger jmppos
= _fs
->GetCurrentPos();
597 VXInteger second_exp
= _fs
->PopTarget();
598 if(trg
!= second_exp
)
600 _fs
->AddInstruction(_OP_MOVE
, trg
, second_exp
);
602 _fs
->SetIntructionParam(jmppos
, 1, _fs
->GetCurrentPos() - jmppos
);
603 _fs
->SetIntructionParam(jzpos
, 1, endfirstexp
- jzpos
+ 1);
611 template<typename T
> void BIN_EXP(VXOpcode op
, T f
,VXInteger op3
= 0)
615 VXInteger op1
= _fs
->PopTarget();
616 VXInteger op2
= _fs
->PopTarget();
617 _fs
->AddInstruction(op
, _fs
->PushTarget(), op1
, op2
, op3
);
627 VXInteger first_exp
= _fs
->PopTarget();
628 VXInteger trg
= _fs
->PushTarget();
629 _fs
->AddInstruction(_OP_OR
, trg
, 0, first_exp
, 0);
630 VXInteger jpos
= _fs
->GetCurrentPos();
633 _fs
->AddInstruction(_OP_MOVE
, trg
, first_exp
);
638 VXInteger second_exp
= _fs
->PopTarget();
639 if(trg
!= second_exp
)
641 _fs
->AddInstruction(_OP_MOVE
, trg
, second_exp
);
644 _fs
->SetIntructionParam(jpos
, 1, (_fs
->GetCurrentPos() - jpos
));
662 VXInteger first_exp
= _fs
->PopTarget();
663 VXInteger trg
= _fs
->PushTarget();
664 _fs
->AddInstruction(_OP_AND
, trg
, 0, first_exp
, 0);
665 VXInteger jpos
= _fs
->GetCurrentPos();
668 _fs
->AddInstruction(_OP_MOVE
, trg
, first_exp
);
673 VXInteger second_exp
= _fs
->PopTarget();
674 if(trg
!= second_exp
)
676 _fs
->AddInstruction(_OP_MOVE
, trg
, second_exp
);
679 _fs
->SetIntructionParam(jpos
, 1, (_fs
->GetCurrentPos() - jpos
));
683 BIN_EXP(_OP_EXISTS
, &VXCompiler::BitwiseOrExp
);
686 BIN_EXP(_OP_INSTANCEOF
, &VXCompiler::BitwiseOrExp
);
700 BIN_EXP(_OP_BITW
, &VXCompiler::BitwiseXorExp
,BW_OR
);
715 BIN_EXP(_OP_BITW
, &VXCompiler::BitwiseAndExp
,BW_XOR
);
730 BIN_EXP(_OP_BITW
, &VXCompiler::EqExp
,BW_AND
);
746 BIN_EXP(_OP_EQ
, &VXCompiler::CompExp
);
749 BIN_EXP(_OP_NE
, &VXCompiler::CompExp
);
752 BIN_EXP(_OP_CMP
, &VXCompiler::CompExp
,CMP_3W
);
767 BIN_EXP(_OP_CMP
, &VXCompiler::ShiftExp
,CMP_G
);
770 BIN_EXP(_OP_CMP
, &VXCompiler::ShiftExp
,CMP_L
);
773 BIN_EXP(_OP_CMP
, &VXCompiler::ShiftExp
,CMP_GE
);
776 BIN_EXP(_OP_CMP
, &VXCompiler::ShiftExp
,CMP_LE
);
792 BIN_EXP(_OP_BITW
, &VXCompiler::PlusExp
,BW_USHIFTR
);
795 BIN_EXP(_OP_BITW
, &VXCompiler::PlusExp
,BW_SHIFTL
);
798 BIN_EXP(_OP_BITW
, &VXCompiler::PlusExp
,BW_SHIFTR
);
805 VXOpcode
ChooseArithOpByToken(VXInteger tok
)
830 VXInteger
ChooseCompArithCharByToken(VXInteger tok
)
847 oper
= 0; //shut up compiler
863 BIN_EXP(ChooseArithOpByToken(_token
), &VXCompiler::MultExp
);
881 BIN_EXP(ChooseArithOpByToken(_token
), &VXCompiler::PrefixedExpr
);
889 //if 'pos' != -1 the previous variable is a local variable
892 VXInteger pos
= Factor();
903 _fs
->GetConstant(Expect(TK_IDENTIFIER
)));
906 Emit2ArgsOP(_OP_GET
);
907 pos
= _fs
->TopTarget();
915 Emit2ArgsOP(_OP_GET
);
921 if(_lex
._prevtoken
== '\n')
923 Error("cannot brake deref/or comma needed after [exp]=exp slot declaration");
931 Emit2ArgsOP(_OP_GET
);
932 pos
= _fs
->TopTarget();
940 Emit2ArgsOP(_OP_GET
);
948 if(IsEndOfStatement())
950 VXInteger diff
= (_token
==TK_MINUSMINUS
) ? -1 : 1;
955 Error("can't '++' or '--' an expression");
959 Emit2ArgsOP(_OP_PINC
, diff
);
963 VXInteger src
= _fs
->PopTarget();
972 VXInteger tmp1
= _fs
->PushTarget();
973 VXInteger tmp2
= _fs
->PushTarget();
974 _fs
->AddInstruction(_OP_GETOUTER
,
976 _fs
->AddInstruction(_OP_PINCL
,
977 tmp1
, tmp2
, 0, diff
);
978 _fs
->AddInstruction(_OP_SETOUTER
,
979 tmp2
, _es
.epos
, tmp2
);
991 /* location of the key */
992 VXInteger key
= _fs
->PopTarget();
993 /* location of the object */
994 VXInteger table
= _fs
->PopTarget();
995 /* location for the closure */
996 VXInteger closure
= _fs
->PushTarget();
997 /* location for 'this' pointer */
998 VXInteger ttarget
= _fs
->PushTarget();
999 _fs
->AddInstruction(_OP_PREPCALL
,
1000 closure
, key
, table
, ttarget
);
1004 //Emit2ArgsOP(_OP_GET);
1005 _fs
->AddInstruction(_OP_MOVE
,
1006 _fs
->PushTarget(), 0);
1009 _fs
->AddInstruction(_OP_GETOUTER
,
1010 _fs
->PushTarget(), _es
.epos
);
1011 _fs
->AddInstruction(_OP_MOVE
,
1012 _fs
->PushTarget(), 0);
1015 _fs
->AddInstruction(_OP_MOVE
,
1016 _fs
->PushTarget(), 0);
1033 _fs
->AddInstruction(_OP_NEWOBJ
,
1037 ParseTableOrClass(',', '}');
1041 _fs
->AddInstruction(_OP_NEWOBJ
,
1042 _fs
->PushTarget(),0,0,
1044 VXInteger apos
= _fs
->GetCurrentPos();
1047 while(_token
!= ']')
1054 VXInteger val
= _fs
->PopTarget();
1055 VXInteger array
= _fs
->TopTarget();
1056 _fs
->AddInstruction(_OP_APPENDARRAY
,
1062 _fs
->SetIntructionParam(apos
, 1, key
);
1067 FunctionExp(_token
);
1070 FunctionExp(_token
,true);
1081 EmitLoadConstInt(-_lex
._nvalue
,-1);
1085 EmitLoadConstFloat(-_lex
._fvalue
,-1);
1098 if(_token
== TK_INTEGER
)
1100 EmitLoadConstInt(~_lex
._nvalue
,-1);
1106 case TK_STRING_LITERAL
:
1107 _fs
->AddInstruction(_OP_LOAD
,
1110 _fs
->CreateString(_lex
._svalue
,
1111 _lex
._longstr
.size()-1)));
1116 _fs
->AddInstruction(_OP_GETBASE
,
1119 _es
.epos
= _fs
->TopTarget();
1123 case TK_CONSTRUCTOR
:
1132 id
= _fs
->CreateString(_lex
._svalue
);
1135 id
= _fs
->CreateString(NAMES_TK_THISVAR
);
1137 case TK_CONSTRUCTOR
:
1138 id
= _fs
->CreateString(NAMES_TK_CTOR
);
1144 if((pos
= _fs
->GetLocalVariable(id
)) != -1)
1146 /* Handle a local variable (includes 'this') */
1147 _fs
->PushTarget(pos
);
1152 else if((pos
= _fs
->GetOuterVariable(id
)) != -1)
1154 /* Handle a free var */
1157 _es
.epos
= _fs
->PushTarget();
1158 _fs
->AddInstruction(_OP_GETOUTER
, _es
.epos
, pos
);
1159 /* _es.etype = EXPR; already default value */
1168 else if(_fs
->IsConstant(id
, constant
))
1170 /* Handle named constant */
1173 if(type(constant
) == VX_OT_TABLE
)
1176 constid
= Expect(TK_IDENTIFIER
);
1177 if(!_table(constant
)->Get(constid
, constval
))
1180 Error("invalid constant [%s.%s]",
1182 _stringval(constid
));
1187 constval
= constant
;
1189 _es
.epos
= _fs
->PushTarget();
1191 /* generate direct or literal function depending on size */
1192 VXOType ctype
= type(constval
);
1196 EmitLoadConstInt(_integer(constval
),
1200 EmitLoadConstFloat(_float(constval
),
1204 _fs
->AddInstruction(
1207 _fs
->GetConstant(constval
));
1215 * Handle a non-local variable, aka a field.
1216 * Push the 'this' pointer on
1217 * the virtual stack (always found in offset 0, so
1218 * no instruction needs to
1219 * be generated), and push the key next. Generate an
1220 * _OP_LOAD instruction
1221 * for the latter. If we are not using the variable as
1222 * a dref expr, generate
1223 * the _OP_GET instruction.
1226 _fs
->AddInstruction(
1229 _fs
->GetConstant(id
));
1232 Emit2ArgsOP(_OP_GET
);
1239 case TK_DOUBLE_COLON
: // "::"
1240 _fs
->AddInstruction(_OP_LOADROOT
, _fs
->PushTarget());
1242 _token
= '.'; /* hack: drop into PrefixExpr, case '.'*/
1247 _fs
->AddInstruction(_OP_LOADNULLS
,
1248 _fs
->PushTarget(),1);
1252 EmitLoadConstInt(_lex
._nvalue
,-1);
1256 EmitLoadConstFloat(_lex
._fvalue
,-1);
1261 _fs
->AddInstruction(
1264 _token
== TK_TRUE
? 1 : 0);
1269 UnaryOP(_OP_TYPEOF
);
1273 UnaryOP(_OP_RESUME
);
1281 PrefixIncDec(_token
);
1292 Error("expression expected");
1297 void EmitLoadConstInt(VXInteger value
,VXInteger target
)
1301 target
= _fs
->PushTarget();
1303 //does it fit in 32 bits?
1304 if((value
& (~((VXInteger
)0xFFFFFFFF))) == 0)
1306 _fs
->AddInstruction(_OP_LOADINT
, target
,value
);
1310 _fs
->AddInstruction(_OP_LOAD
,
1312 _fs
->GetNumericConstant(value
));
1315 void EmitLoadConstFloat(VXFloat value
,VXInteger target
)
1319 target
= _fs
->PushTarget();
1321 if(sizeof(VXFloat
) == sizeof(VXInt32
))
1323 _fs
->AddInstruction(_OP_LOADFLOAT
, target
,*((VXInt32
*)&value
));
1327 _fs
->AddInstruction(_OP_LOAD
,
1329 _fs
->GetNumericConstant(value
));
1333 void UnaryOP(VXOpcode op
)
1336 VXInteger src
= _fs
->PopTarget();
1337 _fs
->AddInstruction(op
, _fs
->PushTarget(), src
);
1356 return (!_es
.donot_get
||
1358 (_token
== '.' || _token
== '[')));
1360 void FunctionCallArgs()
1362 VXInteger nargs
= 1;//this
1363 while(_token
!= ')')
1366 MoveIfCurrentTargetIsLocal();
1373 Error("expression expected, found ')'");
1378 for(VXInteger i
= 0; i
< (nargs
- 1); i
++)
1382 VXInteger stackbase
= _fs
->PopTarget();
1383 VXInteger closure
= _fs
->PopTarget();
1384 _fs
->AddInstruction(_OP_CALL
,
1385 _fs
->PushTarget(), closure
,
1389 void ParseTableOrClass(VXInteger separator
,VXInteger terminator
)
1391 VXInteger tpos
= _fs
->GetCurrentPos();
1392 VXInteger nkeys
= 0;
1393 while(_token
!= terminator
)
1395 bool hasattrs
= false;
1396 bool isstatic
= false;
1397 //check if is an attribute
1398 if(separator
== ';')
1400 if(_token
== TK_ATTR_OPEN
)
1402 _fs
->AddInstruction(_OP_NEWOBJ
,
1403 _fs
->PushTarget(),0,
1406 ParseTableOrClass(',', TK_ATTR_CLOSE
);
1409 if(_token
== TK_STATIC
)
1418 case TK_CONSTRUCTOR
:
1420 VXInteger tk
= _token
;
1422 VXRawObj id
= (tk
== TK_FUNCTION
?
1423 Expect(TK_IDENTIFIER
) :
1424 _fs
->CreateString("constructor"));
1426 _fs
->AddInstruction(_OP_LOAD
,
1428 _fs
->GetConstant(id
));
1430 _fs
->AddInstruction(_OP_CLOSURE
,
1432 _fs
->_functions
.size() - 1, 0);
1442 //case TK_IDENTIFIER:
1443 case TK_STRING_LITERAL
: //JSON
1444 //only works for tables
1445 if(separator
== ',')
1447 _fs
->AddInstruction(
1450 _fs
->GetConstant(Expect(TK_STRING_LITERAL
)));
1456 _fs
->AddInstruction(
1459 _fs
->GetConstant(Expect(TK_IDENTIFIER
)));
1463 if(_token
== separator
)
1465 Lex();//optional comma/semicolon
1468 VXInteger val
= _fs
->PopTarget();
1469 VXInteger key
= _fs
->PopTarget();
1470 VXInteger attrs
= hasattrs
? _fs
->PopTarget():-1;
1471 vox_assert((hasattrs
&& (attrs
== key
-1)) || !hasattrs
);
1472 unsigned char flags
= (
1473 (hasattrs
? NEW_SLVX_OT_ATTRIBUTES_FLAG
: 0) |
1474 (isstatic
? NEW_SLVX_OT_STATIC_FLAG
: 0));
1475 // vvv BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
1476 VXInteger table
= _fs
->TopTarget();
1477 //hack recognizes a table from the separator
1478 if(separator
== ',')
1480 _fs
->AddInstruction(_OP_NEWSLOT
, 0xFF, table
, key
, val
);
1484 //this for classes only as it invokes _newmember
1485 _fs
->AddInstruction(_OP_NEWSLOTA
, flags
, table
, key
, val
);
1488 if(separator
== ',') //hack recognizes a table from the separator
1490 _fs
->SetIntructionParam(tpos
, 1, nkeys
);
1494 void LocalDeclStatement()
1498 if( _token
== TK_FUNCTION
)
1501 varname
= Expect(TK_IDENTIFIER
);
1503 CreateFunction(varname
, false);
1504 _fs
->AddInstruction(_OP_CLOSURE
,
1506 _fs
->_functions
.size() - 1, 0);
1508 _fs
->PushLocalVariable(varname
);
1513 varname
= Expect(TK_IDENTIFIER
);
1518 VXInteger src
= _fs
->PopTarget();
1519 VXInteger dest
= _fs
->PushTarget();
1522 _fs
->AddInstruction(_OP_MOVE
, dest
, src
);
1527 _fs
->AddInstruction(_OP_LOADNULLS
, _fs
->PushTarget(),1);
1530 _fs
->PushLocalVariable(varname
);
1545 bool haselse
= false;
1550 _fs
->AddInstruction(_OP_JZ
, _fs
->PopTarget());
1551 VXInteger jnepos
= _fs
->GetCurrentPos();
1555 if(_token
!= '}' && _token
!= TK_ELSE
)
1557 OptionalSemicolon();
1560 VXInteger endifblock
= _fs
->GetCurrentPos();
1561 if(_token
== TK_ELSE
)
1565 _fs
->AddInstruction(_OP_JMP
);
1566 jmppos
= _fs
->GetCurrentPos();
1569 OptionalSemicolon();
1571 _fs
->SetIntructionParam(jmppos
, 1,
1572 _fs
->GetCurrentPos() - jmppos
);
1574 _fs
->SetIntructionParam(jnepos
, 1,
1575 endifblock
- jnepos
+ (haselse
?1:0));
1578 void WhileStatement()
1580 VXInteger jzpos
, jmppos
;
1581 jmppos
= _fs
->GetCurrentPos();
1586 BEGIN_BREAKBLE_BLOCK();
1587 _fs
->AddInstruction(_OP_JZ
, _fs
->PopTarget());
1588 jzpos
= _fs
->GetCurrentPos();
1592 _fs
->AddInstruction(_OP_JMP
, 0, jmppos
- _fs
->GetCurrentPos() - 1);
1593 _fs
->SetIntructionParam(jzpos
, 1, _fs
->GetCurrentPos() - jzpos
);
1594 END_BREAKBLE_BLOCK(jmppos
);
1597 void DoWhileStatement()
1600 VXInteger jmptrg
= _fs
->GetCurrentPos();
1601 BEGIN_BREAKBLE_BLOCK()
1606 VXInteger continuetrg
= _fs
->GetCurrentPos();
1610 _fs
->AddInstruction(_OP_JZ
, _fs
->PopTarget(), 1);
1611 _fs
->AddInstruction(_OP_JMP
, 0, jmptrg
- _fs
->GetCurrentPos() - 1);
1612 END_BREAKBLE_BLOCK(continuetrg
);
1620 if(_token
== TK_LOCAL
)
1622 LocalDeclStatement();
1624 else if(_token
!= ';')
1631 VXInteger jmppos
= _fs
->GetCurrentPos();
1632 VXInteger jzpos
= -1;
1636 _fs
->AddInstruction(_OP_JZ
, _fs
->PopTarget());
1637 jzpos
= _fs
->GetCurrentPos();
1641 VXInteger expstart
= _fs
->GetCurrentPos() + 1;
1649 VXInteger expend
= _fs
->GetCurrentPos();
1650 VXInteger expsize
= (expend
- expstart
) + 1;
1651 VXInstructionVec exp
;
1654 for(VXInteger i
= 0; i
< expsize
; i
++)
1656 exp
.push_back(_fs
->GetInstruction(expstart
+ i
));
1658 _fs
->PopInstructions(expsize
);
1660 BEGIN_BREAKBLE_BLOCK()
1662 VXInteger continuetrg
= _fs
->GetCurrentPos();
1665 for(VXInteger i
= 0; i
< expsize
; i
++)
1667 _fs
->AddInstruction(exp
[i
]);
1670 _fs
->AddInstruction(_OP_JMP
, 0, jmppos
- _fs
->GetCurrentPos() - 1, 0);
1673 _fs
->SetIntructionParam(jzpos
, 1, _fs
->GetCurrentPos() - jzpos
);
1676 END_BREAKBLE_BLOCK(continuetrg
);
1679 void ForEachStatement()
1681 VXRawObj idxname
, valname
;
1684 valname
= Expect(TK_IDENTIFIER
);
1689 valname
= Expect(TK_IDENTIFIER
);
1693 idxname
= _fs
->CreateString("@INDEX@");
1697 //save the stack size
1699 //put the table in the stack(evaluate the table expression)
1702 VXInteger container
= _fs
->TopTarget();
1703 //push the index local var
1704 VXInteger indexpos
= _fs
->PushLocalVariable(idxname
);
1705 _fs
->AddInstruction(_OP_LOADNULLS
, indexpos
,1);
1706 //push the value local var
1707 VXInteger valuepos
= _fs
->PushLocalVariable(valname
);
1708 _fs
->AddInstruction(_OP_LOADNULLS
, valuepos
,1);
1709 //push reference index
1710 //use invalid id to make it inaccessible
1711 VXInteger itrpos
= _fs
->PushLocalVariable(_fs
->CreateString("@ITERATOR@"));
1712 _fs
->AddInstruction(_OP_LOADNULLS
, itrpos
,1);
1713 VXInteger jmppos
= _fs
->GetCurrentPos();
1714 _fs
->AddInstruction(_OP_FOREACH
, container
, 0, indexpos
);
1715 VXInteger foreachpos
= _fs
->GetCurrentPos();
1716 _fs
->AddInstruction(_OP_POSTFOREACH
, container
, 0, indexpos
);
1717 //generate the statement code
1718 BEGIN_BREAKBLE_BLOCK()
1720 _fs
->AddInstruction(_OP_JMP
, 0, jmppos
- _fs
->GetCurrentPos() - 1);
1721 _fs
->SetIntructionParam(foreachpos
, 1, _fs
->GetCurrentPos() - foreachpos
);
1722 _fs
->SetIntructionParam(foreachpos
+ 1, 1, _fs
->GetCurrentPos() - foreachpos
);
1723 END_BREAKBLE_BLOCK(foreachpos
- 1);
1724 //restore the local variable stack(remove index,val and ref idx)
1728 void SwitchStatement()
1735 VXInteger expr
= _fs
->TopTarget();
1737 VXInteger tonextcondjmp
= -1;
1738 VXInteger skipcondjmp
= -1;
1739 VXInteger __nbreaks__
= _fs
->_unresolvedbreaks
.size();
1740 _fs
->_breaktargets
.push_back(0);
1741 while(_token
== TK_CASE
)
1745 _fs
->AddInstruction(_OP_JMP
, 0, 0);
1746 skipcondjmp
= _fs
->GetCurrentPos();
1747 _fs
->SetIntructionParam(tonextcondjmp
, 1, _fs
->GetCurrentPos() - tonextcondjmp
);
1753 VXInteger trg
= _fs
->PopTarget();
1754 _fs
->AddInstruction(_OP_EQ
, trg
, trg
, expr
);
1755 _fs
->AddInstruction(_OP_JZ
, trg
, 0);
1757 if(skipcondjmp
!= -1)
1759 _fs
->SetIntructionParam(skipcondjmp
, 1,
1760 (_fs
->GetCurrentPos()-skipcondjmp
));
1762 tonextcondjmp
= _fs
->GetCurrentPos();
1768 if(tonextcondjmp
!= -1)
1770 _fs
->SetIntructionParam(tonextcondjmp
, 1,
1771 _fs
->GetCurrentPos()-tonextcondjmp
);
1773 if(_token
== TK_DEFAULT
)
1783 __nbreaks__
= _fs
->_unresolvedbreaks
.size() - __nbreaks__
;
1786 ResolveBreaks(_fs
, __nbreaks__
);
1788 _fs
->_breaktargets
.pop_back();
1791 void FunctionStatement()
1794 Lex(); id
= Expect(TK_IDENTIFIER
);
1796 _fs
->AddInstruction(_OP_LOAD
, _fs
->PushTarget(), _fs
->GetConstant(id
));
1797 if(_token
== TK_DOUBLE_COLON
)
1799 Emit2ArgsOP(_OP_GET
);
1801 while(_token
== TK_DOUBLE_COLON
)
1804 id
= Expect(TK_IDENTIFIER
);
1805 _fs
->AddInstruction(_OP_LOAD
,
1807 _fs
->GetConstant(id
));
1808 if(_token
== TK_DOUBLE_COLON
)
1810 Emit2ArgsOP(_OP_GET
);
1815 _fs
->AddInstruction(_OP_CLOSURE
,
1817 _fs
->_functions
.size() - 1, 0);
1818 EmitDerefOp(_OP_NEWSLOT
);
1822 void ClassStatement()
1827 _es
.donot_get
= true;
1829 if(_es
.etype
== EXPR
)
1831 Error("invalid class name");
1833 else if(_es
.etype
== OBJECT
|| _es
.etype
== BASE
)
1836 EmitDerefOp(_OP_NEWSLOT
);
1841 Error("cannot create a class in a local with the syntax(class <local>)");
1846 VXRawObj
ExpectScalar()
1849 val
._type
= VX_OT_NULL
; val
._unVal
.nInteger
= 0; //shut up GCC 4.x
1853 val
._type
= VX_OT_INTEGER
;
1854 val
._unVal
.nInteger
= _lex
._nvalue
;
1857 val
._type
= VX_OT_FLOAT
;
1858 val
._unVal
.fFloat
= _lex
._fvalue
;
1860 case TK_STRING_LITERAL
:
1861 val
= _fs
->CreateString(_lex
._svalue
,_lex
._longstr
.size()-1);
1868 val
._type
= VX_OT_INTEGER
;
1869 val
._unVal
.nInteger
= -_lex
._nvalue
;
1872 val
._type
= VX_OT_FLOAT
;
1873 val
._unVal
.fFloat
= -_lex
._fvalue
;
1876 Error("scalar expected: integer, float");
1880 Error("scalar expected: integer, float or string");
1885 void EnumStatement()
1888 VXRawObj id
= Expect(TK_IDENTIFIER
);
1890 VXRawObj table
= _fs
->CreateTable();
1892 while(_token
!= '}')
1894 VXRawObj key
= Expect(TK_IDENTIFIER
);
1899 val
= ExpectScalar();
1903 val
._type
= VX_OT_INTEGER
;
1904 val
._unVal
.nInteger
= nval
++;
1906 _table(table
)->NewSlot(VXObject(key
),VXObject(val
));
1912 VXTableObj
*enums
= _table(_ss(_vm
)->_consts
);
1913 VXObject strongid
= id
;
1914 enums
->NewSlot(VXObject(strongid
),VXObject(table
));
1919 void TryCatchStatement()
1923 _fs
->AddInstruction(_OP_PUSHTRAP
,0,0);
1925 if(_fs
->_breaktargets
.size())
1927 _fs
->_breaktargets
.top()++;
1930 if(_fs
->_continuetargets
.size())
1932 _fs
->_continuetargets
.top()++;
1935 VXInteger trappos
= _fs
->GetCurrentPos();
1942 _fs
->AddInstruction(_OP_POPTRAP
, 1, 0);
1943 if(_fs
->_breaktargets
.size())
1945 _fs
->_breaktargets
.top()--;
1947 if(_fs
->_continuetargets
.size())
1949 _fs
->_continuetargets
.top()--;
1951 _fs
->AddInstruction(_OP_JMP
, 0, 0);
1952 VXInteger jmppos
= _fs
->GetCurrentPos();
1953 _fs
->SetIntructionParam(trappos
, 1, (_fs
->GetCurrentPos() - trappos
));
1956 exid
= Expect(TK_IDENTIFIER
);
1960 VXInteger ex_target
= _fs
->PushLocalVariable(exid
);
1961 _fs
->SetIntructionParam(trappos
, 0, ex_target
);
1963 _fs
->SetIntructionParams(jmppos
, 0, (_fs
->GetCurrentPos() - jmppos
), 0);
1968 void FunctionExp(VXInteger ftype
,bool lambda
= false)
1973 CreateFunction(dummy
,lambda
);
1974 _fs
->AddInstruction(_OP_CLOSURE
,
1976 _fs
->_functions
.size() - 1,
1977 ftype
== TK_FUNCTION
?0:1);
1982 VXInteger base
= -1;
1983 VXInteger attrs
= -1;
1984 if(_token
== TK_EXTENDS
)
1986 Lex(); Expression();
1987 base
= _fs
->TopTarget();
1990 if(_token
== TK_ATTR_OPEN
)
1993 _fs
->AddInstruction(_OP_NEWOBJ
, _fs
->PushTarget(),0,NVX_OT_TABLE
);
1994 ParseTableOrClass(',',TK_ATTR_CLOSE
);
1995 attrs
= _fs
->TopTarget();
2006 _fs
->AddInstruction(_OP_NEWOBJ
,
2008 base
, attrs
, NVX_OT_CLASS
);
2009 ParseTableOrClass(';', '}');
2017 _es
.donot_get
= true;
2021 Error("can't delete an expression");
2023 if(_es
.etype
==OBJECT
|| _es
.etype
==BASE
)
2025 Emit2ArgsOP(_OP_DELETE
);
2029 Error("cannot delete an (outer) local");
2034 void PrefixIncDec(VXInteger token
)
2037 VXInteger diff
= (token
==TK_MINUSMINUS
) ? -1 : 1;
2040 _es
.donot_get
= true;
2044 Error("can't '++' or '--' an expression");
2046 else if(_es
.etype
==OBJECT
|| _es
.etype
==BASE
)
2048 Emit2ArgsOP(_OP_INC
, diff
);
2050 else if(_es
.etype
==LOCAL
)
2052 VXInteger src
= _fs
->TopTarget();
2053 _fs
->AddInstruction(_OP_INCL
, src
, src
, 0, diff
);
2055 else if(_es
.etype
==OUTER
)
2057 VXInteger tmp
= _fs
->PushTarget();
2058 _fs
->AddInstruction(_OP_GETOUTER
, tmp
, _es
.epos
);
2059 _fs
->AddInstruction(_OP_INCL
, tmp
, tmp
, 0, diff
);
2060 _fs
->AddInstruction(_OP_SETOUTER
, tmp
, _es
.epos
, tmp
);
2065 void CreateFunction(VXRawObj
&name
,bool lambda
= false)
2067 VXFuncState
*funcstate
= _fs
->PushChildState(_ss(_vm
));
2068 funcstate
->_name
= name
;
2070 funcstate
->AddParameter(_fs
->CreateString(NAMES_TK_THISVAR
));
2071 funcstate
->_sourcename
= _sourcename
;
2072 VXInteger defparams
= 0;
2075 if(_token
== TK_VARPARAMS
)
2079 Error("function with default parameters cannot"
2080 " have variable number of parameters");
2082 funcstate
->AddParameter(_fs
->CreateString(NAMES_VARGV
));
2083 funcstate
->_varparams
= true;
2087 Error("expected ')'");
2093 paramname
= Expect(TK_IDENTIFIER
);
2094 funcstate
->AddParameter(paramname
);
2099 funcstate
->AddDefaultParam(_fs
->TopTarget());
2106 Error("expected '='");
2113 else if(_token
!= ')')
2115 Error("expected ')' or ','");
2120 for(VXInteger n
= 0; n
< defparams
; n
++)
2125 VXFuncState
*currchunk
= _fs
;
2130 _fs
->AddInstruction(_OP_RETURN
, 1, _fs
->PopTarget());
2136 funcstate
->AddLineInfos(
2137 (_lex
._prevtoken
== '\n') ?
2138 _lex
._lasttokenline
: _lex
._currentline
,
2140 funcstate
->AddInstruction(_OP_RETURN
, -1);
2141 funcstate
->SetStackSize(0);
2143 VXFuncProtoObj
*func
= funcstate
->BuildProto();
2145 funcstate
->Dump(func
);
2148 _fs
->_functions
.push_back(func
);
2149 _fs
->PopChildState();
2152 void ResolveBreaks(VXFuncState
*funcstate
, VXInteger ntoresolve
)
2154 while(ntoresolve
> 0)
2156 VXInteger pos
= funcstate
->_unresolvedbreaks
.back();
2157 funcstate
->_unresolvedbreaks
.pop_back();
2158 //set the jmp instruction
2159 funcstate
->SetIntructionParams(pos
, 0, funcstate
->GetCurrentPos() - pos
, 0);
2164 void ResolveContinues(VXFuncState
*funcstate
,
2165 VXInteger ntoresolve
,
2166 VXInteger targetpos
)
2168 while(ntoresolve
> 0)
2170 VXInteger pos
= funcstate
->_unresolvedcontinues
.back();
2171 funcstate
->_unresolvedcontinues
.pop_back();
2172 //set the jmp instruction
2173 funcstate
->SetIntructionParams(pos
, 0, targetpos
- pos
, 0);
2181 VXObject _sourcename
;
2185 VXInteger _debugline
;
2189 char *compilererror
;
2194 bool Compile(VXState
*vm
,VXLexReadFunc rg
,
2196 const char *sourcename
,
2201 VXCompiler
p(vm
, rg
, up
, sourcename
, raiseerror
, lineinfo
);
2202 return p
.Compile(out
);