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:
parent
ae0f3c5ebb
commit
9d1a5d9f3d
7 changed files with 155 additions and 9 deletions
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -2758,6 +2758,7 @@ void BfPrinter::Visit(BfTypeDeclaration* typeDeclaration)
|
|||
ExpectSpace();
|
||||
QueueVisitChild(typeDeclaration->mNameNode);
|
||||
QueueVisitChild(typeDeclaration->mGenericParams);
|
||||
QueueVisitChild(typeDeclaration->mAutoCtor);
|
||||
if (typeDeclaration->mColonToken != NULL)
|
||||
{
|
||||
ExpectSpace();
|
||||
|
|
|
@ -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, ¶ms, &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);
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue