Ver código fonte

Simplification of the "goto" implementation, it's usable with care, goto/jump crossing declaration/initialization need to show an error message, still need work.

mingodad 9 anos atrás
pai
commit
45512ad52d

+ 4 - 1
SquiLu/samples/test-goto.nut

@@ -4,6 +4,9 @@ local function test10(x)
 {
 	print("goto start");
 goto start;
+	local zz = 77; //this should be an error
+	x = 99;
+//goto p2;
 change:
 	x = 5;
 	try
@@ -15,7 +18,7 @@ change:
 	}
 //goto dad;
 start:
-	print("start");
+	print("start", zz);
 	if(x > 10)
 	{
 		try

+ 65 - 72
SquiLu/squirrel/sqcompiler.cpp

@@ -61,7 +61,6 @@ struct SQScope {
 						} \
 						_scope = __oldscope__; \
 						_scope_consts.pop_back();\
-						EndScopeCheckGotoLabels(_scope.stacksize);\
 					}
 
 #define END_SCOPE() {	SQInteger oldouters = _fs->_outers;\
@@ -618,18 +617,17 @@ public:
 		case TK_GOTO: {
 		    //error if outside any function
 			if(!_fs->_parent) Error(_SC("'goto' has to be in a function block"));
-		    Warning(_SC("%s:%d:%d warning goto is only parsed right now\n"),
-                        _stringval(_sourcename), _lex.data->currentline, _lex.data->currentcolumn);
 		    Lex(); //ignore for now
 		    id = Expect(TK_IDENTIFIER);
 			SQGotoLabelsInfo info;
 			info.name = id;
 			info.line = _lex.data->currentline; //need to get line number here
 			info.traps = _fs->_traps;
-		    Expect(_SC(';'));
+			info.nested = _scope.nested;
+		    //Expect(_SC(';'));
 
+			if(info.traps) _fs->AddInstruction(_OP_NOP, 0, 0); //for _OP_POPTRAP
 			RESOLVE_OUTERS();
-			_fs->AddInstruction(_OP_NOP, 0, 0); //for _OP_POPTRAP
 			_fs->AddInstruction(_OP_JMP, 0, -1234);
 			//instruction pos
 			info.pos = _fs->GetCurrentPos();
@@ -741,7 +739,7 @@ public:
 			id = ExpectTypeToken();
 			SQObjectPtr strongid = id;
 			CheckLocalNameScope(id, _scope.nested);
-			Expect(_SC(';'));
+			//Expect(_SC(';'));
 			TypesNewSlot(strongid,SQObjectPtr(type_val));
 			}
 			break;
@@ -753,7 +751,7 @@ public:
 			SQObjectPtr strongid = id;
 			CheckLocalNameScope(id, _scope.nested);
 			SQObject type_val = ExpectTypeToken();
-			Expect(_SC(';'));
+			//Expect(_SC(';'));
 			TypesNewSlot(strongid,SQObjectPtr(type_val));
 			}
         break;
@@ -792,9 +790,10 @@ public:
             if(lhtk == _SC(':'))
             {
                 if(!_fs->_parent) Error(_SC("'label' has to be inside a function block"));
-                if(!_fs->AddGotoTarget(id, _lex.data->currentline, _fs->_traps)) Error(_SC("Label already declared"));
-                Warning(_SC("%s:%d:%d warning labels are only parsed right now\n"),
-                        _stringval(_sourcename), _lex.data->currentline, _lex.data->currentcolumn);
+                if(!_fs->AddGotoTarget(id, _lex.data->currentline, _fs->_traps, _scope.nested))
+                {
+                    Error(_SC("Label already declared"));
+                }
                 Lex(); //eat ':'
                 Lex();
                 break;
@@ -2519,7 +2518,7 @@ error:
 		else {
 			Statement(false);
 		}
-		ResolveGotos(0, true);
+		ResolveGotos();
 		funcstate->AddLineInfos(_lex.data->prevtoken == _SC('\n')?_lex.data->lasttokenline:_lex.data->currentline, _lineinfo, true);
         funcstate->AddInstruction(_OP_RETURN, -1);
 		funcstate->SetStackSize(0);
@@ -2539,86 +2538,80 @@ error:
         //set the jmp instruction
 
         SQInteger poptraps = goto_info.traps - label.traps;
-        if(poptraps)
+        SQInt32 ioffset = 1;
+        while(poptraps)
         {
-            SQInstruction &i_op_poptrap = _fs->GetInstruction(goto_info.pos-1);
+            SQInstruction &i_op_poptrap = _fs->GetInstruction(goto_info.pos-ioffset);
+            if(i_op_poptrap.op != _OP_NOP)
+            {
+                if(ioffset < 2)
+                {
+                    ++ioffset;
+                    continue;
+                }
+                Error(_SC("Compiler: This should not happen i_op_poptrap.op != _OP_NOP"));
+            }
             //printf("poptraps for %s = %d : %d\n", _stringval(label.name), (int)poptraps, (int)i_op_poptrap._arg0);
             i_op_poptrap.op = _OP_POPTRAP;
             i_op_poptrap._arg0 = poptraps;
+            break;
         }
 
         _fs->SetIntructionParams(goto_info.pos, 0, jump_pos, 0);
 	}
