mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-14 14:24:10 +02:00
Deferred evaluation support for binary operators
This commit is contained in:
parent
7093476126
commit
0ebd306d93
5 changed files with 108 additions and 18 deletions
|
@ -5,6 +5,8 @@ USING_NS_BF;
|
||||||
BfDeferEvalChecker::BfDeferEvalChecker()
|
BfDeferEvalChecker::BfDeferEvalChecker()
|
||||||
{
|
{
|
||||||
mNeedsDeferEval = false;
|
mNeedsDeferEval = false;
|
||||||
|
mDeferLiterals = true;
|
||||||
|
mDeferLambdaBind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BfDeferEvalChecker::Visit(BfAstNode* attribExpr)
|
void BfDeferEvalChecker::Visit(BfAstNode* attribExpr)
|
||||||
|
@ -31,7 +33,8 @@ void BfDeferEvalChecker::Visit(BfLiteralExpression* literalExpr)
|
||||||
case BfTypeCode_UIntPtr:
|
case BfTypeCode_UIntPtr:
|
||||||
case BfTypeCode_IntUnknown:
|
case BfTypeCode_IntUnknown:
|
||||||
case BfTypeCode_UIntUnknown:
|
case BfTypeCode_UIntUnknown:
|
||||||
mNeedsDeferEval = true;
|
if (mDeferLiterals)
|
||||||
|
mNeedsDeferEval = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mNeedsDeferEval = false;
|
mNeedsDeferEval = false;
|
||||||
|
@ -82,6 +85,12 @@ void BfDeferEvalChecker::Visit(BfInvocationExpression* invocationExpr)
|
||||||
VisitChild(invocationExpr->mTarget);
|
VisitChild(invocationExpr->mTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BfDeferEvalChecker::Visit(BfLambdaBindExpression* lambdaBindExpr)
|
||||||
|
{
|
||||||
|
if (mDeferLambdaBind)
|
||||||
|
mNeedsDeferEval = true;
|
||||||
|
}
|
||||||
|
|
||||||
void BfDeferEvalChecker::Visit(BfConditionalExpression* condExpr)
|
void BfDeferEvalChecker::Visit(BfConditionalExpression* condExpr)
|
||||||
{
|
{
|
||||||
VisitChild(condExpr->mConditionExpression);
|
VisitChild(condExpr->mConditionExpression);
|
||||||
|
|
|
@ -9,6 +9,8 @@ class BfDeferEvalChecker : public BfStructuralVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool mNeedsDeferEval;
|
bool mNeedsDeferEval;
|
||||||
|
bool mDeferLambdaBind;
|
||||||
|
bool mDeferLiterals;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BfDeferEvalChecker();
|
BfDeferEvalChecker();
|
||||||
|
@ -21,6 +23,7 @@ public:
|
||||||
virtual void Visit(BfTupleExpression* tupleExpr) override;
|
virtual void Visit(BfTupleExpression* tupleExpr) override;
|
||||||
virtual void Visit(BfMemberReferenceExpression* memberRefExpr) override;
|
virtual void Visit(BfMemberReferenceExpression* memberRefExpr) override;
|
||||||
virtual void Visit(BfInvocationExpression* invocationExpr) override;
|
virtual void Visit(BfInvocationExpression* invocationExpr) override;
|
||||||
|
virtual void Visit(BfLambdaBindExpression* lambdaBindExpr) override;
|
||||||
virtual void Visit(BfConditionalExpression* condExpr) override;
|
virtual void Visit(BfConditionalExpression* condExpr) override;
|
||||||
virtual void Visit(BfUnaryOperatorExpression* unaryOpExpr) override;
|
virtual void Visit(BfUnaryOperatorExpression* unaryOpExpr) override;
|
||||||
virtual void Visit(BfObjectCreateExpression* objCreateExpr) override;
|
virtual void Visit(BfObjectCreateExpression* objCreateExpr) override;
|
||||||
|
|
|
@ -5008,6 +5008,7 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
|
||||||
if (argExpr != NULL)
|
if (argExpr != NULL)
|
||||||
{
|
{
|
||||||
BfDeferEvalChecker deferEvalChecker;
|
BfDeferEvalChecker deferEvalChecker;
|
||||||
|
deferEvalChecker.mDeferLambdaBind = false;
|
||||||
argExpr->Accept(&deferEvalChecker);
|
argExpr->Accept(&deferEvalChecker);
|
||||||
deferParamEval = deferEvalChecker.mNeedsDeferEval;
|
deferParamEval = deferEvalChecker.mNeedsDeferEval;
|
||||||
}
|
}
|
||||||
|
@ -17762,18 +17763,29 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
|
||||||
CheckResultForReading(ptr);
|
CheckResultForReading(ptr);
|
||||||
BfTypedValue leftValue = ptr;
|
BfTypedValue leftValue = ptr;
|
||||||
|
|
||||||
auto expectedType = ptr.mType;
|
bool deferBinop = false;
|
||||||
if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
|
BfDeferEvalChecker deferEvalChecker;
|
||||||
expectedType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
deferEvalChecker.mDeferLiterals = false;
|
||||||
|
assignExpr->mRight->Accept(&deferEvalChecker);
|
||||||
|
if (deferEvalChecker.mNeedsDeferEval)
|
||||||
|
deferBinop = true;
|
||||||
|
|
||||||
if ((!rightValue) && (assignExpr->mRight != NULL))
|
if (!deferBinop)
|
||||||
{
|
{
|
||||||
rightValue = mModule->CreateValueFromExpression(assignExpr->mRight, expectedType, (BfEvalExprFlags)(BfEvalExprFlags_AllowSplat | BfEvalExprFlags_NoCast));
|
auto expectedType = ptr.mType;
|
||||||
|
if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
|
||||||
|
expectedType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
||||||
|
|
||||||
|
if ((!rightValue) && (assignExpr->mRight != NULL))
|
||||||
|
{
|
||||||
|
rightValue = mModule->CreateValueFromExpression(assignExpr->mRight, expectedType, (BfEvalExprFlags)(BfEvalExprFlags_AllowSplat | BfEvalExprFlags_NoCast));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
|
BfResolvedArgs argValues;
|
||||||
|
|
||||||
if (rightValue)
|
if ((rightValue) || (deferBinop))
|
||||||
{
|
{
|
||||||
auto checkTypeInst = leftValue.mType->ToTypeInstance();
|
auto checkTypeInst = leftValue.mType->ToTypeInstance();
|
||||||
while (checkTypeInst != NULL)
|
while (checkTypeInst != NULL)
|
||||||
|
@ -17788,8 +17800,26 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto paramType = methodInst->GetParamType(0);
|
auto paramType = methodInst->GetParamType(0);
|
||||||
if (!mModule->CanCast(rightValue, paramType))
|
if (deferBinop)
|
||||||
continue;
|
{
|
||||||
|
if (argValues.mArguments == NULL)
|
||||||
|
{
|
||||||
|
SizedArray<BfExpression*, 2> argExprs;
|
||||||
|
argExprs.push_back(assignExpr->mRight);
|
||||||
|
BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
|
||||||
|
argValues.Init(&sizedArgExprs);
|
||||||
|
ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval);
|
||||||
|
}
|
||||||
|
|
||||||
|
rightValue = ResolveArgValue(argValues.mResolvedArgs[0], paramType);
|
||||||
|
if (!rightValue)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!mModule->CanCast(rightValue, paramType))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
mModule->SetElementType(assignExpr->mOpToken, BfSourceElementType_Method);
|
mModule->SetElementType(assignExpr->mOpToken, BfSourceElementType_Method);
|
||||||
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(assignExpr->mOpToken)))
|
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(assignExpr->mOpToken)))
|
||||||
|
@ -17817,8 +17847,12 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
|
||||||
|
|
||||||
if (!handled)
|
if (!handled)
|
||||||
{
|
{
|
||||||
|
auto flags = BfBinOpFlag_ForceLeftType;
|
||||||
|
if (deferBinop)
|
||||||
|
flags = (BfBinOpFlags)(flags | BfBinOpFlag_DeferRight);
|
||||||
|
|
||||||
leftValue = mModule->LoadValue(leftValue);
|
leftValue = mModule->LoadValue(leftValue);
|
||||||
PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, BfBinOpFlag_ForceLeftType, leftValue, rightValue);
|
PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, flags, leftValue, rightValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20417,6 +20451,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
||||||
{
|
{
|
||||||
bool noClassify = (flags & BfBinOpFlag_NoClassify) != 0;
|
bool noClassify = (flags & BfBinOpFlag_NoClassify) != 0;
|
||||||
bool forceLeftType = (flags & BfBinOpFlag_ForceLeftType) != 0;
|
bool forceLeftType = (flags & BfBinOpFlag_ForceLeftType) != 0;
|
||||||
|
bool deferRight = (flags & BfBinOpFlag_DeferRight) != 0;
|
||||||
|
|
||||||
|
if (deferRight)
|
||||||
|
{
|
||||||
|
rightValue = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
|
||||||
|
}
|
||||||
|
|
||||||
if ((rightValue.mValue.IsConst()) && (!leftValue.mValue.IsConst()))
|
if ((rightValue.mValue.IsConst()) && (!leftValue.mValue.IsConst()))
|
||||||
{
|
{
|
||||||
|
@ -20646,7 +20686,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
||||||
BfIRValue convLeftValue;
|
BfIRValue convLeftValue;
|
||||||
BfIRValue convRightValue;
|
BfIRValue convRightValue;
|
||||||
|
|
||||||
if ((resultType->IsVar()) || (otherType->IsVar()))
|
if (((resultType->IsVar()) || (otherType->IsVar())) && (!deferRight))
|
||||||
{
|
{
|
||||||
bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual);
|
bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual);
|
||||||
if (isComparison)
|
if (isComparison)
|
||||||
|
@ -20794,7 +20834,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipOpOverload)
|
if (!skipOpOverload)
|
||||||
{
|
{
|
||||||
BfBinaryOp findBinaryOp = binaryOp;
|
BfBinaryOp findBinaryOp = binaryOp;
|
||||||
|
|
||||||
bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual);
|
bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual);
|
||||||
|
@ -20802,16 +20842,28 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
||||||
for (int pass = 0; pass < 2; pass++)
|
for (int pass = 0; pass < 2; pass++)
|
||||||
{
|
{
|
||||||
BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp);
|
BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp);
|
||||||
bool foundOp = false;
|
bool foundOp = false;
|
||||||
|
|
||||||
SizedArray<BfResolvedArg, 2> args;
|
|
||||||
BfResolvedArg leftArg;
|
BfResolvedArg leftArg;
|
||||||
leftArg.mExpression = leftExpression;
|
leftArg.mExpression = leftExpression;
|
||||||
leftArg.mTypedValue = leftValue;
|
leftArg.mTypedValue = leftValue;
|
||||||
BfResolvedArg rightArg;
|
BfResolvedArg rightArg;
|
||||||
rightArg.mExpression = rightExpression;
|
rightArg.mExpression = rightExpression;
|
||||||
rightArg.mTypedValue = rightValue;
|
rightArg.mTypedValue = rightValue;
|
||||||
|
|
||||||
|
if (deferRight)
|
||||||
|
{
|
||||||
|
BfResolvedArgs argValues;
|
||||||
|
SizedArray<BfExpression*, 2> argExprs;
|
||||||
|
argExprs.push_back(BfNodeDynCast<BfExpression>(rightExpression));
|
||||||
|
BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
|
||||||
|
argValues.Init(&sizedArgExprs);
|
||||||
|
ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval);
|
||||||
|
rightArg = argValues.mResolvedArgs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
SizedArray<BfResolvedArg, 2> args;
|
||||||
|
|
||||||
if (pass == 0)
|
if (pass == 0)
|
||||||
{
|
{
|
||||||
args.push_back(leftArg);
|
args.push_back(leftArg);
|
||||||
|
@ -20820,8 +20872,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args.push_back(rightArg);
|
args.push_back(rightArg);
|
||||||
args.push_back(leftArg);
|
args.push_back(leftArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
|
BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
|
||||||
methodMatcher.mBfEvalExprFlags = BfEvalExprFlags_NoAutoComplete;
|
methodMatcher.mBfEvalExprFlags = BfEvalExprFlags_NoAutoComplete;
|
||||||
BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule);
|
BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule);
|
||||||
|
@ -21135,7 +21188,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
||||||
if (flippedBinaryOp != BfBinaryOp_None)
|
if (flippedBinaryOp != BfBinaryOp_None)
|
||||||
findBinaryOp = flippedBinaryOp;
|
findBinaryOp = flippedBinaryOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prevResultType = resultType;
|
auto prevResultType = resultType;
|
||||||
if ((leftValue.mType->IsPrimitiveType()) && (!rightValue.mType->IsTypedPrimitive()))
|
if ((leftValue.mType->IsPrimitiveType()) && (!rightValue.mType->IsTypedPrimitive()))
|
||||||
resultType = leftValue.mType;
|
resultType = leftValue.mType;
|
||||||
|
@ -21144,6 +21197,16 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deferRight)
|
||||||
|
{
|
||||||
|
auto expectedType = resultType;
|
||||||
|
if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
|
||||||
|
expectedType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
||||||
|
rightValue = mModule->CreateValueFromExpression(BfNodeDynCast<BfExpression>(rightExpression), expectedType, (BfEvalExprFlags)(BfEvalExprFlags_AllowSplat | BfEvalExprFlags_NoCast));
|
||||||
|
PerformBinaryOperation(leftExpression, rightExpression, binaryOp, opToken, (BfBinOpFlags)(flags & ~BfBinOpFlag_DeferRight), leftValue, rightValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mModule->IsUnboundGeneric(resultType))
|
if (mModule->IsUnboundGeneric(resultType))
|
||||||
{
|
{
|
||||||
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
|
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
|
||||||
|
|
|
@ -347,7 +347,8 @@ enum BfBinOpFlags
|
||||||
BfBinOpFlag_NoClassify = 1,
|
BfBinOpFlag_NoClassify = 1,
|
||||||
BfBinOpFlag_ForceLeftType = 2,
|
BfBinOpFlag_ForceLeftType = 2,
|
||||||
BfBinOpFlag_IgnoreOperatorWithWrongResult = 4,
|
BfBinOpFlag_IgnoreOperatorWithWrongResult = 4,
|
||||||
BfBinOpFlag_IsConstraintCheck = 8
|
BfBinOpFlag_IsConstraintCheck = 8,
|
||||||
|
BfBinOpFlag_DeferRight = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
class BfExprEvaluator : public BfStructuralVisitor
|
class BfExprEvaluator : public BfStructuralVisitor
|
||||||
|
|
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
namespace System
|
||||||
|
{
|
||||||
|
extension Event<T>
|
||||||
|
{
|
||||||
|
public implicit void operator+=(T dlg) mut
|
||||||
|
{
|
||||||
|
Add(dlg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace Tests
|
namespace Tests
|
||||||
{
|
{
|
||||||
class Delegates
|
class Delegates
|
||||||
|
@ -146,6 +157,9 @@ namespace Tests
|
||||||
|
|
||||||
ClassB<int8>.DelegateB dlg2 = scope (val) => val + 123;
|
ClassB<int8>.DelegateB dlg2 = scope (val) => val + 123;
|
||||||
Test.Assert(dlg2(3) == 126);
|
Test.Assert(dlg2(3) == 126);
|
||||||
|
|
||||||
|
Event<EventHandler> e = .();
|
||||||
|
e += scope (sender, e) => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Modify(ref int a, ref Splattable b)
|
public static void Modify(ref int a, ref Splattable b)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue