浏览代码

'not case' expression, case variable scope change

Brian Fiete 5 月之前
父节点
当前提交
5feb0c044b

+ 2 - 2
BeefLibs/corlib/src/TimeZoneInfo.bf

@@ -2423,8 +2423,8 @@ namespace System {
 					if (dynamicKey.GetValue(c_firstEntryValue) case .Ok(let val))
 					if (dynamicKey.GetValue(c_firstEntryValue) case .Ok(let val))
 						first = val.Get<int32>();
 						first = val.Get<int32>();
 					int32 last = -1;
 					int32 last = -1;
-					if (dynamicKey.GetValue(c_lastEntryValue) case .Ok(let val))
-						last = val.Get<int32>();
+					if (dynamicKey.GetValue(c_lastEntryValue) case .Ok(let val2))
+						last = val2.Get<int32>();
 					
 					
                     if ((first == -1) || (last == -1) || (first > last)) {
                     if ((first == -1) || (last == -1) || (first > last)) {
                         rules = null;
                         rules = null;

+ 2 - 0
IDEHelper/Compiler/BfAst.cpp

@@ -1461,6 +1461,8 @@ const char* Beefy::BfTokenToString(BfToken token)
 		return "namespace";
 		return "namespace";
 	case BfToken_New:
 	case BfToken_New:
 		return "new";
 		return "new";
+	case BfToken_Not:
+		return "not";
 	case BfToken_Null:
 	case BfToken_Null:
 		return "null";
 		return "null";
 	case BfToken_Nullable:
 	case BfToken_Nullable:

+ 2 - 0
IDEHelper/Compiler/BfAst.h

@@ -229,6 +229,7 @@ enum BfToken : uint8
 	BfToken_NameOf,
 	BfToken_NameOf,
 	BfToken_Namespace,
 	BfToken_Namespace,
 	BfToken_New,
 	BfToken_New,
+	BfToken_Not,
 	BfToken_Null,
 	BfToken_Null,
 	BfToken_Nullable,
 	BfToken_Nullable,
 	BfToken_OffsetOf,
 	BfToken_OffsetOf,
@@ -2365,6 +2366,7 @@ class BfCaseExpression : public BfExpression
 public:
 public:
 	BF_AST_TYPE(BfCaseExpression, BfExpression);
 	BF_AST_TYPE(BfCaseExpression, BfExpression);
 
 
+	BfAstNode* mNotToken;
 	BfTokenNode* mCaseToken;
 	BfTokenNode* mCaseToken;
 	BfExpression* mCaseExpression;
 	BfExpression* mCaseExpression;
 	BfTokenNode* mEqualsNode;
 	BfTokenNode* mEqualsNode;

+ 1 - 0
IDEHelper/Compiler/BfElementVisitor.cpp

@@ -724,6 +724,7 @@ void BfElementVisitor::Visit(BfCaseExpression* caseExpr)
 {
 {
 	Visit(caseExpr->ToBase());
 	Visit(caseExpr->ToBase());
 
 
+	VisitChild(caseExpr->mNotToken);
 	VisitChild(caseExpr->mCaseToken);
 	VisitChild(caseExpr->mCaseToken);
 	VisitChild(caseExpr->mCaseExpression);
 	VisitChild(caseExpr->mCaseExpression);
 	VisitChild(caseExpr->mEqualsNode);
 	VisitChild(caseExpr->mEqualsNode);

+ 13 - 3
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -3884,7 +3884,7 @@ void BfExprEvaluator::DoCaseExpression(BfTypedValue caseValAddr, BfCaseExpressio
 
 
 		if (hasVariable)
 		if (hasVariable)
 		{
 		{
-			CheckVariableDeclaration(caseExpr, false, true, false);
+			CheckVariableDeclaration(caseExpr, false, false, false);
 		}
 		}
 
 
 		// We can avoid clearing on mismatch if we can be sure we ONLY enter the true block on a match.
 		// We can avoid clearing on mismatch if we can be sure we ONLY enter the true block on a match.
@@ -4038,6 +4038,9 @@ void BfExprEvaluator::Visit(BfCaseExpression* caseExpr)
 
 
 		mResult = BfTypedValue(phiValue, boolType);
 		mResult = BfTypedValue(phiValue, boolType);
 	}
 	}
+
+	if (caseExpr->mNotToken != NULL)
+		mResult.mValue = mModule->mBfIRBuilder->CreateNot(mResult.mValue);
 }
 }
 
 
 void BfExprEvaluator::Visit(BfTypedValueExpression* typedValueExpr)
 void BfExprEvaluator::Visit(BfTypedValueExpression* typedValueExpr)
@@ -4390,6 +4393,13 @@ BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef)
 	}
 	}
 	else if (varDecl->mAddr)
 	else if (varDecl->mAddr)
 	{
 	{
+		if ((!mModule->mBfIRBuilder->mIgnoreWrites) && (varDecl->mAddr.IsFake()) && (!varDecl->mResolvedType->IsValuelessType()))
+		{
+			// In an ignore case match we can may need to create a fake "out" when someone tries to read it
+			auto defaultTypedValue = mModule->GetDefaultTypedValue(varDecl->mResolvedType, true, BfDefaultValueKind_Addr);
+			varDecl->mAddr = defaultTypedValue.mValue;
+		}
+
 		if ((varDecl->mResolvedType->IsRef()) && (!allowRef))
 		if ((varDecl->mResolvedType->IsRef()) && (!allowRef))
 		{
 		{
 			BfRefType* refType = (BfRefType*)varDecl->mResolvedType;
 			BfRefType* refType = (BfRefType*)varDecl->mResolvedType;
@@ -7744,7 +7754,7 @@ void BfExprEvaluator::FinishDeferredEvals(BfResolvedArgs& argValues)
 					if (curScope->mScopeKind == BfScopeKind_StatementTarget)
 					if (curScope->mScopeKind == BfScopeKind_StatementTarget)
 					{
 					{
 						// Move this variable into the parent scope
 						// Move this variable into the parent scope
-						curScope->mLocalVarStart = (int)mModule->mCurMethodState->mLocals.size();
+						curScope->mLocalVarStart = (int)mModule->mCurMethodState->mLocals.size();						
 					}
 					}
 				}
 				}
 			}
 			}
