Fixed compiler warnings in squirrel (minor stuff, patch is submitted to upstream)
[supertux.git] / src / squirrel / squirrel / sqcompiler.cpp
index a6bab09..5c468e1 100644 (file)
@@ -11,6 +11,7 @@
 #include "sqfuncstate.h"
 #include "sqlexer.h"
 #include "sqvm.h"
+#include "sqtable.h"
 
 #define DEREF_NO_DEREF -1
 #define DEREF_FIELD            -2
@@ -87,7 +88,7 @@ public:
        }
        SQObject Expect(SQInteger tok)
        {
-
+               
                if(_token != tok) {
                        if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
                                //ret = SQString::Create(_ss(_vm),_SC("constructor"));
@@ -212,7 +213,7 @@ public:
                        SQOpcode op;
                        if(_token == TK_RETURN) {
                                op = _OP_RETURN;
-
+                               
                        }
                        else {
                                op = _OP_YIELD;
@@ -227,11 +228,11 @@ public:
                                _fs->_returnexp = retexp;
                                _fs->AddInstruction(op, 1, _fs->PopTarget());
                        }
-                       else{
+                       else{ 
                                if(op == _OP_RETURN && _fs->_traps > 0)
                                        _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
                                _fs->_returnexp = -1;
-                               _fs->AddInstruction(op, 0xFF);
+                               _fs->AddInstruction(op, 0xFF); 
                        }
                        break;}
                case TK_BREAK:
@@ -258,6 +259,9 @@ public:
                case TK_CLASS:
                        ClassStatement();
                        break;
+               case TK_ENUM:
+                       EnumStatement();
+                       break;
                case _SC('{'):{
                                SQInteger stacksize = _fs->GetStackSize();
                                Lex();
@@ -274,6 +278,19 @@ public:
                        CommaExpr();
                        _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
                        break;
+               case TK_CONST:
+                       {
+                       Lex();
+                       SQObject id = Expect(TK_IDENTIFIER);
+                       Expect('=');
+                       SQObject val = ExpectScalar();
+                       OptionalSemicolon();
+                       SQTable *enums = _table(_ss(_vm)->_consts);
+                       SQObjectPtr strongid = id; 
+                       enums->NewSlot(strongid,SQObjectPtr(val));
+                       strongid.Null();
+                       }
+                       break;
                default:
                        CommaExpr();
                        _fs->PopTarget();
@@ -472,7 +489,7 @@ public:
                case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
                case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
                case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;
-               default: return;
+               default: return;        
                }
        }
        void ShiftExp()
@@ -482,7 +499,7 @@ public:
                case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
                case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
                case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
-               default: return;
+               default: return;        
                }
        }
        void PlusExp()
@@ -494,7 +511,7 @@ public:
                default: return;
                }
        }
