1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Ranges (ie: for (int a in 0..<count) for (int i in 1…10))

This commit is contained in:
Brian Fiete 2021-07-21 07:48:37 -07:00
parent e561a26695
commit 465050b81d
11 changed files with 418 additions and 18 deletions

View 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;
}
}
}
}

View 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;
}
}
}

View file

@ -1545,6 +1545,8 @@ const char* Beefy::BfTokenToString(BfToken token)
return ".."; return "..";
case BfToken_DotDotDot: case BfToken_DotDotDot:
return "..."; return "...";
case BfToken_DotDotLess:
return "..<";
case BfToken_QuestionDot: case BfToken_QuestionDot:
return "?."; return "?.";
case BfToken_QuestionLBracket: case BfToken_QuestionLBracket:
@ -1639,22 +1641,24 @@ int Beefy::BfGetBinaryOpPrecendence(BfBinaryOp binOp)
case BfBinaryOp_OverflowMultiply: case BfBinaryOp_OverflowMultiply:
case BfBinaryOp_Divide: case BfBinaryOp_Divide:
case BfBinaryOp_Modulus: case BfBinaryOp_Modulus:
return 13; return 14;
case BfBinaryOp_Add: case BfBinaryOp_Add:
case BfBinaryOp_Subtract: case BfBinaryOp_Subtract:
case BfBinaryOp_OverflowAdd: case BfBinaryOp_OverflowAdd:
case BfBinaryOp_OverflowSubtract: case BfBinaryOp_OverflowSubtract:
return 12; return 13;
case BfBinaryOp_LeftShift: case BfBinaryOp_LeftShift:
case BfBinaryOp_RightShift: case BfBinaryOp_RightShift:
return 11; return 12;
case BfBinaryOp_BitwiseAnd: case BfBinaryOp_BitwiseAnd:
return 10; return 11;
case BfBinaryOp_ExclusiveOr: case BfBinaryOp_ExclusiveOr:
return 9; return 10;
case BfBinaryOp_BitwiseOr: case BfBinaryOp_BitwiseOr:
return 9;
case BfBinaryOp_Range:
case BfBinaryOp_ClosedRange:
return 8; return 8;
// "Range" inserted here if we were copying swift
case BfBinaryOp_Is: case BfBinaryOp_Is:
case BfBinaryOp_As: case BfBinaryOp_As:
return 7; return 7;
@ -1715,6 +1719,8 @@ const char* Beefy::BfGetOpName(BfBinaryOp binOp)
case BfBinaryOp_NullCoalesce: return "??"; case BfBinaryOp_NullCoalesce: return "??";
case BfBinaryOp_Is: return "is"; case BfBinaryOp_Is: return "is";
case BfBinaryOp_As: return "as"; case BfBinaryOp_As: return "as";
case BfBinaryOp_Range: return "..<";
case BfBinaryOp_ClosedRange: return "...";
default: return "???"; default: return "???";
} }
} }
@ -1740,6 +1746,9 @@ 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_PartialRangeUpTo: return "..<";
case BfUnaryOp_PartialRangeThrough: return "...";
case BfUnaryOp_PartialRangeFrom: return "...";
default: return "???"; default: return "???";
} }
} }
@ -1798,6 +1807,10 @@ BfBinaryOp Beefy::BfTokenToBinaryOp(BfToken token)
return BfBinaryOp_ConditionalOr; return BfBinaryOp_ConditionalOr;
case BfToken_DblQuestion: case BfToken_DblQuestion:
return BfBinaryOp_NullCoalesce; return BfBinaryOp_NullCoalesce;
case BfToken_DotDotLess:
return BfBinaryOp_Range;
case BfToken_DotDotDot:
return BfBinaryOp_ClosedRange;
default: default:
return BfBinaryOp_None; return BfBinaryOp_None;
} }
@ -1835,6 +1848,10 @@ 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_DotDotDot:
return BfUnaryOp_PartialRangeThrough;
case BfToken_DotDotLess:
return BfUnaryOp_PartialRangeUpTo;
default: default:
return BfUnaryOp_None; return BfUnaryOp_None;
} }

View file

