1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

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

This commit is contained in:
Brian Fiete 2021-01-02 12:54:05 -08:00
parent ae0f3c5ebb
commit 9d1a5d9f3d
7 changed files with 155 additions and 9 deletions

View file

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

View file

@ -489,6 +489,13 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
methodDef->mIsVirtual = true; methodDef->mIsVirtual = true;
} }
bool isAutoCtor = false;
if (auto autoCtorDeclaration = BfNodeDynCast<BfAutoConstructorDeclaration>(methodDeclaration))
{
methodDef->mProtection = BfProtection_Public;
isAutoCtor = true;
}
if (auto ctorDeclaration = BfNodeDynCast<BfConstructorDeclaration>(methodDeclaration)) if (auto ctorDeclaration = BfNodeDynCast<BfConstructorDeclaration>(methodDeclaration))
{ {
methodDef->mIsMutating = true; methodDef->mIsMutating = true;
@ -645,8 +652,16 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
paramDef->mMethodGenericParamIdx = mSystem->GetGenericParamIdx(methodDef->mGenericParams, paramDef->mTypeRef); paramDef->mMethodGenericParamIdx = mSystem->GetGenericParamIdx(methodDef->mGenericParams, paramDef->mTypeRef);
if (paramDecl->mModToken == NULL) if (paramDecl->mModToken == NULL)
paramDef->mParamKind = BfParamKind_Normal; paramDef->mParamKind = BfParamKind_Normal;
else // else if (paramDecl->mModToken->mToken == BfToken_Params)
paramDef->mParamKind = BfParamKind_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")) 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); ParseAttributes(methodDeclaration->mAttributes, methodDef);
return 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)) if (auto defineBlock = BfNodeDynCast<BfBlock>(typeDeclaration->mDefineNode))
{ {
for (auto& member : *defineBlock) for (auto& member : *defineBlock)
@ -1829,8 +1864,9 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
else if (auto defineTokenNode = BfNodeDynCast<BfTokenNode>(typeDeclaration->mDefineNode)) else if (auto defineTokenNode = BfNodeDynCast<BfTokenNode>(typeDeclaration->mDefineNode))
{ {
if (defineTokenNode->GetToken() == BfToken_Semicolon) if (defineTokenNode->GetToken() == BfToken_Semicolon)
{ {
mCurTypeDef->mIsOpaque = true; if (typeDeclaration->mAutoCtor == NULL)
mCurTypeDef->mIsOpaque = true;
} }
} }

View file

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

View file

@ -3876,7 +3876,7 @@ void BfModule::ResolveConstField(BfTypeInstance* typeInstance, BfFieldInstance*
BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfFieldDef* field) 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(); auto fieldType = fieldInstance->GetResolvedType();
if ((field->mIsConst) && (!isDeclType)) if ((field->mIsConst) && (!isDeclType))
@ -16155,7 +16155,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
} }
EmitInitBlocks(_CheckInitBlock); EmitInitBlocks(_CheckInitBlock);
if (hadInlineInitBlock) if (hadInlineInitBlock)
{ {
RestoreScopeState(); 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) // Call base ctor (if applicable)
BfTypeInstance* targetType = NULL; BfTypeInstance* targetType = NULL;
BfAstNode* targetRefNode = NULL; BfAstNode* targetRefNode = NULL;
@ -19521,7 +19549,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
for (auto localVar : mCurMethodState->mLocals) for (auto localVar : mCurMethodState->mLocals)
{ {
if ((skipEndChecks) || (methodDef->mBody == NULL)) if (auto autoCtorDecl = BfNodeDynCast<BfAutoConstructorDeclaration>(methodDeclaration))
{
//
}
else if ((skipEndChecks) || (methodDef->mBody == NULL))
break; break;
LocalVariableDone(localVar, true); LocalVariableDone(localVar, true);
} }
@ -21751,7 +21783,12 @@ genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var);
{ {
if (methodDeclaration->mEndSemicolon == NULL) if (methodDeclaration->mEndSemicolon == NULL)
{ {
AssertParseErrorState(); if (auto autoCtorDecl = BfNodeDynCast<BfAutoConstructorDeclaration>(methodDeclaration))
{
//
}
else
AssertParseErrorState();
} }
else else
{ {

View file

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

View file

@ -8420,6 +8420,14 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
if (baseTypeIdx > 0) if (baseTypeIdx > 0)
{ {
if (auto tokenNode = BfNodeDynCast<BfTokenNode>(nextNode))
{
if (tokenNode->mToken == BfToken_Semicolon)
{
break;
}
}
BfTokenNode* commaToken = NULL; BfTokenNode* commaToken = NULL;
if (typeDeclaration->mGenericParams != NULL) if (typeDeclaration->mGenericParams != NULL)
{ {
@ -8438,6 +8446,32 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
baseClassCommas.push_back(commaToken); 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); auto baseType = CreateTypeRefAfter(typeDeclaration);
if (baseType == NULL) if (baseType == NULL)
break; break;
@ -8879,7 +8913,7 @@ BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImpl<BfPara
(token == BfToken_Delegate) || (token == BfToken_Function) || (token == BfToken_Delegate) || (token == BfToken_Function) ||
(token == BfToken_Params) || (token == BfToken_LParen) || (token == BfToken_Params) || (token == BfToken_LParen) ||
(token == BfToken_Var) || (token == BfToken_LBracket) || (token == BfToken_Var) || (token == BfToken_LBracket) ||
(token == BfToken_DotDotDot))) (token == BfToken_ReadOnly) || (token == BfToken_DotDotDot)))
{ {
// These get picked up below // These get picked up below
} }
@ -8938,7 +8972,7 @@ BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImpl<BfPara
} }
else 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); Fail("Invalid token", tokenNode);
return NULL; return NULL;
@ -9341,6 +9375,9 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm
endToken = NULL; endToken = NULL;
} }
if (auto autoCtorDecl = BfNodeDynCast<BfAutoConstructorDeclaration>(ctorDecl))
return true;
if ((endToken != NULL) && (endToken->GetToken() == BfToken_Semicolon)) if ((endToken != NULL) && (endToken->GetToken() == BfToken_Semicolon))
{ {
MEMBER_SET_CHECKED_BOOL(methodDeclaration, mEndSemicolon, endToken); MEMBER_SET_CHECKED_BOOL(methodDeclaration, mEndSemicolon, endToken);

View file

@ -124,6 +124,17 @@ namespace Tests
Dictionary<int, StructK> dict; 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] [Test]
static void TestBasics() static void TestBasics()
{ {
@ -142,6 +153,21 @@ namespace Tests
sb0 = .{ mA = 3, mB = 4 }; sb0 = .{ mA = 3, mB = 4 };
Test.Assert(sb0.mA == 3); Test.Assert(sb0.mA == 3);
Test.Assert(sb0.mB == 4); 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] [Test]