-	bool ResolveGotLabel(SQInteger stack_pos, const SQGotoLabelsInfo &label)
-	{
-	    bool resolved = false;
-		for(SQInteger i = _fs->_unresolvedgotos.size()-1; i >= 0; --i) {
-			SQGotoLabelsInfo goto_info = _fs->_unresolvedgotos[i];
-			//printf("ResolveGotLabel : %s : %s\n", _stringval(label.name), _stringval(goto_info.name));
-			if(_string(label.name) == _string(goto_info.name))
-            {
-                if(goto_info.pos < stack_pos)
+	void ResolveGotos()
+	{
+	    //first we walk through the labels and when we come back
+	    //nested labels we remove then because we only allow
+	    //goto/joump out of blocks/scopes
+	    SQInt16 last_nested = -1;
+        for(SQUnsignedInteger idxlabel = 0; idxlabel < _fs->_gototargets.size(); ++idxlabel) {
+            SQGotoLabelsInfo &label = _fs->_gototargets[idxlabel];
+            SQUnsignedInteger resolved = 0;
+            for(SQUnsignedInteger idxGoto = 0; idxGoto < _fs->_unresolvedgotos.size(); ++idxGoto) {
+                SQGotoLabelsInfo &goto_info = _fs->_unresolvedgotos[idxGoto];
+                if(_string(label.name) == _string(goto_info.name))
                 {
-                    _lex.data->currentline = goto_info.line;
-                    Error(_SC("Goto can not jump to nested label '%s'"), _stringval(label.name));
+                    if(label.nested > goto_info.nested)
+                    {
+                        _lex.data->currentline = goto_info.line;
+                        Error(_SC("Goto can not jump inside nested block/scope '%s'"), _stringval(goto_info.name));
+                    }
+                    AdjustGotoInstruction(goto_info, label);
+                    //we dcrease idxGoto here to compensate the removal inside the for loop
+                    _fs->_unresolvedgotos.remove(idxGoto--);
+                    ++resolved;
                 }
-                resolved = true;
-                AdjustGotoInstruction(goto_info, label);
-                _fs->_unresolvedgotos.remove(i);
             }
-		}
-		return resolved;
-	}
-	bool ResolveOneGoto(SQGotoLabelsInfo &goto_info)
-	{
-        for(SQInteger i = _fs->_gototargets.size()-1; i >= 0; --i) {
-            SQGotoLabelsInfo &label = _fs->_gototargets[i];
-            if(_string(label.name) == _string(goto_info.name))
+            if(!resolved)
             {
-                AdjustGotoInstruction(goto_info, label);
-                return true;
+                //if a label isn't resolved we have an unused label
+                _lex.data->currentline = label.line;
+                Error(_SC("Label not resolved at this point '%s'"), _stringval(label.name));
             }
-        }
-        return false;
-	}
-	void ResolveGotos(SQInteger stack_pos, bool raiseError=false)
-	{
-        if(_fs->_unresolvedgotos.size() && (_fs->_unresolvedgotos.top().pos >= stack_pos))
-        {
-            //we can resolve gotos upward here
-            for(SQInteger i = _fs->_unresolvedgotos.size()-1; i >= 0; --i) {
-                SQGotoLabelsInfo &goto_info = _fs->_unresolvedgotos[i];
-                if(!ResolveOneGoto(goto_info) && raiseError)
+            if(label.nested < last_nested)
+            {
+                //remove any previous nested label to prevent goto/jump inside blocks/scopes
+                SQUnsignedInteger i = idxlabel - 1;
+                for(; i > 0; --i)
                 {
-                    _lex.data->currentline = goto_info.line;
-                    Error(_SC("Goto can not jump to undeclared label '%s'"), _stringval(goto_info.name));
+                    if(_fs->_gototargets[i].nested <= label.nested) break;
+                    _fs->_gototargets.remove(i);
+                    //we decrease the index idxlabel here due to remove before
+                    //the current idxlabel
+                    --idxlabel;
                 }
             }
+            last_nested = label.nested;
         }
-	}
-	void EndScopeCheckGotoLabels(SQInteger stack_pos)
-	{
-	    //do we have declared any new label ?
-        if(_fs->_gototargets.size() && (_fs->_gototargets.top().pos >= stack_pos))
+
+        if(_fs->_unresolvedgotos.size())
         {
-            //any new label at this point should have a goto call inside/nested this block
-            SQGotoLabelsInfo &label = _fs->_gototargets.top();
-            while(label.pos >= stack_pos) {
-                if(!ResolveGotLabel(stack_pos, label))
-                {
-                    _lex.data->currentline = label.line;
-                    Error(_SC("Label not resolved at this point '%s'"), _stringval(label.name));
-                }
-                _fs->_gototargets.pop_back();
-                if(_fs->_gototargets.empty())
-                {
-                    break;
-                }
-                label = _fs->_gototargets.top();
-            }
+            //if we still have any unresolved goto it's an error, let's show the first
+            SQGotoLabelsInfo &goto_info = _fs->_unresolvedgotos[0];
+            _lex.data->currentline = goto_info.line;
+            Error(_SC("Goto can not jump to undeclared label '%s'"), _stringval(goto_info.name));
         }
-	    //do we have declared any new goto ?
-	    ResolveGotos(stack_pos);
 	}
 	void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
 	{

+ 1 - 1
SquiLu/squirrel/sqfuncproto.h

@@ -66,7 +66,7 @@ struct SQLocalVarInfo
 };
 
 struct SQLineInfo { SQInteger _line;SQInteger _op; };
-struct SQGotoLabelsInfo { SQObjectPtr name; SQInt32 pos; SQInt16 line; SQInt16 traps;};
+struct SQGotoLabelsInfo { SQObjectPtr name; SQInt32 pos; SQInt16 line; SQInt16 traps; SQInt16 nested;};
 
 typedef sqvector<SQOuterVar> SQOuterVarVec;
 typedef sqvector<SQLocalVarInfo> SQLocalVarInfoVec;

+ 2 - 1
SquiLu/squirrel/sqfuncstate.cpp

@@ -391,7 +391,7 @@ SQInteger SQFuncState::FindGotoTarget(const SQObject &name)
 	return -1;
 }
 
-bool SQFuncState::AddGotoTarget(const SQObject &name, SQInteger line, SQInteger traps)
+bool SQFuncState::AddGotoTarget(const SQObject &name, SQInteger line, SQInteger traps, SQInteger nested)
 {
     if(FindGotoTarget(name) >= 0) return false;
 	SQGotoLabelsInfo info;
@@ -400,6 +400,7 @@ bool SQFuncState::AddGotoTarget(const SQObject &name, SQInteger line, SQInteger
 	info.pos = GetCurrentPos();
 	info.line = line;
 	info.traps = traps;
+	info.nested = nested;
 	_gototargets.push_back(info);
 	return true;
 }

+ 1 - 1
SquiLu/squirrel/sqfuncstate.h

@@ -53,7 +53,7 @@ struct SQFuncState
 	SQObject CreateTable();
 	bool IsConstant(const SQObject &name,SQObject &e);
 	SQInteger FindGotoTarget(const SQObject &name);
-	bool AddGotoTarget(const SQObject &name, SQInteger line, SQInteger traps);
+	bool AddGotoTarget(const SQObject &name, SQInteger line, SQInteger traps, SQInteger nested);
 	SQGotoLabelsInfoVec _unresolvedgotos;
 	SQGotoLabelsInfoVec _gototargets;
 	SQInteger _returnexp;