@ -232,6 +232,7 @@ enum BfToken : uint8
BfToken_Dot, BfToken_Dot,
BfToken_DotDot, BfToken_DotDot,
BfToken_DotDotDot, BfToken_DotDotDot,
BfToken_DotDotLess,
BfToken_QuestionDot, BfToken_QuestionDot,
BfToken_QuestionLBracket, BfToken_QuestionLBracket,
BfToken_AutocompleteDot, BfToken_AutocompleteDot,
@ -1821,7 +1822,9 @@ enum BfBinaryOp
BfBinaryOp_ConditionalOr, BfBinaryOp_ConditionalOr,
BfBinaryOp_NullCoalesce, BfBinaryOp_NullCoalesce,
BfBinaryOp_Is, BfBinaryOp_Is,
BfBinaryOp_As BfBinaryOp_As,
BfBinaryOp_Range,
BfBinaryOp_ClosedRange,
}; };
enum BfAssignmentOp enum BfAssignmentOp
@ -1859,7 +1862,10 @@ enum BfUnaryOp
BfUnaryOp_Out, BfUnaryOp_Out,
BfUnaryOp_Mut, BfUnaryOp_Mut,
BfUnaryOp_Params, BfUnaryOp_Params,
BfUnaryOp_Cascade BfUnaryOp_Cascade,
BfUnaryOp_PartialRangeUpTo,
BfUnaryOp_PartialRangeThrough,
BfUnaryOp_PartialRangeFrom,
}; };
class BfTokenNode : public BfAstNode class BfTokenNode : public BfAstNode

View file

@ -382,6 +382,8 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mArray3TypeDef = NULL; mArray3TypeDef = NULL;
mArray4TypeDef = NULL; mArray4TypeDef = NULL;
mSpanTypeDef = NULL; mSpanTypeDef = NULL;
mRangeTypeDef = NULL;
mClosedRangeTypeDef = NULL;
mAttributeTypeDef = NULL; mAttributeTypeDef = NULL;
mAttributeUsageAttributeTypeDef = NULL; mAttributeUsageAttributeTypeDef = NULL;
mClassVDataTypeDef = NULL; mClassVDataTypeDef = NULL;
@ -6722,7 +6724,9 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mArray2TypeDef = _GetRequiredType("System.Array2", 1); mArray2TypeDef = _GetRequiredType("System.Array2", 1);
mArray3TypeDef = _GetRequiredType("System.Array3", 1); mArray3TypeDef = _GetRequiredType("System.Array3", 1);
mArray4TypeDef = _GetRequiredType("System.Array4", 1); mArray4TypeDef = _GetRequiredType("System.Array4", 1);
mSpanTypeDef = _GetRequiredType("System.Span", 1); mSpanTypeDef = _GetRequiredType("System.Span", 1);
mRangeTypeDef = _GetRequiredType("System.Range");
mClosedRangeTypeDef = _GetRequiredType("System.ClosedRange");
mAttributeTypeDef = _GetRequiredType("System.Attribute"); mAttributeTypeDef = _GetRequiredType("System.Attribute");
mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute"); mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute");
mClassVDataTypeDef = _GetRequiredType("System.ClassVData"); mClassVDataTypeDef = _GetRequiredType("System.ClassVData");

View file

@ -347,6 +347,8 @@ public:
BfTypeDef* mArray3TypeDef; BfTypeDef* mArray3TypeDef;
BfTypeDef* mArray4TypeDef; BfTypeDef* mArray4TypeDef;
BfTypeDef* mSpanTypeDef; BfTypeDef* mSpanTypeDef;
BfTypeDef* mRangeTypeDef;
BfTypeDef* mClosedRangeTypeDef;
BfTypeDef* mClassVDataTypeDef; BfTypeDef* mClassVDataTypeDef;

View file

@ -20433,7 +20433,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
} }
if (leftValue.mType->IsRef()) if (leftValue.mType->IsRef())
leftValue.mType = leftValue.mType->GetUnderlyingType(); leftValue.mType = leftValue.mType->GetUnderlyingType();
if ((binaryOp == BfBinaryOp_ConditionalAnd) || (binaryOp == BfBinaryOp_ConditionalOr)) if ((binaryOp == BfBinaryOp_ConditionalAnd) || (binaryOp == BfBinaryOp_ConditionalOr))
{ {
if (mModule->mCurMethodState->mDeferredLocalAssignData != NULL) if (mModule->mCurMethodState->mDeferredLocalAssignData != NULL)
@ -20670,7 +20670,7 @@ bool BfExprEvaluator::PerformBinaryOperation_NullCoalesce(BfTokenNode* opToken,
mModule->AddBasicBlock(endBB); mModule->AddBasicBlock(endBB);
if (assignTo != NULL) if (assignTo != NULL)
{ {
mResult = *assignTo; mResult = *assignTo;
} }
else else
@ -20689,12 +20689,35 @@ bool BfExprEvaluator::PerformBinaryOperation_NullCoalesce(BfTokenNode* opToken,
void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExpression* rightExpression, BfBinaryOp binaryOp, BfTokenNode* opToken, BfBinOpFlags flags) 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; BfTypedValue leftValue;
if (leftExpression != NULL) if (leftExpression != NULL)
{ {
leftValue = mModule->CreateValueFromExpression(leftExpression, mExpectingType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast | BfEvalExprFlags_AllowIntUnknown)); 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) bool BfExprEvaluator::CheckConstCompare(BfBinaryOp binaryOp, BfAstNode* opToken, const BfTypedValue& leftValue, const BfTypedValue& rightValue)

View file

@ -2316,6 +2316,13 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
mToken = BfToken_DotDotDot; mToken = BfToken_DotDotDot;
mSyntaxToken = BfSyntaxToken_Token; mSyntaxToken = BfSyntaxToken_Token;
} }
else if (mSrc[mSrcIdx + 1] == '<')
{
mSrcIdx += 2;
mTokenEnd = mSrcIdx;
mToken = BfToken_DotDotLess;
mSyntaxToken = BfSyntaxToken_Token;
}
else else
{ {
mSrcIdx++; mSrcIdx++;
@ -2526,8 +2533,15 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
bool endNumber = false; 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 // 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 // Switch to floating point mode
//double dVal = val; //double dVal = val;

View file

@ -2287,7 +2287,7 @@ void BfPrinter::Visit(BfUnaryOperatorExpression* unaryOpExpr)
{ {
Visit(unaryOpExpr->ToBase()); 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) if (!postOp)
VisitChild(unaryOpExpr->mOpToken); VisitChild(unaryOpExpr->mOpToken);
if ((unaryOpExpr->mOp == BfUnaryOp_Ref) || (unaryOpExpr->mOp == BfUnaryOp_Mut) || (unaryOpExpr->mOp == BfUnaryOp_Out) || (unaryOpExpr->mOp == BfUnaryOp_Params) || (unaryOpExpr->mOp == BfUnaryOp_Cascade)) if ((unaryOpExpr->mOp == BfUnaryOp_Ref) || (unaryOpExpr->mOp == BfUnaryOp_Mut) || (unaryOpExpr->mOp == BfUnaryOp_Out) || (unaryOpExpr->mOp == BfUnaryOp_Params) || (unaryOpExpr->mOp == BfUnaryOp_Cascade))

View file

@ -2353,12 +2353,22 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
((token == BfToken_RChevron) || (token == BfToken_RDblChevron))) ((token == BfToken_RChevron) || (token == BfToken_RDblChevron)))
return exprLeft; return exprLeft;
if ((token == BfToken_DblPlus) || (token == BfToken_DblMinus)) BfUnaryOp postUnaryOp = BfUnaryOp_None;
{ if (token == BfToken_DblPlus)
// Post-increment, post-decrement 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)
{
auto unaryOpExpr = mAlloc->Alloc<BfUnaryOperatorExpression>(); auto unaryOpExpr = mAlloc->Alloc<BfUnaryOperatorExpression>();
ReplaceNode(exprLeft, unaryOpExpr); ReplaceNode(exprLeft, unaryOpExpr);
unaryOpExpr->mOp = (token == BfToken_DblPlus) ? BfUnaryOp_PostIncrement : BfUnaryOp_PostDecrement; unaryOpExpr->mOp = postUnaryOp;
MEMBER_SET(unaryOpExpr, mOpToken, tokenNode); MEMBER_SET(unaryOpExpr, mOpToken, tokenNode);
MEMBER_SET(unaryOpExpr, mExpression, exprLeft); MEMBER_SET(unaryOpExpr, mExpression, exprLeft);
exprLeft = unaryOpExpr; exprLeft = unaryOpExpr;

View file

@ -72,6 +72,16 @@ namespace Tests
} }
Test.Assert(iterations == 19); Test.Assert(iterations == 19);
Test.Assert(sGetValCount == 20); 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) public static void TestEnumerator1(EnumeratorTest e)