// 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
}