@@ -9360,7 +9370,7 @@ BfTypedValue BfExprEvaluator::ResolveArgValue(BfResolvedArg& resolvedArg, BfType
 		if (curScope->mScopeKind == BfScopeKind_StatementTarget)
 		if (curScope->mScopeKind == BfScopeKind_StatementTarget)
 		{
 		{
 			// Move this variable into the parent scope
 			// Move this variable into the parent scope
-			curScope->mLocalVarStart = (int)mModule->mCurMethodState->mLocals.size();
+			curScope->mLocalVarStart = (int)mModule->mCurMethodState->mLocals.size();			
 		}
 		}
 	}
 	}
 	return argValue;
 	return argValue;

+ 16 - 8
IDEHelper/Compiler/BfModule.cpp

@@ -16309,22 +16309,30 @@ void BfModule::CheckVariableDef(BfLocalVariable* variableDef)
 		auto checkLocal = localVarEntryPtr->mLocalVar;
 		auto checkLocal = localVarEntryPtr->mLocalVar;
 		if ((checkLocal->mLocalVarIdx >= mCurMethodState->GetLocalStartIdx()) && (!checkLocal->mIsShadow))
 		if ((checkLocal->mLocalVarIdx >= mCurMethodState->GetLocalStartIdx()) && (!checkLocal->mIsShadow))
 		{
 		{
-			BfError* error;
+			auto _Fail = [&](int warningNum, String str, BfAstNode* refNode)
+			{
+				BfError* error = Warn(warningNum, str, refNode);				
+				if ((checkLocal->mNameNode != NULL) && (error != NULL))
+					mCompiler->mPassInstance->MoreInfo("Previous declaration", checkLocal->mNameNode);
+			};
+			
+			auto checkScope = mCurMethodState->mCurScope;
+			if (checkScope->mScopeKind == BfScopeKind_StatementTarget)			
+				checkScope = checkScope->mPrevScope;			
+
 			if (checkLocal->mIsImplicitParam)
 			if (checkLocal->mIsImplicitParam)
 				return; // Ignore 'redefinition'
 				return; // Ignore 'redefinition'
 			if (checkLocal->IsParam())
 			if (checkLocal->IsParam())
 			{
 			{
 				if (variableDef->IsParam())
 				if (variableDef->IsParam())
-					error = Fail(StrFormat("A parameter named '%s' has already been declared", variableDef->mName.c_str()), variableDef->mNameNode);
+					_Fail(4200, StrFormat("A parameter named '%s' has already been declared", variableDef->mName.c_str()), variableDef->mNameNode);
 				else
 				else
-					error = Fail(StrFormat("The name '%s' is already used by a parameter. Consider declaring 'var %s;' if you wish to make a mutable copy of that parameter.", variableDef->mName.c_str(), variableDef->mName.c_str()), variableDef->mNameNode);
+					_Fail(4200, StrFormat("The name '%s' is already used by a parameter. Consider declaring 'var %s;' if you wish to make a mutable copy of that parameter.", variableDef->mName.c_str(), variableDef->mName.c_str()), variableDef->mNameNode);
 			}
 			}
-			else if (checkLocal->mLocalVarIdx < mCurMethodState->mCurScope->mLocalVarStart)
-				error = Fail(StrFormat("A variable named '%s' has already been declared in this parent's scope", variableDef->mName.c_str()), variableDef->mNameNode);
+			else if (checkLocal->mLocalVarIdx < checkScope->mLocalVarStart)
+				_Fail(4200, StrFormat("A variable named '%s' has already been declared in an outer scope", variableDef->mName.c_str()), variableDef->mNameNode);
 			else
 			else
-				error = Fail(StrFormat("A variable named '%s' has already been declared in this scope", variableDef->mName.c_str()), variableDef->mNameNode);
-			if ((checkLocal->mNameNode != NULL) && (error != NULL))
-				mCompiler->mPassInstance->MoreInfo("Previous declaration", checkLocal->mNameNode);
+				_Fail(4200, StrFormat("A variable named '%s' has already been declared in this scope", variableDef->mName.c_str()), variableDef->mNameNode);
 			return;
 			return;
 		}
 		}
 	}
 	}

+ 1 - 0
IDEHelper/Compiler/BfModule.h

@@ -1929,6 +1929,7 @@ public:
 	bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL);
 	bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL);
 	BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true);
 	BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true);
 	void DoAddLocalVariable(BfLocalVariable* localVar);
 	void DoAddLocalVariable(BfLocalVariable* localVar);
+	void FixLocalVariable(BfLocalVariable* localVar);
 	void DoLocalVariableDebugInfo(BfLocalVariable* localVar, bool doAliasValue = false, BfIRValue declareBefore = BfIRValue(), BfIRInitType initType = BfIRInitType_NotSet);
 	void DoLocalVariableDebugInfo(BfLocalVariable* localVar, bool doAliasValue = false, BfIRValue declareBefore = BfIRValue(), BfIRInitType initType = BfIRInitType_NotSet);
 	BfLocalVariable* AddLocalVariableDef(BfLocalVariable* localVarDef, bool addDebugInfo = false, bool doAliasValue = false, BfIRValue declareBefore = BfIRValue(), BfIRInitType initType = BfIRInitType_NotSet);
 	BfLocalVariable* AddLocalVariableDef(BfLocalVariable* localVarDef, bool addDebugInfo = false, bool doAliasValue = false, BfIRValue declareBefore = BfIRValue(), BfIRInitType initType = BfIRInitType_NotSet);
 	bool TryLocalVariableInit(BfLocalVariable* localVar);
 	bool TryLocalVariableInit(BfLocalVariable* localVar);

+ 20 - 0
IDEHelper/Compiler/BfParser.cpp

@@ -3691,6 +3691,26 @@ void BfParser::ParseBlock(BfBlock* astNode, int depth, bool isInterpolate)
 				Fail("Unexpected ending brace");
 				Fail("Unexpected ending brace");
 			break;
 			break;
 		}
 		}
