using System;
using System.Linq.Expressions;
using System.Reflection;
using static Python.Runtime.OpsHelper;
namespace Python.Runtime
{
static class OpsHelper
{
public static BindingFlags BindingFlags => BindingFlags.Public | BindingFlags.Static;
public static Func Binary(Func func)
{
var a = Expression.Parameter(typeof(T), "a");
var b = Expression.Parameter(typeof(T), "b");
var body = func(a, b);
var lambda = Expression.Lambda>(body, a, b);
return lambda.Compile();
}
public static Func Unary(Func func)
{
var value = Expression.Parameter(typeof(T), "value");
var body = func(value);
var lambda = Expression.Lambda>(body, value);
return lambda.Compile();
}
public static bool IsOpsHelper(this MethodBase method)
=> method.DeclaringType.GetCustomAttribute() is not null;
public static Expression EnumUnderlyingValue(Expression enumValue)
=> Expression.Convert(enumValue, enumValue.Type.GetEnumUnderlyingType());
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
internal class OpsAttribute: Attribute { }
[Ops]
internal static class FlagEnumOps where T : Enum
{
static readonly Func and = BinaryOp(Expression.And);
static readonly Func or = BinaryOp(Expression.Or);
static readonly Func xor = BinaryOp(Expression.ExclusiveOr);
static readonly Func invert = UnaryOp(Expression.OnesComplement);
#pragma warning disable IDE1006
public static T op_BitwiseAnd(T a, T b) => and(a, b);
public static T op_BitwiseOr(T a, T b) => or(a, b);
public static T op_ExclusiveOr(T a, T b) => xor(a, b);
public static T op_OnesComplement(T value) => invert(value);
#pragma warning restore IDE1006
static Expression FromNumber(Expression number)
=> Expression.Convert(number, typeof(T));
static Func BinaryOp(Func op)
{
return Binary((a, b) =>
{
var numericA = EnumUnderlyingValue(a);
var numericB = EnumUnderlyingValue(b);
var numericResult = op(numericA, numericB);
return FromNumber(numericResult);
});
}
static Func UnaryOp(Func op)
{
return Unary(value =>
{
var numeric = EnumUnderlyingValue(value);
var numericResult = op(numeric);
return FromNumber(numericResult);
});
}
}
[Ops]
internal static class EnumOps where T : Enum
{
[ForbidPythonThreads]
#pragma warning disable IDE1006 // Naming Styles - must match Python
public static PyInt __index__(T value)
#pragma warning restore IDE1006 // Naming Styles
=> typeof(T).GetEnumUnderlyingType() == typeof(UInt64)
? new PyInt(Convert.ToUInt64(value))
: new PyInt(Convert.ToInt64(value));
[ForbidPythonThreads]
#pragma warning disable IDE1006 // Naming Styles - must match Python
public static PyInt __int__(T value) => __index__(value);
#pragma warning restore IDE1006 // Naming Styles
}
}