1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Named arguments

This commit is contained in:
Brian Fiete 2022-06-24 18:41:54 -07:00
parent d204922403
commit 79320652e3
15 changed files with 341 additions and 37 deletions

View file

@ -1017,6 +1017,77 @@ namespace IDE.ui
if (cursorSection >= textSections.Count - 1)
cursorSection = textSections.Count - 2;
if (cursorSection < mAutoComplete.mInvokeSrcPositions.Count)
{
var argText = mAutoComplete.mTargetEditWidget.mEditWidgetContent.ExtractString(mAutoComplete.mInvokeSrcPositions[cursorSection - 1],
mAutoComplete.mInvokeSrcPositions[cursorSection] - mAutoComplete.mInvokeSrcPositions[cursorSection - 1], .. scope .());
int colonPos = argText.IndexOf(':');
if (colonPos != -1)
{
do
{
bool foundSep = false;
int nameStart = -1;
for (int i = colonPos - 1; i >= 0; i--)
{
char8 c = argText[i];
if (nameStart == -1)
{
if ((c != '_') && (!c.IsLetterOrDigit))
nameStart = i + 1;
}
else
{
if (!c.IsWhiteSpace)
{
if ((!foundSep) &&
((c == ',') || (c == '(')))
foundSep = true;
else
break;
}
}
}
if (nameStart == -1)
break;
var argParamName = argText.Substring(nameStart, colonPos - nameStart);
for (int checkSectionIdx = 1; checkSectionIdx < textSections.Count; checkSectionIdx++)
{
var sectionStr = textSections[checkSectionIdx];
var checkParamName = sectionStr;
if (checkParamName.EndsWith(','))
checkParamName.RemoveFromEnd(1);
for (int checkIdx = checkParamName.Length - 1; checkIdx >= 0; checkIdx--)
{
char8 c = checkParamName[checkIdx];
if (c.IsWhiteSpace)
{
checkParamName.RemoveFromStart(checkIdx + 1);
break;
}
}
if (checkParamName == argParamName)
{
cursorSection = checkSectionIdx;
break;
}
}
}
}
/*if ((argText.StartsWith('(')) || (argText.StartsWith(',')))
argText.Remove(0, 1);
argText.Trim();
Debug.WriteLine($"ArgText: {argText}");*/
}
float paramX = 0;
for (int sectionIdx = 0; sectionIdx < textSections.Count; sectionIdx++)
{

View file

@ -141,6 +141,11 @@ void BfStructuralVisitor::Visit(BfExpressionStatement* exprStmt)
Visit(exprStmt->ToBase());
}
void BfStructuralVisitor::Visit(BfNamedExpression* namedExpr)
{
Visit(namedExpr->ToBase());
}
void BfStructuralVisitor::Visit(BfAttributedExpression* attribExpr)
{
Visit(attribExpr->ToBase());

View file

@ -278,6 +278,7 @@ class BfStatement;
class BfLabelableStatement;
class BfExpression;
class BfExpressionStatement;
class BfNamedExpression;
class BfAttributedExpression;
class BfAttributedStatement;
class BfLiteralExpression;
@ -447,6 +448,7 @@ public:
virtual void Visit(BfLabeledBlock* labeledBlock);
virtual void Visit(BfExpression* expr);
virtual void Visit(BfExpressionStatement* exprStmt);
virtual void Visit(BfNamedExpression* namedExpr);
virtual void Visit(BfAttributedExpression* attribExpr);
virtual void Visit(BfStatement* stmt);
virtual void Visit(BfAttributedStatement* attribStmt);
@ -2812,6 +2814,16 @@ public:
BfFieldDtorDeclaration* mDtor;
}; BF_AST_DECL(BfLambdaBindExpression, BfExpression);
class BfNamedExpression : public BfExpression
{
public:
BF_AST_TYPE(BfNamedExpression, BfExpression);
BfIdentifierNode* mNameNode;
BfTokenNode* mColonToken;
BfExpression* mExpression;
}; BF_AST_DECL(BfNamedExpression, BfExpression);
class BfAttributedExpression : public BfExpression
{
public:

View file

@ -13,6 +13,12 @@ BfDeferEvalChecker::BfDeferEvalChecker()
void BfDeferEvalChecker::Check(BfAstNode* node)
{
if (auto namedNode = BfNodeDynCastExact<BfNamedExpression>(node))
node = namedNode->mExpression;
if (node == NULL)
return;
SetAndRestoreValue<BfAstNode*> rootNode(mRootNode, node);
node->Accept(this);
}
@ -22,6 +28,11 @@ void BfDeferEvalChecker::Visit(BfAstNode* attribExpr)
mNeedsDeferEval = false;
}
void BfDeferEvalChecker::Visit(BfAttributedExpression* attributedExpr)
{
VisitChild(attributedExpr->mExpression);
}
void BfDeferEvalChecker::Visit(BfInitializerExpression* collectionInitExpr)
{
VisitChild(collectionInitExpr->mTarget);

View file

@ -19,8 +19,9 @@ public:
void Check(BfAstNode* node);
virtual void Visit(BfAstNode* node) override;
virtual void Visit(BfInitializerExpression* collectionInitExpr);
virtual void Visit(BfAttributedExpression* attributedExpr) override;
virtual void Visit(BfInitializerExpression* collectionInitExpr) override;
virtual void Visit(BfLiteralExpression* literalExpr) override;
virtual void Visit(BfCastExpression* castExpr) override;
virtual void Visit(BfParenthesizedExpression* parenExpr) override;

View file

@ -185,6 +185,15 @@ void BfElementVisitor::Visit(BfExpressionStatement* exprStmt)
VisitChild(exprStmt->mExpression);
}
void BfElementVisitor::Visit(BfNamedExpression* namedExpr)
{
Visit(namedExpr->ToBase());
VisitChild(namedExpr->mNameNode);
VisitChild(namedExpr->mColonToken);
VisitChild(namedExpr->mExpression);
}
void BfElementVisitor::Visit(BfAttributedExpression* attribExpr)
{
Visit(attribExpr->ToBase());

View file

@ -16,6 +16,7 @@ public:
virtual void Visit(BfLabeledBlock* labeledBlock);
virtual void Visit(BfExpression* expr);
virtual void Visit(BfExpressionStatement* exprStmt);
virtual void Visit(BfNamedExpression* namedExpr);
virtual void Visit(BfAttributedExpression* attribExpr);
virtual void Visit(BfStatement* stmt);
virtual void Visit(BfAttributedStatement* attribStmt);

View file

@ -173,6 +173,7 @@ void BfMethodMatcher::Init(const BfMethodGenericArguments& methodGenericArgument
mSelfType = NULL;
mMethodType = BfMethodType_Normal;
mCheckReturnType = NULL;
mHasArgNames = false;
mHadExplicitGenericArguments = false;
mHadOpenGenericArguments = methodGenericArguments.mIsOpen;
mHadPartialGenericArguments = methodGenericArguments.mIsPartial;
@ -206,6 +207,9 @@ void BfMethodMatcher::Init(const BfMethodGenericArguments& methodGenericArgument
mHasVarArguments = true;
}
}
if (arg.mNameNode != NULL)
mHasArgNames = true;
}
if (methodGenericArguments.mArguments != NULL)
@ -1644,7 +1648,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
// because on structs we know the exact type
if ((checkMethod->mIsOverride) && (!mBypassVirtual) && (!typeInstance->IsValueType()))
return false;
mMethodCheckCount++;
BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod);
@ -1741,6 +1745,40 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
goto NoMatch;
}
}
if (mHasArgNames)
{
checkMethod->BuildParamNameMap();
bool prevWasNull = false;
for (int argIdx = (int)mArguments.mSize - 1; argIdx >= 0; argIdx--)
{
auto& arg = mArguments[argIdx];
if (arg.mNameNode != NULL)
{
if (prevWasNull)
{
if (argIdx >= checkMethod->mParams.mSize)
goto NoMatch;
if (checkMethod->mParams[argIdx]->mName != arg.mNameNode->ToStringView())
goto NoMatch;
}
else
{
if (!checkMethod->mParamNameMap->ContainsKey(arg.mNameNode->ToStringView()))
goto NoMatch;
}
prevWasNull = false;
}
else
{
prevWasNull = true;
}
}
}
for (auto& checkGenericArgRef : mCheckMethodGenericArguments)
checkGenericArgRef = NULL;
@ -3364,6 +3402,12 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
mModule->FinishAttributeState(&attributeState);
}
void BfExprEvaluator::Visit(BfNamedExpression* namedExpr)
{
if (namedExpr->mExpression != NULL)
VisitChild(namedExpr->mExpression);
}
void BfExprEvaluator::Visit(BfBlock* blockExpr)
{
if (mModule->mCurMethodState == NULL)
@ -5753,6 +5797,12 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
bool handled = false;
bool evaluated = false;
if (auto namedExpression = BfNodeDynCastExact<BfNamedExpression>(argExpr))
{
resolvedArg.mNameNode = namedExpression->mNameNode;
argExpr = namedExpression->mExpression;
}
if (auto interpolateExpr = BfNodeDynCastExact<BfStringInterpolationExpression>(argExpr))
{
if ((interpolateExpr->mAllocNode == NULL) || ((flags & BfResolveArgsFlag_InsideStringInterpolationAlloc) != 0))
@ -7308,6 +7358,81 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
return mModule->GetDefaultTypedValue(returnType);
}
bool hasNamedArgs = false;
for (auto& arg : argValues)
if (arg.mNameNode != NULL)
hasNamedArgs = true;
if (hasNamedArgs)
{
methodDef->BuildParamNameMap();
BfIdentifierNode* outOfPlaceName = NULL;
int curParamIdx = 0;
SizedArrayImpl<BfResolvedArg> origArgValues = argValues;
argValues.Clear();
for (int argIdx = 0; argIdx < origArgValues.mSize; argIdx++)
{
int paramIdx = curParamIdx;
auto& argValue = origArgValues[argIdx];
if (argValue.mNameNode != NULL)
{
int namedParamIdx = -1;
if (methodDef->mParamNameMap->TryGetValue(argValue.mNameNode->ToStringView(), &namedParamIdx))
{
paramIdx = namedParamIdx;
}
else
{
if (mModule->PreFail())
{
mModule->Fail(StrFormat("The best overload for '%s' does not have a parameter named '%s'", methodInstance->mMethodDef->mName.c_str(),
argValue.mNameNode->ToString().c_str()), argValue.mNameNode);
}
}
if (paramIdx != curParamIdx)
outOfPlaceName = argValue.mNameNode;
}
else if (outOfPlaceName != NULL)
{
if (mModule->PreFail())
mModule->Fail(StrFormat("Named argument '%s' is used out-of-position but is followed by an unnamed argument", outOfPlaceName->ToString().c_str()), outOfPlaceName);
outOfPlaceName = NULL;
}
if ((paramIdx < methodInstance->GetParamCount()) && (paramIdx != argIdx))
{
if (methodInstance->GetParamKind(paramIdx) == BfParamKind_Normal)
{
auto wantType = methodInstance->GetParamType(paramIdx);
auto resolvedValue = ResolveArgValue(argValue, wantType);
if (resolvedValue)
{
argValue.mTypedValue = resolvedValue;
argValue.mArgFlags = (BfArgFlags)(argValue.mArgFlags | BfArgFlag_Finalized);
}
}
}
while (paramIdx >= argValues.mSize)
argValues.Add(BfResolvedArg());
if (argValues[paramIdx].mExpression != NULL)
{
if (argValue.mNameNode != NULL)
{
if (mModule->PreFail())
mModule->Fail(StrFormat("Named argument '%s' cannot be specified multiple times", argValue.mNameNode->ToString().c_str()), argValue.mNameNode);
}
}
argValues[paramIdx] = argValue;
curParamIdx++;
}
}
int argIdx = 0;
int paramIdx = 0;
@ -7608,7 +7733,11 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
mModule->Warn(BfWarning_BF4205_StringInterpolationParam, "Expanded string interpolation argument not used as 'params'. If string allocation was intended then consider adding a specifier such as 'scope'.", errorRef);
}
if ((arg == NULL) && (argValues[argExprIdx].mExpression != NULL))
// if ((arg == NULL) && (argValues[argExprIdx].mExpression != NULL))
// hadMissingArg = true;
if ((arg == NULL) && (!argValues[argExprIdx].mTypedValue))
hadMissingArg = true;
}
else
@ -7710,7 +7839,13 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
if (mModule->PreFail())
{
if (error == NULL)
error = mModule->Fail(StrFormat("Not enough parameters specified, expected %d more.", methodInstance->GetParamCount() - paramIdx), refNode);
{
if (hasNamedArgs)
error = mModule->Fail(StrFormat("There is no argument given that corresponds to the required formal parameter '%s' of '%s'.",
methodInstance->GetParamName(paramIdx).c_str(), mModule->MethodToString(methodInstance).c_str()), refNode);
else
error = mModule->Fail(StrFormat("Not enough parameters specified, expected %d more.", methodInstance->GetParamCount() - paramIdx), refNode);
}
if ((error != NULL) && (methodInstance->mMethodDef->mMethodDeclaration != NULL))
mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode());
}
@ -8439,6 +8574,9 @@ static int sInvocationIdx = 0;
BfTypedValue BfExprEvaluator::ResolveArgValue(BfResolvedArg& resolvedArg, BfType* wantType, BfTypedValue* receivingValue, BfParamKind paramKind, BfIdentifierNode* paramNameNode)
{
BfTypedValue argValue = resolvedArg.mTypedValue;
if ((resolvedArg.mArgFlags & BfArgFlag_Finalized) != 0)
return argValue;
if ((resolvedArg.mArgFlags & (BfArgFlag_DelegateBindAttempt | BfArgFlag_LambdaBindAttempt | BfArgFlag_UnqualifiedDotAttempt | BfArgFlag_DeferredEval)) != 0)
{
if ((!argValue) || (argValue.mValue.IsFake()) || (resolvedArg.mWantsRecalc))

View file

@ -22,7 +22,8 @@ enum BfArgFlags
BfArgFlag_StringInterpolateFormat = 0x800,
BfArgFlag_StringInterpolateArg = 0x1000,
BfArgFlag_Cascade = 0x2000,
BfArgFlag_Volatile = 0x8000
BfArgFlag_Volatile = 0x8000,
BfArgFlag_Finalized = 0x10000,
};
enum BfResolveArgsFlags
@ -58,6 +59,7 @@ class BfResolvedArg
public:
BfTypedValue mTypedValue;
BfTypedValue mUncastedTypedValue;
BfIdentifierNode* mNameNode;
BfType* mResolvedType;
BfAstNode* mExpression;
BfArgFlags mArgFlags;
@ -68,6 +70,7 @@ public:
public:
BfResolvedArg()
{
mNameNode = NULL;
mResolvedType = NULL;
mExpression = NULL;
mArgFlags = BfArgFlag_None;
@ -211,6 +214,7 @@ public:
BfType* mCheckReturnType;
BfMethodType mMethodType;
BfCheckedKind mCheckedKind;
bool mHasArgNames;
bool mHadExplicitGenericArguments;
bool mHadOpenGenericArguments;
bool mHadPartialGenericArguments;
@ -243,7 +247,7 @@ public:
BfTypeVector mBestMethodGenericArguments;
BfTypeVector mExplicitMethodGenericArguments;
bool mFakeConcreteTarget;
Array<BfAmbiguousEntry> mAmbiguousEntries;
Array<BfAmbiguousEntry> mAmbiguousEntries;
public:
BfTypedValue ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute, BfType *origCheckType = NULL, BfResolveArgFlags flags = BfResolveArgFlag_None);
@ -534,6 +538,7 @@ public:
virtual void Visit(BfErrorNode* errorNode) override;
virtual void Visit(BfTypeReference* typeRef) override;
virtual void Visit(BfAttributedExpression* attribExpr) override;
virtual void Visit(BfNamedExpression* namedExpr) override;
virtual void Visit(BfBlock* blockExpr) override;
virtual void Visit(BfVariableDeclaration* varDecl) override;
virtual void Visit(BfCaseExpression* caseExpr) override;

View file

@ -1033,6 +1033,16 @@ void BfPrinter::Visit(BfExpressionStatement* exprStmt)
VisitChild(exprStmt->mTrailingSemicolon);
}
void BfPrinter::Visit(BfNamedExpression* namedExpr)
{
Visit(namedExpr->ToBase());
VisitChild(namedExpr->mNameNode);
VisitChild(namedExpr->mColonToken);
ExpectSpace();
VisitChild(namedExpr->mExpression);
}
void BfPrinter::Visit(BfAttributedExpression* attribExpr)
{
Visit(attribExpr->ToBase());

View file

@ -128,6 +128,7 @@ public:
virtual void Visit(BfNewNode * newNode) override;
virtual void Visit(BfExpression* expr) override;
virtual void Visit(BfExpressionStatement* exprStmt) override;
virtual void Visit(BfNamedExpression* namedExpr) override;
virtual void Visit(BfAttributedExpression* attribExpr) override;
virtual void Visit(BfStatement* stmt) override;
virtual void Visit(BfLabelableStatement* labelableStmt) override;

View file

@ -5806,6 +5806,8 @@ BfTokenNode* BfReducer::ReadArguments(BfAstNode* parentNode, BfAstNode* afterNod
}
}
BfExpression* argumentExpr = NULL;
if (allowSkippedArgs)
{
auto nextNode = mVisitorPos.GetNext();
@ -5824,9 +5826,33 @@ BfTokenNode* BfReducer::ReadArguments(BfAstNode* parentNode, BfAstNode* afterNod
continue;
}
}
if (auto identifierNode = BfNodeDynCastExact<BfIdentifierNode>(nextNode))
{
if (auto nextNextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.Get(mVisitorPos.mReadPos + 2)))
{
if (nextNextToken->mToken == BfToken_Colon)
{
auto namedExpr = mAlloc->Alloc<BfNamedExpression>();
ReplaceNode(identifierNode, namedExpr);
MEMBER_SET(namedExpr, mNameNode, identifierNode);
MEMBER_SET(namedExpr, mColonToken, nextNextToken)
mVisitorPos.MoveNext();
mVisitorPos.MoveNext();
auto innerExpr = CreateExpressionAfter(namedExpr, CreateExprFlags_AllowVariableDecl);
if (innerExpr != NULL)
{
MEMBER_SET(namedExpr, mExpression, innerExpr);
}
argumentExpr = namedExpr;
}
}
}
}
auto argumentExpr = CreateExpressionAfter(afterNode, CreateExprFlags_AllowVariableDecl);
if (argumentExpr == NULL)
argumentExpr = CreateExpressionAfter(afterNode, CreateExprFlags_AllowVariableDecl);
if ((argumentExpr != NULL) || (endToken != BfToken_None))
arguments->push_back(argumentExpr);
if (argumentExpr == NULL)
@ -7409,32 +7435,6 @@ BfInvocationExpression* BfReducer::CreateInvocationExpression(BfAstNode* target,
{
if (nextToken->GetToken() == BfToken_Colon)
{
/*auto scopedInvocationTarget = mAlloc->Alloc<BfScopedInvocationTarget>();
ReplaceNode(invocationExpr->mTarget, scopedInvocationTarget);
scopedInvocationTarget->mTarget = invocationExpr->mTarget;
invocationExpr->mTarget = scopedInvocationTarget;
MEMBER_SET(scopedInvocationTarget, mColonToken, nextToken);
mVisitorPos.MoveNext();
if (auto nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
{
if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin))
{
MEMBER_SET(scopedInvocationTarget, mScopeName, nextToken);
mVisitorPos.MoveNext();
}
}
else if (auto identifier = BfNodeDynCast<BfIdentifierNode>(mVisitorPos.GetNext()))
{
MEMBER_SET(scopedInvocationTarget, mScopeName, identifier);
mVisitorPos.MoveNext();
}
if (scopedInvocationTarget->mScopeName == NULL)
{
FailAfter("Expected scope name", scopedInvocationTarget);
}*/
auto scopedInvocationTarget = CreateScopedInvocationTarget(invocationExpr->mTarget, nextToken);
invocationExpr->SetSrcEnd(scopedInvocationTarget->GetSrcEnd());
}

View file

@ -542,6 +542,7 @@ void BfMethodDef::FreeMembers()
for (auto genericParam : mGenericParams)
delete genericParam;
mGenericParams.Clear();
delete mParamNameMap;
}
BfMethodDeclaration* BfMethodDef::GetMethodDeclaration()
@ -660,6 +661,16 @@ int BfMethodDef::GetExplicitParamCount()
return (int)mParams.size();
}
void BfMethodDef::BuildParamNameMap()
{
if (mParamNameMap != NULL)
return;
mParamNameMap = new Dictionary<StringView, int>();
for (int i = 0; i < mParams.mSize; i++)
(*mParamNameMap)[mParams[i]->mName] = i;
}
///
void BfTypeDef::Reset()

