Brian Fiete 4 лет назад
Родитель
Сommit
2dbcca8ca4

+ 3 - 0
IDEHelper/Compiler/BfAst.cpp

@@ -1672,6 +1672,7 @@ const char* Beefy::BfGetOpName(BfUnaryOp unaryOp)
 	case BfUnaryOp_Out: return "out";
 	case BfUnaryOp_Out: return "out";
 	case BfUnaryOp_Mut: return "mut";
 	case BfUnaryOp_Mut: return "mut";
 	case BfUnaryOp_Params: return "params";
 	case BfUnaryOp_Params: return "params";
+	case BfUnaryOp_Cascade: return "..";
 	default: return "???";
 	default: return "???";
 	}
 	}
 }
 }
@@ -1759,6 +1760,8 @@ BfUnaryOp Beefy::BfTokenToUnaryOp(BfToken token)
 		return BfUnaryOp_Out;
 		return BfUnaryOp_Out;
 	case BfToken_Params:
 	case BfToken_Params:
 		return BfUnaryOp_Params;
 		return BfUnaryOp_Params;
+	case BfToken_DotDot:
+		return BfUnaryOp_Cascade;
 	default:
 	default:
 		return BfUnaryOp_None;
 		return BfUnaryOp_None;
 	}
 	}

+ 2 - 1
IDEHelper/Compiler/BfAst.h

@@ -1834,7 +1834,8 @@ enum BfUnaryOp
 	BfUnaryOp_Ref,
 	BfUnaryOp_Ref,
 	BfUnaryOp_Out,
 	BfUnaryOp_Out,
 	BfUnaryOp_Mut,
 	BfUnaryOp_Mut,
-	BfUnaryOp_Params,	
+	BfUnaryOp_Params,
+	BfUnaryOp_Cascade
 };
 };
 
 
 class BfTokenNode : public BfAstNode
 class BfTokenNode : public BfAstNode

+ 26 - 5
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -4616,8 +4616,7 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
 	SizedArray<BfExpression*, 8> deferredArgs;
 	SizedArray<BfExpression*, 8> deferredArgs;
 
 
 	int argIdx = 0;
 	int argIdx = 0;
-	//for (int argIdx = 0; argIdx < argCount ; argIdx++)
-
+	
 	while (true)
 	while (true)
 	{
 	{
 		//printf("Args: %p %p %d\n", resolvedArgs.mArguments, resolvedArgs.mArguments->mVals, resolvedArgs.mArguments->mSize);
 		//printf("Args: %p %p %d\n", resolvedArgs.mArguments, resolvedArgs.mArguments->mVals, resolvedArgs.mArguments->mSize);
@@ -4683,6 +4682,15 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
 			}
 			}
 		}
 		}
 
 
+		if (auto unaryOpExpr = BfNodeDynCastExact<BfUnaryOperatorExpression>(argExpr))
+		{
+			if (unaryOpExpr->mOp == BfUnaryOp_Cascade)
+			{
+				resolvedArg.mArgFlags = (BfArgFlags)(resolvedArg.mArgFlags | BfArgFlag_Cascade);
+				argExpr = unaryOpExpr->mExpression;
+			}
+		}
+
 		bool deferParamEval = false;
 		bool deferParamEval = false;
 		if ((flags & BfResolveArgsFlag_DeferParamEval) != 0)
 		if ((flags & BfResolveArgsFlag_DeferParamEval) != 0)
 		{
 		{
@@ -5899,6 +5907,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 		BF_ASSERT(returnType->IsInterface());
 		BF_ASSERT(returnType->IsInterface());
 	}*/
 	}*/
 
 
+	Array<BfTypedValue> argCascades;
 	BfTypedValue target = inTarget;
 	BfTypedValue target = inTarget;
 
 
 	if (!skipThis)
 	if (!skipThis)
@@ -6607,6 +6616,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 				argValue = mModule->LoadValue(argValue);
 				argValue = mModule->LoadValue(argValue);
 		}
 		}
 		
 		
+		if ((argExprIdx != -1) && (argExprIdx < (int)argValues.size()) && ((argValues[argExprIdx].mArgFlags & BfArgFlag_Cascade) != 0))
+			argCascades.Add(argValue);
 	
 	
 		if (expandedParamsArray)
 		if (expandedParamsArray)
 		{
 		{
@@ -6773,8 +6784,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 	}
 	}
 
 
 	auto func = moduleMethodInstance.mFunc;	
 	auto func = moduleMethodInstance.mFunc;	
-	BfTypedValue result = CreateCall(targetSrc, methodInstance, func, bypassVirtual, irArgs);	
-	return result;
+	BfTypedValue callResult = CreateCall(targetSrc, methodInstance, func, bypassVirtual, irArgs);	
+
+	if (argCascades.mSize == 1)
+		return argCascades[0];
+	if (argCascades.mSize > 1)
+		return mModule->CreateTuple(argCascades, {});
+
+	return callResult;
 }
 }
 
 
 BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, BfTypeInstance* targetType, BfResolvedArgs& argValues, bool callCtorBodyOnly, bool allowAppendAlloc, BfTypedValue* appendIndexValue)
 BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, BfTypeInstance* targetType, BfResolvedArgs& argValues, bool callCtorBodyOnly, bool allowAppendAlloc, BfTypedValue* appendIndexValue)
@@ -19376,7 +19393,11 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
 			}			
 			}			
 		}
 		}
 		break;
 		break;
-		
+	case BfUnaryOp_Cascade:
+		{
+			mModule->Fail("Illegal use of argument cascade expression", opToken);
+		}
+		break;
 	default:
 	default:
 		mModule->Fail("INTERNAL ERROR: Unhandled unary operator", unaryOpExpr);
 		mModule->Fail("INTERNAL ERROR: Unhandled unary operator", unaryOpExpr);
 		break;
 		break;

+ 2 - 1
IDEHelper/Compiler/BfExprEvaluator.h

@@ -20,7 +20,8 @@ enum BfArgFlags
 	BfArgFlag_ParamsExpr = 0x200,
 	BfArgFlag_ParamsExpr = 0x200,
 	BfArgFlag_UninitializedExpr = 0x400,
 	BfArgFlag_UninitializedExpr = 0x400,
 	BfArgFlag_StringInterpolateFormat = 0x800,
 	BfArgFlag_StringInterpolateFormat = 0x800,
-	BfArgFlag_StringInterpolateArg = 0x1000
+	BfArgFlag_StringInterpolateArg = 0x1000,
+	BfArgFlag_Cascade = 0x2000
 };
 };
 
 
 enum BfResolveArgsFlags
 enum BfResolveArgsFlags

+ 23 - 0
IDEHelper/Compiler/BfModule.cpp

@@ -13830,6 +13830,29 @@ void BfModule::CreateDIRetVal()
 	}	
 	}	
 }
 }
 
 
+BfTypedValue BfModule::CreateTuple(const Array<BfTypedValue>& values, const Array<String>& fieldNames)
+{
+	BfTypeVector fieldTypes;
+	for (auto arg : values)
+		fieldTypes.Add(arg.mType);
+	
+	auto tupleType = CreateTupleType(fieldTypes, fieldNames);
+
+	auto tupleTypedValue = BfTypedValue(CreateAlloca(tupleType), tupleType, true);
+	for (int fieldIdx = 0; fieldIdx < tupleType->mFieldInstances.size(); fieldIdx++)
+	{
+		auto& fieldInstance = tupleType->mFieldInstances[fieldIdx];
+		if (fieldInstance.mDataIdx <= 0)
+			continue;
+
+		auto typedVal = values[fieldIdx];
+		typedVal = LoadOrAggregateValue(typedVal);
+		mBfIRBuilder->CreateAlignedStore(typedVal.mValue, mBfIRBuilder->CreateInBoundsGEP(tupleTypedValue.mValue, 0, fieldInstance.mDataIdx), typedVal.mType->mAlign);
+	}
+
+	return tupleTypedValue;
+}
+
 void BfModule::CheckVariableDef(BfLocalVariable* variableDef)
 void BfModule::CheckVariableDef(BfLocalVariable* variableDef)
 {	
 {	
 	if (variableDef->mName.IsEmpty())
 	if (variableDef->mName.IsEmpty())

+ 1 - 0
IDEHelper/Compiler/BfModule.h

@@ -1737,6 +1737,7 @@ public:
 	bool TryLocalVariableInit(BfLocalVariable* localVar);
 	bool TryLocalVariableInit(BfLocalVariable* localVar);
 	void LocalVariableDone(BfLocalVariable* localVar, bool isMethodExit);
 	void LocalVariableDone(BfLocalVariable* localVar, bool isMethodExit);
 	void CreateDIRetVal();
 	void CreateDIRetVal();
+	BfTypedValue CreateTuple(const Array<BfTypedValue>& values, const Array<String>& fieldNames);
 	void CheckTupleVariableDeclaration(BfTupleExpression* tupleExpr, BfType* initType);
 	void CheckTupleVariableDeclaration(BfTupleExpression* tupleExpr, BfType* initType);
 	void HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl, BfTupleExpression* tupleExpr, BfTypedValue initTupleValue, bool isReadOnly, bool isConst, bool forceAddr, BfIRBlock* declBlock = NULL);
 	void HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl, BfTupleExpression* tupleExpr, BfTypedValue initTupleValue, bool isReadOnly, bool isConst, bool forceAddr, BfIRBlock* declBlock = NULL);
 	void HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl);
 	void HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl);

+ 8 - 1
IDEHelper/Compiler/BfReducer.cpp

@@ -2250,8 +2250,15 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
 					unaryOpExpr->mOp = unaryOp;
 					unaryOpExpr->mOp = unaryOp;
 					unaryOpExpr->mOpToken = tokenNode;
 					unaryOpExpr->mOpToken = tokenNode;
 					ReplaceNode(tokenNode, unaryOpExpr);
 					ReplaceNode(tokenNode, unaryOpExpr);
+
+					CreateExprFlags innerFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_EarlyExit);
+					if (unaryOp == BfUnaryOp_Cascade)
+					{
+						innerFlags = (CreateExprFlags)(innerFlags | (createExprFlags & CreateExprFlags_AllowVariableDecl));
+					}
+
 					// 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, (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_EarlyExit));
+					unaryOpExpr->mExpression = CreateExpressionAfter(unaryOpExpr, innerFlags);
 					if (unaryOpExpr->mExpression == NULL)
 					if (unaryOpExpr->mExpression == NULL)
 						return NULL;
 						return NULL;
 					MoveNode(unaryOpExpr->mExpression, unaryOpExpr);
 					MoveNode(unaryOpExpr->mExpression, unaryOpExpr);

+ 33 - 0
IDEHelper/Tests/src/Cascades.bf

@@ -0,0 +1,33 @@
+using System;
+
+namespace Tests
+{
+	class Cascades
+	{
+		public static void MethodA(int a, float b)
+		{
+
+		}
+
+		public static void MethodB(int a, out float b)
+		{
+			b = 100;
+		}
+
+		[Test]
+		public static void TestBasics()
+		{
+			int a = MethodA(.. 12, 2.3f);
+			Test.Assert(a == 12);
+			var (b, c) = MethodA(.. 12, .. 2.3f);
+			Test.Assert(b == 12);
+			Test.Assert(c == 2.3f);
+			var d = MethodA(.. 12, .. 2.3f);
+			Test.Assert(d == (12, 2.3f));
+			var f = ref MethodB(12, .. var e);
+			e += 23;
+			Test.Assert(e == (int)123);
+			Test.Assert(f == (int)123);
+		}
+	}
+}