// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Immutable; using System.Linq.Expressions; using System.Reflection; namespace EpicGames.BuildGraph.Expressions { /// /// Abstract base class for expressions returning an object /// /// The native type which mirrors this object [BgType(typeof(BgObjectType<>))] public abstract class BgObject : BgExpr { /// /// Constant representation of an empty object /// public static BgObject Empty { get; } = new BgObjectEmptyExpr(); /// /// Constructor /// /// Flags for this expression protected BgObject(BgExprFlags flags) : base(flags) { } /// /// Sets the value of a property in the object /// /// Name of the field /// Value for the field /// New object with the field set public BgObject Set(string name, BgExpr value) => new BgObjectSetExpr(this, name, value); /// /// Sets the value of a property in the object /// /// Name of the field /// Value for the field /// New object with the field set public BgObject Set(Expression> property, TExpr value) where TExpr : BgExpr { MemberExpression member = ((MemberExpression)property.Body); PropertyInfo propertyInfo = (PropertyInfo)member.Member; string name = propertyInfo.GetCustomAttribute()?.Name ?? propertyInfo.Name; return Set(name, value); } /// /// Gets the value of a field in the object /// /// Name of the field /// Default value for the field, if it's not defined /// Value of the field public TExpr Get(string name, TExpr defaultValue) where TExpr : BgExpr => BgType.Wrap(new BgObjectGetExpr(this, name, defaultValue)); /// /// Gets the value of a field in the object /// /// Expression indicating the property to retrieve /// Default value for the property /// Value of the field public TExpr Get(Expression> property, TExpr defaultValue) where TExpr : BgExpr { MemberExpression member = ((MemberExpression)property.Body); PropertyInfo propertyInfo = (PropertyInfo)member.Member; string name = propertyInfo.GetCustomAttribute()?.Name ?? propertyInfo.Name; return Get(name, defaultValue); } /// public override BgString ToBgString() => "{Object}"; } /// /// Traits for a /// class BgObjectType : BgType> where T : new() { /// public override BgObject Constant(object value) => new BgObjectConstantExpr((ImmutableDictionary)value); /// public override BgObject Wrap(BgExpr expr) => new BgObjectWrappedExpr(expr); } #region Expression classes class BgObjectEmptyExpr : BgObject { public BgObjectEmptyExpr() : base(BgExprFlags.NotInterned) { } public override void Write(BgBytecodeWriter writer) { writer.WriteOpcode(BgOpcode.ObjEmpty); } } class BgObjectConstantExpr : BgObject { public ImmutableDictionary Fields { get; } public BgObjectConstantExpr(ImmutableDictionary fields) : base(BgExprFlags.NotInterned) { Fields = fields; } public override void Write(BgBytecodeWriter writer) { throw new NotImplementedException(); } } class BgObjectSetExpr : BgObject { public BgObject Object { get; } public string Name { get; } public BgExpr Value { get; } public BgObjectSetExpr(BgObject obj, string name, BgExpr value) : base(BgExprFlags.NotInterned) { Object = obj; Name = name; Value = value; } public override void Write(BgBytecodeWriter writer) { writer.WriteOpcode(BgOpcode.ObjSet); writer.WriteExpr(Object); writer.WriteName(Name); writer.WriteExpr(Value); } } class BgObjectGetExpr : BgObject { public BgObject Object { get; } public string Name { get; } public BgExpr DefaultValue { get; } public BgObjectGetExpr(BgObject obj, string name, BgExpr defaultValue) : base(BgExprFlags.NotInterned) { Object = obj; Name = name; DefaultValue = defaultValue; } public override void Write(BgBytecodeWriter writer) { writer.WriteOpcode(BgOpcode.ObjGet); writer.WriteExpr(Object); writer.WriteName(Name); writer.WriteExpr(DefaultValue); } } class BgObjectWrappedExpr : BgObject { BgExpr Expr { get; } public BgObjectWrappedExpr(BgExpr expr) : base(expr.Flags) { Expr = expr; } public override void Write(BgBytecodeWriter writer) => Expr.Write(writer); } #endregion }