mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 20:12:21 +02:00
Enhanced ranges
This commit is contained in:
parent
eec2cb5e6c
commit
27fd5552cc
12 changed files with 365 additions and 22 deletions
|
@ -260,6 +260,17 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
public Span<T> this[IndexRange range]
|
||||
{
|
||||
#if !DEBUG
|
||||
[Inline]
|
||||
#endif
|
||||
get
|
||||
{
|
||||
return Span<T>(&mFirstElement, mLength)[range];
|
||||
}
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public T* CArray()
|
||||
{
|
||||
|
|
|
@ -211,6 +211,17 @@ namespace System.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public Span<T> this[IndexRange range]
|
||||
{
|
||||
#if !DEBUG
|
||||
[Inline]
|
||||
#endif
|
||||
get
|
||||
{
|
||||
return Span<T>(mItems, mSize)[range];
|
||||
}
|
||||
}
|
||||
|
||||
public ref T Front
|
||||
{
|
||||
get
|
||||
|
|
|
@ -8,6 +8,24 @@ namespace System
|
|||
|
||||
}
|
||||
|
||||
enum Index
|
||||
{
|
||||
case FromFront(int offset);
|
||||
case FromEnd(int offset);
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case .FromFront(let offset):
|
||||
offset.ToString(strBuffer);
|
||||
case .FromEnd(let offset):
|
||||
strBuffer.Append('^');
|
||||
offset.ToString(strBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Range : RangeExpression, IEnumerable<int>
|
||||
{
|
||||
protected int mStart;
|
||||
|
@ -110,6 +128,11 @@ namespace System
|
|||
mEnd = 0;
|
||||
}
|
||||
|
||||
public static operator IndexRange(Range list)
|
||||
{
|
||||
return .(.FromFront(list.mStart), .FromFront(list.mEnd), false);
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
|
@ -192,6 +215,103 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
struct IndexRange : RangeExpression
|
||||
{
|
||||
public Index mStart;
|
||||
public Index mEnd;
|
||||
public bool mIsClosed;
|
||||
|
||||
public this()
|
||||
{
|
||||
this = default;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public this(Index start, Index end, bool isClosed=true)
|
||||
{
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
mIsClosed = isClosed;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public this(int start, Index end, bool isClosed=true)
|
||||
{
|
||||
mStart = .FromFront(start);
|
||||
mEnd = end;
|
||||
mIsClosed = isClosed;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public this(Index start, int end, bool isClosed=true)
|
||||
{
|
||||
mStart = start;
|
||||
mEnd = .FromFront(end);
|
||||
mIsClosed = isClosed;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public this(int start, int end, bool isClosed=true)
|
||||
{
|
||||
mStart = .FromFront(start);
|
||||
mEnd = .FromFront(end);
|
||||
mIsClosed = isClosed;
|
||||
}
|
||||
|
||||
public Index Start
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mStart;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
mStart = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Index End
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
set mut
|
||||
{
|
||||
mEnd = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsClosed
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mIsClosed;
|
||||
}
|
||||
|
||||
set mut
|
||||
{
|
||||
mIsClosed = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
mStart.ToString(strBuffer);
|
||||
if (mIsClosed)
|
||||
strBuffer.Append("...");
|
||||
else
|
||||
strBuffer.Append("..<");
|
||||
mEnd.ToString(strBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
struct ClosedRange : RangeExpression, IEnumerable<int>
|
||||
{
|
||||
protected int mStart;
|
||||
|
@ -294,6 +414,11 @@ namespace System
|
|||
mEnd = 0;
|
||||
}
|
||||
|
||||
public static operator IndexRange(ClosedRange list)
|
||||
{
|
||||
return .(.FromFront(list.mStart), .FromFront(list.mEnd), true);
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
|
|
|
@ -134,6 +134,53 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
public Span<T> this[IndexRange range]
|
||||
{
|
||||
#if !DEBUG
|
||||
[Inline]
|
||||
#endif
|
||||
get
|
||||
{
|
||||
T* start;
|
||||
switch (range.mStart)
|
||||
{
|
||||
case .FromFront(let offset):
|
||||
Debug.Assert((uint)offset <= (uint)mLength);
|
||||
start = mPtr + offset;
|
||||
case .FromEnd(let offset):
|
||||
Debug.Assert((uint)offset <= (uint)mLength);
|
||||
start = mPtr + mLength - 1 - offset;
|
||||
}
|
||||
T* end;
|
||||
if (range.mIsClosed)
|
||||
{
|
||||
switch (range.mEnd)
|
||||
{
|
||||
case .FromFront(let offset):
|
||||
Debug.Assert((uint)offset < (uint)mLength);
|
||||
end = mPtr + offset + 1;
|
||||
case .FromEnd(let offset):
|
||||
Debug.Assert((uint)offset < (uint)mLength);
|
||||
end = mPtr + mLength - offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (range.mEnd)
|
||||
{
|
||||
case .FromFront(let offset):
|
||||
Debug.Assert((uint)offset <= (uint)mLength);
|
||||
end = mPtr + offset;
|
||||
case .FromEnd(let offset):
|
||||
Debug.Assert((uint)offset <= (uint)mLength);
|
||||
end = mPtr + mLength - 1 - offset;
|
||||
}
|
||||
}
|
||||
|
||||
return .(start, end - start);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<T> Slice(int index)
|
||||
{
|
||||
Debug.Assert((uint)index <= (uint)mLength);
|
||||
|
|
|
@ -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