Browse Source

Added auto-constructors (ie: 'struct Vec : this(float x, float y);')

Brian Fiete 4 years ago
parent
commit
9d1a5d9f3d

+ 8 - 0
IDEHelper/Compiler/BfAst.h

@@ -338,6 +338,7 @@ class BfMemberReferenceExpression;
 class BfDynamicCastExpression;
 class BfCheckTypeExpression;
 class BfConstructorDeclaration;
+class BfAutoConstructorDeclaration;
 class BfDestructorDeclaration;
 class BfQualifiedTypeReference;
 class BfUsingDirective;
@@ -2282,6 +2283,7 @@ public:
 	BfTokenNode* mTypeNode;
 	BfIdentifierNode* mNameNode;	
 	BfAstNode* mDefineNode;		
+	BfAutoConstructorDeclaration* mAutoCtor;
 	BfGenericParamsDeclaration* mGenericParams;
 	BfGenericConstraintsDeclaration* mGenericConstraintsDeclaration;
 	bool mIgnoreDeclaration;
@@ -2994,6 +2996,12 @@ public:
 	
 };	BF_AST_DECL(BfConstructorDeclaration, BfMethodDeclaration);
 
+class BfAutoConstructorDeclaration : public BfConstructorDeclaration
+{
+public:
+	BF_AST_TYPE(BfAutoConstructorDeclaration, BfConstructorDeclaration);
+};	BF_AST_DECL(BfAutoConstructorDeclaration, BfConstructorDeclaration);
+
 class BfDestructorDeclaration : public BfMethodDeclaration
 {
 public:	

+ 39 - 3
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -489,6 +489,13 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 			methodDef->mIsVirtual = true;		
 	}
 
+	bool isAutoCtor = false;
+	if (auto autoCtorDeclaration = BfNodeDynCast<BfAutoConstructorDeclaration>(methodDeclaration))
+	{
+		methodDef->mProtection = BfProtection_Public;
+		isAutoCtor = true;
+	}
+
 	if (auto ctorDeclaration = BfNodeDynCast<BfConstructorDeclaration>(methodDeclaration))
 	{
 		methodDef->mIsMutating = true;
@@ -645,8 +652,16 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 		paramDef->mMethodGenericParamIdx = mSystem->GetGenericParamIdx(methodDef->mGenericParams, paramDef->mTypeRef);
 		if (paramDecl->mModToken == NULL)
 			paramDef->mParamKind = BfParamKind_Normal;		
-		else //
+		else if (paramDecl->mModToken->mToken == BfToken_Params)
 			paramDef->mParamKind = BfParamKind_Params;
+		else if ((paramDecl->mModToken->mToken == BfToken_ReadOnly) && (isAutoCtor))
+		{
+			// Readonly specifier
+		}
+		else
+		{
+			Fail(StrFormat("Invalid use of '%s' specifier", BfTokenToString(paramDecl->mModToken->mToken)), paramDecl->mModToken);
+		}
 
 		if ((mCurTypeDef->mIsFunction) && (paramIdx == 0) && (paramDef->mName == "this"))
 		{
@@ -707,6 +722,23 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 		}
 	}
 
+	if (isAutoCtor)
+	{
+		for (auto paramDef : methodDef->mParams)
+		{
+			auto fieldDef = new BfFieldDef();
+			fieldDef->mName = paramDef->mName;
+			fieldDef->mTypeRef = paramDef->mTypeRef;
+			fieldDef->mProtection = BfProtection_Public;
+			fieldDef->mDeclaringType = mCurTypeDef;
+			fieldDef->mIdx = mCurTypeDef->mFields.mSize;
+			if ((paramDef->mParamDeclaration->mModToken != NULL) &&
+				(paramDef->mParamDeclaration->mModToken->mToken == BfToken_ReadOnly))
+				fieldDef->mIsReadOnly = true;
+			mCurTypeDef->mFields.Add(fieldDef);
+		}
+	}
+
 	ParseAttributes(methodDeclaration->mAttributes, methodDef);	
 	return methodDef;
 }
@@ -1819,6 +1851,9 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 		}
 	}
 	
