mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 03:52:19 +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]
|
[Inline]
|
||||||
public T* CArray()
|
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
|
public ref T Front
|
||||||
{
|
{
|
||||||
get
|
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>
|
struct Range : RangeExpression, IEnumerable<int>
|
||||||
{
|
{
|
||||||
protected int mStart;
|
protected int mStart;
|
||||||
|
@ -110,6 +128,11 @@ namespace System
|
||||||
mEnd = 0;
|
mEnd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static operator IndexRange(Range list)
|
||||||
|
{
|
||||||
|
return .(.FromFront(list.mStart), .FromFront(list.mEnd), false);
|
||||||
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Enumerator GetEnumerator()
|
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>
|
struct ClosedRange : RangeExpression, IEnumerable<int>
|
||||||
{
|
{
|
||||||
protected int mStart;
|
protected int mStart;
|
||||||
|
@ -294,6 +414,11 @@ namespace System
|
||||||
mEnd = 0;
|
mEnd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static operator IndexRange(ClosedRange list)
|
||||||
|
{
|
||||||
|
return .(.FromFront(list.mStart), .FromFront(list.mEnd), true);
|
||||||
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Enumerator GetEnumerator()
|
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)
|
public Span<T> Slice(int index)
|
||||||
{
|
{
|
||||||
Debug.Assert((uint)index <= (uint)mLength);
|
Debug.Assert((uint)index <= (uint)mLength);
|
||||||
|
|
|
@ -1753,9 +1753,10 @@ const char* Beefy::BfGetOpName(BfUnaryOp unaryOp)
|
||||||
case BfUnaryOp_Mut: return "mut";
|
case BfUnaryOp_Mut: return "mut";
|
||||||
case BfUnaryOp_Params: return "params";
|
case BfUnaryOp_Params: return "params";
|
||||||
case BfUnaryOp_Cascade: return "..";
|
case BfUnaryOp_Cascade: return "..";
|
||||||
|
case BfUnaryOp_FromEnd: return "^";
|
||||||
case BfUnaryOp_PartialRangeUpTo: return "..<";
|
case BfUnaryOp_PartialRangeUpTo: return "..<";
|
||||||
case BfUnaryOp_PartialRangeThrough: return "...";
|
case BfUnaryOp_PartialRangeThrough: return "...";
|
||||||
case BfUnaryOp_PartialRangeFrom: return "...";
|
case BfUnaryOp_PartialRangeFrom: return "...";
|
||||||
default: return "???";
|
default: return "???";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1855,6 +1856,8 @@ BfUnaryOp Beefy::BfTokenToUnaryOp(BfToken token)
|
||||||
return BfUnaryOp_Params;
|
return BfUnaryOp_Params;
|
||||||
case BfToken_DotDot:
|
case BfToken_DotDot:
|
||||||
return BfUnaryOp_Cascade;
|
return BfUnaryOp_Cascade;
|
||||||
|
case BfToken_Carat:
|
||||||
|
return BfUnaryOp_FromEnd;
|
||||||
case BfToken_DotDotDot:
|
case BfToken_DotDotDot:
|
||||||
return BfUnaryOp_PartialRangeThrough;
|
return BfUnaryOp_PartialRangeThrough;
|
||||||
case BfToken_DotDotLess:
|
case BfToken_DotDotLess:
|
||||||
|
|
|
@ -1866,6 +1866,7 @@ enum BfUnaryOp
|
||||||
BfUnaryOp_Mut,
|
BfUnaryOp_Mut,
|
||||||
BfUnaryOp_Params,
|
BfUnaryOp_Params,
|
||||||
BfUnaryOp_Cascade,
|
BfUnaryOp_Cascade,
|
||||||
|
BfUnaryOp_FromEnd,
|
||||||
BfUnaryOp_PartialRangeUpTo,
|
BfUnaryOp_PartialRangeUpTo,
|
||||||
BfUnaryOp_PartialRangeThrough,
|
BfUnaryOp_PartialRangeThrough,
|
||||||
BfUnaryOp_PartialRangeFrom,
|
BfUnaryOp_PartialRangeFrom,
|
||||||
|
|
|
@ -384,6 +384,8 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
|
||||||
mSpanTypeDef = NULL;
|
mSpanTypeDef = NULL;
|
||||||
mRangeTypeDef = NULL;
|
mRangeTypeDef = NULL;
|
||||||
mClosedRangeTypeDef = NULL;
|
mClosedRangeTypeDef = NULL;
|
||||||
|
mIndexTypeDef = NULL;
|
||||||
|
mIndexRangeTypeDef = NULL;
|
||||||
mAttributeTypeDef = NULL;
|
mAttributeTypeDef = NULL;
|
||||||
mAttributeUsageAttributeTypeDef = NULL;
|
mAttributeUsageAttributeTypeDef = NULL;
|
||||||
mClassVDataTypeDef = NULL;
|
mClassVDataTypeDef = NULL;
|
||||||
|
@ -6723,6 +6725,8 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
||||||
mSpanTypeDef = _GetRequiredType("System.Span", 1);
|
mSpanTypeDef = _GetRequiredType("System.Span", 1);
|
||||||
mRangeTypeDef = _GetRequiredType("System.Range");
|
mRangeTypeDef = _GetRequiredType("System.Range");
|
||||||
mClosedRangeTypeDef = _GetRequiredType("System.ClosedRange");
|
mClosedRangeTypeDef = _GetRequiredType("System.ClosedRange");
|
||||||
|
mIndexTypeDef = _GetRequiredType("System.Index");
|
||||||
|
mIndexRangeTypeDef = _GetRequiredType("System.IndexRange");
|
||||||
mAttributeTypeDef = _GetRequiredType("System.Attribute");
|
mAttributeTypeDef = _GetRequiredType("System.Attribute");
|
||||||
mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute");
|
mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute");
|
||||||
mClassVDataTypeDef = _GetRequiredType("System.ClassVData");
|
mClassVDataTypeDef = _GetRequiredType("System.ClassVData");
|
||||||
|
|
|
@ -349,6 +349,8 @@ public:
|
||||||
BfTypeDef* mSpanTypeDef;
|
BfTypeDef* mSpanTypeDef;
|
||||||
BfTypeDef* mRangeTypeDef;
|
BfTypeDef* mRangeTypeDef;
|
||||||
BfTypeDef* mClosedRangeTypeDef;
|
BfTypeDef* mClosedRangeTypeDef;
|
||||||
|
BfTypeDef* mIndexTypeDef;
|
||||||
|
BfTypeDef* mIndexRangeTypeDef;
|
||||||
|
|
||||||
BfTypeDef* mClassVDataTypeDef;
|
BfTypeDef* mClassVDataTypeDef;
|
||||||
|
|
||||||
|
|
|
@ -15220,11 +15220,6 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
|
||||||
}
|
}
|
||||||
|
|
||||||
auto autoComplete = GetAutoComplete();
|
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))
|
if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo) && (autoComplete->mMethodMatchInfo != NULL) && (autoComplete->mMethodMatchInfo->mInstanceList.size() != 0))
|
||||||
autoComplete->mIsCapturingMethodMatchInfo = false;
|
autoComplete->mIsCapturingMethodMatchInfo = false;
|
||||||
|
|
||||||
|
@ -19797,6 +19792,13 @@ void BfExprEvaluator::Visit(BfUnaryOperatorExpression* unaryOpExpr)
|
||||||
|
|
||||||
void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags)
|
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.
|
// If this is a cast, we don't want the value to be coerced before the unary operator is applied.
|
||||||
// WAIT: Why not?
|
// WAIT: Why not?
|
||||||
|
@ -20456,8 +20458,32 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
|
||||||
mModule->Fail("Illegal use of argument cascade expression", opToken);
|
mModule->Fail("Illegal use of argument cascade expression", opToken);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
mModule->Fail("INTERNAL ERROR: Unhandled unary operator", unaryOpExpr);
|
mModule->Fail(StrFormat("Illegal use of '%s' unary operator", BfGetOpName(unaryOp)), unaryOpExpr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20792,12 +20818,74 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
|
||||||
{
|
{
|
||||||
auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
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);
|
auto alloca = mModule->CreateAlloca(allocType);
|
||||||
|
|
||||||
|
BfTypedValueExpression leftTypedValueExpr;
|
||||||
|
BfTypedValueExpression rightTypedValueExpr;
|
||||||
|
BfTypedValueExpression isClosedTypedValueExpr;
|
||||||
|
|
||||||
SizedArray<BfExpression*, 2> argExprs;
|
SizedArray<BfExpression*, 2> argExprs;
|
||||||
argExprs.Add(leftExpression);
|
if (leftExpression != NULL)
|
||||||
argExprs.Add(rightExpression);
|
{
|
||||||
|
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;
|
BfSizedArray<BfExpression*> args = argExprs;
|
||||||
|
|
||||||
|
|
|
@ -2277,14 +2277,15 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
||||||
|
|
||||||
CreateExprFlags innerFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_EarlyExit);
|
CreateExprFlags innerFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_EarlyExit);
|
||||||
if (unaryOp == BfUnaryOp_Cascade)
|
if (unaryOp == BfUnaryOp_Cascade)
|
||||||
{
|
|
||||||
innerFlags = (CreateExprFlags)(innerFlags | (createExprFlags & CreateExprFlags_AllowVariableDecl));
|
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
|
// Don't attempt binary or unary operations- they will always be lower precedence
|
||||||
unaryOpExpr->mExpression = CreateExpressionAfter(unaryOpExpr, innerFlags);
|
unaryOpExpr->mExpression = CreateExpressionAfter(unaryOpExpr, innerFlags);
|
||||||
if (unaryOpExpr->mExpression == NULL)
|
if (unaryOpExpr->mExpression == NULL)
|
||||||
return NULL;
|
return unaryOpExpr;
|
||||||
MoveNode(unaryOpExpr->mExpression, unaryOpExpr);
|
MoveNode(unaryOpExpr->mExpression, unaryOpExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2356,7 +2357,8 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
||||||
|
|
||||||
if (exprLeft == NULL)
|
if (exprLeft == NULL)
|
||||||
{
|
{
|
||||||
Fail("Expected expression", node);
|
if ((createExprFlags & CreateExprFlags_AllowEmpty) == 0)
|
||||||
|
Fail("Expected expression", node);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2377,7 +2379,7 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
||||||
if (token == BfToken_DblPlus)
|
if (token == BfToken_DblPlus)
|
||||||
postUnaryOp = BfUnaryOp_PostIncrement;
|
postUnaryOp = BfUnaryOp_PostIncrement;
|
||||||
if (token == BfToken_DblMinus)
|
if (token == BfToken_DblMinus)
|
||||||
postUnaryOp = BfUnaryOp_PostDecrement;
|
postUnaryOp = BfUnaryOp_PostDecrement;
|
||||||
|
|
||||||
if (token == BfToken_DotDotDot)
|
if (token == BfToken_DotDotDot)
|
||||||
{
|
{
|
||||||
|
@ -2700,17 +2702,36 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
||||||
{
|
{
|
||||||
if ((createExprFlags & CreateExprFlags_EarlyExit) != 0)
|
if ((createExprFlags & CreateExprFlags_EarlyExit) != 0)
|
||||||
return exprLeft;
|
return exprLeft;
|
||||||
auto binOpExpression = mAlloc->Alloc<BfBinaryOperatorExpression>();
|
|
||||||
ReplaceNode(exprLeft, binOpExpression);
|
|
||||||
binOpExpression->mLeft = exprLeft;
|
|
||||||
binOpExpression->mOp = binOp;
|
|
||||||
MEMBER_SET(binOpExpression, mOpToken, tokenNode);
|
|
||||||
mVisitorPos.MoveNext();
|
mVisitorPos.MoveNext();
|
||||||
|
|
||||||
// We only need to check binary operator precedence at the "top level" binary operator
|
// We only need to check binary operator precedence at the "top level" binary operator
|
||||||
rhsCreateExprFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_NoCheckBinOpPrecedence);
|
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)
|
if (exprRight == NULL)
|
||||||
return binOpExpression;
|
return binOpExpression;
|
||||||
MEMBER_SET(binOpExpression, mRight, exprRight);
|
MEMBER_SET(binOpExpression, mRight, exprRight);
|
||||||
|
|
|
@ -26,7 +26,8 @@ public:
|
||||||
CreateExprFlags_ExitOnParenExpr = 0x80,
|
CreateExprFlags_ExitOnParenExpr = 0x80,
|
||||||
CreateExprFlags_NoCheckBinOpPrecedence = 0x100,
|
CreateExprFlags_NoCheckBinOpPrecedence = 0x100,
|
||||||
CreateExprFlags_BreakOnCascade = 0x200,
|
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
|
enum CreateStmtFlags
|
||||||
|
|
|
@ -133,6 +133,35 @@ namespace Tests
|
||||||
Test.Assert((1..<3).Contains(1..<3));
|
Test.Assert((1..<3).Contains(1..<3));
|
||||||
Test.Assert(!(1..<3).Contains(1..<4));
|
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)
|
public static void TestEnumerator1(EnumeratorTest e)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue