// Copyright Epic Games, Inc. All Rights Reserved.
using System;
namespace EpicGames.BuildGraph.Expressions
{
///
/// Abstract base class for function expressions
///
public abstract class BgFunc
{
///
/// The function expression.
///
public BgExpr Body { get; }
///
/// Constructor
///
/// Expression to be evaluated
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;
}
}
///
/// A function taking no arguments
///
/// Result type
public class BgFunc : BgFunc
where TResult : BgExpr
{
///
/// Constructor
///
/// Function to construct from
public BgFunc(Func func)
: base(func())
{
}
///
/// Implicit conversion from a regular C# function
///
public static implicit operator BgFunc(Func func) => new BgFunc(func);
///
/// Call the function with the given arguments
///
/// Result from the function
public TResult Call() => BgType.Wrap(new BgFuncCallExpr(this));
}
///
/// A function taking a single argument
///
/// Type of the function argument
/// Result type
public class BgFunc : BgFunc
where TArg : BgExpr
where TResult : BgExpr
{
///
/// Constructor
///
/// Function to construct from
public BgFunc(Func func)
: base(func(BgType.Wrap(new BgFuncArgumentExpr(0))))
{
}
///
/// Implicit conversion from a regular C# function
///
public static implicit operator BgFunc(Func func) => new BgFunc(func);
///
/// Call the function with the given arguments
///
/// Argument to pass to the function
/// Result from the function
public TResult Call(TArg arg) => BgType.Wrap(new BgFuncCallExpr(this, arg));
}
///
/// A function taking two arguments
///
/// Type of the first function argument
/// Type of the second function argument
/// Result type
public class BgFunc : BgFunc
where TArg1 : BgExpr
where TArg2 : BgExpr
where TResult : BgExpr
{
///
/// Constructor
///
/// Function to construct from
public BgFunc(Func func)
: base(func(BgType.Wrap(new BgFuncArgumentExpr(0)), BgType.Wrap(new BgFuncArgumentExpr(1))))
{
}
///
/// Implicit conversion from a regular C# function
///
public static implicit operator BgFunc(Func func) => new BgFunc(func);
///
/// Call the function with the given arguments
///
/// First argument to the function
/// Second argument to the function
/// Result from the function
public TResult Call(TArg1 arg1, TArg2 arg2) => BgType.Wrap(new BgFuncCallExpr(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 : 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
}