-
+       
        void MultExp()
        {
                PrefixedExpr();
@@ -512,7 +529,7 @@ public:
                        switch(_token) {
                        case _SC('.'): {
                                pos = -1;
-                               Lex();
+                               Lex(); 
                                if(_token == TK_PARENT) {
                                        Lex();
                                        if(!NeedGet())
@@ -530,7 +547,7 @@ public:
                                break;
                        case _SC('['):
                                if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
-                               Lex(); Expression(); Expect(_SC(']'));
+                               Lex(); Expression(); Expect(_SC(']')); 
                                pos = -1;
                                if(NeedGet()) Emit2ArgsOP(_OP_GET);
                                _exst._deref = DEREF_FIELD;
@@ -538,7 +555,7 @@ public:
                                break;
                        case TK_MINUSMINUS:
                        case TK_PLUSPLUS:
-                       if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) {
+                       if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { 
                                SQInteger tok = _token; Lex();
                                if(pos < 0)
                                        Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);
@@ -546,11 +563,11 @@ public:
                                        SQInteger src = _fs->PopTarget();
                                        _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);
                                }
-
+                               
                        }
                        return;
-                       break;
-                       case _SC('('):
+                       break;  
+                       case _SC('('): 
                                {
                                if(_exst._deref != DEREF_NO_DEREF) {
                                        if(pos<0) {
@@ -582,7 +599,7 @@ public:
                case TK_STRING_LITERAL: {
                                //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));
                                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
-                               Lex();
+                               Lex(); 
                        }
                        break;
                case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;
@@ -599,6 +616,7 @@ public:
                case TK_THIS:{
                        _exst._freevar = false;
                        SQObject id;
+                       SQObject constant;
                                switch(_token) {
                                        case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
                                        case TK_THIS: id = _fs->CreateString(_SC("this")); break;
@@ -610,15 +628,45 @@ public:
                                        //checks if is a free variable
                                        if((pos = _fs->GetOuterVariable(id)) != -1) {
                                                _exst._deref = _fs->PushTarget();
-                                               _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);
+                                               _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);        
                                                _exst._freevar = true;
-                                       } else {
+                                       }
+                                       else if(_fs->IsConstant(id,constant)) { //line 634
+                                               SQObjectPtr constval;
+                                               SQObject constid;
+                                               if(type(constant) == OT_TABLE) {
+                                                       Expect('.'); constid = Expect(TK_IDENTIFIER);
+                                                       if(!_table(constant)->Get(constid,constval)) {
+                                                               constval.Null();
+                                                               Error(_SC("invalid constant [%s.%s]"), _stringval(id),_stringval(constid));
+                                                       }
+                                               }
+                                               else {
+                                                       constval = constant;
+                                               }
+                                               _exst._deref = _fs->PushTarget();
+                                               SQObjectType ctype = type(constval);
+                                               if(ctype == OT_INTEGER && (_integer(constval) & (~0x7FFFFFFF)) == 0) {
+                                                       _fs->AddInstruction(_OP_LOADINT, _exst._deref,_integer(constval));
+                                               }
+                                               else if(ctype == OT_FLOAT && sizeof(SQFloat) == sizeof(SQInt32)) {
+                                                       SQFloat f = _float(constval);
+                                                       _fs->AddInstruction(_OP_LOADFLOAT, _exst._deref,*((SQInt32 *)&f));
+                                               }
+                                               else {
+                                                       _fs->AddInstruction(_OP_LOAD, _exst._deref, _fs->GetConstant(constval));
+                                               }
+
+                                               _exst._freevar = true;
+                                       }
+                                       else {
                                                _fs->PushTarget(0);
                                                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
                                                if(NeedGet()) Emit2ArgsOP(_OP_GET);
                                                _exst._deref = DEREF_FIELD;
                                        }
                                }
+                               
                                else{
                                        _fs->PushTarget(pos);
                                        _exst._deref = pos;
@@ -633,7 +681,7 @@ public:
                        _token = _SC('.'); //hack
                        return -1;
                        break;
-               case TK_NULL:
+               case TK_NULL: 
                        _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
                        Lex();
                        break;
@@ -648,7 +696,12 @@ public:
                                                 }
                        break;
                case TK_FLOAT:
-                       _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));
+                       if(sizeof(SQFloat) == sizeof(SQInt32)) {
+                               _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue));
+                       }
+                       else {
+                               _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));
+                       }
                        Lex();
                        break;
                case TK_TRUE: case TK_FALSE:
@@ -660,7 +713,7 @@ public:
                                SQInteger apos = _fs->GetCurrentPos(),key = 0;
                                Lex();
                                while(_token != _SC(']')) {
-                    Expression();
+                    Expression(); 
                                        if(_token == _SC(',')) Lex();
                                        SQInteger val = _fs->PopTarget();
                                        SQInteger array = _fs->TopTarget();
@@ -684,7 +737,7 @@ public:
                case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;
                case TK_RESUME : UnaryOP(_OP_RESUME); break;
                case TK_CLONE : UnaryOP(_OP_CLONE); break;
-               case TK_MINUSMINUS :
+               case TK_MINUSMINUS : 
                case TK_PLUSPLUS :PrefixIncDec(_token); break;
                case TK_DELETE : DeleteExpr(); break;
                case TK_DELEGATE : DelegateExpr(); break;
@@ -709,16 +762,16 @@ public:
                }
                return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));
        }
-
+       
        void FunctionCallArgs()
        {
                SQInteger nargs = 1;//this
                 while(_token != _SC(')')) {
                         Expression(true);
                         MoveIfCurrentTargetIsLocal();
-                        nargs++;
-                        if(_token == _SC(',')){
-                                Lex();
+                        nargs++; 
+                        if(_token == _SC(',')){ 
+                                Lex(); 
                                 if(_token == ')') Error(_SC("expression expected, found ')'"));
                         }
                 }
@@ -731,7 +784,7 @@ public:
        void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')
        {
                SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
-
+               
                while(_token != terminator) {
                        bool hasattrs = false;
                        bool isstatic = false;
@@ -799,7 +852,7 @@ public:
                        }
                        _fs->PopTarget();
                        _fs->PushLocalVariable(varname);
-
+               
                } while(_token == _SC(','));
        }
        void IfStatement()
@@ -810,11 +863,11 @@ public:
                _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
                SQInteger jnepos = _fs->GetCurrentPos();
                SQInteger stacksize = _fs->GetStackSize();
-
+               
                Statement();
                //
                if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
-
+               
                CleanStack(stacksize);
                SQInteger endifblock = _fs->GetCurrentPos();
                if(_token == TK_ELSE){
@@ -835,18 +888,18 @@ public:
                SQInteger stacksize = _fs->GetStackSize();
                jmppos = _fs->GetCurrentPos();
                Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
-
+               
                BEGIN_BREAKBLE_BLOCK();
                _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
                jzpos = _fs->GetCurrentPos();
                stacksize = _fs->GetStackSize();
-
+               
                Statement();
-
+               
                CleanStack(stacksize);
                _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
                _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
-
+               
                END_BREAKBLE_BLOCK(jmppos);
        }
        void DoWhileStatement()
@@ -905,7 +958,7 @@ public:
                _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
                if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
                CleanStack(stacksize);
-
+               
                END_BREAKBLE_BLOCK(continuetrg);
        }
        void ForEachStatement()
@@ -920,7 +973,7 @@ public:
                        idxname = _fs->CreateString(_SC("@INDEX@"));
                }
                Expect(TK_IN);
-
+               
                //save the stack size
                SQInteger stacksize = _fs->GetStackSize();
                //put the table in the stack(evaluate the table expression)
@@ -938,11 +991,13 @@ public:
                SQInteger jmppos = _fs->GetCurrentPos();
                _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
                SQInteger foreachpos = _fs->GetCurrentPos();
+               _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
                //generate the statement code
                BEGIN_BREAKBLE_BLOCK()
                Statement();
                _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
                _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
+               _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
                //restore the local variable stack(remove index,val and ref idx)
                CleanStack(stacksize);
                END_BREAKBLE_BLOCK(foreachpos - 1);
@@ -993,7 +1048,7 @@ public:
                __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
                if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
                _fs->_breaktargets.pop_back();
-
+               
        }
        void FunctionStatement()
        {
@@ -1002,7 +1057,7 @@ public:
                _fs->PushTarget(0);
                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
                if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
-
+               
                while(_token == TK_DOUBLE_COLON) {
                        Lex();
                        id = Expect(TK_IDENTIFIER);
@@ -1031,6 +1086,62 @@ public:
                }
                else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
        }
+       SQObject ExpectScalar()
+       {
+               SQObject val;
+               switch(_token) {
+                       case TK_INTEGER:
+                               val._type = OT_INTEGER;
+                               val._unVal.nInteger = _lex._nvalue;
+                               break;
+                       case TK_FLOAT:
+                               val._type = OT_FLOAT;
+                               val._unVal.fFloat = _lex._fvalue;
+                               break;
+                       case TK_STRING_LITERAL:
+                               val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+                               break;
+                       default:
+                       Error(_SC("scalar expected : integer,float or string"));
+               }
+               Lex();
+               return val;
+       }
+       void EnumStatement()
+       {
+               
+               Lex(); 
+               SQObject id = Expect(TK_IDENTIFIER);
+               Expect(_SC('{'));
+               
+               SQObject table = _fs->CreateTable();
+               SQInteger nval = 0;
+               while(_token != _SC('}')) {
+                       SQObject key = Expect(TK_IDENTIFIER);
+                       SQObject val;
+                       if(_token == _SC('=')) {
+                               Lex();
+                               val = ExpectScalar();
+                       }
+                       else {
+                               val._type = OT_INTEGER;
+                               val._unVal.nInteger = nval++;
+                       }
+                       _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
+                       if(_token == ',') Lex();
+               }
+               SQTable *enums = _table(_ss(_vm)->_consts);
+               SQObjectPtr strongid = id; 
+               /*SQObjectPtr dummy;
+               if(enums->Get(strongid,dummy)) {
+                       dummy.Null(); strongid.Null();
+                       Error(_SC("enumeration already exists"));
+               }*/
+               enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
+               strongid.Null();
+               Lex();
+               
+       }
        void TryCatchStatement()
        {
                SQObject exid;
@@ -1118,14 +1229,16 @@ public:
        }
        void CreateFunction(SQObject &name)
        {
-
+               
                SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
                funcstate->_name = name;
                SQObject paramname;
                funcstate->AddParameter(_fs->CreateString(_SC("this")));
                funcstate->_sourcename = _sourcename;
+               SQInteger defparams = 0;
                while(_token!=_SC(')')) {
                        if(_token == TK_VARPARAMS) {
+                               if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
                                funcstate->_varparams = true;
                                Lex();
                                if(_token != _SC(')')) Error(_SC("expected ')'"));
@@ -1134,11 +1247,23 @@ public:
                        else {
                                paramname = Expect(TK_IDENTIFIER);
                                funcstate->AddParameter(paramname);
+                               if(_token == _SC('=')) { 
+                                       Lex();
+                                       Expression();
+                                       funcstate->AddDefaultParam(_fs->TopTarget());
+                                       defparams++;
+                               }
+                               else {
+                                       if(defparams > 0) Error(_SC("expected '='"));
+                               }
                                if(_token == _SC(',')) Lex();
                                else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
                        }
                }
                Expect(_SC(')'));
+               for(SQInteger n = 0; n < defparams; n++) {
+                       _fs->PopTarget();
+               }
                //outer values
                if(_token == _SC(':')) {
                        Lex(); Expect(_SC('('));
@@ -1151,7 +1276,7 @@ public:
                        }
                        Lex();
                }
-
+               
                SQFuncState *currchunk = _fs;
                _fs = funcstate;
                Statement();