+		else if (mToken == BfToken_Case)
+		{
+			if (childArr.mSize > 0)
+			{
+				auto prevNode = childArr[childArr.mSize - 1];
+				if (auto prevIdentifier = BfNodeDynCastExact<BfIdentifierNode>(prevNode))
+				{
+					if (prevIdentifier->Equals("not"))
+					{
+						auto bfTokenNode = mAlloc->Alloc<BfTokenNode>();
+						bfTokenNode->Init(prevIdentifier->mTriviaStart, prevIdentifier->mSrcStart, prevIdentifier->mSrcEnd);
+						bfTokenNode->SetToken(BfToken_Not);
+						childArr[childArr.mSize - 1] = bfTokenNode;
+					}
+				}
+			}
+
+			astNode->Add(childNode);
+			childArr.Add(childNode);
+		}
 		else
 		else
 		{
 		{
 			if (mToken == BfToken_LParen)
 			if (mToken == BfToken_LParen)

+ 2 - 0
IDEHelper/Compiler/BfPrinter.cpp

@@ -2080,6 +2080,8 @@ void BfPrinter::Visit(BfCaseExpression* caseExpr)
 	{
 	{
 		VisitChild(caseExpr->mValueExpression);
 		VisitChild(caseExpr->mValueExpression);
 		ExpectSpace();
 		ExpectSpace();
+		VisitChild(caseExpr->mNotToken);
+		ExpectSpace();
 		VisitChild(caseExpr->mCaseToken);
 		VisitChild(caseExpr->mCaseToken);
 		BF_ASSERT(caseExpr->mEqualsNode == NULL);
 		BF_ASSERT(caseExpr->mEqualsNode == NULL);
 		ExpectSpace();
 		ExpectSpace();

+ 44 - 5
IDEHelper/Compiler/BfReducer.cpp

@@ -1899,6 +1899,22 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
 	{
 	{
 		if (auto tokenNode = BfNodeDynCast<BfTokenNode>(node))
 		if (auto tokenNode = BfNodeDynCast<BfTokenNode>(node))
 		{
 		{
+			BfAstNode* notNode = NULL;
+			if (tokenNode->mToken == BfToken_Not)
+			{
+				auto nextNode = mVisitorPos.GetNext();
+				if (auto nextTokenNode = BfNodeDynCast<BfTokenNode>(nextNode))
+				{
+					if (nextTokenNode->mToken == BfToken_Case)
+					{
+						mVisitorPos.MoveNext();
+						notNode = tokenNode;
+						node = nextNode;
+						tokenNode = nextTokenNode;
+					}
+				}
+			}
+
 			BfToken token = tokenNode->GetToken();
 			BfToken token = tokenNode->GetToken();
 
 
 			auto nextNode = mVisitorPos.GetNext();
 			auto nextNode = mVisitorPos.GetNext();
@@ -2112,8 +2128,18 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
 			else if (token == BfToken_Case)
 			else if (token == BfToken_Case)
 			{
 			{
 				auto caseExpr = mAlloc->Alloc<BfCaseExpression>();
 				auto caseExpr = mAlloc->Alloc<BfCaseExpression>();
-				ReplaceNode(tokenNode, caseExpr);
-				caseExpr->mCaseToken = tokenNode;
+				
+				if (notNode != NULL)
+				{
+					ReplaceNode(notNode, caseExpr);
+					caseExpr->mNotToken = notNode;
+					MEMBER_SET(caseExpr, mCaseToken, tokenNode);
+				}
+				else
+				{
+					ReplaceNode(tokenNode, caseExpr);
+					caseExpr->mCaseToken = tokenNode;
+				}				
 
 
 				if (auto bindToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
 				if (auto bindToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
 				{
 				{
@@ -2694,7 +2720,8 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
 				continue;
 				continue;
 			}
 			}
 
 
-			if ((token == BfToken_Case) && ((createExprFlags & CreateStmtFlags_NoCaseExpr) == 0))
+			if (((token == BfToken_Case) || (token == BfToken_Not)) 
+				&& ((createExprFlags & CreateStmtFlags_NoCaseExpr) == 0))
 			{
 			{
 				if ((createExprFlags & CreateExprFlags_EarlyExit) != 0)
 				if ((createExprFlags & CreateExprFlags_EarlyExit) != 0)
 					return exprLeft;
 					return exprLeft;
@@ -2710,8 +2737,20 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
 				auto caseExpr = mAlloc->Alloc<BfCaseExpression>();
 				auto caseExpr = mAlloc->Alloc<BfCaseExpression>();
 				ReplaceNode(exprLeft, caseExpr);
 				ReplaceNode(exprLeft, caseExpr);
 				caseExpr->mValueExpression = exprLeft;
 				caseExpr->mValueExpression = exprLeft;
-				MEMBER_SET(caseExpr, mCaseToken, tokenNode);
-				mVisitorPos.MoveNext();
+
+				if (token == BfToken_Not)
+				{
+					MEMBER_SET(caseExpr, mNotToken, tokenNode);
+					mVisitorPos.MoveNext();
+					tokenNode = ExpectTokenAfter(caseExpr, BfToken_Case);
+					MEMBER_SET(caseExpr, mCaseToken, tokenNode);
+				}
+				else
+				{
+					MEMBER_SET(caseExpr, mCaseToken, tokenNode);
+					mVisitorPos.MoveNext();
+				}
+								
 				exprLeft = caseExpr;
 				exprLeft = caseExpr;
 
 
 				if (auto bindTokenNode = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
 				if (auto bindTokenNode = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))

+ 6 - 0
IDEHelper/Compiler/BfSourceClassifier.cpp

@@ -463,6 +463,12 @@ void BfSourceClassifier::Visit(BfTokenNode* tokenNode)
 		SetElementType(tokenNode, BfSourceElementType_Normal);
 		SetElementType(tokenNode, BfSourceElementType_Normal);
 }
 }
 
 
+void BfSourceClassifier::Visit(BfCaseExpression* caseExpr)
+{
+	BfElementVisitor::Visit(caseExpr);
+	SetElementType(caseExpr->mNotToken, BfSourceElementType_Keyword);
+}
+
 void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 {
 {
 	//BfElementVisitor::Visit(invocationExpr);
 	//BfElementVisitor::Visit(invocationExpr);

+ 1 - 0
IDEHelper/Compiler/BfSourceClassifier.h

@@ -125,6 +125,7 @@ public:
 	virtual void Visit(BfLiteralExpression* literalExpr) override;
 	virtual void Visit(BfLiteralExpression* literalExpr) override;
 	virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression) override;
 	virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression) override;
 	virtual void Visit(BfTokenNode* tokenNode) override;
 	virtual void Visit(BfTokenNode* tokenNode) override;
+	virtual void Visit(BfCaseExpression* caseExpr) override;
 	virtual void Visit(BfInvocationExpression* invocationExpr) override;
 	virtual void Visit(BfInvocationExpression* invocationExpr) override;
 	virtual void Visit(BfIndexerExpression* indexerExpr) override;
 	virtual void Visit(BfIndexerExpression* indexerExpr) override;
 	virtual void Visit(BfConstructorDeclaration* ctorDeclaration) override;
 	virtual void Visit(BfConstructorDeclaration* ctorDeclaration) override;

+ 13 - 0
IDEHelper/Compiler/BfStmtEvaluator.cpp

@@ -2441,6 +2441,13 @@ void BfModule::HandleCaseEnumMatch_Tuple(BfTypedValue tupleVal, const BfSizedArr
 
 
 			auto localVar = HandleVariableDeclaration(varDecl, tupleElement, false, true);
 			auto localVar = HandleVariableDeclaration(varDecl, tupleElement, false, true);
 			localVar->mReadFromId = 0; // Don't give usage errors for binds
 			localVar->mReadFromId = 0; // Don't give usage errors for binds
+
+			auto curScope = mCurMethodState->mCurScope;
+			if (curScope->mScopeKind == BfScopeKind_StatementTarget)
+			{
+				// Move this variable into the parent scope				
+				curScope->mLocalVarStart = localVar->mLocalVarIdx + 1;								
+			}
 			continue;
 			continue;
 		}
 		}
 
 
@@ -2464,6 +2471,12 @@ void BfModule::HandleCaseEnumMatch_Tuple(BfTypedValue tupleVal, const BfSizedArr
 
 
 					auto localVar = HandleVariableDeclaration(resolvedType, binOpExpr->mRight, tupleElement, false, true);
 					auto localVar = HandleVariableDeclaration(resolvedType, binOpExpr->mRight, tupleElement, false, true);
 					localVar->mReadFromId = 0; // Don't give usage errors for binds
 					localVar->mReadFromId = 0; // Don't give usage errors for binds
+					auto curScope = mCurMethodState->mCurScope;
+					if (curScope->mScopeKind == BfScopeKind_StatementTarget)
+					{
+						// Move this variable into the parent scope				
+						curScope->mLocalVarStart = localVar->mLocalVarIdx + 1;												
+					}
 					continue;
 					continue;
 				}
 				}
 			}
 			}

+ 1 - 1
IDEHelper/Tests/src/Nullable.bf

@@ -128,7 +128,7 @@ namespace Tests
 			}
 			}
 
 
 			irn = null;
 			irn = null;
-			if (irn case .Ok(let val))
+			if (irn case .Ok(let val2))
 			{
 			{
 				Test.FatalError();
 				Test.FatalError();
 			}
 			}

+ 9 - 0
IDEHelper/Tests/src/Switches.bf

@@ -91,6 +91,15 @@ namespace Tests
 			bool eq = iResult case .Ok(ref result);
 			bool eq = iResult case .Ok(ref result);
 			Test.Assert(result == 99);
 			Test.Assert(result == 99);
 
 
+			if (iResult not case .Ok(var result2))
+			{
+			}
+			else
+			{
+				Test.FatalError();
+			}
+			Test.Assert(result2 == 0);
+
 			const ETest t = .B(234.5f);
 			const ETest t = .B(234.5f);
 			switch (t)
 			switch (t)
 			{
 			{