From 229a5aa5c54f4d330b964ee0e4f03df960b2f5ea Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 18 Jun 2020 06:12:14 -0700 Subject: [PATCH] Initializer expressions --- IDEHelper/Compiler/BfAst.cpp | 5 ++ IDEHelper/Compiler/BfAst.h | 16 +++- IDEHelper/Compiler/BfDefBuilder.cpp | 6 +- IDEHelper/Compiler/BfElementVisitor.cpp | 13 +++ IDEHelper/Compiler/BfElementVisitor.h | 1 + IDEHelper/Compiler/BfExprEvaluator.cpp | 106 +++++++++++++++++++++++- IDEHelper/Compiler/BfExprEvaluator.h | 1 + IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfModule.h | 6 +- IDEHelper/Compiler/BfPrinter.cpp | 19 +++++ IDEHelper/Compiler/BfPrinter.h | 1 + IDEHelper/Compiler/BfReducer.cpp | 71 ++++++++++++++-- IDEHelper/Compiler/BfReducer.h | 1 + IDEHelper/Compiler/BfStmtEvaluator.cpp | 13 +-- IDEHelper/Tests/src/Initializers.bf | 44 ++++++++++ IDEHelper/Tests/src/Operators.bf | 9 ++ IDEHelper/Tests/src/Tuples.bf | 9 ++ 17 files changed, 305 insertions(+), 18 deletions(-) create mode 100644 IDEHelper/Tests/src/Initializers.bf diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index d6914842..294aca47 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -196,6 +196,11 @@ void BfStructuralVisitor::Visit(BfSizedArrayCreateExpression* createExpr) Visit(createExpr->ToBase()); } +void BfStructuralVisitor::Visit(BfInitializerExpression* initExpr) +{ + Visit(initExpr->ToBase()); +} + void BfStructuralVisitor::Visit(BfCollectionInitializerExpression* collectionInitExpr) { Visit(collectionInitExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 3bbff37c..36eba795 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -354,6 +354,7 @@ class BfStrideOfExpression; class BfDefaultExpression; class BfUninitializedExpression; class BfConditionalExpression; +class BfInitializerExpression; class BfCollectionInitializerExpression; class BfSizedArrayCreateExpression; class BfEmptyStatement; @@ -435,6 +436,7 @@ public: virtual void Visit(BfBaseExpression* baseExpr); virtual void Visit(BfMixinExpression* thisExpr); virtual void Visit(BfSizedArrayCreateExpression* createExpr); + virtual void Visit(BfInitializerExpression* collectionInitExpr); virtual void Visit(BfCollectionInitializerExpression* collectionInitExpr); virtual void Visit(BfTypeReference* typeRef); virtual void Visit(BfNamedTypeReference* typeRef); @@ -2017,6 +2019,18 @@ public: BfVariant mValue; }; BF_AST_DECL(BfLiteralExpression, BfExpression); +class BfInitializerExpression : public BfExpression +{ +public: + BF_AST_TYPE(BfInitializerExpression, BfExpression); + + BfExpression* mTarget; + BfTokenNode* mOpenBrace; + BfSizedArray mValues; + BfSizedArray mCommas; + BfTokenNode* mCloseBrace; +}; BF_AST_DECL(BfInitializerExpression, BfExpression); + class BfCollectionInitializerExpression : public BfExpression { public: @@ -2606,7 +2620,7 @@ public: BfTokenNode* mOpenToken; BfTokenNode* mCloseToken; BfSizedArray mArguments; - BfSizedArray mCommas; + BfSizedArray mCommas; }; BF_AST_DECL(BfObjectCreateExpression, BfMethodBoundExpression); class BfBoxExpression : public BfExpression diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index b8bd42dc..694d34d6 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -1920,9 +1920,13 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) if ((needsDefaultCtor) && (!hasDefaultCtor)) { + BfProtection prot = hasCtor ? BfProtection_Hidden : BfProtection_Public; + if (mCurTypeDef->mName == mSystem->mEmptyAtom) + prot = BfProtection_Hidden; + // Create default constructor. If it's the only constructor then make it public, // otherwise make it private so we can still internally use it but the user can't - auto methodDef = AddMethod(mCurTypeDef, BfMethodType_Ctor, hasCtor ? BfProtection_Hidden : BfProtection_Public, false, ""); + auto methodDef = AddMethod(mCurTypeDef, BfMethodType_Ctor, prot, false, ""); methodDef->mIsMutating = true; } diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index a49da055..38995d4b 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -244,6 +244,19 @@ void BfElementVisitor::Visit(BfSizedArrayCreateExpression* createExpr) VisitChild(createExpr->mInitializer); } +void BfElementVisitor::Visit(BfInitializerExpression* initExpr) +{ + Visit(initExpr->ToBase()); + + VisitChild(initExpr->mTarget); + VisitChild(initExpr->mOpenBrace); + for (auto& val : initExpr->mValues) + VisitChild(val); + for (auto& val : initExpr->mCommas) + VisitChild(val); + VisitChild(initExpr->mCloseBrace); +} + void BfElementVisitor::Visit(BfCollectionInitializerExpression* collectionInitExpr) { Visit(collectionInitExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfElementVisitor.h b/IDEHelper/Compiler/BfElementVisitor.h index 4d4a3dcf..badba377 100644 --- a/IDEHelper/Compiler/BfElementVisitor.h +++ b/IDEHelper/Compiler/BfElementVisitor.h @@ -43,6 +43,7 @@ public: virtual void Visit(BfBaseExpression* baseExpr); virtual void Visit(BfMixinExpression* thisExpr); virtual void Visit(BfSizedArrayCreateExpression* createExpr); + virtual void Visit(BfInitializerExpression* initExpr); virtual void Visit(BfCollectionInitializerExpression* collectionInitExpr); virtual void Visit(BfTypeReference* typeRef); virtual void Visit(BfNamedTypeReference* typeRef); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 663b9e06..9ac785f7 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -8433,6 +8433,111 @@ void BfExprEvaluator::Visit(BfSizedArrayCreateExpression* createExpr) InitializedSizedArray(arrayType, createExpr->mInitializer->mOpenBrace, createExpr->mInitializer->mValues, createExpr->mInitializer->mCommas, createExpr->mInitializer->mCloseBrace); } +void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) +{ + VisitChild(initExpr->mTarget); + if (!mResult) + mResult = mModule->GetDefaultTypedValue(mModule->mContext->mBfObjectType); + + BfTypedValue initValue = GetResult(true); + bool isFirstAdd = true; + BfFunctionBindResult addFunctionBindResult; + addFunctionBindResult.mWantsArgs = true; + + for (auto elementExpr : initExpr->mValues) + { + bool wasValidInitKind = false; + + if (auto assignExpr = BfNodeDynCast(elementExpr)) + { + BfTypedValue fieldResult; + if (auto identifierNode = BfNodeDynCast(assignExpr->mLeft)) + { + StringT<128> findName; + identifierNode->ToString(findName); + fieldResult = LookupField(identifierNode, initValue, findName, BfLookupFieldFlag_IsImplicitThis); + if (fieldResult.mKind == BfTypedValueKind_TempAddr) + fieldResult.mKind = BfTypedValueKind_Addr; + + wasValidInitKind = true; + + if ((fieldResult) || (mPropDef != NULL)) + { + mResult = fieldResult; + PerformAssignment(assignExpr, true, BfTypedValue()); + mResult = BfTypedValue(); + } + else + { + mModule->Fail(StrFormat("'%s' does not contain a definition for '%s'", mModule->TypeToString(initValue.mType).c_str(), + findName.c_str()), identifierNode); + } + } + } + else + { + auto autoComplete = GetAutoComplete(); + if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(elementExpr))) + { + if (auto identiferNode = BfNodeDynCast(elementExpr)) + { + auto typeInstance = initValue.mType->ToTypeInstance(); + if (typeInstance != NULL) + { + String filter; + identiferNode->ToString(filter); + autoComplete->AddTypeMembers(typeInstance, false, true, filter, typeInstance, false, true); + } + } + } + + bool wasFirstAdd = isFirstAdd; + if (isFirstAdd) + { + BfExprEvaluator exprEvaluator(mModule); + exprEvaluator.mFunctionBindResult = &addFunctionBindResult; + SizedArray argExprs; + argExprs.push_back(elementExpr); + BfSizedArray sizedArgExprs(argExprs); + BfResolvedArgs argValues(&sizedArgExprs); + exprEvaluator.ResolveArgValues(argValues); + exprEvaluator.MatchMethod(elementExpr, NULL, initValue, false, false, "Add", argValues, NULL); + + if (addFunctionBindResult.mMethodInstance != NULL) + CreateCall(addFunctionBindResult.mMethodInstance, addFunctionBindResult.mFunc, true, addFunctionBindResult.mIRArgs); + + isFirstAdd = false; + } + else if ((addFunctionBindResult.mMethodInstance == NULL) || (addFunctionBindResult.mMethodInstance->GetParamCount() == 0)) + { + mModule->CreateValueFromExpression(elementExpr); + } + else + { + auto argValue = mModule->CreateValueFromExpression(elementExpr, addFunctionBindResult.mMethodInstance->GetParamType(0)); + if ((argValue) && (!mModule->mBfIRBuilder->mIgnoreWrites)) + { + SizedArray irArgs; + PushThis(elementExpr, initValue, addFunctionBindResult.mMethodInstance, irArgs); + PushArg(argValue, irArgs); + for (int argIdx = (int)irArgs.size(); argIdx < (int)addFunctionBindResult.mIRArgs.size(); argIdx++) + irArgs.Add(addFunctionBindResult.mIRArgs[argIdx]); + CreateCall(addFunctionBindResult.mMethodInstance, addFunctionBindResult.mFunc, true, irArgs); + } + } + + wasValidInitKind = true; + } + + if (!wasValidInitKind) + { + mModule->Fail("Invalid initializer member declarator", initExpr); + } + } + + mResult = initValue; +} + void BfExprEvaluator::Visit(BfCollectionInitializerExpression* arrayInitExpr) { mModule->Fail("Collection initializer not usable here", arrayInitExpr); @@ -13369,7 +13474,6 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo } curMethodState->AddScope(&scopeData); curMethodState->mCurScope->mMixinDepth++; - curMethodState->mIsEmbedded = false; // We can't flush scope state because we extend params in as arbitrary values mModule->NewScopeState(true, false); diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index fa78bcb3..44045118 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -436,6 +436,7 @@ public: virtual void Visit(BfBaseExpression* baseExpr) override; virtual void Visit(BfMixinExpression* mixinExpr) override; virtual void Visit(BfSizedArrayCreateExpression* createExpr) override; + virtual void Visit(BfInitializerExpression* initExpr) override; virtual void Visit(BfCollectionInitializerExpression* initExpr) override; virtual void Visit(BfTypeOfExpression* typeOfExpr) override; virtual void Visit(BfSizeOfExpression* sizeOfExpr) override; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index d1445a0e..e39e30fd 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -1097,7 +1097,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen) // code as we walk the AST //mBfIRBuilder->mDbgVerifyCodeGen = true; if ( - (mModuleName == "-") + (mModuleName == "-") //|| (mModuleName == "Tests_FuncRefs_Class") //|| (mModuleName == "Tests_FuncRefs") ) diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 615976e3..6ecb4059 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -909,8 +909,7 @@ public: BfIRValue mDynStackRevIdx; // Increments when we restore the stack, which can invalidate dynSize for dynamic looped allocs BfIRBlock mIRExitBlock; BfBreakData* mBreakData; - int mBlockNestLevel; // 0 = top level - bool mIsEmbedded; // Is an embedded statement (ie: if () stmt) not wrapped in a block + int mBlockNestLevel; // 0 = top level bool mIgnoreObjectAccessCheck; bool mDisableChecks; BfMixinState* mMixinState; @@ -969,8 +968,7 @@ public: mBlockNestLevel = 0; mInPostReturn = false; mCrossingMixin = false; - mNoBind = false; - mIsEmbedded = false; + mNoBind = false; mIgnoreObjectAccessCheck = false; mDisableChecks = false; mInConditionalBlock = false; diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index c4d4fb52..1928b8b5 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -1206,6 +1206,25 @@ void BfPrinter::Visit(BfSizedArrayCreateExpression* createExpr) VisitChildWithPrecedingSpace(createExpr->mInitializer); } +void BfPrinter::Visit(BfInitializerExpression* initExpr) +{ + Visit(initExpr->ToBase()); + + VisitChild(initExpr->mTarget); + ExpectSpace(); + VisitChild(initExpr->mOpenBrace); + for (int i = 0; i < (int)initExpr->mValues.size(); i++) + { + if (i > 0) + { + VisitChild(initExpr->mCommas[i - 1]); + ExpectSpace(); + } + VisitChild(initExpr->mValues[i]); + } + VisitChild(initExpr->mCloseBrace); +} + void BfPrinter::Visit(BfCollectionInitializerExpression* initExpr) { Visit(initExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfPrinter.h b/IDEHelper/Compiler/BfPrinter.h index 89955378..c393b2ea 100644 --- a/IDEHelper/Compiler/BfPrinter.h +++ b/IDEHelper/Compiler/BfPrinter.h @@ -130,6 +130,7 @@ public: virtual void Visit(BfBaseExpression* baseExpr) override; virtual void Visit(BfMixinExpression* mixinExpr) override; virtual void Visit(BfSizedArrayCreateExpression* createExpr) override; + virtual void Visit(BfInitializerExpression* initExpr) override; virtual void Visit(BfCollectionInitializerExpression* initExpr) override; virtual void Visit(BfTypeReference* typeRef) override; virtual void Visit(BfNamedTypeReference* typeRef) override; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 8a2a8f61..82a7de18 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -1750,7 +1750,11 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat else if (isDelegateBind) exprLeft = CreateDelegateBindExpression(allocNode); else + { exprLeft = CreateObjectCreateExpression(allocNode); + if (auto initExpr = TryCreateInitializerExpression(exprLeft)) + exprLeft = initExpr; + } if (token == BfToken_Append) { @@ -2642,6 +2646,8 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat else if (token == BfToken_LParen) { exprLeft = CreateInvocationExpression(exprLeft, (CreateExprFlags)(createExprFlags & ~(CreateExprFlags_NoCast))); + if (auto initExpr = TryCreateInitializerExpression(exprLeft)) + exprLeft = initExpr; } else if ((token == BfToken_LBracket) || (token == BfToken_QuestionLBracket)) { @@ -6900,6 +6906,60 @@ BfInvocationExpression* BfReducer::CreateInvocationExpression(BfAstNode* target, return invocationExpr; } +BfInitializerExpression * BfReducer::TryCreateInitializerExpression(BfExpression* target) +{ + auto block = BfNodeDynCast(mVisitorPos.GetNext()); + if (block == NULL) + return NULL; + + mVisitorPos.MoveNext(); + + auto initializerExpr = mAlloc->Alloc(); + ReplaceNode(target, initializerExpr); + initializerExpr->mTarget = target; + MEMBER_SET(initializerExpr, mOpenBrace, block->mOpenBrace); + + SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); + + bool isDone = !mVisitorPos.MoveNext(); + + BfDeferredAstSizedArray values(initializerExpr->mValues, mAlloc); + BfDeferredAstSizedArray commas(initializerExpr->mCommas, mAlloc); + + BfAstNode* nextNode = NULL; + while (!isDone) + { + BfAstNode* node = mVisitorPos.GetCurrent(); + + auto expr = CreateExpression(node); + isDone = !mVisitorPos.MoveNext(); + if (expr != NULL) + values.Add(expr); + + if (!isDone) + { + bool foundComma = false; + + node = mVisitorPos.GetCurrent(); + if (auto tokenNode = BfNodeDynCast(node)) + { + if (tokenNode->mToken == BfToken_Comma) + { + foundComma = true; + commas.Add(tokenNode); + mVisitorPos.MoveNext(); + } + } + } + } + + mVisitorPos.Trim(); + + MEMBER_SET(initializerExpr, mCloseBrace, block->mCloseBrace); + + return initializerExpr; +} + BfDelegateBindExpression* BfReducer::CreateDelegateBindExpression(BfAstNode* allocNode) { auto delegateBindExpr = mAlloc->Alloc(); @@ -7402,7 +7462,7 @@ BfObjectCreateExpression* BfReducer::CreateObjectCreateExpression(BfAstNode* all if (tokenNode == NULL) return objectCreateExpr; MEMBER_SET(objectCreateExpr, mCloseToken, tokenNode); - + return objectCreateExpr; } @@ -8606,15 +8666,16 @@ BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImplmIgnoreWrites; - - SetAndRestoreValue prevEmbedded(mCurMethodState->mIsEmbedded, block == NULL); + mCurMethodState->mInHeadScope = false; BfScopeData scopeData; @@ -3122,7 +3121,14 @@ void BfModule::VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEval VisitCodeBlock(block); } else + { + if (auto varDecl = BfNodeDynCast(stmt)) + { + Fail("Variable declarations must be wrapped in a block statement", varDecl); + } + VisitChild(stmt); + } } if ((block != NULL) && (closeBrace != NULL)) @@ -3720,9 +3726,6 @@ void BfModule::Visit(BfVariableDeclaration* varDecl) UpdateSrcPos(varDecl); - if (mCurMethodState->mIsEmbedded) - Fail("Variable declarations must be wrapped in a block statement", varDecl); - BfTupleExpression* tupleVariableDeclaration = BfNodeDynCast(varDecl->mNameNode); if (tupleVariableDeclaration != NULL) { diff --git a/IDEHelper/Tests/src/Initializers.bf b/IDEHelper/Tests/src/Initializers.bf new file mode 100644 index 00000000..d9633706 --- /dev/null +++ b/IDEHelper/Tests/src/Initializers.bf @@ -0,0 +1,44 @@ +using System; + +namespace Tests +{ + class Initializers + { + struct StructA + { + public int mA = 123; + public int mB; + public int mC; + public int mD; + + public int ValC + { + set mut + { + mC = value; + } + } + + public void Add(float val, float? val2 = 234) mut + { + mD += (int)val; + mD += (int)val2 * 10; + } + + public void Add(int val) + { + Test.FatalError("Shouldn't be called"); + } + } + + [Test] + public static void TestBasics() + { + StructA sa = .() { mB = 345, ValC = 456, 567.8f, 789}; + Test.Assert(sa.mA == 123); + Test.Assert(sa.mB == 345); + Test.Assert(sa.mC == 456); + Test.Assert(sa.mD == 6036); + } + } +} diff --git a/IDEHelper/Tests/src/Operators.bf b/IDEHelper/Tests/src/Operators.bf index acc65ec1..44251b1b 100644 --- a/IDEHelper/Tests/src/Operators.bf +++ b/IDEHelper/Tests/src/Operators.bf @@ -263,12 +263,21 @@ namespace Tests const String cStr1 = "A" + "B"; const String cStr2 = cStr1 + "C" + cStrD; Test.Assert(cStr2 == "ABCD"); + Test.Assert(cStr2 === "ABCD"); const char8* cStr3 = "A" + "B"; const char8* cStr4 = cStr1 + "C" + cStrPD; Test.Assert(StringView(cStr4) == "ABCD"); TestDefaults(); + + String strA = scope String("ABCD"); + Test.Assert(strA == cStr2); + Test.Assert(strA !== cStr1); + + let strTup = (strA, strA); + Test.Assert(strTup == (cStr2, cStr2)); + Test.Assert(strTup !== (cStr2, cStr2)); } public static TTo Convert(TFrom val) where TTo : operator explicit TFrom diff --git a/IDEHelper/Tests/src/Tuples.bf b/IDEHelper/Tests/src/Tuples.bf index 43fc986b..fbee6169 100644 --- a/IDEHelper/Tests/src/Tuples.bf +++ b/IDEHelper/Tests/src/Tuples.bf @@ -6,6 +6,12 @@ namespace Tests { class Tuples { + public static void Add(ref (int32, float) val) + { + val.0 += 100; + val.1 += 200; + } + [Test] public static void TestBasic() { @@ -21,6 +27,9 @@ namespace Tests let v0 = tVal1.0; Test.Assert(v0 == 2); + + Add(ref tVal1); + Test.Assert(tVal1 == (a: 102, b: 203)); } class ValClass