+	if (typeDeclaration->mAutoCtor != NULL)
+		VisitChildNoRef(typeDeclaration->mAutoCtor);
+
 	if (auto defineBlock = BfNodeDynCast<BfBlock>(typeDeclaration->mDefineNode))
 	{
 		for (auto& member : *defineBlock)
@@ -1829,8 +1864,9 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 	else if (auto defineTokenNode = BfNodeDynCast<BfTokenNode>(typeDeclaration->mDefineNode))
 	{
 		if (defineTokenNode->GetToken() == BfToken_Semicolon)
-		{
-			mCurTypeDef->mIsOpaque = true;
+		{	
+			if (typeDeclaration->mAutoCtor == NULL)
+				mCurTypeDef->mIsOpaque = true;
 		}
 	}
 

+ 1 - 0
IDEHelper/Compiler/BfElementVisitor.cpp

@@ -1147,6 +1147,7 @@ void BfElementVisitor::Visit(BfTypeDeclaration* typeDeclaration)
 	VisitChild(typeDeclaration->mTypeNode);
 	VisitChild(typeDeclaration->mNameNode);
 	VisitChild(typeDeclaration->mColonToken);
+	VisitChild(typeDeclaration->mAutoCtor);
 	for (auto& baseClass : typeDeclaration->mBaseClasses)
 		VisitChild(baseClass);
 	for (auto& comma : typeDeclaration->mBaseClassCommas)

+ 41 - 4
IDEHelper/Compiler/BfModule.cpp

@@ -3876,7 +3876,7 @@ void BfModule::ResolveConstField(BfTypeInstance* typeInstance, BfFieldInstance*
 
 BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfFieldDef* field)
 {	
-	bool isDeclType = BfNodeDynCastExact<BfDeclTypeRef>(field->mFieldDeclaration->mTypeRef) != NULL;
+	bool isDeclType = (field->mFieldDeclaration != NULL) && BfNodeDynCastExact<BfDeclTypeRef>(field->mFieldDeclaration->mTypeRef) != NULL;
 
 	auto fieldType = fieldInstance->GetResolvedType();
 	if ((field->mIsConst) && (!isDeclType))
@@ -16155,7 +16155,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
 			}
 
 			EmitInitBlocks(_CheckInitBlock);
-
+			
 			if (hadInlineInitBlock)
 			{
 				RestoreScopeState();
@@ -16229,6 +16229,34 @@ void BfModule::EmitCtorBody(bool& skipBody)
 		}		
 	}
 
+	if (!methodInstance->mIsAutocompleteMethod)
+	{
+		if (auto autoDecl = BfNodeDynCast<BfAutoConstructorDeclaration>(methodDeclaration))
+		{
+			BfExprEvaluator exprEvaluator(this);
+			for (int paramIdx = 0; paramIdx < methodDef->mParams.mSize; paramIdx++)
+			{
+				auto paramDef = methodDef->mParams[paramIdx];
+				auto& fieldInstance = mCurTypeInstance->mFieldInstances[paramIdx];
+				BF_ASSERT(paramDef->mName == fieldInstance.GetFieldDef()->mName);
+				if (fieldInstance.mDataIdx < 0)
+					continue;
+
+				auto localVar = mCurMethodState->mLocals[paramIdx + 1];
+				BF_ASSERT(localVar->mName == paramDef->mName);
+				auto localVal = exprEvaluator.LoadLocal(localVar);
+
+				if (paramDef->mParamKind != BfParamKind_Normal)
+					continue;
+
+				auto thisVal = GetThis();
+				auto fieldPtr = mBfIRBuilder->CreateInBoundsGEP(thisVal.mValue, 0, fieldInstance.mDataIdx);
+				mBfIRBuilder->CreateAlignedStore(localVar->mValue, fieldPtr, localVar->mResolvedType->mAlign);
+				MarkFieldInitialized(&fieldInstance);
+			}
+		}
+	}
+
 	// Call base ctor (if applicable)
 	BfTypeInstance* targetType = NULL;		
 	BfAstNode* targetRefNode = NULL;
@@ -19521,7 +19549,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 
 	for (auto localVar : mCurMethodState->mLocals)
 	{
-		if ((skipEndChecks) || (methodDef->mBody == NULL))
+		if (auto autoCtorDecl = BfNodeDynCast<BfAutoConstructorDeclaration>(methodDeclaration))
+		{
+			//
+		}
+		else if ((skipEndChecks) || (methodDef->mBody == NULL))
 			break;
 		LocalVariableDone(localVar, true);
 	}
@@ -21751,7 +21783,12 @@ genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var);
 	{
 		if (methodDeclaration->mEndSemicolon == NULL)
 		{
-			AssertParseErrorState();
+			if (auto autoCtorDecl = BfNodeDynCast<BfAutoConstructorDeclaration>(methodDeclaration))
+			{
+				// 
+			}
+			else
+				AssertParseErrorState();
 		}
 		else
 		{

+ 1 - 0
IDEHelper/Compiler/BfPrinter.cpp

@@ -2758,6 +2758,7 @@ void BfPrinter::Visit(BfTypeDeclaration* typeDeclaration)
 	ExpectSpace();
 	QueueVisitChild(typeDeclaration->mNameNode);
 	QueueVisitChild(typeDeclaration->mGenericParams);
+	QueueVisitChild(typeDeclaration->mAutoCtor);
 	if (typeDeclaration->mColonToken != NULL)
 	{
 		ExpectSpace();

+ 39 - 2
IDEHelper/Compiler/BfReducer.cpp

@@ -8420,6 +8420,14 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 
 				if (baseTypeIdx > 0)
 				{
+					if (auto tokenNode = BfNodeDynCast<BfTokenNode>(nextNode))
+					{
+						if (tokenNode->mToken == BfToken_Semicolon)
+						{
+							break;
+						}
+					}
+
 					BfTokenNode* commaToken = NULL;
 					if (typeDeclaration->mGenericParams != NULL)
 					{
@@ -8438,6 +8446,32 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 					baseClassCommas.push_back(commaToken);
 				}
 
+				if (auto tokenNode = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
+				{
+					if (tokenNode->mToken == BfToken_This)
+					{
+						mVisitorPos.MoveNext();												
+						auto ctorDecl = mAlloc->Alloc<BfAutoConstructorDeclaration>();
+						BfDeferredAstSizedArray<BfParameterDeclaration*> params(ctorDecl->mParams, mAlloc);
+						BfDeferredAstSizedArray<BfTokenNode*> commas(ctorDecl->mCommas, mAlloc);
+						ctorDecl->mReturnType = NULL;
+						ReplaceNode(tokenNode, ctorDecl);
+						MEMBER_SET(ctorDecl, mThisToken, tokenNode);						
+						ParseMethod(ctorDecl, &params, &commas);
+						
+						if (typeDeclaration->mAutoCtor == NULL)
+						{
+							MEMBER_SET(typeDeclaration, mAutoCtor, ctorDecl);
+						}
+						else
+						{
+							Fail("Only one auto-constructor is allowed", ctorDecl);
+							AddErrorNode(ctorDecl);
+						}
+						continue;
+					}
+				}
+
 				auto baseType = CreateTypeRefAfter(typeDeclaration);
 				if (baseType == NULL)
 					break;
@@ -8879,7 +8913,7 @@ BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImpl<BfPara
 				(token == BfToken_Delegate) || (token == BfToken_Function) ||
 				(token == BfToken_Params) || (token == BfToken_LParen) ||
 				(token == BfToken_Var) || (token == BfToken_LBracket) ||
-				(token == BfToken_DotDotDot)))
+				(token == BfToken_ReadOnly) || (token == BfToken_DotDotDot)))
 			{
 				// These get picked up below
 			}
@@ -8938,7 +8972,7 @@ BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImpl<BfPara
 			}
 			else
 			{
-				if ((token != BfToken_Out) && (token != BfToken_Ref) && (token != BfToken_Mut) && (token != BfToken_Params))
+				if ((token != BfToken_Out) && (token != BfToken_Ref) && (token != BfToken_Mut) && (token != BfToken_Params) && (token != BfToken_ReadOnly))
 				{
 					Fail("Invalid token", tokenNode);
 					return NULL;
@@ -9341,6 +9375,9 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm
 		endToken = NULL;
 	}
 
+	if (auto autoCtorDecl = BfNodeDynCast<BfAutoConstructorDeclaration>(ctorDecl))
+		return true;
+
 	if ((endToken != NULL) && (endToken->GetToken() == BfToken_Semicolon))
 	{
 		MEMBER_SET_CHECKED_BOOL(methodDeclaration, mEndSemicolon, endToken);

+ 26 - 0
IDEHelper/Tests/src/Structs.bf

@@ -124,6 +124,17 @@ namespace Tests
 			Dictionary<int, StructK> dict;
 		}
 
+		struct StructL : this(int a, int b);
+
+		struct StructM : this(readonly int a, readonly int b)
+		{
+			public int c;
+			this
+			{
+				c = 100;
+			}
+		}
+
 		[Test]
 		static void TestBasics()
 		{
@@ -142,6 +153,21 @@ namespace Tests
 			sb0 = .{ mA = 3, mB = 4 };
 			Test.Assert(sb0.mA == 3);
 			Test.Assert(sb0.mB == 4);
+
+			StructL sl = .(12, 23);
+			Test.Assert(sl.a == 12);
+			Test.Assert(sl.b == 23);
+
+			StructM sm = .(12, 23);
+			[IgnoreErrors]
+			{
+				sm.a += 100;
+				sm.b += 100;
+				sm.c += 100;
+			}
+			Test.Assert(sm.a == 12);
+			Test.Assert(sm.b == 23);
+			Test.Assert(sm.c == 200);
 		}
 
 		[Test]