moved back to old acc
[vox.git] / src / core / compiler.cpp
blob305a4c5ef1760e60f4b02d830960eb73dac8aeb8
2 // continue: line 720
5 #ifndef VOX_NO_COMPILER
6 #include <stdarg.h>
7 #include <setjmp.h>
9 #include "opcodes.hpp"
10 #include "string.hpp"
11 #include "funcproto.hpp"
12 #include "compiler.hpp"
13 #include "funcstate.hpp"
14 #include "lexer.hpp"
15 #include "vm.hpp"
16 #include "table.hpp"
17 #include "names.hpp"
19 #define EXPR 1
20 #define OBJECT 2
21 #define BASE 3
22 #define LOCAL 4
23 #define OUTER 5
25 struct VXExpState {
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 */
31 struct VXScope {
32 VXInteger outers;
33 VXInteger stacksize;
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) \
43 { \
44 if(_fs->CountOuters(_scope.stacksize)) \
45 { \
46 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
47 } \
50 #define END_VXCOPE_NO_CLOSE() \
51 { \
52 if(_fs->GetStackSize() != _scope.stacksize) \
53 { \
54 _fs->SetStackSize(_scope.stacksize); \
55 } \
56 _scope = __oldscope__; \
59 #define END_VXCOPE() \
60 { \
61 VXInteger oldouters = _fs->_outers; \
62 if(_fs->GetStackSize() != _scope.stacksize) \
63 { \
64 _fs->SetStackSize(_scope.stacksize); \
65 if(oldouters != _fs->_outers) \
66 { \
67 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
68 } \
69 } \
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) \
80 { \
81 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; \
82 __ncontinues__ = _fs->_unresolvedcontinues.size() - __ncontinues__; \
83 if(__ncontinues__>0)\
84 { \
85 ResolveContinues(_fs,__ncontinues__,continue_target); \
86 } \
87 if(__nbreaks__>0) \
88 { \
89 ResolveBreaks(_fs,__nbreaks__); \
90 } \
91 _fs->_breaktargets.pop_back(); \
92 _fs->_continuetargets.pop_back(); \
95 class VXCompiler
97 public:
98 VXCompiler(VXState *v,
99 VXLexReadFunc rg,
100 VXUserPointer up,
101 const char* sourcename,
102 bool raiseerror,
103 bool lineinfo)
105 _vm = v;
106 _lex.Init(_ss(v), rg, up, HandleError,this);
107 _sourcename = VXStringObj::Create(_ss(v), sourcename);
108 _lineinfo = lineinfo;_raiseerror = raiseerror;
109 _scope.outers = 0;
110 _scope.stacksize = 0;
111 compilererror = NULL;
114 static void HandleError(void *ud, const char *s)
116 VXCompiler *c = (VXCompiler *)ud;
117 c->Error(s);
120 void Error(const char *s, ...)
122 static char temp[256];
123 va_list vl;
124 va_start(vl, s);
125 vsprintf(temp, s, vl);
126 va_end(vl);
127 compilererror = temp;
128 longjmp(_errorjmp,1);
131 void Lex()
133 _token = _lex.Lex();
136 VXRawObj Expect(VXInteger tok)
138 if(_token != tok)
140 if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER)
142 //do nothing
144 else
146 const char *etypename;
147 if(tok > 255)
149 switch(tok)
151 case TK_IDENTIFIER:
152 etypename = "IDENTIFIER";
153 break;
154 case TK_STRING_LITERAL:
155 etypename = "STRING_LITERAL";
156 break;
157 case TK_INTEGER:
158 etypename = "INTEGER";
159 break;
160 case TK_FLOAT:
161 etypename = "FLOAT";
162 break;
163 default:
164 etypename = _lex.Tok2Str(tok);
166 Error("expected '%s'", etypename);
168 Error("expected '%c'", tok);
171 VXObject ret;
172 switch(tok)
174 case TK_IDENTIFIER:
175 ret = _fs->CreateString(_lex._svalue);
176 break;
177 case TK_STRING_LITERAL:
178 ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
179 break;
180 case TK_INTEGER:
181 ret = VXObject(_lex._nvalue);
182 break;
183 case TK_FLOAT:
184 ret = VXObject(_lex._fvalue);
185 break;
187 Lex();
188 return ret;
190 bool IsEndOfStatement()
192 return (
193 (_lex._prevtoken == '\n') ||
194 (_token == VOX_EOB) ||
195 (_token == '}') ||
196 (_token == ';')
199 void OptionalSemicolon()
201 if(_token == ';')
203 Lex();
204 return;
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)
222 _debugline = 1;
223 _debugop = 0;
225 VXFuncState funcstate(_ss(_vm), NULL, HandleError,this);
226 funcstate._name = VXStringObj::Create(_ss(_vm), NAMES_MAINFUNC);
227 _fs = &funcstate;
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)
235 Lex();
236 while(_token > 0)
238 Statement();
239 if(_lex._prevtoken != '}' && _lex._prevtoken != ';')
241 OptionalSemicolon();
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();
249 #ifdef _DEBUG_DUMP
250 _fs->Dump(_funcproto(o));
251 #endif
253 else
255 if(_raiseerror && _ss(_vm)->_compilererrorhandler)
257 _ss(_vm)->_compilererrorhandler(
258 _vm,
259 compilererror,
260 type(_sourcename)==VX_OT_STRING?_stringval(_sourcename):"unknown",
261 _lex._currentline,
262 _lex._currentcolumn);
264 _vm->_lasterror = VXStringObj::Create(_ss(_vm), compilererror, -1);
265 return false;
267 return true;
270 void Statements()
272 while(_token != '}' && _token != TK_DEFAULT && _token != TK_CASE)
274 Statement();
275 if(_lex._prevtoken != '}' && _lex._prevtoken != ';')
277 OptionalSemicolon();
282 void Statement(bool closeframe = true)
284 _fs->AddLineInfos(_lex._currentline, _lineinfo);
285 switch(_token)
287 case ';':
288 Lex();
289 break;
291 case TK_IF:
292 IfStatement();
293 break;
295 case TK_WHILE:
296 WhileStatement();
297 break;
299 case TK_DO:
300 DoWhileStatement();
301 break;
303 case TK_FOR:
304 ForStatement();
305 break;
307 case TK_FOREACH:
308 ForEachStatement();
309 break;
311 case TK_SWITCH:
312 SwitchStatement();
313 break;
315 case TK_LOCAL:
316 LocalDeclStatement();
317 break;
319 case TK_RETURN:
320 case TK_YIELD:
322 VXOpcode op;
323 if(_token == TK_RETURN)
325 op = _OP_RETURN;
327 else
329 op = _OP_YIELD;
330 _fs->_bgenerator = true;
332 Lex();
333 if(!IsEndOfStatement())
335 VXInteger retexp = _fs->GetCurrentPos()+1;
336 CommaExpr();
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());
344 else
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());
351 break;
354 case TK_BREAK:
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);
363 RESOLVE_OUTERS();
364 _fs->AddInstruction(_OP_JMP, 0, -1234);
365 _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
366 Lex();
367 break;
369 case TK_CONTINUE:
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);
378 RESOLVE_OUTERS();
379 _fs->AddInstruction(_OP_JMP, 0, -1234);
380 _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
381 Lex();
382 break;
384 case TK_FUNCTION:
385 FunctionStatement();
386 break;
388 case TK_CLASS:
389 ClassStatement();
390 break;
392 case TK_ENUM:
393 EnumStatement();
394 break;
396 case '{':
398 BEGIN_VXCOPE();
399 Lex();
400 Statements();
401 Expect('}');
402 if(closeframe)
404 END_VXCOPE();
406 else
408 END_VXCOPE_NO_CLOSE();
411 break;
413 case TK_TRY:
414 TryCatchStatement();
415 break;
417 case TK_THROW:
418 Lex();
419 CommaExpr();
420 _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
421 break;
423 case TK_CONST:
425 Lex();
426 VXRawObj id = Expect(TK_IDENTIFIER);
427 Expect('=');
428 VXRawObj val = ExpectScalar();
429 OptionalSemicolon();
430 VXTableObj *enums = _table(_ss(_vm)->_consts);
431 VXObject strongid = id;
432 enums->NewSlot(strongid,VXObject(val));
433 strongid.Null();
435 break;
437 default:
438 CommaExpr();
439 _fs->DiscardTarget();
440 //_fs->PopTarget();
441 break;
443 _fs->SnoozeOpt();
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 */
464 switch(etype)
466 case LOCAL:
468 VXInteger p2 = _fs->PopTarget(); //src in OP_GET
469 VXInteger p1 = _fs->PopTarget(); //key in OP_GET
470 _fs->PushTarget(p1);
471 //EmitCompArithLocal(tok, p1, p1, p2);
472 _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
474 break;
475 case OBJECT:
476 case BASE:
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 */
482 _fs->AddInstruction(
483 _OP_COMPARITH,
484 _fs->PushTarget(),
485 (src<<16)|val,
486 key,
487 ChooseCompArithCharByToken(tok));
489 break;
490 case OUTER:
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);
498 break;
502 void CommaExpr()
504 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
507 void Expression()
509 VXExpState es = _es;
510 _es.etype = EXPR;
511 _es.epos = -1;
512 _es.donot_get = false;
513 LogicalOrExp();
514 switch(_token)
516 case '=':
517 case TK_NEWSLOT:
518 case TK_MINUSEQ:
519 case TK_PLUSEQ:
520 case TK_MULEQ:
521 case TK_DIVEQ:
522 case TK_MODEQ:
524 VXInteger op = _token;
525 VXInteger ds = _es.etype;
526 VXInteger pos = _es.epos;
527 if(ds == EXPR)
529 Error("can't assign expression");
531 Lex();
532 Expression();
533 switch(op)
535 case TK_NEWSLOT:
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
542 else
544 //Error("can't \"create\" a local slot");
545 Error("can't use variable as slot that was previously declared local");
547 break;
548 case '=': //ASSIGN
549 switch(ds)
551 case LOCAL:
553 VXInteger src = _fs->PopTarget();
554 VXInteger dst = _fs->TopTarget();
555 _fs->AddInstruction(_OP_MOVE, dst, src);
557 break;
558 case OBJECT:
559 case BASE:
560 EmitDerefOp(_OP_SET);
561 break;
562 case OUTER:
564 VXInteger src = _fs->PopTarget();
565 VXInteger dst = _fs->PushTarget();
566 _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
569 break;
570 case TK_MINUSEQ:
571 case TK_PLUSEQ:
572 case TK_MULEQ:
573 case TK_DIVEQ:
574 case TK_MODEQ:
575 EmitCompoundArith(op, ds, pos);
576 break;
579 break;
580 case '?':
582 Lex();
583 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
584 VXInteger jzpos = _fs->GetCurrentPos();
585 VXInteger trg = _fs->PushTarget();
586 Expression();
587 VXInteger first_exp = _fs->PopTarget();
588 if(trg != first_exp)
590 _fs->AddInstruction(_OP_MOVE, trg, first_exp);
592 VXInteger endfirstexp = _fs->GetCurrentPos();
593 _fs->AddInstruction(_OP_JMP, 0, 0);
594 Expect(':');
595 VXInteger jmppos = _fs->GetCurrentPos();
596 Expression();
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);
604 _fs->SnoozeOpt();
606 break;
608 _es = es;
611 template<typename T> void BIN_EXP(VXOpcode op, T f,VXInteger op3 = 0)
613 Lex();
614 (this->*f)();
615 VXInteger op1 = _fs->PopTarget();
616 VXInteger op2 = _fs->PopTarget();
617 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
620 void LogicalOrExp()
622 LogicalAndExp();
623 for(;;)
625 if(_token == TK_OR)
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();
631 if(trg != first_exp)
633 _fs->AddInstruction(_OP_MOVE, trg, first_exp);
635 Lex();
636 LogicalOrExp();
637 _fs->SnoozeOpt();
638 VXInteger second_exp = _fs->PopTarget();
639 if(trg != second_exp)
641 _fs->AddInstruction(_OP_MOVE, trg, second_exp);
643 _fs->SnoozeOpt();
644 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
645 break;
647 else
649 return;
653 void LogicalAndExp()
655 BitwiseOrExp();
656 for(;;)
658 switch(_token)
660 case TK_AND:
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();
666 if(trg != first_exp)
668 _fs->AddInstruction(_OP_MOVE, trg, first_exp);
670 Lex();
671 LogicalAndExp();
672 _fs->SnoozeOpt();
673 VXInteger second_exp = _fs->PopTarget();
674 if(trg != second_exp)
676 _fs->AddInstruction(_OP_MOVE, trg, second_exp);
678 _fs->SnoozeOpt();
679 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
680 break;
682 case TK_IN:
683 BIN_EXP(_OP_EXISTS, &VXCompiler::BitwiseOrExp);
684 break;
685 case TK_INSTANCEOF:
686 BIN_EXP(_OP_INSTANCEOF, &VXCompiler::BitwiseOrExp);
687 break;
688 default:
689 return;
693 void BitwiseOrExp()
695 BitwiseXorExp();
696 for(;;)
698 if(_token == '|')
700 BIN_EXP(_OP_BITW, &VXCompiler::BitwiseXorExp,BW_OR);
702 else
704 return;
708 void BitwiseXorExp()
710 BitwiseAndExp();
711 for(;;)
713 if(_token == '^')
715 BIN_EXP(_OP_BITW, &VXCompiler::BitwiseAndExp,BW_XOR);
717 else
719 return;
723 void BitwiseAndExp()
725 EqExp();
726 for(;;)
728 if(_token == '&')
730 BIN_EXP(_OP_BITW, &VXCompiler::EqExp,BW_AND);
732 else
734 return;
738 void EqExp()
740 CompExp();
741 for(;;)
743 switch(_token)
745 case TK_EQ:
746 BIN_EXP(_OP_EQ, &VXCompiler::CompExp);
747 break;
748 case TK_NE:
749 BIN_EXP(_OP_NE, &VXCompiler::CompExp);
750 break;
751 case TK_3WAYSCMP:
752 BIN_EXP(_OP_CMP, &VXCompiler::CompExp,CMP_3W);
753 break;
754 default:
755 return;
759 void CompExp()
761 ShiftExp();
762 for(;;)
764 switch(_token)
766 case '>':
767 BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_G);
768 break;
769 case '<':
770 BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_L);
771 break;
772 case TK_GE:
773 BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_GE);
774 break;
775 case TK_LE:
776 BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_LE);
777 break;
778 default:
779 return;
784 void ShiftExp()
786 PlusExp();
787 for(;;)
789 switch(_token)
791 case TK_USHIFTR:
792 BIN_EXP(_OP_BITW, &VXCompiler::PlusExp,BW_USHIFTR);
793 break;
794 case TK_SHIFTL:
795 BIN_EXP(_OP_BITW, &VXCompiler::PlusExp,BW_SHIFTL);
796 break;
797 case TK_SHIFTR:
798 BIN_EXP(_OP_BITW, &VXCompiler::PlusExp,BW_SHIFTR);
799 break;
800 default: return;
805 VXOpcode ChooseArithOpByToken(VXInteger tok)
807 switch(tok)
809 case TK_PLUSEQ:
810 case '+':
811 return _OP_ADD;
812 case TK_MINUSEQ:
813 case '-':
814 return _OP_SUB;
815 case TK_MULEQ:
816 case '*':
817 return _OP_MUL;
818 case TK_DIVEQ:
819 case '/':
820 return _OP_DIV;
821 case TK_MODEQ:
822 case '%':
823 return _OP_MOD;
824 default:
825 vox_assert(0);
827 return _OP_ADD;
830 VXInteger ChooseCompArithCharByToken(VXInteger tok)
832 VXInteger oper;
833 switch(tok)
835 case TK_MINUSEQ:
836 oper = '-';
837 break;
838 case TK_PLUSEQ:
839 oper = '+'; break;
840 case TK_MULEQ:
841 oper = '*'; break;
842 case TK_DIVEQ:
843 oper = '/'; break;
844 case TK_MODEQ:
845 oper = '%'; break;
846 default:
847 oper = 0; //shut up compiler
848 vox_assert(0);
849 break;
851 return oper;
854 void PlusExp()
856 MultExp();
857 for(;;)
859 switch(_token)
861 case '+':
862 case '-':
863 BIN_EXP(ChooseArithOpByToken(_token), &VXCompiler::MultExp);
864 break;
865 default:
866 return;
871 void MultExp()
873 PrefixedExpr();
874 for(;;)
876 switch(_token)
878 case '*':
879 case '/':
880 case '%':
881 BIN_EXP(ChooseArithOpByToken(_token), &VXCompiler::PrefixedExpr);
882 break;
883 default:
884 return;
889 //if 'pos' != -1 the previous variable is a local variable
890 void PrefixedExpr()
892 VXInteger pos = Factor();
893 for(;;)
895 switch(_token)
897 case '.':
898 pos = -1;
899 Lex();
900 _fs->AddInstruction(
901 _OP_LOAD,
902 _fs->PushTarget(),
903 _fs->GetConstant(Expect(TK_IDENTIFIER)));
904 if(_es.etype==BASE)
906 Emit2ArgsOP(_OP_GET);
907 pos = _fs->TopTarget();
908 _es.etype = EXPR;
909 _es.epos = pos;
911 else
913 if(NeedGet())
915 Emit2ArgsOP(_OP_GET);
917 _es.etype = OBJECT;
919 break;
920 case '[':
921 if(_lex._prevtoken == '\n')
923 Error("cannot brake deref/or comma needed after [exp]=exp slot declaration");
925 Lex();
926 Expression();
927 Expect(']');
928 pos = -1;
929 if(_es.etype==BASE)
931 Emit2ArgsOP(_OP_GET);
932 pos = _fs->TopTarget();
933 _es.etype = EXPR;
934 _es.epos = pos;
936 else
938 if(NeedGet())
940 Emit2ArgsOP(_OP_GET);
942 _es.etype = OBJECT;
944 break;
945 case TK_MINUSMINUS:
946 case TK_PLUSPLUS:
948 if(IsEndOfStatement())
949 return;
950 VXInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
951 Lex();
952 switch(_es.etype)
954 case EXPR:
955 Error("can't '++' or '--' an expression");
956 break;
957 case OBJECT:
958 case BASE:
959 Emit2ArgsOP(_OP_PINC, diff);
960 break;
961 case LOCAL:
963 VXInteger src = _fs->PopTarget();
964 _fs->AddInstruction(
965 _OP_PINCL,
966 _fs->PushTarget(),
967 src, 0, diff);
969 break;
970 case OUTER:
972 VXInteger tmp1 = _fs->PushTarget();
973 VXInteger tmp2 = _fs->PushTarget();
974 _fs->AddInstruction(_OP_GETOUTER,
975 tmp2, _es.epos);
976 _fs->AddInstruction(_OP_PINCL,
977 tmp1, tmp2, 0, diff);
978 _fs->AddInstruction(_OP_SETOUTER,
979 tmp2, _es.epos, tmp2);
980 _fs->PopTarget();
984 return;
985 break;
986 case '(':
987 switch(_es.etype)
989 case OBJECT:
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);
1002 break;
1003 case BASE:
1004 //Emit2ArgsOP(_OP_GET);
1005 _fs->AddInstruction(_OP_MOVE,
1006 _fs->PushTarget(), 0);
1007 break;
1008 case OUTER:
1009 _fs->AddInstruction(_OP_GETOUTER,
1010 _fs->PushTarget(), _es.epos);
1011 _fs->AddInstruction(_OP_MOVE,
1012 _fs->PushTarget(), 0);
1013 break;
1014 default:
1015 _fs->AddInstruction(_OP_MOVE,
1016 _fs->PushTarget(), 0);
1018 _es.etype = EXPR;
1019 Lex();
1020 FunctionCallArgs();
1021 break;
1022 default:
1023 return;
1027 VXInteger Factor()
1029 _es.etype = EXPR;
1030 switch(_token)
1032 case '{':
1033 _fs->AddInstruction(_OP_NEWOBJ,
1034 _fs->PushTarget(),
1035 0, NVX_OT_TABLE);
1036 Lex();
1037 ParseTableOrClass(',', '}');
1038 break;
1039 case '[':
1041 _fs->AddInstruction(_OP_NEWOBJ,
1042 _fs->PushTarget(),0,0,
1043 NVX_OT_ARRAY);
1044 VXInteger apos = _fs->GetCurrentPos();
1045 VXInteger key = 0;
1046 Lex();
1047 while(_token != ']')
1049 Expression();
1050 if(_token == ',')
1052 Lex();
1054 VXInteger val = _fs->PopTarget();
1055 VXInteger array = _fs->TopTarget();
1056 _fs->AddInstruction(_OP_APPENDARRAY,
1057 array,
1058 val,
1059 AAT_STACK);
1060 key++;
1062 _fs->SetIntructionParam(apos, 1, key);
1063 Lex();
1065 break;
1066 case TK_FUNCTION:
1067 FunctionExp(_token);
1068 break;
1069 case '@':
1070 FunctionExp(_token,true);
1071 break;
1072 case TK_CLASS:
1073 Lex();
1074 ClassExp();
1075 break;
1076 case '-':
1077 Lex();
1078 switch(_token)
1080 case TK_INTEGER:
1081 EmitLoadConstInt(-_lex._nvalue,-1);
1082 Lex();
1083 break;
1084 case TK_FLOAT:
1085 EmitLoadConstFloat(-_lex._fvalue,-1);
1086 Lex();
1087 break;
1088 default:
1089 UnaryOP(_OP_NEG);
1091 break;
1092 case '!':
1093 Lex();
1094 UnaryOP(_OP_NOT);
1095 break;
1096 case '~':
1097 Lex();
1098 if(_token == TK_INTEGER)
1100 EmitLoadConstInt(~_lex._nvalue,-1);
1101 Lex();
1102 break;
1104 UnaryOP(_OP_BWNOT);
1105 break;
1106 case TK_STRING_LITERAL:
1107 _fs->AddInstruction(_OP_LOAD,
1108 _fs->PushTarget(),
1109 _fs->GetConstant(
1110 _fs->CreateString(_lex._svalue,
1111 _lex._longstr.size()-1)));
1112 Lex();
1113 break;
1114 case TK_BASE:
1115 Lex();
1116 _fs->AddInstruction(_OP_GETBASE,
1117 _fs->PushTarget());
1118 _es.etype = BASE;
1119 _es.epos = _fs->TopTarget();
1120 return (_es.epos);
1121 break;
1122 case TK_IDENTIFIER:
1123 case TK_CONSTRUCTOR:
1124 case TK_THIS:
1126 VXRawObj id;
1127 VXRawObj constant;
1129 switch(_token)
1131 case TK_IDENTIFIER:
1132 id = _fs->CreateString(_lex._svalue);
1133 break;
1134 case TK_THIS:
1135 id = _fs->CreateString(NAMES_TK_THISVAR);
1136 break;
1137 case TK_CONSTRUCTOR:
1138 id = _fs->CreateString(NAMES_TK_CTOR);
1139 break;
1142 VXInteger pos = -1;
1143 Lex();
1144 if((pos = _fs->GetLocalVariable(id)) != -1)
1146 /* Handle a local variable (includes 'this') */
1147 _fs->PushTarget(pos);
1148 _es.etype = LOCAL;
1149 _es.epos = pos;
1152 else if((pos = _fs->GetOuterVariable(id)) != -1)
1154 /* Handle a free var */
1155 if(NeedGet())
1157 _es.epos = _fs->PushTarget();
1158 _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);
1159 /* _es.etype = EXPR; already default value */
1161 else
1163 _es.etype = OUTER;
1164 _es.epos = pos;
1168 else if(_fs->IsConstant(id, constant))
1170 /* Handle named constant */
1171 VXObject constval;
1172 VXRawObj constid;
1173 if(type(constant) == VX_OT_TABLE)
1175 Expect('.');
1176 constid = Expect(TK_IDENTIFIER);
1177 if(!_table(constant)->Get(constid, constval))
1179 constval.Null();
1180 Error("invalid constant [%s.%s]",
1181 _stringval(id),
1182 _stringval(constid));
1185 else
1187 constval = constant;
1189 _es.epos = _fs->PushTarget();
1191 /* generate direct or literal function depending on size */
1192 VXOType ctype = type(constval);
1193 switch(ctype)
1195 case VX_OT_INTEGER:
1196 EmitLoadConstInt(_integer(constval),
1197 _es.epos);
1198 break;
1199 case VX_OT_FLOAT:
1200 EmitLoadConstFloat(_float(constval),
1201 _es.epos);
1202 break;
1203 default:
1204 _fs->AddInstruction(
1205 _OP_LOAD,
1206 _es.epos,
1207 _fs->GetConstant(constval));
1208 break;
1210 _es.etype = EXPR;
1212 else
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.
1225 _fs->PushTarget(0);
1226 _fs->AddInstruction(
1227 _OP_LOAD,
1228 _fs->PushTarget(),
1229 _fs->GetConstant(id));
1230 if(NeedGet())
1232 Emit2ArgsOP(_OP_GET);
1234 _es.etype = OBJECT;
1236 return _es.epos;
1238 break;
1239 case TK_DOUBLE_COLON: // "::"
1240 _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());
1241 _es.etype = OBJECT;
1242 _token = '.'; /* hack: drop into PrefixExpr, case '.'*/
1243 _es.epos = -1;
1244 return _es.epos;
1245 break;
1246 case TK_NULL:
1247 _fs->AddInstruction(_OP_LOADNULLS,
1248 _fs->PushTarget(),1);
1249 Lex();
1250 break;
1251 case TK_INTEGER:
1252 EmitLoadConstInt(_lex._nvalue,-1);
1253 Lex();
1254 break;
1255 case TK_FLOAT:
1256 EmitLoadConstFloat(_lex._fvalue,-1);
1257 Lex();
1258 break;
1259 case TK_TRUE:
1260 case TK_FALSE:
1261 _fs->AddInstruction(
1262 _OP_LOADBOOL,
1263 _fs->PushTarget(),
1264 _token == TK_TRUE ? 1 : 0);
1265 Lex();
1266 break;
1267 case TK_TYPEOF:
1268 Lex();
1269 UnaryOP(_OP_TYPEOF);
1270 break;
1271 case TK_RESUME:
1272 Lex();
1273 UnaryOP(_OP_RESUME);
1274 break;
1275 case TK_CLONE:
1276 Lex();
1277 UnaryOP(_OP_CLONE);
1278 break;
1279 case TK_MINUSMINUS:
1280 case TK_PLUSPLUS:
1281 PrefixIncDec(_token);
1282 break;
1283 case TK_DELETE:
1284 DeleteExpr();
1285 break;
1286 case '(':
1287 Lex();
1288 CommaExpr();
1289 Expect(')');
1290 break;
1291 default:
1292 Error("expression expected");
1294 return -1;
1297 void EmitLoadConstInt(VXInteger value,VXInteger target)
1299 if(target < 0)
1301 target = _fs->PushTarget();
1303 //does it fit in 32 bits?
1304 if((value & (~((VXInteger)0xFFFFFFFF))) == 0)
1306 _fs->AddInstruction(_OP_LOADINT, target,value);
1308 else
1310 _fs->AddInstruction(_OP_LOAD,
1311 target,
1312 _fs->GetNumericConstant(value));
1315 void EmitLoadConstFloat(VXFloat value,VXInteger target)
1317 if(target < 0)
1319 target = _fs->PushTarget();
1321 if(sizeof(VXFloat) == sizeof(VXInt32))
1323 _fs->AddInstruction(_OP_LOADFLOAT, target,*((VXInt32 *)&value));
1325 else
1327 _fs->AddInstruction(_OP_LOAD,
1328 target,
1329 _fs->GetNumericConstant(value));
1333 void UnaryOP(VXOpcode op)
1335 PrefixedExpr();
1336 VXInteger src = _fs->PopTarget();
1337 _fs->AddInstruction(op, _fs->PushTarget(), src);
1340 bool NeedGet()
1342 switch(_token)
1344 case '=':
1345 case '(':
1346 case TK_NEWSLOT:
1347 case TK_MODEQ:
1348 case TK_MULEQ:
1349 case TK_DIVEQ:
1350 case TK_MINUSEQ:
1351 case TK_PLUSEQ:
1352 case TK_PLUSPLUS:
1353 case TK_MINUSMINUS:
1354 return false;
1356 return (!_es.donot_get ||
1357 (_es.donot_get &&
1358 (_token == '.' || _token == '[')));
1360 void FunctionCallArgs()
1362 VXInteger nargs = 1;//this
1363 while(_token != ')')
1365 Expression();
1366 MoveIfCurrentTargetIsLocal();
1367 nargs++;
1368 if(_token == ',')
1370 Lex();
1371 if(_token == ')')
1373 Error("expression expected, found ')'");
1377 Lex();
1378 for(VXInteger i = 0; i < (nargs - 1); i++)
1380 _fs->PopTarget();
1382 VXInteger stackbase = _fs->PopTarget();
1383 VXInteger closure = _fs->PopTarget();
1384 _fs->AddInstruction(_OP_CALL,
1385 _fs->PushTarget(), closure,
1386 stackbase, nargs);
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,
1404 NVX_OT_TABLE);
1405 Lex();
1406 ParseTableOrClass(',', TK_ATTR_CLOSE);
1407 hasattrs = true;
1409 if(_token == TK_STATIC)
1411 isstatic = true;
1412 Lex();
1415 switch(_token)
1417 case TK_FUNCTION:
1418 case TK_CONSTRUCTOR:
1420 VXInteger tk = _token;
1421 Lex();
1422 VXRawObj id = (tk == TK_FUNCTION ?
1423 Expect(TK_IDENTIFIER) :
1424 _fs->CreateString("constructor"));
1425 Expect('(');
1426 _fs->AddInstruction(_OP_LOAD,
1427 _fs->PushTarget(),
1428 _fs->GetConstant(id));
1429 CreateFunction(id);
1430 _fs->AddInstruction(_OP_CLOSURE,
1431 _fs->PushTarget(),
1432 _fs->_functions.size() - 1, 0);
1434 break;
1435 case '[':
1436 Lex();
1437 CommaExpr();
1438 Expect(']');
1439 Expect('=');
1440 Expression();
1441 break;
1442 //case TK_IDENTIFIER:
1443 case TK_STRING_LITERAL: //JSON
1444 //only works for tables
1445 if(separator == ',')
1447 _fs->AddInstruction(
1448 _OP_LOAD,
1449 _fs->PushTarget(),
1450 _fs->GetConstant(Expect(TK_STRING_LITERAL)));
1451 Expect(':');
1452 Expression();
1453 break;
1455 default:
1456 _fs->AddInstruction(
1457 _OP_LOAD,
1458 _fs->PushTarget(),
1459 _fs->GetConstant(Expect(TK_IDENTIFIER)));
1460 Expect('=');
1461 Expression();
1463 if(_token == separator)
1465 Lex();//optional comma/semicolon
1467 nkeys++;
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);
1482 else
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);
1492 Lex();
1494 void LocalDeclStatement()
1496 VXRawObj varname;
1497 Lex();
1498 if( _token == TK_FUNCTION)
1500 Lex();
1501 varname = Expect(TK_IDENTIFIER);
1502 Expect('(');
1503 CreateFunction(varname, false);
1504 _fs->AddInstruction(_OP_CLOSURE,
1505 _fs->PushTarget(),
1506 _fs->_functions.size() - 1, 0);
1507 _fs->PopTarget();
1508 _fs->PushLocalVariable(varname);
1509 return;
1513 varname = Expect(TK_IDENTIFIER);
1514 if(_token == '=')
1516 Lex();
1517 Expression();
1518 VXInteger src = _fs->PopTarget();
1519 VXInteger dest = _fs->PushTarget();
1520 if(dest != src)
1522 _fs->AddInstruction(_OP_MOVE, dest, src);
1525 else
1527 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
1529 _fs->PopTarget();
1530 _fs->PushLocalVariable(varname);
1531 if(_token == ',')
1533 Lex();
1535 else
1537 break;
1539 } while(1);
1542 void IfStatement()
1544 VXInteger jmppos;
1545 bool haselse = false;
1546 Lex();
1547 Expect('(');
1548 CommaExpr();
1549 Expect(')');
1550 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
1551 VXInteger jnepos = _fs->GetCurrentPos();
1552 BEGIN_VXCOPE();
1553 Statement();
1555 if(_token != '}' && _token != TK_ELSE)
1557 OptionalSemicolon();
1559 END_VXCOPE();
1560 VXInteger endifblock = _fs->GetCurrentPos();
1561 if(_token == TK_ELSE)
1563 haselse = true;
1564 BEGIN_VXCOPE();
1565 _fs->AddInstruction(_OP_JMP);
1566 jmppos = _fs->GetCurrentPos();
1567 Lex();
1568 Statement();
1569 OptionalSemicolon();
1570 END_VXCOPE();
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();
1582 Lex();
1583 Expect('(');
1584 CommaExpr();
1585 Expect(')');
1586 BEGIN_BREAKBLE_BLOCK();
1587 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
1588 jzpos = _fs->GetCurrentPos();
1589 BEGIN_VXCOPE();
1590 Statement();
1591 END_VXCOPE();
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()
1599 Lex();
1600 VXInteger jmptrg = _fs->GetCurrentPos();
1601 BEGIN_BREAKBLE_BLOCK()
1602 BEGIN_VXCOPE();
1603 Statement();
1604 END_VXCOPE();
1605 Expect(TK_WHILE);
1606 VXInteger continuetrg = _fs->GetCurrentPos();
1607 Expect('(');
1608 CommaExpr();
1609 Expect(')');
1610 _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
1611 _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
1612 END_BREAKBLE_BLOCK(continuetrg);
1615 void ForStatement()
1617 Lex();
1618 BEGIN_VXCOPE();
1619 Expect('(');
1620 if(_token == TK_LOCAL)
1622 LocalDeclStatement();
1624 else if(_token != ';')
1626 CommaExpr();
1627 _fs->PopTarget();
1629 Expect(';');
1630 _fs->SnoozeOpt();
1631 VXInteger jmppos = _fs->GetCurrentPos();
1632 VXInteger jzpos = -1;
1633 if(_token != ';')
1635 CommaExpr();
1636 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
1637 jzpos = _fs->GetCurrentPos();
1639 Expect(';');
1640 _fs->SnoozeOpt();
1641 VXInteger expstart = _fs->GetCurrentPos() + 1;
1642 if(_token != ')')
1644 CommaExpr();
1645 _fs->PopTarget();
1647 Expect(')');
1648 _fs->SnoozeOpt();
1649 VXInteger expend = _fs->GetCurrentPos();
1650 VXInteger expsize = (expend - expstart) + 1;
1651 VXInstructionVec exp;
1652 if(expsize > 0)
1654 for(VXInteger i = 0; i < expsize; i++)
1656 exp.push_back(_fs->GetInstruction(expstart + i));
1658 _fs->PopInstructions(expsize);
1660 BEGIN_BREAKBLE_BLOCK()
1661 Statement();
1662 VXInteger continuetrg = _fs->GetCurrentPos();
1663 if(expsize > 0)
1665 for(VXInteger i = 0; i < expsize; i++)
1667 _fs->AddInstruction(exp[i]);
1670 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
1671 if(jzpos> 0)
1673 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
1675 END_VXCOPE();
1676 END_BREAKBLE_BLOCK(continuetrg);
1679 void ForEachStatement()
1681 VXRawObj idxname, valname;
1682 Lex();
1683 Expect('(');
1684 valname = Expect(TK_IDENTIFIER);
1685 if(_token == ',')
1687 idxname = valname;
1688 Lex();
1689 valname = Expect(TK_IDENTIFIER);
1691 else
1693 idxname = _fs->CreateString("@INDEX@");
1695 Expect(TK_IN);
1697 //save the stack size
1698 BEGIN_VXCOPE();
1699 //put the table in the stack(evaluate the table expression)
1700 Expression();
1701 Expect(')');
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()
1719 Statement();
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)
1725 END_VXCOPE();
1728 void SwitchStatement()
1730 Lex();
1731 Expect('(');
1732 CommaExpr();
1733 Expect(')');
1734 Expect('{');
1735 VXInteger expr = _fs->TopTarget();
1736 bool bfirst = true;
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)
1743 if(!bfirst)
1745 _fs->AddInstruction(_OP_JMP, 0, 0);
1746 skipcondjmp = _fs->GetCurrentPos();
1747 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1749 //condition
1750 Lex();
1751 Expression();
1752 Expect(':');
1753 VXInteger trg = _fs->PopTarget();
1754 _fs->AddInstruction(_OP_EQ, trg, trg, expr);
1755 _fs->AddInstruction(_OP_JZ, trg, 0);
1756 //end condition
1757 if(skipcondjmp != -1)
1759 _fs->SetIntructionParam(skipcondjmp, 1,
1760 (_fs->GetCurrentPos()-skipcondjmp));
1762 tonextcondjmp = _fs->GetCurrentPos();
1763 BEGIN_VXCOPE();
1764 Statements();
1765 END_VXCOPE();
1766 bfirst = false;
1768 if(tonextcondjmp != -1)
1770 _fs->SetIntructionParam(tonextcondjmp, 1,
1771 _fs->GetCurrentPos()-tonextcondjmp);
1773 if(_token == TK_DEFAULT)
1775 Lex();
1776 Expect(':');
1777 BEGIN_VXCOPE();
1778 Statements();
1779 END_VXCOPE();
1781 Expect('}');
1782 _fs->PopTarget();
1783 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1784 if(__nbreaks__ > 0)
1786 ResolveBreaks(_fs, __nbreaks__);
1788 _fs->_breaktargets.pop_back();
1791 void FunctionStatement()
1793 VXRawObj id;
1794 Lex(); id = Expect(TK_IDENTIFIER);
1795 _fs->PushTarget(0);
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)
1803 Lex();
1804 id = Expect(TK_IDENTIFIER);
1805 _fs->AddInstruction(_OP_LOAD,
1806 _fs->PushTarget(),
1807 _fs->GetConstant(id));
1808 if(_token == TK_DOUBLE_COLON)
1810 Emit2ArgsOP(_OP_GET);
1813 Expect('(');
1814 CreateFunction(id);
1815 _fs->AddInstruction(_OP_CLOSURE,
1816 _fs->PushTarget(),
1817 _fs->_functions.size() - 1, 0);
1818 EmitDerefOp(_OP_NEWSLOT);
1819 _fs->PopTarget();
1822 void ClassStatement()
1824 VXExpState es;
1825 Lex();
1826 es = _es;
1827 _es.donot_get = true;
1828 PrefixedExpr();
1829 if(_es.etype == EXPR)
1831 Error("invalid class name");
1833 else if(_es.etype == OBJECT || _es.etype == BASE)
1835 ClassExp();
1836 EmitDerefOp(_OP_NEWSLOT);
1837 _fs->PopTarget();
1839 else
1841 Error("cannot create a class in a local with the syntax(class <local>)");
1843 _es = es;
1846 VXRawObj ExpectScalar()
1848 VXRawObj val;
1849 val._type = VX_OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x
1850 switch(_token)
1852 case TK_INTEGER:
1853 val._type = VX_OT_INTEGER;
1854 val._unVal.nInteger = _lex._nvalue;
1855 break;
1856 case TK_FLOAT:
1857 val._type = VX_OT_FLOAT;
1858 val._unVal.fFloat = _lex._fvalue;
1859 break;
1860 case TK_STRING_LITERAL:
1861 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
1862 break;
1863 case '-':
1864 Lex();
1865 switch(_token)
1867 case TK_INTEGER:
1868 val._type = VX_OT_INTEGER;
1869 val._unVal.nInteger = -_lex._nvalue;
1870 break;
1871 case TK_FLOAT:
1872 val._type = VX_OT_FLOAT;
1873 val._unVal.fFloat = -_lex._fvalue;
1874 break;
1875 default:
1876 Error("scalar expected: integer, float");
1878 break;
1879 default:
1880 Error("scalar expected: integer, float or string");
1882 Lex();
1883 return val;
1885 void EnumStatement()
1887 Lex();
1888 VXRawObj id = Expect(TK_IDENTIFIER);
1889 Expect('{');
1890 VXRawObj table = _fs->CreateTable();
1891 VXInteger nval = 0;
1892 while(_token != '}')
1894 VXRawObj key = Expect(TK_IDENTIFIER);
1895 VXRawObj val;
1896 if(_token == '=')
1898 Lex();
1899 val = ExpectScalar();
1901 else
1903 val._type = VX_OT_INTEGER;
1904 val._unVal.nInteger = nval++;
1906 _table(table)->NewSlot(VXObject(key),VXObject(val));
1907 if(_token == ',')
1909 Lex();
1912 VXTableObj *enums = _table(_ss(_vm)->_consts);
1913 VXObject strongid = id;
1914 enums->NewSlot(VXObject(strongid),VXObject(table));
1915 strongid.Null();
1916 Lex();
1919 void TryCatchStatement()
1921 VXRawObj exid;
1922 Lex();
1923 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
1924 _fs->_traps++;
1925 if(_fs->_breaktargets.size())
1927 _fs->_breaktargets.top()++;
1930 if(_fs->_continuetargets.size())
1932 _fs->_continuetargets.top()++;
1935 VXInteger trappos = _fs->GetCurrentPos();
1937 BEGIN_VXCOPE();
1938 Statement();
1939 END_VXCOPE();
1941 _fs->_traps--;
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));
1954 Expect(TK_CATCH);
1955 Expect('(');
1956 exid = Expect(TK_IDENTIFIER);
1957 Expect(')');
1959 BEGIN_VXCOPE();
1960 VXInteger ex_target = _fs->PushLocalVariable(exid);
1961 _fs->SetIntructionParam(trappos, 0, ex_target);
1962 Statement();
1963 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1964 END_VXCOPE();
1968 void FunctionExp(VXInteger ftype,bool lambda = false)
1970 Lex();
1971 Expect('(');
1972 VXObject dummy;
1973 CreateFunction(dummy,lambda);
1974 _fs->AddInstruction(_OP_CLOSURE,
1975 _fs->PushTarget(),
1976 _fs->_functions.size() - 1,
1977 ftype == TK_FUNCTION?0:1);
1980 void ClassExp()
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)
1992 Lex();
1993 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NVX_OT_TABLE);
1994 ParseTableOrClass(',',TK_ATTR_CLOSE);
1995 attrs = _fs->TopTarget();
1997 Expect('{');
1998 if(attrs != -1)
2000 _fs->PopTarget();
2002 if(base != -1)
2004 _fs->PopTarget();
2006 _fs->AddInstruction(_OP_NEWOBJ,
2007 _fs->PushTarget(),
2008 base, attrs, NVX_OT_CLASS);
2009 ParseTableOrClass(';', '}');
2012 void DeleteExpr()
2014 VXExpState es;
2015 Lex();
2016 es = _es;
2017 _es.donot_get = true;
2018 PrefixedExpr();
2019 if(_es.etype==EXPR)
2021 Error("can't delete an expression");
2023 if(_es.etype==OBJECT || _es.etype==BASE)
2025 Emit2ArgsOP(_OP_DELETE);
2027 else
2029 Error("cannot delete an (outer) local");
2031 _es = es;
2034 void PrefixIncDec(VXInteger token)
2036 VXExpState es;
2037 VXInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
2038 Lex();
2039 es = _es;
2040 _es.donot_get = true;
2041 PrefixedExpr();
2042 if(_es.etype==EXPR)
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);
2062 _es = es;
2065 void CreateFunction(VXRawObj &name,bool lambda = false)
2067 VXFuncState *funcstate = _fs->PushChildState(_ss(_vm));
2068 funcstate->_name = name;
2069 VXRawObj paramname;
2070 funcstate->AddParameter(_fs->CreateString(NAMES_TK_THISVAR));
2071 funcstate->_sourcename = _sourcename;
2072 VXInteger defparams = 0;
2073 while(_token!=')')
2075 if(_token == TK_VARPARAMS)
2077 if(defparams > 0)
2079 Error("function with default parameters cannot"
2080 " have variable number of parameters");
2082 funcstate->AddParameter(_fs->CreateString(NAMES_VARGV));
2083 funcstate->_varparams = true;
2084 Lex();
2085 if(_token != ')')
2087 Error("expected ')'");
2089 break;
2091 else
2093 paramname = Expect(TK_IDENTIFIER);
2094 funcstate->AddParameter(paramname);
2095 if(_token == '=')
2097 Lex();
2098 Expression();
2099 funcstate->AddDefaultParam(_fs->TopTarget());
2100 defparams++;
2102 else
2104 if(defparams > 0)
2106 Error("expected '='");
2109 if(_token == ',')
2111 Lex();
2113 else if(_token != ')')
2115 Error("expected ')' or ','");
2119 Expect(')');
2120 for(VXInteger n = 0; n < defparams; n++)
2122 _fs->PopTarget();
2125 VXFuncState *currchunk = _fs;
2126 _fs = funcstate;
2127 if(lambda)
2129 Expression();
2130 _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());
2132 else
2134 Statement(false);
2136 funcstate->AddLineInfos(
2137 (_lex._prevtoken == '\n') ?
2138 _lex._lasttokenline : _lex._currentline,
2139 _lineinfo, true);
2140 funcstate->AddInstruction(_OP_RETURN, -1);
2141 funcstate->SetStackSize(0);
2143 VXFuncProtoObj *func = funcstate->BuildProto();
2144 #ifdef _DEBUG_DUMP
2145 funcstate->Dump(func);
2146 #endif
2147 _fs = currchunk;
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);
2160 ntoresolve--;
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);
2174 ntoresolve--;
2178 private:
2179 VXInteger _token;
2180 VXFuncState *_fs;
2181 VXObject _sourcename;
2182 VXLexer _lex;
2183 bool _lineinfo;
2184 bool _raiseerror;
2185 VXInteger _debugline;
2186 VXInteger _debugop;
2187 VXExpState _es;
2188 VXScope _scope;
2189 char *compilererror;
2190 jmp_buf _errorjmp;
2191 VXState *_vm;
2194 bool Compile(VXState *vm,VXLexReadFunc rg,
2195 VXUserPointer up,
2196 const char *sourcename,
2197 VXObject &out,
2198 bool raiseerror,
2199 bool lineinfo)
2201 VXCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
2202 return p.Compile(out);
2205 #endif