mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +02:00
Enhanced ranges
This commit is contained in:
parent
eec2cb5e6c
commit
27fd5552cc
12 changed files with 365 additions and 22 deletions
|
@ -1753,9 +1753,10 @@ const char* Beefy::BfGetOpName(BfUnaryOp unaryOp)
|
|||
case BfUnaryOp_Mut: return "mut";
|
||||
case BfUnaryOp_Params: return "params";
|
||||
case BfUnaryOp_Cascade: return "..";
|
||||
case BfUnaryOp_FromEnd: return "^";
|
||||
case BfUnaryOp_PartialRangeUpTo: return "..<";
|
||||
case BfUnaryOp_PartialRangeThrough: return "...";
|
||||
case BfUnaryOp_PartialRangeFrom: return "...";
|
||||
case BfUnaryOp_PartialRangeFrom: return "...";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
@ -1855,6 +1856,8 @@ BfUnaryOp Beefy::BfTokenToUnaryOp(BfToken token)
|
|||
return BfUnaryOp_Params;
|
||||
case BfToken_DotDot:
|
||||
return BfUnaryOp_Cascade;
|
||||
case BfToken_Carat:
|
||||
return BfUnaryOp_FromEnd;
|
||||
case BfToken_DotDotDot:
|
||||
return BfUnaryOp_PartialRangeThrough;
|
||||
case BfToken_DotDotLess:
|
||||
|
|
|
@ -1866,6 +1866,7 @@ enum BfUnaryOp
|
|||
BfUnaryOp_Mut,
|
||||
BfUnaryOp_Params,
|
||||
BfUnaryOp_Cascade,
|
||||
BfUnaryOp_FromEnd,
|
||||
BfUnaryOp_PartialRangeUpTo,
|
||||
BfUnaryOp_PartialRangeThrough,
|
||||
BfUnaryOp_PartialRangeFrom,
|
||||
|
|
|
@ -384,6 +384,8 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
|
|||
mSpanTypeDef = NULL;
|
||||
mRangeTypeDef = NULL;
|
||||
mClosedRangeTypeDef = NULL;
|
||||
mIndexTypeDef = NULL;
|
||||
mIndexRangeTypeDef = NULL;
|
||||
mAttributeTypeDef = NULL;
|
||||
mAttributeUsageAttributeTypeDef = NULL;
|
||||
mClassVDataTypeDef = NULL;
|
||||
|
@ -6723,6 +6725,8 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
|||
mSpanTypeDef = _GetRequiredType("System.Span", 1);
|
||||
mRangeTypeDef = _GetRequiredType("System.Range");
|
||||
mClosedRangeTypeDef = _GetRequiredType("System.ClosedRange");
|
||||
mIndexTypeDef = _GetRequiredType("System.Index");
|
||||
mIndexRangeTypeDef = _GetRequiredType("System.IndexRange");
|
||||
mAttributeTypeDef = _GetRequiredType("System.Attribute");
|
||||
mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute");
|
||||
mClassVDataTypeDef = _GetRequiredType("System.ClassVData");
|
||||
|
|
|
@ -349,6 +349,8 @@ public:
|
|||
BfTypeDef* mSpanTypeDef;
|
||||
BfTypeDef* mRangeTypeDef;
|
||||
BfTypeDef* mClosedRangeTypeDef;
|
||||
BfTypeDef* mIndexTypeDef;
|
||||
BfTypeDef* mIndexRangeTypeDef;
|
||||
|
||||
BfTypeDef* mClassVDataTypeDef;
|
||||
|
||||
|
|
|
@ -15220,11 +15220,6 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
|
|||
}
|
||||
|
||||
auto autoComplete = GetAutoComplete();
|
||||
if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo) && (autoComplete->mMethodMatchInfo == NULL))
|
||||
{
|
||||
NOP;
|
||||
}
|
||||
|
||||
if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo) && (autoComplete->mMethodMatchInfo != NULL) && (autoComplete->mMethodMatchInfo->mInstanceList.size() != 0))
|
||||
autoComplete->mIsCapturingMethodMatchInfo = false;
|
||||
|
||||
|
@ -19797,6 +19792,13 @@ void BfExprEvaluator::Visit(BfUnaryOperatorExpression* unaryOpExpr)
|
|||
|
||||
void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags)
|
||||
{
|
||||
if ((unaryOpExpr == NULL) && (unaryOp == BfUnaryOp_PartialRangeThrough))
|
||||
{
|
||||
PerformBinaryOperation(NULL, NULL, BfBinaryOp_ClosedRange, opToken, BfBinOpFlag_None);
|
||||
return;
|
||||
}
|
||||
|
||||
///
|
||||
{
|
||||
// If this is a cast, we don't want the value to be coerced before the unary operator is applied.
|
||||
// WAIT: Why not?
|
||||
|
@ -20456,8 +20458,32 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
|
|||
mModule->Fail("Illegal use of argument cascade expression", opToken);
|
||||
}
|
||||
break;
|
||||
case BfUnaryOp_FromEnd:
|
||||
{
|
||||
CheckResultForReading(mResult);
|
||||
auto value = mModule->Cast(unaryOpExpr, mResult, mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||
value = mModule->LoadValue(value);
|
||||
if (value)
|
||||
{
|
||||
auto indexType = mModule->ResolveTypeDef(mModule->mCompiler->mIndexTypeDef);
|
||||
auto alloca = mModule->CreateAlloca(indexType);
|
||||
mModule->mBfIRBuilder->CreateStore(value.mValue, mModule->mBfIRBuilder->CreateInBoundsGEP(mModule->mBfIRBuilder->CreateInBoundsGEP(alloca, 0, 1), 0, 1));
|
||||
mModule->mBfIRBuilder->CreateStore(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Int8, 1), mModule->mBfIRBuilder->CreateInBoundsGEP(alloca, 0, 2));
|
||||
mResult = BfTypedValue(alloca, indexType, BfTypedValueKind_Addr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BfUnaryOp_PartialRangeUpTo:
|
||||
PerformBinaryOperation(NULL, unaryOpExpr, BfBinaryOp_Range, opToken, BfBinOpFlag_None);
|
||||
break;
|
||||
case BfUnaryOp_PartialRangeThrough:
|
||||
PerformBinaryOperation(NULL, unaryOpExpr, BfBinaryOp_ClosedRange, opToken, BfBinOpFlag_None);
|
||||
break;
|
||||
case BfUnaryOp_PartialRangeFrom:
|
||||
PerformBinaryOperation(unaryOpExpr, NULL, BfBinaryOp_ClosedRange, opToken, BfBinOpFlag_None);
|
||||
break;
|
||||
default:
|
||||
mModule->Fail("INTERNAL ERROR: Unhandled unary operator", unaryOpExpr);
|
||||
mModule->Fail(StrFormat("Illegal use of '%s' unary operator", BfGetOpName(unaryOp)), unaryOpExpr);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -20792,12 +20818,74 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
|
|||
{
|
||||
auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
||||
|
||||
auto allocType = mModule->ResolveTypeDef((binaryOp == BfBinaryOp_Range) ? mModule->mCompiler->mRangeTypeDef : mModule->mCompiler->mClosedRangeTypeDef)->ToTypeInstance();
|
||||
bool isIndexExpr = false;
|
||||
BfTypeDef* typeDef = NULL;
|
||||
if (auto unaryOpExpr = BfNodeDynCast<BfUnaryOperatorExpression>(leftExpression))
|
||||
if (unaryOpExpr->mOp == BfUnaryOp_FromEnd)
|
||||
isIndexExpr = true;
|
||||
if (rightExpression == NULL)
|
||||
isIndexExpr = true;
|
||||
if (auto unaryOpExpr = BfNodeDynCast<BfUnaryOperatorExpression>(rightExpression))
|
||||
if (unaryOpExpr->mOp == BfUnaryOp_FromEnd)
|
||||
isIndexExpr = true;
|
||||
|
||||
if (isIndexExpr)
|
||||
typeDef = mModule->mCompiler->mIndexRangeTypeDef;
|
||||
else
|
||||
typeDef = (binaryOp == BfBinaryOp_Range) ? mModule->mCompiler->mRangeTypeDef : mModule->mCompiler->mClosedRangeTypeDef;
|
||||
|
||||
auto allocType = mModule->ResolveTypeDef(typeDef)->ToTypeInstance();
|
||||
auto alloca = mModule->CreateAlloca(allocType);
|
||||
|
||||
BfTypedValueExpression leftTypedValueExpr;
|
||||
BfTypedValueExpression rightTypedValueExpr;
|
||||
BfTypedValueExpression isClosedTypedValueExpr;
|
||||
|
||||
SizedArray<BfExpression*, 2> argExprs;
|
||||
argExprs.Add(leftExpression);
|
||||
argExprs.Add(rightExpression);
|
||||
if (leftExpression != NULL)
|
||||
{
|
||||
argExprs.Add(leftExpression);
|
||||
}
|
||||
else
|
||||
{
|
||||
leftTypedValueExpr.mRefNode = opToken;
|
||||
leftTypedValueExpr.mTypedValue = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||
argExprs.Add(&leftTypedValueExpr);
|
||||
}
|
||||
|
||||
if (rightExpression != NULL)
|
||||
{
|
||||
argExprs.Add(rightExpression);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add as a `^0`
|
||||
auto indexType = mModule->ResolveTypeDef(mModule->mCompiler->mIndexTypeDef)->ToTypeInstance();
|
||||
rightTypedValueExpr.mRefNode = opToken;
|
||||
|
||||
auto valueTypeEmpty = mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(indexType->mBaseType), {});
|
||||
|
||||
SizedArray<BfIRValue, 8> tupleMembers;
|
||||
tupleMembers.Add(valueTypeEmpty);
|
||||
tupleMembers.Add(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0));
|
||||
auto tupleValue = mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(indexType->mFieldInstances[0].mResolvedType), tupleMembers);
|
||||
|
||||
SizedArray<BfIRValue, 8> indexMembers;
|
||||
indexMembers.Add(valueTypeEmpty);
|
||||
indexMembers.Add(tupleValue);
|
||||
indexMembers.Add(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Int8, 1));
|
||||
auto indexValue = mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(indexType), indexMembers);
|
||||
|
||||
rightTypedValueExpr.mTypedValue = BfTypedValue(indexValue, indexType);
|
||||
argExprs.Add(&rightTypedValueExpr);
|
||||
}
|
||||
|
||||
if (isIndexExpr)
|
||||
{
|
||||
isClosedTypedValueExpr.mRefNode = opToken;
|
||||
isClosedTypedValueExpr.mTypedValue = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, (binaryOp == BfBinaryOp_ClosedRange) ? 1 : 0), mModule->GetPrimitiveType(BfTypeCode_Boolean));
|
||||
argExprs.Add(&isClosedTypedValueExpr);
|
||||
}
|
||||
|
||||
BfSizedArray<BfExpression*> args = argExprs;
|
||||
|
||||
|
|
|
@ -2277,14 +2277,15 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
|
||||
CreateExprFlags innerFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_EarlyExit);
|
||||
if (unaryOp == BfUnaryOp_Cascade)
|
||||
{
|
||||
innerFlags = (CreateExprFlags)(innerFlags | (createExprFlags & CreateExprFlags_AllowVariableDecl));
|
||||
}
|
||||
|
||||
if (unaryOp == BfUnaryOp_PartialRangeThrough) // This allows for just a naked '...'
|
||||
innerFlags = (CreateExprFlags)(innerFlags | CreateExprFlags_AllowEmpty);
|
||||
|
||||
// Don't attempt binary or unary operations- they will always be lower precedence
|
||||
unaryOpExpr->mExpression = CreateExpressionAfter(unaryOpExpr, innerFlags);
|
||||
if (unaryOpExpr->mExpression == NULL)
|
||||
return NULL;
|
||||
return unaryOpExpr;
|
||||
MoveNode(unaryOpExpr->mExpression, unaryOpExpr);
|
||||
}
|
||||
|
||||
|
@ -2356,7 +2357,8 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
|
||||
if (exprLeft == NULL)
|
||||
{
|
||||
Fail("Expected expression", node);
|
||||
if ((createExprFlags & CreateExprFlags_AllowEmpty) == 0)
|
||||
Fail("Expected expression", node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2377,7 +2379,7 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
if (token == BfToken_DblPlus)
|
||||
postUnaryOp = BfUnaryOp_PostIncrement;
|
||||
if (token == BfToken_DblMinus)
|
||||
postUnaryOp = BfUnaryOp_PostDecrement;
|
||||
postUnaryOp = BfUnaryOp_PostDecrement;
|
||||
|
||||
if (token == BfToken_DotDotDot)
|
||||
{
|
||||
|
@ -2700,17 +2702,36 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
{
|
||||
if ((createExprFlags & CreateExprFlags_EarlyExit) != 0)
|
||||
return exprLeft;
|
||||
auto binOpExpression = mAlloc->Alloc<BfBinaryOperatorExpression>();
|
||||
ReplaceNode(exprLeft, binOpExpression);
|
||||
binOpExpression->mLeft = exprLeft;
|
||||
binOpExpression->mOp = binOp;
|
||||
MEMBER_SET(binOpExpression, mOpToken, tokenNode);
|
||||
|
||||
mVisitorPos.MoveNext();
|
||||
|
||||
// We only need to check binary operator precedence at the "top level" binary operator
|
||||
rhsCreateExprFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_NoCheckBinOpPrecedence);
|
||||
|
||||
auto exprRight = CreateExpressionAfter(binOpExpression, rhsCreateExprFlags);
|
||||
if (tokenNode->mToken == BfToken_DotDotDot)
|
||||
rhsCreateExprFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_AllowEmpty);
|
||||
|
||||
BfExpression* exprRight = CreateExpressionAfter(tokenNode, rhsCreateExprFlags);
|
||||
|
||||
if (exprRight == NULL)
|
||||
{
|
||||
if (tokenNode->mToken == BfToken_DotDotDot)
|
||||
{
|
||||
auto unaryOpExpression = mAlloc->Alloc<BfUnaryOperatorExpression>();
|
||||
ReplaceNode(exprLeft, unaryOpExpression);
|
||||
unaryOpExpression->mExpression = exprLeft;
|
||||
unaryOpExpression->mOp = BfUnaryOp_PartialRangeFrom;
|
||||
MEMBER_SET(unaryOpExpression, mOpToken, tokenNode);
|
||||
return unaryOpExpression;
|
||||
}
|
||||
}
|
||||
|
||||
auto binOpExpression = mAlloc->Alloc<BfBinaryOperatorExpression>();
|
||||
ReplaceNode(exprLeft, binOpExpression);
|
||||
binOpExpression->mLeft = exprLeft;
|
||||
binOpExpression->mOp = binOp;
|
||||
MEMBER_SET(binOpExpression, mOpToken, tokenNode);
|
||||
|
||||
if (exprRight == NULL)
|
||||
return binOpExpression;
|
||||
MEMBER_SET(binOpExpression, mRight, exprRight);
|
||||
|
|
|
@ -26,7 +26,8 @@ public:
|
|||
CreateExprFlags_ExitOnParenExpr = 0x80,
|
||||
CreateExprFlags_NoCheckBinOpPrecedence = 0x100,
|
||||
CreateExprFlags_BreakOnCascade = 0x200,
|
||||
CreateExprFlags_EarlyExit = 0x400 // Don't attempt binary or ternary operations
|
||||
CreateExprFlags_EarlyExit = 0x400, // Don't attempt binary or ternary operations
|
||||
CreateExprFlags_AllowEmpty = 0x800
|
||||
};
|
||||
|
||||
enum CreateStmtFlags
|
||||
|
|
|
@ -133,6 +133,35 @@ namespace Tests
|
|||
Test.Assert((1..<3).Contains(1..<3));
|
||||
Test.Assert(!(1..<3).Contains(1..<4));
|
||||
|
||||
List<int> iList = scope .() { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
|
||||
total = 0;
|
||||
for (int i in iList[...])
|
||||
total += i;
|
||||
Test.Assert(total == 10+20+30+40+50+60+70+80+90+100);
|
||||
|
||||
total = 0;
|
||||
for (int i in iList[1...])
|
||||
total += i;
|
||||
Test.Assert(total == 20+30+40+50+60+70+80+90+100);
|
||||
|
||||
total = 0;
|
||||
for (int i in iList[...^1])
|
||||
total += i;
|
||||
Test.Assert(total == 10+20+30+40+50+60+70+80+90);
|
||||
|
||||
total = 0;
|
||||
for (int i in iList[..<^1])
|
||||
total += i;
|
||||
Test.Assert(total == 10+20+30+40+50+60+70+80);
|
||||
|
||||
total = 0;
|
||||
for (int i in iList[...^1][1...^1])
|
||||
total += i;
|
||||
Test.Assert(total == 20+30+40+50+60+70+80);
|
||||
|
||||
var str = scope String();
|
||||
(2...^3).ToString(str);
|
||||
Test.Assert(str == "2...^3");
|
||||
}
|
||||
|
||||
public static void TestEnumerator1(EnumeratorTest e)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue