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))
|
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))
|
if (dynamicKey.GetValue(c_lastEntryValue) case .Ok(let val2))
|
||||||
last = val.Get<int32>();
|
last = val2.Get<int32>();
|
||||||
|
|
||||||
if ((first == -1) || (last == -1) || (first > last)) {
|
if ((first == -1) || (last == -1) || (first > last)) {
|
||||||
rules = null;
|
rules = null;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
else if (checkLocal->mLocalVarIdx < checkScope->mLocalVarStart)
|
||||||
error = Fail(StrFormat("A variable named '%s' has already been declared in this parent's scope", variableDef->mName.c_str()), variableDef->mNameNode);
|
_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);
|
_Fail(4200, 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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
||||||
|
if (notNode != NULL)
|
||||||
|
{
|
||||||
|
ReplaceNode(notNode, caseExpr);
|
||||||
|
caseExpr->mNotToken = notNode;
|
||||||
|
MEMBER_SET(caseExpr, mCaseToken, tokenNode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ReplaceNode(tokenNode, caseExpr);
|
ReplaceNode(tokenNode, caseExpr);
|
||||||
caseExpr->mCaseToken = tokenNode;
|
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;
|
||||||
|
|
||||||
|
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);
|
MEMBER_SET(caseExpr, mCaseToken, tokenNode);
|
||||||
mVisitorPos.MoveNext();
|
mVisitorPos.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
exprLeft = caseExpr;
|
exprLeft = caseExpr;
|
||||||
|
|
||||||
if (auto bindTokenNode = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
|
if (auto bindTokenNode = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue