// Copyright Epic Games, Inc. All Rights Reserved.
using System;
namespace EpicGames.BuildGraph.Expressions
{
///
/// Abstract base class for expressions returning a 32-bit integer value
///
[BgType(typeof(BgIntType))]
public abstract class BgInt : BgExpr
{
///
/// Implicit conversion from an integer value
///
public static implicit operator BgInt(int value)
{
return new BgIntConstantExpr(value);
}
///
/// Constructor
///
/// Flags for this expression
protected BgInt(BgExprFlags flags)
: base(flags)
{
}
///
public static BgInt operator -(BgInt value) => new BgIntUnaryExpr(BgOpcode.IntNegate, value);
///
public static BgInt operator +(BgInt lhs, BgInt rhs) => new BgIntBinaryExpr(BgOpcode.IntAdd, lhs, rhs);
///
public static BgInt operator -(BgInt lhs, BgInt rhs) => new BgIntBinaryExpr(BgOpcode.IntAdd, lhs, -rhs);
///
public static BgInt operator *(BgInt lhs, BgInt rhs) => new BgIntBinaryExpr(BgOpcode.IntMultiply, lhs, rhs);
///
public static BgInt operator /(BgInt lhs, BgInt rhs) => new BgIntBinaryExpr(BgOpcode.IntDivide, lhs, rhs);
///
public static BgInt operator %(BgInt lhs, BgInt rhs) => new BgIntBinaryExpr(BgOpcode.IntModulo, lhs, rhs);
///
public static BgBool operator <(BgInt lhs, BgInt rhs) => new BgIntTestExpr(BgOpcode.IntLt, lhs, rhs);
///
public static BgBool operator >(BgInt lhs, BgInt rhs) => new BgIntTestExpr(BgOpcode.IntGt, lhs, rhs);
///
public static BgBool operator ==(BgInt lhs, BgInt rhs) => new BgIntTestExpr(BgOpcode.IntEq, lhs, rhs);
///
public static BgBool operator !=(BgInt lhs, BgInt rhs) => !(lhs == rhs);
///
public static BgBool operator <=(BgInt lhs, BgInt rhs) => !(lhs > rhs);
///
public static BgBool operator >=(BgInt lhs, BgInt rhs) => !(lhs < rhs);
///
public override bool Equals(object? obj) => throw new InvalidOperationException();
///
public override int GetHashCode() => throw new InvalidOperationException();
///
public override BgString ToBgString()
{
throw new NotImplementedException();
}
}
///
/// Traits for a
///
class BgIntType : BgType
{
///
public override BgInt Constant(object value) => new BgIntConstantExpr((int)value);
///
public override BgInt Wrap(BgExpr expr) => new BgIntWrappedExpr(expr);
}
#region Expression classes
class BgIntUnaryExpr : BgInt
{
public BgOpcode Opcode { get; }
public BgInt Value { get; }
public BgIntUnaryExpr(BgOpcode opcode, BgInt value)
: base(value.Flags & BgExprFlags.Eager)
{
Opcode = opcode;
Value = value;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(Opcode);
writer.WriteExpr(Value);
}
}
class BgIntBinaryExpr : BgInt
{
public BgOpcode Opcode { get; }
public BgInt Lhs { get; }
public BgInt Rhs { get; }
public BgIntBinaryExpr(BgOpcode opcode, BgInt lhs, BgInt rhs)
: base(lhs.Flags & rhs.Flags & BgExprFlags.Eager)
{
Opcode = opcode;
Lhs = lhs;
Rhs = rhs;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(Opcode);
writer.WriteExpr(Lhs);
writer.WriteExpr(Rhs);
}
}
class BgIntTestExpr : BgBool
{
public BgOpcode Opcode { get; }
public BgInt Lhs { get; }
public BgInt Rhs { get; }
public BgIntTestExpr(BgOpcode opcode, BgInt lhs, BgInt rhs)
: base(lhs.Flags & rhs.Flags & BgExprFlags.Eager)
{
Opcode = opcode;
Lhs = lhs;
Rhs = rhs;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(Opcode);
writer.WriteExpr(Lhs);
writer.WriteExpr(Rhs);
}
}
class BgIntChooseExpr : BgInt
{
public BgBool Condition { get; }
public BgInt ValueIfTrue { get; }
public BgInt ValueIfFalse { get; }
public BgIntChooseExpr(BgBool condition, BgInt valueIfTrue, BgInt valueIfFalse)
: base(BgExprFlags.None)
{
Condition = condition;
ValueIfTrue = valueIfTrue;
ValueIfFalse = valueIfFalse;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(BgOpcode.Choose);
writer.WriteExpr(Condition);
writer.WriteExpr(ValueIfTrue);
writer.WriteExpr(ValueIfFalse);
}
}
class BgIntConstantExpr : BgInt
{
public int Value { get; }
public BgIntConstantExpr(int value)
: base(BgExprFlags.NotInterned | BgExprFlags.Eager)
{
Value = value;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(BgOpcode.IntLiteral);
writer.WriteSignedInteger(Value);
}
}
class BgIntWrappedExpr : BgInt
{
BgExpr Expr { get; }
public BgIntWrappedExpr(BgExpr expr)
: base(expr.Flags)
{
Expr = expr;
}
public override void Write(BgBytecodeWriter writer) => Expr.Write(writer);
}
class BgIntToBgStringExpr : BgString
{
BgInt Expr { get; }
public BgIntToBgStringExpr(BgInt expr)
: base(expr.Flags & BgExprFlags.Eager)
{
Expr = expr;
}
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(BgOpcode.IntToString);
writer.WriteExpr(Expr);
}
}
#endregion
///
/// An integer option expression
///
public class BgIntOption : BgInt
{
///
/// Name of the option
///
public BgString Name { get; }
///
/// Label to display next to the option
///
public BgString? Label { get; }
///
/// Help text to display for the user
///
public BgString? Description { get; }
///
/// Default value for the option
///
public BgInt? DefaultValue { get; }
///
/// Minimum allowed value
///
public BgInt? MinValue { get; }
///
/// Maximum allowed value
///
public BgInt? MaxValue { get; }
///
/// Constructor
///
public BgIntOption(string name, BgString? description = null, BgInt? defaultValue = null, BgInt? minValue = null, BgInt? maxValue = null, BgString? label = null)
: base(BgExprFlags.None)
{
Name = name;
Label = label;
Description = description;
DefaultValue = defaultValue;
MinValue = minValue;
MaxValue = maxValue;
}
///
public override void Write(BgBytecodeWriter writer)
{
writer.WriteOpcode(BgOpcode.IntOption);
writer.WriteExpr(CreateOptionsObject());
}
BgObject CreateOptionsObject()
{
BgObject option = BgObject.Empty;
option = option.Set(x => x.Name, Name);
if (Label is not null)
{
option = option.Set(x => x.Label, Label);
}
if (Description is not null)
{
option = option.Set(x => x.Description, Description);
}
if (DefaultValue is not null)
{
option = option.Set(x => x.DefaultValue, DefaultValue);
}
if (MinValue is not null)
{
option = option.Set(x => x.MinValue, MinValue);
}
if (MaxValue is not null)
{
option = option.Set(x => x.MaxValue, MaxValue);
}
return option;
}
}
}