diff --git a/IDE/src/ui/AutoComplete.bf b/IDE/src/ui/AutoComplete.bf index 1c4122fc..bdfcb871 100644 --- a/IDE/src/ui/AutoComplete.bf +++ b/IDE/src/ui/AutoComplete.bf @@ -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++) { diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index 299ff4d8..bc0772fd 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -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()); diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 94538ed0..b9c528fb 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -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: diff --git a/IDEHelper/Compiler/BfDeferEvalChecker.cpp b/IDEHelper/Compiler/BfDeferEvalChecker.cpp index aa4b6f72..6a53b437 100644 --- a/IDEHelper/Compiler/BfDeferEvalChecker.cpp +++ b/IDEHelper/Compiler/BfDeferEvalChecker.cpp @@ -13,6 +13,12 @@ BfDeferEvalChecker::BfDeferEvalChecker() void BfDeferEvalChecker::Check(BfAstNode* node) { + if (auto namedNode = BfNodeDynCastExact(node)) + node = namedNode->mExpression; + + if (node == NULL) + return; + SetAndRestoreValue 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); diff --git a/IDEHelper/Compiler/BfDeferEvalChecker.h b/IDEHelper/Compiler/BfDeferEvalChecker.h index 5492ab28..05877119 100644 --- a/IDEHelper/Compiler/BfDeferEvalChecker.h +++ b/IDEHelper/Compiler/BfDeferEvalChecker.h @@ -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; diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index c5ad402b..bd088c9b 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -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()); diff --git a/IDEHelper/Compiler/BfElementVisitor.h b/IDEHelper/Compiler/BfElementVisitor.h index 4d08b799..992a5b88 100644 --- a/IDEHelper/Compiler/BfElementVisitor.h +++ b/IDEHelper/Compiler/BfElementVisitor.h @@ -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); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 4accd037..90633939 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -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(argExpr)) + { + resolvedArg.mNameNode = namedExpression->mNameNode; + argExpr = namedExpression->mExpression; + } + if (auto interpolateExpr = BfNodeDynCastExact(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 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)) diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 95b49914..12492037 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -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 mAmbiguousEntries; + Array 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; diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index 03368a79..fd82179f 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -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()); diff --git a/IDEHelper/Compiler/BfPrinter.h b/IDEHelper/Compiler/BfPrinter.h index 7601e6f1..31122775 100644 --- a/IDEHelper/Compiler/BfPrinter.h +++ b/IDEHelper/Compiler/BfPrinter.h @@ -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; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 788d1ea9..ec1f9ee9 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -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(nextNode)) + { + if (auto nextNextToken = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2))) + { + if (nextNextToken->mToken == BfToken_Colon) + { + auto namedExpr = mAlloc->Alloc(); + 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(); - ReplaceNode(invocationExpr->mTarget, scopedInvocationTarget); - scopedInvocationTarget->mTarget = invocationExpr->mTarget; - invocationExpr->mTarget = scopedInvocationTarget; - MEMBER_SET(scopedInvocationTarget, mColonToken, nextToken); - - mVisitorPos.MoveNext(); - if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) - { - if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin)) - { - MEMBER_SET(scopedInvocationTarget, mScopeName, nextToken); - mVisitorPos.MoveNext(); - } - } - else if (auto identifier = BfNodeDynCast(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()); } diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 365dd36c..28bd3b48 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -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(); + for (int i = 0; i < mParams.mSize; i++) + (*mParamNameMap)[mParams[i]->mName] = i; +} + /// void BfTypeDef::Reset() diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index f3240700..ee2b7f3a 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -873,6 +873,7 @@ public: Array mParams; Array mGenericParams; Array mExternalConstraints; + Dictionary* 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 diff --git a/IDEHelper/Tests/src/MethodCalls.bf b/IDEHelper/Tests/src/MethodCalls.bf index ac895b1e..e48e3886 100644 --- a/IDEHelper/Tests/src/MethodCalls.bf +++ b/IDEHelper/Tests/src/MethodCalls.bf @@ -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); } } }