mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 19:48:20 +02:00
Ranges (ie: for (int a in 0..<count)
for (int i in 1…10)
)
This commit is contained in:
parent
e561a26695
commit
465050b81d
11 changed files with 418 additions and 18 deletions
271
BeefLibs/corlib/src/Range.bf
Normal file
271
BeefLibs/corlib/src/Range.bf
Normal file
|
@ -0,0 +1,271 @@
|
|||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System
|
||||
{
|
||||
interface RangeExpression
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct Range : RangeExpression, IEnumerable<int>
|
||||
{
|
||||
protected int mStart;
|
||||
protected int mEnd;
|
||||
|
||||
public this()
|
||||
{
|
||||
mStart = 0;
|
||||
mEnd = 0;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public this(int start, int end)
|
||||
{
|
||||
Debug.Assert(end >= start);
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd - mStart;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
mEnd = mStart + value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Start
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mStart;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
mStart = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int End
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
set mut
|
||||
{
|
||||
mEnd = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd == mStart;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(int idx)
|
||||
{
|
||||
return (idx >= mStart) && (idx < mStart);
|
||||
}
|
||||
|
||||
public void Clear() mut
|
||||
{
|
||||
mStart = 0;
|
||||
mEnd = 0;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return Enumerator(this);
|
||||
}
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
strBuffer.AppendF($"{mStart}..<{mEnd}");
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
private int mEnd;
|
||||
private int mIndex;
|
||||
|
||||
[Inline]
|
||||
public this(Range range)
|
||||
{
|
||||
mIndex = range.mStart - 1;
|
||||
mEnd = range.mEnd;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public ref int Index
|
||||
{
|
||||
get mut
|
||||
{
|
||||
return ref mIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public int End => mEnd;
|
||||
|
||||
[Inline]
|
||||
public Result<int> GetNext() mut
|
||||
{
|
||||
if (mIndex + 1 >= mEnd)
|
||||
return .Err;
|
||||
return ++mIndex;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct ClosedRange : RangeExpression, IEnumerable<int>
|
||||
{
|
||||
protected int mStart;
|
||||
protected int mEnd;
|
||||
|
||||
public this()
|
||||
{
|
||||
mStart = 0;
|
||||
mEnd = 0;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public this(int start, int end)
|
||||
{
|
||||
Debug.Assert(end >= start);
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd - mStart;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
mEnd = mStart + value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Start
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mStart;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
mStart = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int End
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
set mut
|
||||
{
|
||||
mEnd = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd == mStart;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(int idx)
|
||||
{
|
||||
return (idx >= mStart) && (idx < mStart);
|
||||
}
|
||||
|
||||
public void Clear() mut
|
||||
{
|
||||
mStart = 0;
|
||||
mEnd = 0;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return Enumerator(this);
|
||||
}
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
strBuffer.AppendF($"{mStart}...{mEnd}");
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
private int mEnd;
|
||||
private int mIndex;
|
||||
|
||||
[Inline]
|
||||
public this(ClosedRange range)
|
||||
{
|
||||
mIndex = range.mStart - 1;
|
||||
mEnd = range.mEnd;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public ref int Index
|
||||
{
|
||||
get mut
|
||||
{
|
||||
return ref mIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public int End => mEnd;
|
||||
|
||||
[Inline]
|
||||
public Result<int> GetNext() mut
|
||||
{
|
||||
if (mIndex >= mEnd)
|
||||
return .Err;
|
||||
return ++mIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
IDE/mintest/minlib/src/System/Range.bf
Normal file
43
IDE/mintest/minlib/src/System/Range.bf
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System
|
||||
{
|
||||
struct Range
|
||||
{
|
||||
protected int mStart;
|
||||
protected int mEnd;
|
||||
|
||||
public this()
|
||||
{
|
||||
mStart = 0;
|
||||
mEnd = 0;
|
||||
}
|
||||
|
||||
public this(int start, int end)
|
||||
{
|
||||
Debug.Assert(end >= start);
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
}
|
||||
}
|
||||
|
||||
struct ClosedRange
|
||||
{
|
||||
protected int mStart;
|
||||
protected int mEnd;
|
||||
|
||||
public this()
|
||||
{
|
||||
mStart = 0;
|
||||
mEnd = 0;
|
||||
}
|
||||
|
||||
public this(int start, int end)
|
||||
{
|
||||
Debug.Assert(end >= start);
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1545,6 +1545,8 @@ const char* Beefy::BfTokenToString(BfToken token)
|
|||
return "..";
|
||||
case BfToken_DotDotDot:
|
||||
return "...";
|
||||
case BfToken_DotDotLess:
|
||||
return "..<";
|
||||
case BfToken_QuestionDot:
|
||||
return "?.";
|
||||
case BfToken_QuestionLBracket:
|
||||
|
@ -1639,22 +1641,24 @@ int Beefy::BfGetBinaryOpPrecendence(BfBinaryOp binOp)
|
|||
case BfBinaryOp_OverflowMultiply:
|
||||
case BfBinaryOp_Divide:
|
||||
case BfBinaryOp_Modulus:
|
||||
return 13;
|
||||
return 14;
|
||||
case BfBinaryOp_Add:
|
||||
case BfBinaryOp_Subtract:
|
||||
case BfBinaryOp_OverflowAdd:
|
||||
case BfBinaryOp_OverflowSubtract:
|
||||
return 12;
|
||||
return 13;
|
||||
case BfBinaryOp_LeftShift:
|
||||
case BfBinaryOp_RightShift:
|
||||
return 11;
|
||||
return 12;
|
||||
case BfBinaryOp_BitwiseAnd:
|
||||
return 10;
|
||||
return 11;
|
||||
case BfBinaryOp_ExclusiveOr:
|
||||
return 9;
|
||||
return 10;
|
||||
case BfBinaryOp_BitwiseOr:
|
||||
return 9;
|
||||
case BfBinaryOp_Range:
|
||||
case BfBinaryOp_ClosedRange:
|
||||
return 8;
|
||||
// "Range" inserted here if we were copying swift
|
||||
case BfBinaryOp_Is:
|
||||
case BfBinaryOp_As:
|
||||
return 7;
|
||||
|
@ -1715,6 +1719,8 @@ const char* Beefy::BfGetOpName(BfBinaryOp binOp)
|
|||
case BfBinaryOp_NullCoalesce: return "??";
|
||||
case BfBinaryOp_Is: return "is";
|
||||
case BfBinaryOp_As: return "as";
|
||||
case BfBinaryOp_Range: return "..<";
|
||||
case BfBinaryOp_ClosedRange: return "...";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
@ -1740,6 +1746,9 @@ const char* Beefy::BfGetOpName(BfUnaryOp unaryOp)
|
|||
case BfUnaryOp_Mut: return "mut";
|
||||
case BfUnaryOp_Params: return "params";
|
||||
case BfUnaryOp_Cascade: return "..";
|
||||
case BfUnaryOp_PartialRangeUpTo: return "..<";
|
||||
case BfUnaryOp_PartialRangeThrough: return "...";
|
||||
case BfUnaryOp_PartialRangeFrom: return "...";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
@ -1798,6 +1807,10 @@ BfBinaryOp Beefy::BfTokenToBinaryOp(BfToken token)
|
|||
return BfBinaryOp_ConditionalOr;
|
||||
case BfToken_DblQuestion:
|
||||
return BfBinaryOp_NullCoalesce;
|
||||
case BfToken_DotDotLess:
|
||||
return BfBinaryOp_Range;
|
||||
case BfToken_DotDotDot:
|
||||
return BfBinaryOp_ClosedRange;
|
||||
default:
|
||||
return BfBinaryOp_None;
|
||||
}
|
||||
|
@ -1835,6 +1848,10 @@ BfUnaryOp Beefy::BfTokenToUnaryOp(BfToken token)
|
|||
return BfUnaryOp_Params;
|
||||
case BfToken_DotDot:
|
||||
return BfUnaryOp_Cascade;
|
||||
case BfToken_DotDotDot:
|
||||
return BfUnaryOp_PartialRangeThrough;
|
||||
case BfToken_DotDotLess:
|
||||
return BfUnaryOp_PartialRangeUpTo;
|
||||
default:
|
||||
return BfUnaryOp_None;
|
||||
}
|
||||
|
|
|
@ -232,6 +232,7 @@ enum BfToken : uint8
|
|||
BfToken_Dot,
|
||||
BfToken_DotDot,
|
||||
BfToken_DotDotDot,
|
||||
BfToken_DotDotLess,
|
||||
BfToken_QuestionDot,
|
||||
BfToken_QuestionLBracket,
|
||||
BfToken_AutocompleteDot,
|
||||
|
@ -1821,7 +1822,9 @@ enum BfBinaryOp
|
|||
BfBinaryOp_ConditionalOr,
|
||||
BfBinaryOp_NullCoalesce,
|
||||
BfBinaryOp_Is,
|
||||
BfBinaryOp_As
|
||||
BfBinaryOp_As,
|
||||
BfBinaryOp_Range,
|
||||
BfBinaryOp_ClosedRange,
|
||||
};
|
||||
|
||||
enum BfAssignmentOp
|
||||
|
@ -1859,7 +1862,10 @@ enum BfUnaryOp
|
|||
BfUnaryOp_Out,
|
||||
BfUnaryOp_Mut,
|
||||
BfUnaryOp_Params,
|
||||
BfUnaryOp_Cascade
|
||||
BfUnaryOp_Cascade,
|
||||
BfUnaryOp_PartialRangeUpTo,
|
||||
BfUnaryOp_PartialRangeThrough,
|
||||
BfUnaryOp_PartialRangeFrom,
|
||||
};
|
||||
|
||||
class BfTokenNode : public BfAstNode
|
||||
|
|
|
@ -382,6 +382,8 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
|
|||
mArray3TypeDef = NULL;
|
||||
mArray4TypeDef = NULL;
|
||||
mSpanTypeDef = NULL;
|
||||
mRangeTypeDef = NULL;
|
||||
mClosedRangeTypeDef = NULL;
|
||||
mAttributeTypeDef = NULL;
|
||||
mAttributeUsageAttributeTypeDef = NULL;
|
||||
mClassVDataTypeDef = NULL;
|
||||
|
@ -6723,6 +6725,8 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
|||
mArray3TypeDef = _GetRequiredType("System.Array3", 1);
|
||||
mArray4TypeDef = _GetRequiredType("System.Array4", 1);
|
||||
mSpanTypeDef = _GetRequiredType("System.Span", 1);
|
||||
mRangeTypeDef = _GetRequiredType("System.Range");
|
||||
mClosedRangeTypeDef = _GetRequiredType("System.ClosedRange");
|
||||
mAttributeTypeDef = _GetRequiredType("System.Attribute");
|
||||
mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute");
|
||||
mClassVDataTypeDef = _GetRequiredType("System.ClassVData");
|
||||
|
|
|
@ -347,6 +347,8 @@ public:
|
|||
BfTypeDef* mArray3TypeDef;
|
||||
BfTypeDef* mArray4TypeDef;
|
||||
BfTypeDef* mSpanTypeDef;
|
||||
BfTypeDef* mRangeTypeDef;
|
||||
BfTypeDef* mClosedRangeTypeDef;
|
||||
|
||||
BfTypeDef* mClassVDataTypeDef;
|
||||
|
||||
|
|
|
@ -20689,12 +20689,35 @@ bool BfExprEvaluator::PerformBinaryOperation_NullCoalesce(BfTokenNode* opToken,
|
|||
|
||||
void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExpression* rightExpression, BfBinaryOp binaryOp, BfTokenNode* opToken, BfBinOpFlags flags)
|
||||
{
|
||||
if ((binaryOp == BfBinaryOp_Range) || (binaryOp == BfBinaryOp_ClosedRange))
|
||||
{
|
||||
auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
||||
|
||||
auto allocType = mModule->ResolveTypeDef((binaryOp == BfBinaryOp_Range) ? mModule->mCompiler->mRangeTypeDef : mModule->mCompiler->mClosedRangeTypeDef)->ToTypeInstance();
|
||||
auto alloca = mModule->CreateAlloca(allocType);
|
||||
|
||||
SizedArray<BfExpression*, 2> argExprs;
|
||||
argExprs.Add(leftExpression);
|
||||
argExprs.Add(rightExpression);
|
||||
|
||||
BfSizedArray<BfExpression*> args = argExprs;
|
||||
|
||||
BfResolvedArgs argValues;
|
||||
argValues.Init(&args);
|
||||
ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval);
|
||||
|
||||
mResult = BfTypedValue(alloca, allocType, true);
|
||||
MatchConstructor(opToken, NULL, mResult, allocType, argValues, true, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BfTypedValue leftValue;
|
||||
if (leftExpression != NULL)
|
||||
{
|
||||
leftValue = mModule->CreateValueFromExpression(leftExpression, mExpectingType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast | BfEvalExprFlags_AllowIntUnknown));
|
||||
}
|
||||
return PerformBinaryOperation(leftExpression, rightExpression, binaryOp, opToken, flags, leftValue);
|
||||
PerformBinaryOperation(leftExpression, rightExpression, binaryOp, opToken, flags, leftValue);
|
||||
}
|
||||
|
||||
bool BfExprEvaluator::CheckConstCompare(BfBinaryOp binaryOp, BfAstNode* opToken, const BfTypedValue& leftValue, const BfTypedValue& rightValue)
|
||||
|
|
|
@ -2316,6 +2316,13 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
|
|||
mToken = BfToken_DotDotDot;
|
||||
mSyntaxToken = BfSyntaxToken_Token;
|
||||
}
|
||||
else if (mSrc[mSrcIdx + 1] == '<')
|
||||
{
|
||||
mSrcIdx += 2;
|
||||
mTokenEnd = mSrcIdx;
|
||||
mToken = BfToken_DotDotLess;
|
||||
mSyntaxToken = BfSyntaxToken_Token;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSrcIdx++;
|
||||
|
@ -2526,8 +2533,15 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
|
|||
|
||||
bool endNumber = false;
|
||||
|
||||
bool hasDot = c == '.';
|
||||
if ((hasDot) && (mSrc[mSrcIdx] == '.'))
|
||||
{
|
||||
// Skip float parsing if we have a double-dot `1..` case
|
||||
hasDot = false;
|
||||
}
|
||||
|
||||
// The 'prevIsDot' helps tuple lookups like "tuple.0.0", interpreting those as two integers rather than a float
|
||||
if (((c == '.') && (!prevIsDot)) || (hasExp))
|
||||
if (((hasDot) && (!prevIsDot)) || (hasExp))
|
||||
{
|
||||
// Switch to floating point mode
|
||||
//double dVal = val;
|
||||
|
|
|
@ -2287,7 +2287,7 @@ void BfPrinter::Visit(BfUnaryOperatorExpression* unaryOpExpr)
|
|||
{
|
||||
Visit(unaryOpExpr->ToBase());
|
||||
|
||||
bool postOp = (unaryOpExpr->mOp == BfUnaryOp_PostIncrement) || (unaryOpExpr->mOp == BfUnaryOp_PostDecrement);
|
||||
bool postOp = (unaryOpExpr->mOp == BfUnaryOp_PostIncrement) || (unaryOpExpr->mOp == BfUnaryOp_PostDecrement) || (unaryOpExpr->mOp == BfUnaryOp_PartialRangeFrom);
|
||||
if (!postOp)
|
||||
VisitChild(unaryOpExpr->mOpToken);
|
||||
if ((unaryOpExpr->mOp == BfUnaryOp_Ref) || (unaryOpExpr->mOp == BfUnaryOp_Mut) || (unaryOpExpr->mOp == BfUnaryOp_Out) || (unaryOpExpr->mOp == BfUnaryOp_Params) || (unaryOpExpr->mOp == BfUnaryOp_Cascade))
|
||||
|
|
|
@ -2353,12 +2353,22 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
((token == BfToken_RChevron) || (token == BfToken_RDblChevron)))
|
||||
return exprLeft;
|
||||
|
||||
if ((token == BfToken_DblPlus) || (token == BfToken_DblMinus))
|
||||
BfUnaryOp postUnaryOp = BfUnaryOp_None;
|
||||
if (token == BfToken_DblPlus)
|
||||
postUnaryOp = BfUnaryOp_PostIncrement;
|
||||
if (token == BfToken_DblMinus)
|
||||
postUnaryOp = BfUnaryOp_PostDecrement;
|
||||
|
||||
if (token == BfToken_DotDotDot)
|
||||
{
|
||||
//TODO: Detect if this is a BfUnaryOp_PartialRangeFrom
|
||||
}
|
||||
|
||||
if (postUnaryOp != BfUnaryOp_None)
|
||||
{
|
||||
// Post-increment, post-decrement
|
||||
auto unaryOpExpr = mAlloc->Alloc<BfUnaryOperatorExpression>();
|
||||
ReplaceNode(exprLeft, unaryOpExpr);
|
||||
unaryOpExpr->mOp = (token == BfToken_DblPlus) ? BfUnaryOp_PostIncrement : BfUnaryOp_PostDecrement;
|
||||
unaryOpExpr->mOp = postUnaryOp;
|
||||
MEMBER_SET(unaryOpExpr, mOpToken, tokenNode);
|
||||
MEMBER_SET(unaryOpExpr, mExpression, exprLeft);
|
||||
exprLeft = unaryOpExpr;
|
||||
|
|
|
@ -72,6 +72,16 @@ namespace Tests
|
|||
}
|
||||
Test.Assert(iterations == 19);
|
||||
Test.Assert(sGetValCount == 20);
|
||||
|
||||
int total = 0;
|
||||
for (int i in 1..<10)
|
||||
total += i;
|
||||
Test.Assert(total == 1+2+3+4+5+6+7+8+9);
|
||||
|
||||
total = 0;
|
||||
for (int i in 1...10)
|
||||
total += i;
|
||||
Test.Assert(total == 1+2+3+4+5+6+7+8+9+10);
|
||||
}
|
||||
|
||||
public static void TestEnumerator1(EnumeratorTest e)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue