From 0692fb44a4816ac734e7f41da3c54bfa07344b07 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 2 Jan 2021 06:14:29 -0800 Subject: [PATCH] Added '.{ x = 1, y = 2}' initializer expression --- IDEHelper/Compiler/BfAst.h | 2 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 67 ++++++++++++++++++++- IDEHelper/Compiler/BfReducer.cpp | 81 +++++++++++++++++--------- IDEHelper/Compiler/BfReducer.h | 2 +- IDEHelper/Tests/src/Structs.bf | 8 +++ 5 files changed, 127 insertions(+), 33 deletions(-) diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 9f3178c5..2debcda4 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -2120,7 +2120,7 @@ class BfInitializerExpression : public BfExpression public: BF_AST_TYPE(BfInitializerExpression, BfExpression); - BfExpression* mTarget; + BfAstNode* mTarget; BfTokenNode* mOpenBrace; BfSizedArray mValues; BfSizedArray mCommas; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 089c5979..944eb4db 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -9240,11 +9240,54 @@ void BfExprEvaluator::Visit(BfSizedArrayCreateExpression* createExpr) } void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) -{ - VisitChild(initExpr->mTarget); +{ + uint64 unassignedFieldFlags = 0; + + if (auto typeRef = BfNodeDynCast(initExpr->mTarget)) + { + BfType* type = NULL; + if (auto typeRef = BfNodeDynCast(initExpr->mTarget)) + { + type = mExpectingType; + } + if (type == NULL) + type = mModule->ResolveTypeRef(typeRef); + if (type != NULL) + { + if (type->IsValueType()) + { + if (mReceivingValue != NULL) + { + mResult = *mReceivingValue; + mReceivingValue = NULL; + } + else + { + mResult = BfTypedValue(mModule->CreateAlloca(type), type, true); + } + auto typeInstance = type->ToTypeInstance(); + if (typeInstance != NULL) + unassignedFieldFlags = (1 << typeInstance->mMergedFieldDataCount) - 1; + } + else + { + mModule->Fail("Initializer expressions can only be used on value types or allocated values", initExpr->mTarget); + } + } + } + else + VisitChild(initExpr->mTarget); if (!mResult) mResult = mModule->GetDefaultTypedValue(mModule->mContext->mBfObjectType); + BfIRBlock initBlock = BfIRBlock(); + if (unassignedFieldFlags != 0) + { + initBlock = mModule->mBfIRBuilder->CreateBlock("initStart", true); + mModule->mBfIRBuilder->CreateBr(initBlock); + mModule->mBfIRBuilder->SetInsertPoint(initBlock); + } + BfTypedValue initValue = GetResult(true); bool isFirstAdd = true; BfFunctionBindResult addFunctionBindResult; @@ -9261,10 +9304,21 @@ void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) { StringT<128> findName; identifierNode->ToString(findName); + mResultFieldInstance = NULL; fieldResult = LookupField(identifierNode, initValue, findName, BfLookupFieldFlag_IsImplicitThis); if ((fieldResult.mKind == BfTypedValueKind_TempAddr) || (fieldResult.mKind == BfTypedValueKind_RestrictedTempAddr)) fieldResult.mKind = BfTypedValueKind_Addr; + if ((mResultFieldInstance != NULL) && (mResultFieldInstance->mMergedDataIdx != -1)) + { + int resultLocalVarField = 0; + int resultLocalVarFieldCount = 0; + mResultFieldInstance->GetDataRange(resultLocalVarField, resultLocalVarFieldCount); + + for (int i = 0; i < resultLocalVarFieldCount; i++) + unassignedFieldFlags &= ~((int64)1 << (resultLocalVarField - 1 + i)); + } + wasValidInitKind = true; if ((fieldResult) || (mPropDef != NULL)) @@ -9341,6 +9395,15 @@ void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) } } + if (unassignedFieldFlags != 0) + { + auto curBlock = mModule->mBfIRBuilder->GetInsertBlock(); + mModule->mBfIRBuilder->SetInsertPointAtStart(initBlock); + mModule->mBfIRBuilder->CreateMemSet(initValue.mValue, mModule->GetConstValue(0, mModule->GetPrimitiveType(BfTypeCode_Int8)), + mModule->GetConstValue(initValue.mType->mSize), initValue.mType->mAlign); + mModule->mBfIRBuilder->SetInsertPoint(curBlock); + } + mResult = initValue; } diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index be2d4445..20aad098 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -1692,6 +1692,17 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat } }*/ } + else if (endNodeIdx != -1) + { + if (auto blockNode = BfNodeDynCast(mVisitorPos.Get(endNodeIdx))) + { + auto typeRef = CreateTypeRef(mVisitorPos.GetCurrent()); + if (typeRef) + { + exprLeft = TryCreateInitializerExpression(typeRef); + } + } + } } if (exprLeft == NULL) @@ -1917,43 +1928,55 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat } else if (token == BfToken_Dot) // Abbreviated dot syntax ".EnumVal" { - auto memberReferenceExpr = mAlloc->Alloc(); - ReplaceNode(tokenNode, memberReferenceExpr); - MEMBER_SET(memberReferenceExpr, mDotToken, tokenNode); - - bool handled = false; - if (auto nextToken = BfNodeDynCastExact(mVisitorPos.GetNext())) + // Initializer ".{ x = 1, y = 2 }" + if (auto blockNode = BfNodeDynCast(mVisitorPos.GetNext())) { - if (nextToken->GetToken() == BfToken_LParen) + auto typeRef = CreateTypeRef(mVisitorPos.GetCurrent()); + if (typeRef) { - // It's an unnamed dot ctor - handled = true; + exprLeft = TryCreateInitializerExpression(typeRef); } } - - if (!handled) + else { - auto memberName = ExpectIdentifierAfter(memberReferenceExpr); - if (memberName != NULL) + auto memberReferenceExpr = mAlloc->Alloc(); + ReplaceNode(tokenNode, memberReferenceExpr); + MEMBER_SET(memberReferenceExpr, mDotToken, tokenNode); + + bool handled = false; + if (auto nextToken = BfNodeDynCastExact(mVisitorPos.GetNext())) { - MEMBER_SET(memberReferenceExpr, mMemberName, memberName); + if (nextToken->GetToken() == BfToken_LParen) + { + // It's an unnamed dot ctor + handled = true; + } } - } - // We don't set exprLeft here because it's illegal to do ".EnumVal.SomethingElse". That wouldn't make - // sense because the abbreviated syntax relies on type inference and the ".SomethingElse" wouldn't be - // the right type (whatever it is), AND mostly importantly, it breaks autocomplete when we are typing - // "KEnum val = ." above a line that starts with a something like a method call "OtherThing.MethodCall()" - // The exception is if we're creating an enum val with a payload - //auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); - //if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_LParen)) - { - exprLeft = memberReferenceExpr; + if (!handled) + { + auto memberName = ExpectIdentifierAfter(memberReferenceExpr); + if (memberName != NULL) + { + MEMBER_SET(memberReferenceExpr, mMemberName, memberName); + } + } + // We don't set exprLeft here because it's illegal to do ".EnumVal.SomethingElse". That wouldn't make + // sense because the abbreviated syntax relies on type inference and the ".SomethingElse" wouldn't be + // the right type (whatever it is), AND mostly importantly, it breaks autocomplete when we are typing + // "KEnum val = ." above a line that starts with a something like a method call "OtherThing.MethodCall()" + // The exception is if we're creating an enum val with a payload + + //auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); + //if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_LParen)) + { + exprLeft = memberReferenceExpr; + } + /*else + { + return memberReferenceExpr; + }*/ } - /*else - { - return memberReferenceExpr; - }*/ } else if (token == BfToken_LBracket) { @@ -7072,7 +7095,7 @@ BfInvocationExpression* BfReducer::CreateInvocationExpression(BfAstNode* target, return invocationExpr; } -BfInitializerExpression* BfReducer::TryCreateInitializerExpression(BfExpression* target) +BfInitializerExpression* BfReducer::TryCreateInitializerExpression(BfAstNode* target) { auto block = BfNodeDynCast(mVisitorPos.GetNext()); if (block == NULL) diff --git a/IDEHelper/Compiler/BfReducer.h b/IDEHelper/Compiler/BfReducer.h index 7b9fafb6..e882a168 100644 --- a/IDEHelper/Compiler/BfReducer.h +++ b/IDEHelper/Compiler/BfReducer.h @@ -203,7 +203,7 @@ public: BfObjectCreateExpression* CreateObjectCreateExpression(BfAstNode* allocNode); BfScopedInvocationTarget* CreateScopedInvocationTarget(BfAstNode*& targetRef, BfTokenNode* colonToken); BfInvocationExpression* CreateInvocationExpression(BfAstNode* target, CreateExprFlags createExprFlags = CreateExprFlags_None); - BfInitializerExpression* TryCreateInitializerExpression(BfExpression* target); + BfInitializerExpression* TryCreateInitializerExpression(BfAstNode* target); BfExpression* CreateIndexerExpression(BfExpression* target); BfMemberReferenceExpression* CreateMemberReferenceExpression(BfAstNode* target); BfTupleExpression* CreateTupleExpression(BfTokenNode* newNode, BfExpression* innerExpr = NULL); diff --git a/IDEHelper/Tests/src/Structs.bf b/IDEHelper/Tests/src/Structs.bf index 4f5dd1da..a1b13b1c 100644 --- a/IDEHelper/Tests/src/Structs.bf +++ b/IDEHelper/Tests/src/Structs.bf @@ -134,6 +134,14 @@ namespace Tests sb1.mA = 1; sb1.mB = 2; Test.Assert(sb0 == sb1); + + sb0 = StructB { mA = 2 }; + Test.Assert(sb0.mA == 2); + Test.Assert(sb0.mB == 0); + + sb0 = .{ mA = 3, mB = 4 }; + Test.Assert(sb0.mA == 3); + Test.Assert(sb0.mB == 4); } [Test]