mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 20:12:21 +02:00
String interpolation
This commit is contained in:
parent
22cc81862b
commit
281f19e04c
15 changed files with 379 additions and 59 deletions
|
@ -166,6 +166,11 @@ void BfStructuralVisitor::Visit(BfLiteralExpression* literalExpr)
|
||||||
Visit(literalExpr->ToBase());
|
Visit(literalExpr->ToBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BfStructuralVisitor::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
|
||||||
|
{
|
||||||
|
Visit(stringInterpolationExpression->ToBase());
|
||||||
|
}
|
||||||
|
|
||||||
void BfStructuralVisitor::Visit(BfIdentifierNode* identifierNode)
|
void BfStructuralVisitor::Visit(BfIdentifierNode* identifierNode)
|
||||||
{
|
{
|
||||||
Visit(identifierNode->ToBase());
|
Visit(identifierNode->ToBase());
|
||||||
|
|
|
@ -261,6 +261,7 @@ class BfExpressionStatement;
|
||||||
class BfAttributedExpression;
|
class BfAttributedExpression;
|
||||||
class BfAttributedStatement;
|
class BfAttributedStatement;
|
||||||
class BfLiteralExpression;
|
class BfLiteralExpression;
|
||||||
|
class BfStringInterpolationExpression;
|
||||||
class BfBlock;
|
class BfBlock;
|
||||||
class BfBlockExtension;
|
class BfBlockExtension;
|
||||||
class BfRootNode;
|
class BfRootNode;
|
||||||
|
@ -443,6 +444,7 @@ public:
|
||||||
virtual void Visit(BfTokenNode* tokenNode);
|
virtual void Visit(BfTokenNode* tokenNode);
|
||||||
virtual void Visit(BfTokenPairNode* tokenPairNode);
|
virtual void Visit(BfTokenPairNode* tokenPairNode);
|
||||||
virtual void Visit(BfLiteralExpression* literalExpr);
|
virtual void Visit(BfLiteralExpression* literalExpr);
|
||||||
|
virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression);
|
||||||
virtual void Visit(BfIdentifierNode* identifierNode);
|
virtual void Visit(BfIdentifierNode* identifierNode);
|
||||||
virtual void Visit(BfAttributedIdentifierNode* attrIdentifierNode);
|
virtual void Visit(BfAttributedIdentifierNode* attrIdentifierNode);
|
||||||
virtual void Visit(BfQualifiedNameNode* nameNode);
|
virtual void Visit(BfQualifiedNameNode* nameNode);
|
||||||
|
@ -2099,6 +2101,16 @@ public:
|
||||||
BfVariant mValue;
|
BfVariant mValue;
|
||||||
}; BF_AST_DECL(BfLiteralExpression, BfExpression);
|
}; BF_AST_DECL(BfLiteralExpression, BfExpression);
|
||||||
|
|
||||||
|
class BfStringInterpolationExpression : public BfExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BF_AST_TYPE(BfStringInterpolationExpression, BfExpression);
|
||||||
|
|
||||||
|
BfAstNode* mAllocNode;
|
||||||
|
String* mString;
|
||||||
|
BfSizedArray<ASTREF(BfBlock*)> mExpressions;
|
||||||
|
}; BF_AST_DECL(BfStringInterpolationExpression, BfExpression);
|
||||||
|
|
||||||
class BfInitializerExpression : public BfExpression
|
class BfInitializerExpression : public BfExpression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -208,6 +208,16 @@ void BfElementVisitor::Visit(BfLiteralExpression* literalExpr)
|
||||||
Visit(literalExpr->ToBase());
|
Visit(literalExpr->ToBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BfElementVisitor::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
|
||||||
|
{
|
||||||
|
Visit(stringInterpolationExpression->ToBase());
|
||||||
|
VisitChild(stringInterpolationExpression->mAllocNode);
|
||||||
|
for (auto block : stringInterpolationExpression->mExpressions)
|
||||||
|
{
|
||||||
|
VisitChild(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BfElementVisitor::Visit(BfIdentifierNode* identifierNode)
|
void BfElementVisitor::Visit(BfIdentifierNode* identifierNode)
|
||||||
{
|
{
|
||||||
Visit(identifierNode->ToBase());
|
Visit(identifierNode->ToBase());
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
virtual void Visit(BfTokenNode* tokenNode);
|
virtual void Visit(BfTokenNode* tokenNode);
|
||||||
virtual void Visit(BfTokenPairNode* tokenPairNode);
|
virtual void Visit(BfTokenPairNode* tokenPairNode);
|
||||||
virtual void Visit(BfLiteralExpression* literalExpr);
|
virtual void Visit(BfLiteralExpression* literalExpr);
|
||||||
|
virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression);
|
||||||
virtual void Visit(BfIdentifierNode* identifierNode);
|
virtual void Visit(BfIdentifierNode* identifierNode);
|
||||||
virtual void Visit(BfAttributedIdentifierNode* attrIdentifierNode);
|
virtual void Visit(BfAttributedIdentifierNode* attrIdentifierNode);
|
||||||
virtual void Visit(BfQualifiedNameNode* nameNode);
|
virtual void Visit(BfQualifiedNameNode* nameNode);
|
||||||
|
|
|
@ -3200,6 +3200,47 @@ void BfExprEvaluator::Visit(BfLiteralExpression* literalExpr)
|
||||||
GetLiteral(literalExpr, literalExpr->mValue);
|
GetLiteral(literalExpr, literalExpr->mValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BfExprEvaluator::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
|
||||||
|
{
|
||||||
|
if ((mBfEvalExprFlags & BfEvalExprFlags_StringInterpolateFormat) != 0)
|
||||||
|
{
|
||||||
|
BfVariant variant;
|
||||||
|
variant.mTypeCode = BfTypeCode_CharPtr;
|
||||||
|
variant.mString = stringInterpolationExpression->mString;
|
||||||
|
GetLiteral(stringInterpolationExpression, variant);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stringInterpolationExpression->mAllocNode != NULL)
|
||||||
|
{
|
||||||
|
auto stringType = mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)->ToTypeInstance();
|
||||||
|
|
||||||
|
BfTokenNode* newToken = NULL;
|
||||||
|
BfAllocTarget allocTarget = ResolveAllocTarget(stringInterpolationExpression->mAllocNode, newToken);
|
||||||
|
|
||||||
|
CreateObject(NULL, stringInterpolationExpression->mAllocNode, stringType);
|
||||||
|
BfTypedValue newString = mResult;
|
||||||
|
BF_ASSERT(newString);
|
||||||
|
|
||||||
|
SizedArray<BfExpression*, 2> argExprs;
|
||||||
|
argExprs.Add(stringInterpolationExpression);
|
||||||
|
BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
|
||||||
|
BfResolvedArgs argValues(&sizedArgExprs);
|
||||||
|
ResolveArgValues(argValues, BfResolveArgFlag_InsideStringInterpolationAlloc);
|
||||||
|
MatchMethod(stringInterpolationExpression, NULL, newString, false, false, "AppendF", argValues, NULL);
|
||||||
|
mResult = newString;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mModule->Fail("Invalid use of string interpolation expression. Consider adding an allocation specifier such as 'scope'.", stringInterpolationExpression);
|
||||||
|
|
||||||
|
for (auto block : stringInterpolationExpression->mExpressions)
|
||||||
|
{
|
||||||
|
VisitChild(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef)
|
BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef)
|
||||||
{
|
{
|
||||||
if (!mModule->mIsInsideAutoComplete)
|
if (!mModule->mIsInsideAutoComplete)
|
||||||
|
@ -4413,23 +4454,44 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
|
||||||
autoComplete->mIgnoreFixits = true;
|
autoComplete->mIgnoreFixits = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int argIdx = 0; argIdx < argCount ; argIdx++)
|
int deferredArgIdx = 0;
|
||||||
|
SizedArray<BfExpression*, 8> deferredArgs;
|
||||||
|
|
||||||
|
int argIdx = 0;
|
||||||
|
//for (int argIdx = 0; argIdx < argCount ; argIdx++)
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
//printf("Args: %p %p %d\n", resolvedArgs.mArguments, resolvedArgs.mArguments->mVals, resolvedArgs.mArguments->mSize);
|
//printf("Args: %p %p %d\n", resolvedArgs.mArguments, resolvedArgs.mArguments->mVals, resolvedArgs.mArguments->mSize);
|
||||||
|
|
||||||
BfExpression* argExpr = NULL;
|
BfExpression* argExpr = NULL;
|
||||||
if (argIdx < resolvedArgs.mArguments->size())
|
|
||||||
argExpr = (*resolvedArgs.mArguments)[argIdx];
|
int curArgIdx = -1;
|
||||||
|
|
||||||
|
if (deferredArgIdx < deferredArgs.size())
|
||||||
|
{
|
||||||
|
argExpr = deferredArgs[deferredArgIdx++];
|
||||||
|
}
|
||||||
|
else if (argIdx >= argCount)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curArgIdx = argIdx++;
|
||||||
|
if (curArgIdx < resolvedArgs.mArguments->size())
|
||||||
|
argExpr = (*resolvedArgs.mArguments)[curArgIdx];
|
||||||
|
}
|
||||||
|
|
||||||
if (argExpr == NULL)
|
if (argExpr == NULL)
|
||||||
{
|
{
|
||||||
if (argIdx == 0)
|
if (curArgIdx == 0)
|
||||||
{
|
{
|
||||||
if (resolvedArgs.mOpenToken != NULL)
|
if (resolvedArgs.mOpenToken != NULL)
|
||||||
mModule->FailAfter("Expression expected", resolvedArgs.mOpenToken);
|
mModule->FailAfter("Expression expected", resolvedArgs.mOpenToken);
|
||||||
}
|
}
|
||||||
else if (resolvedArgs.mCommas != NULL)
|
else if (resolvedArgs.mCommas != NULL)
|
||||||
mModule->FailAfter("Expression expected", (*resolvedArgs.mCommas)[argIdx - 1]);
|
mModule->FailAfter("Expression expected", (*resolvedArgs.mCommas)[curArgIdx - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto typedValueExpr = BfNodeDynCast<BfTypedValueExpression>(argExpr))
|
if (auto typedValueExpr = BfNodeDynCast<BfTypedValueExpression>(argExpr))
|
||||||
|
@ -4448,6 +4510,16 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
bool evaluated = false;
|
bool evaluated = false;
|
||||||
|
|
||||||
|
if (auto interpolateExpr = BfNodeDynCastExact<BfStringInterpolationExpression>(argExpr))
|
||||||
|
{
|
||||||
|
if ((interpolateExpr->mAllocNode == NULL) || ((flags & BfResolveArgFlag_InsideStringInterpolationAlloc) != 0))
|
||||||
|
{
|
||||||
|
resolvedArg.mArgFlags = (BfArgFlags)(resolvedArg.mArgFlags | BfArgFlag_StringInterpolateFormat);
|
||||||
|
for (auto innerExpr : interpolateExpr->mExpressions)
|
||||||
|
deferredArgs.Add(innerExpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool deferParamEval = false;
|
bool deferParamEval = false;
|
||||||
if ((flags & BfResolveArgFlag_DeferParamEval) != 0)
|
if ((flags & BfResolveArgFlag_DeferParamEval) != 0)
|
||||||
{
|
{
|
||||||
|
@ -4542,6 +4614,10 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
|
||||||
if (!evaluated)
|
if (!evaluated)
|
||||||
{
|
{
|
||||||
exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_AllowParamsExpr);
|
exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_AllowParamsExpr);
|
||||||
|
|
||||||
|
if ((resolvedArg.mArgFlags & BfArgFlag_StringInterpolateFormat) != 0)
|
||||||
|
exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_StringInterpolateFormat);
|
||||||
|
|
||||||
exprEvaluator.Evaluate(argExpr, false, false, true);
|
exprEvaluator.Evaluate(argExpr, false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12035,14 +12111,19 @@ void BfExprEvaluator::CheckObjectCreateTypeRef(BfType* expectingType, BfAstNode*
|
||||||
}
|
}
|
||||||
|
|
||||||
void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
|
{
|
||||||
|
CreateObject(objCreateExpr, objCreateExpr->mNewNode, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAstNode* allocNode, BfType* wantAllocType)
|
||||||
{
|
{
|
||||||
auto autoComplete = GetAutoComplete();
|
auto autoComplete = GetAutoComplete();
|
||||||
if ((autoComplete != NULL) && (objCreateExpr->mTypeRef != NULL))
|
if ((autoComplete != NULL) && (objCreateExpr != NULL) && (objCreateExpr->mTypeRef != NULL))
|
||||||
{
|
{
|
||||||
autoComplete->CheckTypeRef(objCreateExpr->mTypeRef, false, true);
|
autoComplete->CheckTypeRef(objCreateExpr->mTypeRef, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((autoComplete != NULL) && (objCreateExpr->mOpenToken != NULL) && (objCreateExpr->mCloseToken != NULL) &&
|
if ((autoComplete != NULL) && (objCreateExpr != NULL) && (objCreateExpr->mOpenToken != NULL) && (objCreateExpr->mCloseToken != NULL) &&
|
||||||
(objCreateExpr->mOpenToken->mToken == BfToken_LBrace) && (autoComplete->CheckFixit(objCreateExpr->mOpenToken)))
|
(objCreateExpr->mOpenToken->mToken == BfToken_LBrace) && (autoComplete->CheckFixit(objCreateExpr->mOpenToken)))
|
||||||
{
|
{
|
||||||
auto refNode = objCreateExpr->mOpenToken;
|
auto refNode = objCreateExpr->mOpenToken;
|
||||||
|
@ -12055,28 +12136,28 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckObjectCreateTypeRef(mExpectingType, objCreateExpr->mNewNode);
|
CheckObjectCreateTypeRef(mExpectingType, allocNode);
|
||||||
|
|
||||||
BfAttributeState attributeState;
|
BfAttributeState attributeState;
|
||||||
attributeState.mTarget = BfAttributeTargets_Alloc;
|
attributeState.mTarget = BfAttributeTargets_Alloc;
|
||||||
SetAndRestoreValue<BfAttributeState*> prevAttributeState(mModule->mAttributeState, &attributeState);
|
SetAndRestoreValue<BfAttributeState*> prevAttributeState(mModule->mAttributeState, &attributeState);
|
||||||
BfTokenNode* newToken = NULL;
|
BfTokenNode* newToken = NULL;
|
||||||
BfAllocTarget allocTarget = ResolveAllocTarget(objCreateExpr->mNewNode, newToken, &attributeState.mCustomAttributes);
|
BfAllocTarget allocTarget = ResolveAllocTarget(allocNode, newToken, &attributeState.mCustomAttributes);
|
||||||
|
|
||||||
bool isScopeAlloc = newToken->GetToken() == BfToken_Scope;
|
bool isScopeAlloc = newToken->GetToken() == BfToken_Scope;
|
||||||
bool isAppendAlloc = newToken->GetToken() == BfToken_Append;
|
bool isAppendAlloc = newToken->GetToken() == BfToken_Append;
|
||||||
bool isStackAlloc = (newToken->GetToken() == BfToken_Stack) || (isScopeAlloc);
|
bool isStackAlloc = (newToken->GetToken() == BfToken_Stack) || (isScopeAlloc);
|
||||||
bool isArrayAlloc = false;// (objCreateExpr->mArraySizeSpecifier != NULL);
|
bool isArrayAlloc = false;// (objCreateExpr->mArraySizeSpecifier != NULL);
|
||||||
bool isRawArrayAlloc = (objCreateExpr->mStarToken != NULL);
|
bool isRawArrayAlloc = (objCreateExpr != NULL) && (objCreateExpr->mStarToken != NULL);
|
||||||
|
|
||||||
if (isScopeAlloc)
|
if (isScopeAlloc)
|
||||||
{
|
{
|
||||||
if ((mBfEvalExprFlags & BfEvalExprFlags_FieldInitializer) != 0)
|
if ((mBfEvalExprFlags & BfEvalExprFlags_FieldInitializer) != 0)
|
||||||
{
|
{
|
||||||
mModule->Warn(0, "This allocation will only be in scope during the constructor. Consider using a longer-term allocation such as 'new'", objCreateExpr->mNewNode);
|
mModule->Warn(0, "This allocation will only be in scope during the constructor. Consider using a longer-term allocation such as 'new'", allocNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objCreateExpr->mNewNode == newToken) // Scope, no target specified
|
if (allocNode == newToken) // Scope, no target specified
|
||||||
{
|
{
|
||||||
if (mModule->mParentNodeEntry != NULL)
|
if (mModule->mParentNodeEntry != NULL)
|
||||||
{
|
{
|
||||||
|
@ -12086,7 +12167,7 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
{
|
{
|
||||||
// If we are assigning this to a property then it's possible the property setter can actually deal with a temporary allocation so no warning in that case
|
// If we are assigning this to a property then it's possible the property setter can actually deal with a temporary allocation so no warning in that case
|
||||||
if ((mBfEvalExprFlags & BfEvalExprFlags_PendingPropSet) == 0)
|
if ((mBfEvalExprFlags & BfEvalExprFlags_PendingPropSet) == 0)
|
||||||
mModule->Warn(0, "This allocation will immediately go out of scope. Consider specifying a wider scope target such as 'scope::'", objCreateExpr->mNewNode);
|
mModule->Warn(0, "This allocation will immediately go out of scope. Consider specifying a wider scope target such as 'scope::'", allocNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12102,7 +12183,12 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
|
|
||||||
BfType* unresolvedTypeRef = NULL;
|
BfType* unresolvedTypeRef = NULL;
|
||||||
BfType* resolvedTypeRef = NULL;
|
BfType* resolvedTypeRef = NULL;
|
||||||
if (objCreateExpr->mTypeRef == NULL)
|
if (wantAllocType != NULL)
|
||||||
|
{
|
||||||
|
unresolvedTypeRef = wantAllocType;
|
||||||
|
resolvedTypeRef = wantAllocType;
|
||||||
|
}
|
||||||
|
else if (objCreateExpr->mTypeRef == NULL)
|
||||||
{
|
{
|
||||||
if ((!mExpectingType) || (!mExpectingType->IsArray()))
|
if ((!mExpectingType) || (!mExpectingType->IsArray()))
|
||||||
{
|
{
|
||||||
|
@ -12287,12 +12373,12 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
{
|
{
|
||||||
if (!mModule->mCurTypeInstance->IsObject())
|
if (!mModule->mCurTypeInstance->IsObject())
|
||||||
{
|
{
|
||||||
mModule->Fail("Append allocations are only allowed in classes", objCreateExpr->mNewNode);
|
mModule->Fail("Append allocations are only allowed in classes", allocNode);
|
||||||
isAppendAlloc = false;
|
isAppendAlloc = false;
|
||||||
}
|
}
|
||||||
else if ((mBfEvalExprFlags & BfEvalExprFlags_VariableDeclaration) == 0)
|
else if ((mBfEvalExprFlags & BfEvalExprFlags_VariableDeclaration) == 0)
|
||||||
{
|
{
|
||||||
mModule->Fail("Append allocations are only allowed as local variable initializers in constructor body", objCreateExpr->mNewNode);
|
mModule->Fail("Append allocations are only allowed as local variable initializers in constructor body", allocNode);
|
||||||
isAppendAlloc = false;
|
isAppendAlloc = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -12300,22 +12386,22 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
auto methodDef = mModule->mCurMethodInstance->mMethodDef;
|
auto methodDef = mModule->mCurMethodInstance->mMethodDef;
|
||||||
if (methodDef->mMethodType == BfMethodType_CtorCalcAppend)
|
if (methodDef->mMethodType == BfMethodType_CtorCalcAppend)
|
||||||
{
|
{
|
||||||
mModule->Fail("Append allocations are only allowed as local variable declarations in the main method body", objCreateExpr->mNewNode);
|
mModule->Fail("Append allocations are only allowed as local variable declarations in the main method body", allocNode);
|
||||||
isAppendAlloc = false;
|
isAppendAlloc = false;
|
||||||
}
|
}
|
||||||
else if (!methodDef->mHasAppend)
|
else if (!methodDef->mHasAppend)
|
||||||
{
|
{
|
||||||
mModule->Fail("Append allocations can only be used on constructors with [AllowAppend] specified", objCreateExpr->mNewNode);
|
mModule->Fail("Append allocations can only be used on constructors with [AllowAppend] specified", allocNode);
|
||||||
isAppendAlloc = false;
|
isAppendAlloc = false;
|
||||||
}
|
}
|
||||||
else if (methodDef->mMethodType != BfMethodType_Ctor)
|
else if (methodDef->mMethodType != BfMethodType_Ctor)
|
||||||
{
|
{
|
||||||
mModule->Fail("Append allocations are only allowed in constructors", objCreateExpr->mNewNode);
|
mModule->Fail("Append allocations are only allowed in constructors", allocNode);
|
||||||
isAppendAlloc = false;
|
isAppendAlloc = false;
|
||||||
}
|
}
|
||||||
else if (methodDef->mIsStatic)
|
else if (methodDef->mIsStatic)
|
||||||
{
|
{
|
||||||
mModule->Fail("Append allocations are only allowed in non-static constructors", objCreateExpr->mNewNode);
|
mModule->Fail("Append allocations are only allowed in non-static constructors", allocNode);
|
||||||
isAppendAlloc = false;
|
isAppendAlloc = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12731,7 +12817,7 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
|
|
||||||
if ((isStackAlloc) && (mModule->mCurMethodState == NULL))
|
if ((isStackAlloc) && (mModule->mCurMethodState == NULL))
|
||||||
{
|
{
|
||||||
mModule->Fail("Cannot use 'stack' here", objCreateExpr->mNewNode);
|
mModule->Fail("Cannot use 'stack' here", allocNode);
|
||||||
isStackAlloc = false;
|
isStackAlloc = false;
|
||||||
isScopeAlloc = false;
|
isScopeAlloc = false;
|
||||||
}
|
}
|
||||||
|
@ -12810,8 +12896,12 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
BfIRValue appendSizeValue;
|
BfIRValue appendSizeValue;
|
||||||
BfTypedValue emtpyThis(mModule->mBfIRBuilder->GetFakeVal(), resolvedTypeRef, resolvedTypeRef->IsStruct());
|
BfTypedValue emtpyThis(mModule->mBfIRBuilder->GetFakeVal(), resolvedTypeRef, resolvedTypeRef->IsStruct());
|
||||||
|
|
||||||
BfResolvedArgs argValues(objCreateExpr->mOpenToken, &objCreateExpr->mArguments, &objCreateExpr->mCommas, objCreateExpr->mCloseToken);
|
BfResolvedArgs argValues;
|
||||||
|
if (objCreateExpr != NULL)
|
||||||
|
{
|
||||||
|
argValues.Init(objCreateExpr->mOpenToken, &objCreateExpr->mArguments, &objCreateExpr->mCommas, objCreateExpr->mCloseToken);
|
||||||
ResolveArgValues(argValues, BfResolveArgFlag_DeferParamEval); ////
|
ResolveArgValues(argValues, BfResolveArgFlag_DeferParamEval); ////
|
||||||
|
}
|
||||||
|
|
||||||
if (typeInstance == NULL)
|
if (typeInstance == NULL)
|
||||||
{
|
{
|
||||||
|
@ -12821,7 +12911,7 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
mModule->Fail(StrFormat("Only default parameterless constructors can be called on primitive type '%s'", mModule->TypeToString(resolvedTypeRef).c_str()), objCreateExpr->mTypeRef);
|
mModule->Fail(StrFormat("Only default parameterless constructors can be called on primitive type '%s'", mModule->TypeToString(resolvedTypeRef).c_str()), objCreateExpr->mTypeRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((autoComplete != NULL) && (objCreateExpr->mOpenToken != NULL))
|
else if ((autoComplete != NULL) && (objCreateExpr != NULL) && (objCreateExpr->mOpenToken != NULL))
|
||||||
{
|
{
|
||||||
auto wasCapturingMethodInfo = autoComplete->mIsCapturingMethodMatchInfo;
|
auto wasCapturingMethodInfo = autoComplete->mIsCapturingMethodMatchInfo;
|
||||||
autoComplete->CheckInvocation(objCreateExpr, objCreateExpr->mOpenToken, objCreateExpr->mCloseToken, objCreateExpr->mCommas);
|
autoComplete->CheckInvocation(objCreateExpr, objCreateExpr->mOpenToken, objCreateExpr->mCloseToken, objCreateExpr->mCommas);
|
||||||
|
@ -12836,8 +12926,12 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
}
|
}
|
||||||
else if (!resolvedTypeRef->IsFunction())
|
else if (!resolvedTypeRef->IsFunction())
|
||||||
{
|
{
|
||||||
MatchConstructor(objCreateExpr->mTypeRef, objCreateExpr, emtpyThis, typeInstance, argValues, false, true);
|
auto refNode = allocNode;
|
||||||
|
if (objCreateExpr != NULL)
|
||||||
|
refNode = objCreateExpr->mTypeRef;
|
||||||
|
MatchConstructor(refNode, objCreateExpr, emtpyThis, typeInstance, argValues, false, true);
|
||||||
}
|
}
|
||||||
|
if (objCreateExpr != NULL)
|
||||||
mModule->ValidateAllocation(typeInstance, objCreateExpr->mTypeRef);
|
mModule->ValidateAllocation(typeInstance, objCreateExpr->mTypeRef);
|
||||||
|
|
||||||
prevBindResult.Restore();
|
prevBindResult.Restore();
|
||||||
|
@ -12998,7 +13092,7 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr)
|
||||||
BF_ASSERT(removeStackObjMethod);
|
BF_ASSERT(removeStackObjMethod);
|
||||||
if (removeStackObjMethod)
|
if (removeStackObjMethod)
|
||||||
{
|
{
|
||||||
mModule->AddDeferredCall(removeStackObjMethod, irArgs, allocTarget.mScopeData, objCreateExpr);
|
mModule->AddDeferredCall(removeStackObjMethod, irArgs, allocTarget.mScopeData, allocNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ enum BfArgFlags
|
||||||
BfArgFlag_ExpectedTypeCast = 0x80,
|
BfArgFlag_ExpectedTypeCast = 0x80,
|
||||||
BfArgFlag_VariableDeclaration = 0x100,
|
BfArgFlag_VariableDeclaration = 0x100,
|
||||||
BfArgFlag_ParamsExpr = 0x200,
|
BfArgFlag_ParamsExpr = 0x200,
|
||||||
BfArgFlag_UninitializedExpr = 0x400
|
BfArgFlag_UninitializedExpr = 0x400,
|
||||||
|
BfArgFlag_StringInterpolateFormat = 0x800
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BfResolveArgFlags
|
enum BfResolveArgFlags
|
||||||
|
@ -28,6 +29,7 @@ enum BfResolveArgFlags
|
||||||
BfResolveArgFlag_DeferParamValues = 2, // We still evaluate but don't generate code until the method is selected (for SkipCall support)
|
BfResolveArgFlag_DeferParamValues = 2, // We still evaluate but don't generate code until the method is selected (for SkipCall support)
|
||||||
BfResolveArgFlag_DeferParamEval = 4,
|
BfResolveArgFlag_DeferParamEval = 4,
|
||||||
BfResolveArgFlag_AllowUnresolvedTypes = 8,
|
BfResolveArgFlag_AllowUnresolvedTypes = 8,
|
||||||
|
BfResolveArgFlag_InsideStringInterpolationAlloc = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
class BfResolvedArg
|
class BfResolvedArg
|
||||||
|
@ -91,6 +93,14 @@ public:
|
||||||
mCloseToken = closeToken;
|
mCloseToken = closeToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Init(BfTokenNode* openToken, BfSizedArray<BfExpression*>* args, BfSizedArray<BfTokenNode*>* commas, BfTokenNode* closeToken)
|
||||||
|
{
|
||||||
|
mOpenToken = openToken;
|
||||||
|
mArguments = args;
|
||||||
|
mCommas = commas;
|
||||||
|
mCloseToken = closeToken;
|
||||||
|
}
|
||||||
|
|
||||||
void Init(const BfSizedArray<BfExpression*>* args)
|
void Init(const BfSizedArray<BfExpression*>* args)
|
||||||
{
|
{
|
||||||
mOpenToken = NULL;
|
mOpenToken = NULL;
|
||||||
|
@ -100,6 +110,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleFixits(BfModule* module);
|
void HandleFixits(BfModule* module);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BfGenericInferContext
|
class BfGenericInferContext
|
||||||
|
@ -441,6 +452,7 @@ public:
|
||||||
void InitializedSizedArray(BfSizedArrayType* sizedArrayType, BfTokenNode* openToken, const BfSizedArray<BfExpression*>& values, const BfSizedArray<BfTokenNode*>& commas, BfTokenNode* closeToken, BfTypedValue* receivingValue = NULL);
|
void InitializedSizedArray(BfSizedArrayType* sizedArrayType, BfTokenNode* openToken, const BfSizedArray<BfExpression*>& values, const BfSizedArray<BfTokenNode*>& commas, BfTokenNode* closeToken, BfTypedValue* receivingValue = NULL);
|
||||||
void CheckDotToken(BfTokenNode* tokenNode);
|
void CheckDotToken(BfTokenNode* tokenNode);
|
||||||
void DoMemberReference(BfMemberReferenceExpression* memberRefExpr, BfTypedValue* outCascadeValue);
|
void DoMemberReference(BfMemberReferenceExpression* memberRefExpr, BfTypedValue* outCascadeValue);
|
||||||
|
void CreateObject(BfObjectCreateExpression* objCreateExpr, BfAstNode* allocNode, BfType* allocType);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -452,6 +464,7 @@ public:
|
||||||
virtual void Visit(BfCaseExpression* caseExpr) override;
|
virtual void Visit(BfCaseExpression* caseExpr) override;
|
||||||
virtual void Visit(BfTypedValueExpression* typedValueExpr) override;
|
virtual void Visit(BfTypedValueExpression* typedValueExpr) override;
|
||||||
virtual void Visit(BfLiteralExpression* literalExpr) override;
|
virtual void Visit(BfLiteralExpression* literalExpr) override;
|
||||||
|
virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression) override;
|
||||||
virtual void Visit(BfIdentifierNode* identifierNode) override;
|
virtual void Visit(BfIdentifierNode* identifierNode) override;
|
||||||
virtual void Visit(BfAttributedIdentifierNode* attrIdentifierNode) override;
|
virtual void Visit(BfAttributedIdentifierNode* attrIdentifierNode) override;
|
||||||
virtual void Visit(BfQualifiedNameNode* nameNode) override;
|
virtual void Visit(BfQualifiedNameNode* nameNode) override;
|
||||||
|
|
|
@ -66,7 +66,8 @@ enum BfEvalExprFlags
|
||||||
BfEvalExprFlags_FieldInitializer = 0x2000,
|
BfEvalExprFlags_FieldInitializer = 0x2000,
|
||||||
BfEvalExprFlags_VariableDeclaration = 0x4000,
|
BfEvalExprFlags_VariableDeclaration = 0x4000,
|
||||||
BfEvalExprFlags_NoAutoComplete = 0x8000,
|
BfEvalExprFlags_NoAutoComplete = 0x8000,
|
||||||
BfEvalExprFlags_AllowNonConst = 0x10000
|
BfEvalExprFlags_AllowNonConst = 0x10000,
|
||||||
|
BfEvalExprFlags_StringInterpolateFormat = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BfCastFlags
|
enum BfCastFlags
|
||||||
|
|
|
@ -358,6 +358,7 @@ BfParser::BfParser(BfSystem* bfSystem, BfProject* bfProject) : BfSource(bfSystem
|
||||||
//mCurToken = (BfSyntaxToken)0;
|
//mCurToken = (BfSyntaxToken)0;
|
||||||
mToken = BfToken_None;
|
mToken = BfToken_None;
|
||||||
mSyntaxToken = BfSyntaxToken_None;
|
mSyntaxToken = BfSyntaxToken_None;
|
||||||
|
|
||||||
mTokenStart = 0;
|
mTokenStart = 0;
|
||||||
mTokenEnd = 0;
|
mTokenEnd = 0;
|
||||||
mLineNum = 0;
|
mLineNum = 0;
|
||||||
|
@ -1360,7 +1361,7 @@ double BfParser::ParseLiteralDouble()
|
||||||
return strtod(buf, NULL);
|
return strtod(buf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BfParser::NextToken(int endIdx)
|
void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
|
||||||
{
|
{
|
||||||
auto prevToken = mToken;
|
auto prevToken = mToken;
|
||||||
|
|
||||||
|
@ -1372,11 +1373,13 @@ void BfParser::NextToken(int endIdx)
|
||||||
|
|
||||||
bool isLineStart = true;
|
bool isLineStart = true;
|
||||||
bool isVerbatim = false;
|
bool isVerbatim = false;
|
||||||
int verbatimStart = -1;
|
bool isInterpolate = false;
|
||||||
|
int stringStart = -1;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
bool setVerbatim = false;
|
bool setVerbatim = false;
|
||||||
|
bool setInterpolate = false;
|
||||||
uint32 checkTokenHash = 0;
|
uint32 checkTokenHash = 0;
|
||||||
|
|
||||||
if ((endIdx != -1) && (mSrcIdx >= endIdx))
|
if ((endIdx != -1) && (mSrcIdx >= endIdx))
|
||||||
|
@ -1389,6 +1392,15 @@ void BfParser::NextToken(int endIdx)
|
||||||
mTokenEnd = mSrcIdx + 1;
|
mTokenEnd = mSrcIdx + 1;
|
||||||
char c = mSrc[mSrcIdx++];
|
char c = mSrc[mSrcIdx++];
|
||||||
|
|
||||||
|
if (outerIsInterpolate)
|
||||||
|
{
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
mSyntaxToken = BfSyntaxToken_StringQuote;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((mPreprocessorIgnoreDepth > 0) && (endIdx == -1))
|
if ((mPreprocessorIgnoreDepth > 0) && (endIdx == -1))
|
||||||
{
|
{
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
|
@ -1668,7 +1680,7 @@ void BfParser::NextToken(int endIdx)
|
||||||
case '@':
|
case '@':
|
||||||
setVerbatim = true;
|
setVerbatim = true;
|
||||||
c = mSrc[mSrcIdx];
|
c = mSrc[mSrcIdx];
|
||||||
if (c == '\"')
|
if ((c == '\"') || (c == '$'))
|
||||||
{
|
{
|
||||||
setVerbatim = true;
|
setVerbatim = true;
|
||||||
}
|
}
|
||||||
|
@ -1679,19 +1691,29 @@ void BfParser::NextToken(int endIdx)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mSyntaxToken = BfSyntaxToken_Identifier;
|
mSyntaxToken = BfSyntaxToken_Identifier;
|
||||||
//mToken = BfToken_At;
|
|
||||||
//mSyntaxToken = BfSyntaxToken_Token;
|
|
||||||
//Fail("Keyword, identifier, or string expected after verbatim specifier: @"); // CS1646
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '$':
|
||||||
|
setInterpolate = true;
|
||||||
|
c = mSrc[mSrcIdx];
|
||||||
|
if ((c == '\"') || (c == '@'))
|
||||||
|
{
|
||||||
|
setInterpolate = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Fail("Expected to precede string");
|
||||||
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
case '\'':
|
case '\'':
|
||||||
{
|
{
|
||||||
|
SizedArray<BfBlock*, 4> interpolateExpressions;
|
||||||
|
|
||||||
String lineHeader;
|
String lineHeader;
|
||||||
String strLiteral;
|
String strLiteral;
|
||||||
char startChar = c;
|
char startChar = c;
|
||||||
bool isMultiline = false;
|
bool isMultiline = false;
|
||||||
|
int triviaStart = mTriviaStart;
|
||||||
|
|
||||||
if ((mSrc[mSrcIdx] == '"') && (mSrc[mSrcIdx + 1] == '"'))
|
if ((mSrc[mSrcIdx] == '"') && (mSrc[mSrcIdx + 1] == '"'))
|
||||||
{
|
{
|
||||||
|
@ -1984,14 +2006,62 @@ void BfParser::NextToken(int endIdx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
strLiteral += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVerbatim)
|
|
||||||
{
|
{
|
||||||
mTokenStart--;
|
strLiteral += c;
|
||||||
|
|
||||||
|
if (isInterpolate)
|
||||||
|
{
|
||||||
|
if (c == '{')
|
||||||
|
{
|
||||||
|
BfBlock* newBlock = mAlloc->Alloc<BfBlock>();
|
||||||
|
mTokenStart = mSrcIdx - 1;
|
||||||
|
mTriviaStart = mTokenStart;
|
||||||
|
mTokenEnd = mTokenStart + 1;
|
||||||
|
mToken = BfToken_LBrace;
|
||||||
|
newBlock->mOpenBrace = (BfTokenNode*)CreateNode();
|
||||||
|
newBlock->Init(this);
|
||||||
|
ParseBlock(newBlock, 1, true);
|
||||||
|
if (mToken == BfToken_RBrace)
|
||||||
|
{
|
||||||
|
newBlock->mCloseBrace = (BfTokenNode*)CreateNode();
|
||||||
|
newBlock->SetSrcEnd(mSrcIdx);
|
||||||
|
strLiteral += "}";
|
||||||
|
}
|
||||||
|
else if ((mSyntaxToken == BfSyntaxToken_EOF) || (mSyntaxToken == BfSyntaxToken_StringQuote))
|
||||||
|
{
|
||||||
|
mSrcIdx--;
|
||||||
|
mPassInstance->FailAfterAt("Expected '}'", mSourceData, newBlock->GetSrcEnd() - 1);
|
||||||
|
}
|
||||||
|
mInAsmBlock = false;
|
||||||
|
interpolateExpressions.Add(newBlock);
|
||||||
|
}
|
||||||
|
else if (c == '}')
|
||||||
|
{
|
||||||
|
if (!interpolateExpressions.IsEmpty())
|
||||||
|
{
|
||||||
|
auto block = interpolateExpressions.back();
|
||||||
|
if (block->mCloseBrace == NULL)
|
||||||
|
{
|
||||||
|
mTokenStart = mSrcIdx - 1;
|
||||||
|
mTriviaStart = mTokenStart;
|
||||||
|
mTokenEnd = mTokenStart + 1;
|
||||||
|
mToken = BfToken_RBrace;
|
||||||
|
block->mCloseBrace = (BfTokenNode*)CreateNode();
|
||||||
|
block->SetSrcEnd(mSrcIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stringStart != -1)
|
||||||
|
{
|
||||||
|
mTokenStart = stringStart;
|
||||||
|
stringStart = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTriviaStart = triviaStart;
|
||||||
mTokenEnd = mSrcIdx;
|
mTokenEnd = mSrcIdx;
|
||||||
mSyntaxToken = BfSyntaxToken_Literal;
|
mSyntaxToken = BfSyntaxToken_Literal;
|
||||||
if (startChar == '\'')
|
if (startChar == '\'')
|
||||||
|
@ -2046,6 +2116,20 @@ void BfParser::NextToken(int endIdx)
|
||||||
mLiteral.mTypeCode = BfTypeCode_CharPtr;
|
mLiteral.mTypeCode = BfTypeCode_CharPtr;
|
||||||
mLiteral.mString = strLiteralPtr;
|
mLiteral.mString = strLiteralPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isInterpolate)
|
||||||
|
{
|
||||||
|
auto interpolateExpr = mAlloc->Alloc<BfStringInterpolationExpression>();
|
||||||
|
interpolateExpr->mString = mLiteral.mString;
|
||||||
|
interpolateExpr->mTriviaStart = mTriviaStart;
|
||||||
|
interpolateExpr->mSrcStart = mTokenStart;
|
||||||
|
interpolateExpr->mSrcEnd = mSrcIdx;
|
||||||
|
BfSizedArrayInitIndirect(interpolateExpr->mExpressions, interpolateExpressions, mAlloc);
|
||||||
|
mGeneratedNode = interpolateExpr;
|
||||||
|
mSyntaxToken = BfSyntaxToken_GeneratedNode;
|
||||||
|
mToken = BfToken_None;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3098,8 +3182,11 @@ void BfParser::NextToken(int endIdx)
|
||||||
((c >= 'a') && (c <= 'z')) ||
|
((c >= 'a') && (c <= 'z')) ||
|
||||||
(c == '_'))
|
(c == '_'))
|
||||||
{
|
{
|
||||||
if (isVerbatim)
|
if (stringStart != -1)
|
||||||
mTokenStart = verbatimStart;
|
{
|
||||||
|
mTokenStart = stringStart;
|
||||||
|
stringStart = -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -3163,7 +3250,12 @@ void BfParser::NextToken(int endIdx)
|
||||||
if ((setVerbatim) && (!isVerbatim))
|
if ((setVerbatim) && (!isVerbatim))
|
||||||
{
|
{
|
||||||
isVerbatim = true;
|
isVerbatim = true;
|
||||||
verbatimStart = mTokenStart;
|
stringStart = mTokenStart;
|
||||||
|
}
|
||||||
|
if ((setInterpolate) && (!isInterpolate))
|
||||||
|
{
|
||||||
|
isInterpolate = true;
|
||||||
|
stringStart = mTokenStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3171,7 +3263,7 @@ void BfParser::NextToken(int endIdx)
|
||||||
static int gParseBlockIdx = 0;
|
static int gParseBlockIdx = 0;
|
||||||
static int gParseMemberIdx = 0;
|
static int gParseMemberIdx = 0;
|
||||||
|
|
||||||
void BfParser::ParseBlock(BfBlock* astNode, int depth)
|
void BfParser::ParseBlock(BfBlock* astNode, int depth, bool isInterpolate)
|
||||||
{
|
{
|
||||||
gParseBlockIdx++;
|
gParseBlockIdx++;
|
||||||
int startParseBlockIdx = gParseBlockIdx;
|
int startParseBlockIdx = gParseBlockIdx;
|
||||||
|
@ -3180,6 +3272,8 @@ void BfParser::ParseBlock(BfBlock* astNode, int depth)
|
||||||
|
|
||||||
SizedArray<BfAstNode*, 32> childArr;
|
SizedArray<BfAstNode*, 32> childArr;
|
||||||
|
|
||||||
|
int parenDepth = 0;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if ((mSyntaxToken == BfSyntaxToken_Token) && (mToken == BfToken_Asm))
|
if ((mSyntaxToken == BfSyntaxToken_Token) && (mToken == BfToken_Asm))
|
||||||
|
@ -3190,7 +3284,8 @@ void BfParser::ParseBlock(BfBlock* astNode, int depth)
|
||||||
isAsmBlock = true;
|
isAsmBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
NextToken();
|
NextToken(-1, isInterpolate);
|
||||||
|
|
||||||
if (mPreprocessorIgnoredSectionNode != NULL)
|
if (mPreprocessorIgnoredSectionNode != NULL)
|
||||||
{
|
{
|
||||||
if (mSyntaxToken != BfSyntaxToken_EOF)
|
if (mSyntaxToken != BfSyntaxToken_EOF)
|
||||||
|
@ -3265,6 +3360,20 @@ void BfParser::ParseBlock(BfBlock* astNode, int depth)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (mToken == BfToken_LParen)
|
||||||
|
parenDepth++;
|
||||||
|
else if (mToken == BfToken_RParen)
|
||||||
|
parenDepth--;
|
||||||
|
|
||||||
|
if ((isInterpolate) && (parenDepth == 0))
|
||||||
|
{
|
||||||
|
if ((mToken == BfToken_Colon) || (mToken == BfToken_Comma))
|
||||||
|
{
|
||||||
|
mSrcIdx = mTokenStart;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
astNode->Add(childNode);
|
astNode->Add(childNode);
|
||||||
childArr.push_back(childNode);
|
childArr.push_back(childNode);
|
||||||
|
|
||||||
|
@ -3310,6 +3419,8 @@ BfAstNode* BfParser::CreateNode()
|
||||||
mLiteral.mWarnType = 0;
|
mLiteral.mWarnType = 0;
|
||||||
return bfLiteralExpression;
|
return bfLiteralExpression;
|
||||||
}
|
}
|
||||||
|
case BfSyntaxToken_GeneratedNode:
|
||||||
|
return mGeneratedNode;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ enum BfSyntaxToken
|
||||||
BfSyntaxToken_Literal,
|
BfSyntaxToken_Literal,
|
||||||
BfSyntaxToken_CommentLine,
|
BfSyntaxToken_CommentLine,
|
||||||
BfSyntaxToken_CommentBlock,
|
BfSyntaxToken_CommentBlock,
|
||||||
|
BfSyntaxToken_GeneratedNode,
|
||||||
BfSyntaxToken_FAILED,
|
BfSyntaxToken_FAILED,
|
||||||
BfSyntaxToken_HIT_END_IDX,
|
BfSyntaxToken_HIT_END_IDX,
|
||||||
BfSyntaxToken_EOF
|
BfSyntaxToken_EOF
|
||||||
|
@ -174,6 +175,7 @@ public:
|
||||||
int mTriviaStart; // mTriviaStart < mTokenStart when there's leading whitespace
|
int mTriviaStart; // mTriviaStart < mTokenStart when there's leading whitespace
|
||||||
int mTokenStart;
|
int mTokenStart;
|
||||||
int mTokenEnd;
|
int mTokenEnd;
|
||||||
|
BfAstNode* mGeneratedNode;
|
||||||
BfVariant mLiteral;
|
BfVariant mLiteral;
|
||||||
BfToken mToken;
|
BfToken mToken;
|
||||||
BfPreprocesorIgnoredSectionNode* mPreprocessorIgnoredSectionNode;
|
BfPreprocesorIgnoredSectionNode* mPreprocessorIgnoredSectionNode;
|
||||||
|
@ -203,7 +205,7 @@ public:
|
||||||
bool IsUnwarnedAt(BfAstNode* node);
|
bool IsUnwarnedAt(BfAstNode* node);
|
||||||
bool SrcPtrHasToken(const char* name);
|
bool SrcPtrHasToken(const char* name);
|
||||||
uint32 GetTokenHash();
|
uint32 GetTokenHash();
|
||||||
void ParseBlock(BfBlock* astNode, int depth);
|
void ParseBlock(BfBlock* astNode, int depth, bool isInterpolate = false);
|
||||||
double ParseLiteralDouble();
|
double ParseLiteralDouble();
|
||||||
void AddErrorNode(int startIdx, int endIdx);
|
void AddErrorNode(int startIdx, int endIdx);
|
||||||
BfCommentKind GetCommentKind(int startIdx);
|
BfCommentKind GetCommentKind(int startIdx);
|
||||||
|
@ -223,7 +225,7 @@ public:
|
||||||
void SetSource(const char* data, int length);
|
void SetSource(const char* data, int length);
|
||||||
void MoveSource(const char* data, int length); // Takes ownership of data ptr
|
void MoveSource(const char* data, int length); // Takes ownership of data ptr
|
||||||
void RefSource(const char* data, int length);
|
void RefSource(const char* data, int length);
|
||||||
void NextToken(int endIdx = -1);
|
void NextToken(int endIdx = -1, bool outerIsInterpolate = false);
|
||||||
BfAstNode* CreateNode();
|
BfAstNode* CreateNode();
|
||||||
|
|
||||||
void Parse(BfPassInstance* passInstance);
|
void Parse(BfPassInstance* passInstance);
|
||||||
|
|
|
@ -1163,6 +1163,14 @@ void BfPrinter::Visit(BfLiteralExpression* literalExpr)
|
||||||
WriteSourceString(literalExpr);
|
WriteSourceString(literalExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BfPrinter::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
|
||||||
|
{
|
||||||
|
Visit(stringInterpolationExpression->ToBase());
|
||||||
|
String str;
|
||||||
|
stringInterpolationExpression->ToString(str);
|
||||||
|
Write(str);
|
||||||
|
}
|
||||||
|
|
||||||
void BfPrinter::Visit(BfIdentifierNode* identifierNode)
|
void BfPrinter::Visit(BfIdentifierNode* identifierNode)
|
||||||
{
|
{
|
||||||
Visit(identifierNode->ToBase());
|
Visit(identifierNode->ToBase());
|
||||||
|
|
|
@ -138,6 +138,7 @@ public:
|
||||||
virtual void Visit(BfEmptyStatement* emptyStmt) override;
|
virtual void Visit(BfEmptyStatement* emptyStmt) override;
|
||||||
virtual void Visit(BfTokenNode* tokenNode) override;
|
virtual void Visit(BfTokenNode* tokenNode) override;
|
||||||
virtual void Visit(BfLiteralExpression* literalExpr) override;
|
virtual void Visit(BfLiteralExpression* literalExpr) override;
|
||||||
|
virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression) override;
|
||||||
virtual void Visit(BfIdentifierNode* identifierNode) override;
|
virtual void Visit(BfIdentifierNode* identifierNode) override;
|
||||||
virtual void Visit(BfQualifiedNameNode* nameNode) override;
|
virtual void Visit(BfQualifiedNameNode* nameNode) override;
|
||||||
virtual void Visit(BfThisExpression* thisExpr) override;
|
virtual void Visit(BfThisExpression* thisExpr) override;
|
||||||
|
|
|
@ -1427,6 +1427,15 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
||||||
|
|
||||||
AssertCurrentNode(node);
|
AssertCurrentNode(node);
|
||||||
|
|
||||||
|
if (auto interpolateExpr = BfNodeDynCastExact<BfStringInterpolationExpression>(node))
|
||||||
|
{
|
||||||
|
for (auto block : interpolateExpr->mExpressions)
|
||||||
|
{
|
||||||
|
HandleBlock(block, true);
|
||||||
|
}
|
||||||
|
return interpolateExpr;
|
||||||
|
}
|
||||||
|
|
||||||
if ((createExprFlags & (CreateExprFlags_AllowVariableDecl | CreateExprFlags_PermissiveVariableDecl)) != 0)
|
if ((createExprFlags & (CreateExprFlags_AllowVariableDecl | CreateExprFlags_PermissiveVariableDecl)) != 0)
|
||||||
{
|
{
|
||||||
bool isLocalVariable = false;
|
bool isLocalVariable = false;
|
||||||
|
@ -1712,6 +1721,8 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
||||||
bool isDelegateBind = false;
|
bool isDelegateBind = false;
|
||||||
bool isLambdaBind = false;
|
bool isLambdaBind = false;
|
||||||
bool isBoxing = false;
|
bool isBoxing = false;
|
||||||
|
|
||||||
|
|
||||||
auto nextNode = mVisitorPos.GetNext();
|
auto nextNode = mVisitorPos.GetNext();
|
||||||
if (auto nextTokenNode = BfNodeDynCast<BfTokenNode>(nextNode))
|
if (auto nextTokenNode = BfNodeDynCast<BfTokenNode>(nextNode))
|
||||||
{
|
{
|
||||||
|
@ -1736,7 +1747,19 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBoxing)
|
if (auto interpExpr = BfNodeDynCastExact<BfStringInterpolationExpression>(nextNode))
|
||||||
|
{
|
||||||
|
mVisitorPos.MoveNext();
|
||||||
|
auto nextInterpExpr = CreateExpression(nextNode);
|
||||||
|
BF_ASSERT(nextInterpExpr == interpExpr);
|
||||||
|
|
||||||
|
interpExpr->mAllocNode = allocNode;
|
||||||
|
interpExpr->mTriviaStart = allocNode->mTriviaStart;
|
||||||
|
interpExpr->mSrcStart = allocNode->mSrcStart;
|
||||||
|
|
||||||
|
exprLeft = interpExpr;
|
||||||
|
}
|
||||||
|
else if (isBoxing)
|
||||||
{
|
{
|
||||||
auto boxExpr = mAlloc->Alloc<BfBoxExpression>();
|
auto boxExpr = mAlloc->Alloc<BfBoxExpression>();
|
||||||
ReplaceNode(allocNode, boxExpr);
|
ReplaceNode(allocNode, boxExpr);
|
||||||
|
|
|
@ -393,6 +393,20 @@ void BfSourceClassifier::Visit(BfLiteralExpression* literalExpr)
|
||||||
SetElementType(literalExpr, BfSourceElementType_Literal);
|
SetElementType(literalExpr, BfSourceElementType_Literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BfSourceClassifier::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
|
||||||
|
{
|
||||||
|
HandleLeafNode(stringInterpolationExpression);
|
||||||
|
|
||||||
|
Visit(stringInterpolationExpression->ToBase());
|
||||||
|
SetElementType(stringInterpolationExpression, BfSourceElementType_Literal);
|
||||||
|
|
||||||
|
VisitChild(stringInterpolationExpression->mAllocNode);
|
||||||
|
for (auto& expr : stringInterpolationExpression->mExpressions)
|
||||||
|
{
|
||||||
|
VisitChild(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BfSourceClassifier::Visit(BfTokenNode* tokenNode)
|
void BfSourceClassifier::Visit(BfTokenNode* tokenNode)
|
||||||
{
|
{
|
||||||
HandleLeafNode(tokenNode);
|
HandleLeafNode(tokenNode);
|
||||||
|
|
|
@ -109,6 +109,7 @@ public:
|
||||||
virtual void Visit(BfGenericInstanceTypeRef* typeRef) override;
|
virtual void Visit(BfGenericInstanceTypeRef* typeRef) override;
|
||||||
virtual void Visit(BfLocalMethodDeclaration * methodDecl) override;
|
virtual void Visit(BfLocalMethodDeclaration * methodDecl) override;
|
||||||
virtual void Visit(BfLiteralExpression* literalExpr) override;
|
virtual void Visit(BfLiteralExpression* literalExpr) override;
|
||||||
|
virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression) override;
|
||||||
virtual void Visit(BfTokenNode* tokenNode) override;
|
virtual void Visit(BfTokenNode* tokenNode) override;
|
||||||
virtual void Visit(BfInvocationExpression* invocationExpr) override;
|
virtual void Visit(BfInvocationExpression* invocationExpr) override;
|
||||||
virtual void Visit(BfIndexerExpression* indexerExpr) override;
|
virtual void Visit(BfIndexerExpression* indexerExpr) override;
|
||||||
|
|
24
IDEHelper/Tests/src/Strings.bf
Normal file
24
IDEHelper/Tests/src/Strings.bf
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Tests
|
||||||
|
{
|
||||||
|
class Strings
|
||||||
|
{
|
||||||
|
static void FormatString(String outString, String format, params Object[] args)
|
||||||
|
{
|
||||||
|
outString.AppendF(format, params args);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestBasics()
|
||||||
|
{
|
||||||
|
var str0 = scope $@"AB\C";
|
||||||
|
Test.Assert(str0 == "AB\\C");
|
||||||
|
var str1 = scope @$"\A{100+200}B{100+200:X}";
|
||||||
|
Test.Assert(str1 == "\\A300B12C");
|
||||||
|
var str2 = scope String();
|
||||||
|
FormatString(str2, $"\a{200+300}B{200+300:X}");
|
||||||
|
Test.Assert(str2 == "\a500B1F4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue