Browse Source

Refactored the some compiler functions splitting then to use that functionality alone.
Added a "Warning" function to emit warnings to stderr.
Changes to several structures and functions to allow detect redeclaration of already declared variables.
Throwing an error when detecting attempt to declare already declared variables.
Showing a warning message when declaring a variable in a nested scope that will shadow an already declared variable in outer scopes.
Showing a warning when detecting assignment inside if/while/switch/return because usually it is a common mistake.

mingodad 13 years ago
parent
commit
c461d9bd71
4 changed files with 81 additions and 47 deletions
  1. 72 41
      squirrel/sqcompiler.cpp
  2. 3 1
      squirrel/sqfuncproto.h
  3. 4 3
      squirrel/sqfuncstate.cpp
  4. 2 2
      squirrel/sqfuncstate.h

+ 72 - 41
squirrel/sqcompiler.cpp

@@ -29,9 +29,11 @@ struct SQExpState {
 struct SQScope {
 	SQInteger outers;
 	SQInteger stacksize;
+	SQInteger nested;
 };
 
 #define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \
+					 ++_scope.nested; \
 					 _scope.outers = _fs->_outers; \
 					 _scope.stacksize = _fs->GetStackSize();
 
@@ -78,6 +80,7 @@ public:
 		_lineinfo = lineinfo;_raiseerror = raiseerror;
 		_scope.outers = 0;
 		_scope.stacksize = 0;
+		_scope.nested = 0;
 		compilererror = NULL;
 	}
 	static void ThrowError(void *ud, const SQChar *s) {
@@ -94,10 +97,36 @@ public:
 		compilererror = temp;
 		longjmp(_errorjmp,1);
 	}
+	void Warning(const SQChar *s, ...)
+	{
+		va_list vl;
+		va_start(vl, s);
+		scvfprintf(stderr, s, vl);
+		va_end(vl);
+	}
 	void Lex(){	_token = _lex.Lex();}
-	SQObject Expect(SQInteger tok)
+	SQObjectPtr GetTokenObject()
 	{
-		
+		SQObjectPtr ret;
+		switch(_token)
+		{
+		case TK_IDENTIFIER:
+			ret = _fs->CreateString(_lex._svalue);
+			break;
+		case TK_STRING_LITERAL:
+			ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+			break;
+		case TK_INTEGER:
+			ret = SQObjectPtr(_lex._nvalue);
+			break;
+		case TK_FLOAT:
+			ret = SQObjectPtr(_lex._fvalue);
+			break;
+		}
+		Lex();
+		return ret;
+	}
+	void ErrorIfNotToken(SQInteger tok){
 		if(_token != tok) {
 			if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
 				//do nothing
@@ -127,24 +156,11 @@ public:
 				Error(_SC("expected '%c'"), tok);
 			}
 		}
-		SQObjectPtr ret;
-		switch(tok)
-		{
-		case TK_IDENTIFIER:
-			ret = _fs->CreateString(_lex._svalue);
-			break;
-		case TK_STRING_LITERAL:
-			ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
-			break;
-		case TK_INTEGER:
-			ret = SQObjectPtr(_lex._nvalue);
-			break;
-		case TK_FLOAT:
-			ret = SQObjectPtr(_lex._fvalue);
-			break;
-		}
-		Lex();
-		return ret;
+	}
+	SQObject Expect(SQInteger tok)
+	{
+        ErrorIfNotToken(tok);
+		return GetTokenObject();
 	}
 	bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
 	void OptionalSemicolon()
@@ -169,8 +185,8 @@ public:
 		SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
 		funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
 		_fs = &funcstate;
-		_fs->AddParameter(_fs->CreateString(_SC("this")));
-		_fs->AddParameter(_fs->CreateString(_SC("vargv")));
+		_fs->AddParameter(_fs->CreateString(_SC("this")), _scope.nested+1);
+		_fs->AddParameter(_fs->CreateString(_SC("vargv")), _scope.nested+1);
 		_fs->_varparams = true;
 		_fs->_sourcename = _sourcename;
 		SQInteger stacksize = _fs->GetStackSize();
@@ -231,7 +247,7 @@ public:
 			Lex();
 			if(!IsEndOfStatement()) {
 				SQInteger retexp = _fs->GetCurrentPos()+1;
-				CommaExpr();
+				CommaExpr(true);
 				if(op == _OP_RETURN && _fs->_traps > 0)
 					_fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
 				_fs->_returnexp = retexp;
@@ -361,11 +377,11 @@ public:
 			break;
 		}
 	}
-	void CommaExpr()
+	void CommaExpr(bool warningAssign=false)
 	{
-		for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
+		for(Expression(warningAssign);_token == ',';_fs->PopTarget(), Lex(), CommaExpr(warningAssign));
 	}
-	void Expression()
+	void Expression(bool warningAssign=false)
 	{
 		 SQExpState es = _es;
 		_es.etype     = EXPR;
@@ -394,6 +410,8 @@ public:
 					Error(_SC("can't 'create' a local slot"));
 				break;
 			case _SC('='): //ASSIGN
+                if(warningAssign) Warning(_SC("WARNING: making assignment at line %d:%d maybe is not what you want\n"),
+                                          _lex._currentline, _lex._currentcolumn);
 				switch(ds) {
 				case LOCAL:
 					{
@@ -976,6 +994,17 @@ public:
 			_fs->SetIntructionParam(tpos, 1, nkeys);
 		Lex();
 	}
+	void checkLocalNameScope(const SQObject &name, SQInteger scope){
+	    SQInteger found = _fs->GetLocalVariable(name);
+	    if(found >= 0){
+	        SQLocalVarInfo &lvi = _fs->_vlocals[found];
+	        if(lvi._scope == scope)
+                Error(_SC("local '%s' already declared"), _string(name)->_val);
+            else
+                Warning(_SC("WARNING: at line %d:%d local '%s' already declared will be shadowed\n"),
+                        _lex._currentline, _lex._currentcolumn, _string(name)->_val);
+	    }
+	}
 	void LocalDeclStatement()
 	{
 		SQObject varname;
@@ -983,16 +1012,18 @@ public:
 		if( _token == TK_FUNCTION) {
 			Lex();
 			varname = Expect(TK_IDENTIFIER);
+			checkLocalNameScope(varname, _scope.nested);
 			Expect(_SC('('));
 			CreateFunction(varname,false);
 			_fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
 			_fs->PopTarget();
-			_fs->PushLocalVariable(varname);
+			_fs->PushLocalVariable(varname, _scope.nested);
 			return;
 		}
 
 		do {
 			varname = Expect(TK_IDENTIFIER);
+			checkLocalNameScope(varname, _scope.nested);
 			if(_token == _SC('=')) {
 				Lex(); Expression();
 				SQInteger src = _fs->PopTarget();
@@ -1003,7 +1034,7 @@ public:
 				_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
 			}
 			_fs->PopTarget();
-			_fs->PushLocalVariable(varname);
+			_fs->PushLocalVariable(varname, _scope.nested);
 			if(_token == _SC(',')) Lex(); else break;
 		} while(1);
 	}
@@ -1011,7 +1042,7 @@ public:
 	{
 		SQInteger jmppos;
 		bool haselse = false;
-		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
+		Lex(); Expect(_SC('(')); CommaExpr(true); Expect(_SC(')'));
 		_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
 		SQInteger jnepos = _fs->GetCurrentPos();
 		BEGIN_SCOPE();
@@ -1038,8 +1069,8 @@ public:
 	{
 		SQInteger jzpos, jmppos;
 		jmppos = _fs->GetCurrentPos();
-		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
-		
+		Lex(); Expect(_SC('(')); CommaExpr(true); Expect(_SC(')'));
+
 		BEGIN_BREAKBLE_BLOCK();
 		_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
 		jzpos = _fs->GetCurrentPos();
@@ -1063,7 +1094,7 @@ public:
 		END_SCOPE();
 		Expect(TK_WHILE);
 		SQInteger continuetrg = _fs->GetCurrentPos();
-		Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
+		Expect(_SC('(')); CommaExpr(true); Expect(_SC(')'));
 		_fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
 		_fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
 		END_BREAKBLE_BLOCK(continuetrg);
@@ -1132,13 +1163,13 @@ public:
 		Expression(); Expect(_SC(')'));
 		SQInteger container = _fs->TopTarget();
 		//push the index local var
-		SQInteger indexpos = _fs->PushLocalVariable(idxname);
+		SQInteger indexpos = _fs->PushLocalVariable(idxname, _scope.nested);
 		_fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
 		//push the value local var
-		SQInteger valuepos = _fs->PushLocalVariable(valname);
+		SQInteger valuepos = _fs->PushLocalVariable(valname, _scope.nested);
 		_fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
 		//push reference index
-		SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
+		SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@")), _scope.nested); //use invalid id to make it inaccessible
 		_fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
 		SQInteger jmppos = _fs->GetCurrentPos();
 		_fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
@@ -1157,7 +1188,7 @@ public:
 	}
 	void SwitchStatement()
 	{
-		Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
+		Lex(); Expect(_SC('(')); CommaExpr(true); Expect(_SC(')'));
 		Expect(_SC('{'));
 		SQInteger expr = _fs->TopTarget();
 		bool bfirst = true;
@@ -1330,7 +1361,7 @@ public:
 		Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
 		{
 			BEGIN_SCOPE();
-			SQInteger ex_target = _fs->PushLocalVariable(exid);
+			SQInteger ex_target = _fs->PushLocalVariable(exid, _scope.nested);
 			_fs->SetIntructionParam(trappos, 0, ex_target);
 			Statement();
 			_fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
@@ -1412,13 +1443,13 @@ public:
 		SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
 		funcstate->_name = name;
 		SQObject paramname;
-		funcstate->AddParameter(_fs->CreateString(_SC("this")));
+		funcstate->AddParameter(_fs->CreateString(_SC("this")), _scope.nested+1);
 		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->AddParameter(_fs->CreateString(_SC("vargv")));
+				funcstate->AddParameter(_fs->CreateString(_SC("vargv")), _scope.nested+1);
 				funcstate->_varparams = true;
 				Lex();
 				if(_token != _SC(')')) Error(_SC("expected ')'"));
@@ -1426,8 +1457,8 @@ public:
 			}
 			else {
 				paramname = Expect(TK_IDENTIFIER);
-				funcstate->AddParameter(paramname);
-				if(_token == _SC('=')) { 
+				funcstate->AddParameter(paramname, _scope.nested+1);
+				if(_token == _SC('=')) {
 					Lex();
 					Expression();
 					funcstate->AddDefaultParam(_fs->TopTarget());

+ 3 - 1
squirrel/sqfuncproto.h

@@ -32,18 +32,20 @@ struct SQOuterVar
 
 struct SQLocalVarInfo
 {
-	SQLocalVarInfo():_start_op(0),_end_op(0),_pos(0){}
+	SQLocalVarInfo():_start_op(0),_end_op(0),_pos(0),_scope(0){}
 	SQLocalVarInfo(const SQLocalVarInfo &lvi)
 	{
 		_name=lvi._name;
 		_start_op=lvi._start_op;
 		_end_op=lvi._end_op;
 		_pos=lvi._pos;
+		_scope=lvi._scope;
 	}
 	SQObjectPtr _name;
 	SQUnsignedInteger _start_op;
 	SQUnsignedInteger _end_op;
 	SQUnsignedInteger _pos;
+	SQInteger _scope;
 };
 
 struct SQLineInfo { SQInteger _line;SQInteger _op; };

+ 4 - 3
squirrel/sqfuncstate.cpp

@@ -351,13 +351,14 @@ bool SQFuncState::IsLocal(SQUnsignedInteger stkpos)
 	return false;
 }
 
-SQInteger SQFuncState::PushLocalVariable(const SQObject &name)
+SQInteger SQFuncState::PushLocalVariable(const SQObject &name, SQInteger scope)
 {
 	SQInteger pos=_vlocals.size();
 	SQLocalVarInfo lvi;
 	lvi._name=name;
 	lvi._start_op=GetCurrentPos()+1;
 	lvi._pos=_vlocals.size();
+	lvi._scope=scope;
 	_vlocals.push_back(lvi);
 	if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size();
 	return pos;
@@ -413,9 +414,9 @@ SQInteger SQFuncState::GetOuterVariable(const SQObject &name)
 	return -1;
 }
 
-void SQFuncState::AddParameter(const SQObject &name)
+void SQFuncState::AddParameter(const SQObject &name, SQInteger scope)
 {
-	PushLocalVariable(name);
+	PushLocalVariable(name, scope);
 	_parameters.push_back(name);
 }
 

+ 2 - 2
squirrel/sqfuncstate.h

@@ -28,8 +28,8 @@ struct SQFuncState
 	SQInteger GetCurrentPos(){return _instructions.size()-1;}
 	SQInteger GetNumericConstant(const SQInteger cons);
 	SQInteger GetNumericConstant(const SQFloat cons);
-	SQInteger PushLocalVariable(const SQObject &name);
-	void AddParameter(const SQObject &name);
+	SQInteger PushLocalVariable(const SQObject &name, SQInteger scope);
+	void AddParameter(const SQObject &name, SQInteger scope);
 	//void AddOuterValue(const SQObject &name);
 	SQInteger GetLocalVariable(const SQObject &name);
 	void MarkLocalAsOuter(SQInteger pos);