View file

@ -873,6 +873,7 @@ public:
Array<BfParameterDef*> mParams;
Array<BfGenericParamDef*> mGenericParams;
Array<BfExternalConstraintDef> mExternalConstraints;
Dictionary<StringView, int>* mParamNameMap;
BfMethodDef* mNextWithSameName;
Val128 mFullHash;
@ -934,8 +935,8 @@ public:
mAddedAfterEmit = false;
mBody = NULL;
mExplicitInterface = NULL;
mReturnTypeRef = NULL;
mMethodDeclaration = NULL;
mReturnTypeRef = NULL;
mMethodDeclaration = NULL;
mCodeChanged = false;
mWantsBody = true;
mCommutableKind = BfCommutableKind_None;
@ -944,7 +945,8 @@ public:
mMethodType = BfMethodType_Normal;
mCallingConvention = BfCallingConvention_Unspecified;
mHasAppend = false;
mAlwaysInline = false;
mAlwaysInline = false;
mParamNameMap = NULL;
mNextWithSameName = NULL;
}
@ -965,6 +967,7 @@ public:
bool IsCtorOrInit();
String ToString();
int GetExplicitParamCount();
void BuildParamNameMap();
};
class BfOperatorDef : public BfMethodDef

View file

@ -182,6 +182,24 @@ namespace Tests
saPtr.mA += 1000;
}
static int Named(int p1, float p2, int p3)
{
return 10000 + p1*100 + (int)p2*10 + p3;
}
static int Named(int p0, int p1, float p2)
{
return 20000 + p0*100 + p1*10 + (.)p2;
}
static int Named(int p0=1, int p1=2, double p2=3)
{
return 30000 + p0*100 + p1*10 + (.)p2;
}
static int sIdx = 0;
static int GetNext() => ++sIdx;
[Test]
public static void TestBasics()
{
@ -239,6 +257,14 @@ namespace Tests
Test.Assert(sa4.mA == 400);
InStructA(sa4);
Test.Assert(sa4.mA == 1400);
Test.Assert(Named(1, 2, p3:3) == 10123);
Test.Assert(Named(p1: 1, 2, p3: 3) == 10123);
Test.Assert(Named(p0: 1, 2, 3) == 20123);
Test.Assert(Named(1, p1:2, 3) == 20123);
Test.Assert(Named(p3:GetNext(), p2:GetNext(), p1:GetNext()) == 10321);
Test.Assert(Named(p2:GetNext(), p1:GetNext(), p0:GetNext()) == 20654);
Test.Assert(Named(p1:9) == 30193);
}
}
}