1
0
Fork 0
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:
Brian Fiete 2021-01-22 11:37:39 -08:00
parent 7093476126
commit 0ebd306d93
5 changed files with 108 additions and 18 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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));

View file

@ -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

View file

@ -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)