mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
'not case' expression, case variable scope change
This commit is contained in:
parent
471897a150
commit
5feb0c044b
15 changed files with 133 additions and 19 deletions
|
@ -2423,8 +2423,8 @@ namespace System {
|
|||
if (dynamicKey.GetValue(c_firstEntryValue) case .Ok(let val))
|
||||
first = val.Get<int32>();
|
||||
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)) {
|
||||
rules = null;
|
||||
|
|
|
@ -1461,6 +1461,8 @@ const char* Beefy::BfTokenToString(BfToken token)
|
|||
return "namespace";
|
||||
case BfToken_New:
|
||||
return "new";
|
||||
case BfToken_Not:
|
||||
return "not";
|
||||
case BfToken_Null:
|
||||
return "null";
|
||||
case BfToken_Nullable:
|
||||
|
|
|
@ -229,6 +229,7 @@ enum BfToken : uint8
|
|||
BfToken_NameOf,
|
||||
BfToken_Namespace,
|
||||
BfToken_New,
|
||||
BfToken_Not,
|
||||
BfToken_Null,
|
||||
BfToken_Nullable,
|
||||
BfToken_OffsetOf,
|
||||
|
@ -2365,6 +2366,7 @@ class BfCaseExpression : public BfExpression
|
|||
public:
|
||||
BF_AST_TYPE(BfCaseExpression, BfExpression);
|
||||
|
||||
BfAstNode* mNotToken;
|
||||
BfTokenNode* mCaseToken;
|
||||
BfExpression* mCaseExpression;
|
||||
BfTokenNode* mEqualsNode;
|
||||
|
|
|
@ -724,6 +724,7 @@ void BfElementVisitor::Visit(BfCaseExpression* caseExpr)
|
|||
{
|
||||
Visit(caseExpr->ToBase());
|
||||
|
||||
VisitChild(caseExpr->mNotToken);
|
||||
VisitChild(caseExpr->mCaseToken);
|
||||
VisitChild(caseExpr->mCaseExpression);
|
||||
VisitChild(caseExpr->mEqualsNode);
|
||||
|
|
|
@ -3884,7 +3884,7 @@ void BfExprEvaluator::DoCaseExpression(BfTypedValue caseValAddr, BfCaseExpressio
|
|||
|
||||
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.
|
||||
|
@ -4038,6 +4038,9 @@ void BfExprEvaluator::Visit(BfCaseExpression* caseExpr)
|
|||
|
||||
mResult = BfTypedValue(phiValue, boolType);
|
||||
}
|
||||
|
||||
if (caseExpr->mNotToken != NULL)
|
||||
mResult.mValue = mModule->mBfIRBuilder->CreateNot(mResult.mValue);
|
||||
}
|
||||
|
||||
void BfExprEvaluator::Visit(BfTypedValueExpression* typedValueExpr)
|
||||
|
@ -4390,6 +4393,13 @@ BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef)
|
|||
}
|
||||
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))
|
||||
{
|
||||
BfRefType* refType = (BfRefType*)varDecl->mResolvedType;
|
||||
|
@ -7744,7 +7754,7 @@ void BfExprEvaluator::FinishDeferredEvals(BfResolvedArgs& argValues)
|
|||
if (curScope->mScopeKind == BfScopeKind_StatementTarget)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// Move this variable into the parent scope
|
||||
curScope->mLocalVarStart = (int)mModule->mCurMethodState->mLocals.size();
|
||||
curScope->mLocalVarStart = (int)mModule->mCurMethodState->mLocals.size();
|
||||
}
|
||||
}
|
||||
return argValue;
|
||||
|
|
|
@ -16309,22 +16309,30 @@ void BfModule::CheckVariableDef(BfLocalVariable* variableDef)
|
|||
auto checkLocal = localVarEntryPtr->mLocalVar;
|
||||
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)
|
||||
return; // Ignore 'redefinition'
|
||||
if (checkLocal->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
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1929,6 +1929,7 @@ public:
|
|||
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);
|
||||
void DoAddLocalVariable(BfLocalVariable* localVar);
|
||||
void FixLocalVariable(BfLocalVariable* localVar);
|
||||
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);
|
||||
bool TryLocalVariableInit(BfLocalVariable* localVar);
|
||||
|
|
|
@ -3691,6 +3691,26 @@ void BfParser::ParseBlock(BfBlock* astNode, int depth, bool isInterpolate)
|
|||
Fail("Unexpected ending brace");
|
||||
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
|
||||
{
|
||||
if (mToken == BfToken_LParen)
|
||||
|
|
|
@ -2080,6 +2080,8 @@ void BfPrinter::Visit(BfCaseExpression* caseExpr)
|
|||
{
|
||||
VisitChild(caseExpr->mValueExpression);
|
||||
ExpectSpace();
|
||||
VisitChild(caseExpr->mNotToken);
|
||||
ExpectSpace();
|
||||
VisitChild(caseExpr->mCaseToken);
|
||||
BF_ASSERT(caseExpr->mEqualsNode == NULL);
|
||||
ExpectSpace();
|
||||
|
|
|
@ -1899,6 +1899,22 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
{
|
||||
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();
|
||||
|
||||
auto nextNode = mVisitorPos.GetNext();
|
||||
|
@ -2112,8 +2128,18 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
else if (token == BfToken_Case)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
|
@ -2694,7 +2720,8 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
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)
|
||||
return exprLeft;
|
||||
|
@ -2710,8 +2737,20 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
auto caseExpr = mAlloc->Alloc<BfCaseExpression>();
|
||||
ReplaceNode(exprLeft, caseExpr);
|
||||
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;
|
||||
|
||||
if (auto bindTokenNode = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
|
||||
|
|
|
@ -463,6 +463,12 @@ void BfSourceClassifier::Visit(BfTokenNode* tokenNode)
|
|||
SetElementType(tokenNode, BfSourceElementType_Normal);
|
||||
}
|
||||
|
||||
void BfSourceClassifier::Visit(BfCaseExpression* caseExpr)
|
||||
{
|
||||
BfElementVisitor::Visit(caseExpr);
|
||||
SetElementType(caseExpr->mNotToken, BfSourceElementType_Keyword);
|
||||
}
|
||||
|
||||
void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
|
||||
{
|
||||
//BfElementVisitor::Visit(invocationExpr);
|
||||
|
|
|
@ -125,6 +125,7 @@ public:
|
|||
virtual void Visit(BfLiteralExpression* literalExpr) override;
|
||||
virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression) override;
|
||||
virtual void Visit(BfTokenNode* tokenNode) override;
|
||||
virtual void Visit(BfCaseExpression* caseExpr) override;
|
||||
virtual void Visit(BfInvocationExpression* invocationExpr) override;
|
||||
virtual void Visit(BfIndexerExpression* indexerExpr) override;
|
||||
virtual void Visit(BfConstructorDeclaration* ctorDeclaration) override;
|
||||
|
|
|
@ -2441,6 +2441,13 @@ void BfModule::HandleCaseEnumMatch_Tuple(BfTypedValue tupleVal, const BfSizedArr
|
|||
|
||||
auto localVar = HandleVariableDeclaration(varDecl, tupleElement, false, true);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2464,6 +2471,12 @@ void BfModule::HandleCaseEnumMatch_Tuple(BfTypedValue tupleVal, const BfSizedArr
|
|||
|
||||
auto localVar = HandleVariableDeclaration(resolvedType, binOpExpr->mRight, tupleElement, false, true);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace Tests
|
|||
}
|
||||
|
||||
irn = null;
|
||||
if (irn case .Ok(let val))
|
||||
if (irn case .Ok(let val2))
|
||||
{
|
||||
Test.FatalError();
|
||||
}
|
||||
|
|
|
@ -91,6 +91,15 @@ namespace Tests
|
|||
bool eq = iResult case .Ok(ref result);
|
||||
Test.Assert(result == 99);
|
||||
|
||||
if (iResult not case .Ok(var result2))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
Test.FatalError();
|
||||
}
|
||||
Test.Assert(result2 == 0);
|
||||
|
||||
const ETest t = .B(234.5f);
|
||||
switch (t)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue