Files
UnrealEngine/Engine/Source/Programs/Shared/EpicGames.BuildGraph/Expressions/BgFunc.cs
2025-05-18 13:04:45 +08:00

171 lines
4.7 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
namespace EpicGames.BuildGraph.Expressions
{
/// <summary>
/// Abstract base class for function expressions
/// </summary>
public abstract class BgFunc
{
/// <summary>
/// The function expression.
/// </summary>
public BgExpr Body { get; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="body">Expression to be evaluated</param>
protected BgFunc(BgExpr body)
{
// Evaluate the body twice, and determine which expressions are captured outside this context
// Lexical scope can include those expressions too - if they are declared locally, they will not be duplicated
Body = body;
}
}
/// <summary>
/// A function taking no arguments
/// </summary>
/// <typeparam name="TResult">Result type</typeparam>
public class BgFunc<TResult> : BgFunc
where TResult : BgExpr
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="func">Function to construct from</param>
public BgFunc(Func<TResult> func)
: base(func())
{
}
/// <summary>
/// Implicit conversion from a regular C# function
/// </summary>
public static implicit operator BgFunc<TResult>(Func<TResult> func) => new BgFunc<TResult>(func);
/// <summary>
/// Call the function with the given arguments
/// </summary>
/// <returns>Result from the function</returns>
public TResult Call() => BgType.Wrap<TResult>(new BgFuncCallExpr<TResult>(this));
}
/// <summary>
/// A function taking a single argument
/// </summary>
/// <typeparam name="TArg">Type of the function argument</typeparam>
/// <typeparam name="TResult">Result type</typeparam>
public class BgFunc<TArg, TResult> : BgFunc
where TArg : BgExpr
where TResult : BgExpr
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="func">Function to construct from</param>
public BgFunc(Func<TArg, TResult> func)
: base(func(BgType.Wrap<TArg>(new BgFuncArgumentExpr(0))))
{
}
/// <summary>
/// Implicit conversion from a regular C# function
/// </summary>
public static implicit operator BgFunc<TArg, TResult>(Func<TArg, TResult> func) => new BgFunc<TArg, TResult>(func);
/// <summary>
/// Call the function with the given arguments
/// </summary>
/// <param name="arg">Argument to pass to the function</param>
/// <returns>Result from the function</returns>
public TResult Call(TArg arg) => BgType.Wrap<TResult>(new BgFuncCallExpr<TResult>(this, arg));
}
/// <summary>
/// A function taking two arguments
/// </summary>
/// <typeparam name="TArg1">Type of the first function argument</typeparam>
/// <typeparam name="TArg2">Type of the second function argument</typeparam>
/// <typeparam name="TResult">Result type</typeparam>
public class BgFunc<TArg1, TArg2, TResult> : BgFunc
where TArg1 : BgExpr
where TArg2 : BgExpr
where TResult : BgExpr
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="func">Function to construct from</param>
public BgFunc(Func<TArg1, TArg2, TResult> func)
: base(func(BgType.Wrap<TArg1>(new BgFuncArgumentExpr(0)), BgType.Wrap<TArg2>(new BgFuncArgumentExpr(1))))
{
}
/// <summary>
/// Implicit conversion from a regular C# function
/// </summary>
public static implicit operator BgFunc<TArg1, TArg2, TResult>(Func<TArg1, TArg2, TResult> func) => new BgFunc<TArg1, TArg2, TResult>(func);
/// <summary>
/// Call the function with the given arguments
/// </summary>
/// <param name="arg1">First argument to the function</param>
/// <param name="arg2">Second argument to the function</param>
/// <returns>Result from the function</returns>
public TResult Call(TArg1 arg1, TArg2 arg2) => BgType.Wrap<TResult>(new BgFuncCallExpr<TResult>(this, arg1, arg2));
}
#region Expression classes
class BgFuncArgumentExpr : BgExpr
{
uint Index { get; }
public BgFuncArgumentExpr(uint index)
: base(BgExprFlags.NotInterned)
{
Index = index;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(BgOpcode.Argument);
writer.WriteUnsignedInteger(Index);
}
public override BgString ToBgString() => "{Function}";
}
class BgFuncCallExpr<T> : BgExpr where T : BgExpr
{
readonly BgFunc _function;
readonly BgExpr[] _arguments;
public BgFuncCallExpr(BgFunc function, params BgExpr[] arguments)
: base(BgExprFlags.None)
{
_function = function;
_arguments = arguments;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(BgOpcode.Call);
writer.WriteExprAsFragment(_function.Body);
writer.WriteUnsignedInteger((uint)_arguments.Length);
foreach (BgExpr argument in _arguments)
{
argument.Write(writer);
}
}
public override BgString ToBgString() => throw new InvalidOperationException();
}
#endregion
}