using System.Collections.Generic; using System.Linq.Expressions; using System; using System.Linq; using UnityEngine; using System.Reflection; using UnityEditor; using System.Collections.ObjectModel; namespace REST_JSON_API { abstract public partial class SOMDoc { public Func<object[], object[]> PartialInvokeCastingLambdaExpression(out Expression compile_base, out Type[] signature, object[] callArgs = null, bool[] useArgs = null) { List<Type> signature_list; LambdaExpression lambda_orig = GetLambdaExpression(); if (FuncExtensions.IsFuncType(lambda_orig.ReturnType, out int signature_count)) { signature_list = lambda_orig.ReturnType.GetGenericArguments().ToList(); compile_base = lambda_orig.Body; } else { signature_count = lambda_orig.Parameters.Count + 1; signature_list = Enumerable.Append( lambda_orig.Parameters.Select(p => p.Type), lambda_orig.ReturnType) .ToList(); compile_base = lambda_orig; } ParameterExpression object_arr = Expression.Parameter(typeof(object[]), "PARAMS_Arr"); Expression[] cast_new_to_signature = new Expression[signature_count - 1]; List<int> removed = new(); for (int i = 0; i < signature_count - 1; i++) { if (callArgs != null && callArgs.Length < i && (useArgs == null || (useArgs.Length < i && useArgs[i]))) { cast_new_to_signature[i] = Expression.Constant(callArgs[i], signature_list[i]); removed.Add(i); continue; } cast_new_to_signature[i] = Expression.Convert( Expression.ArrayIndex( object_arr, Expression.Constant(i) ), signature_list[i] ); } signature = signature_list.SkipAt(removed).ToArray(); LambdaExpression final_expression = Expression.Lambda( typeof(object[]).IsAssignableFrom(signature[^1]) ? Expression.Invoke(compile_base, cast_new_to_signature) : Expression.NewArrayInit( typeof(object), new Expression[] { Expression.Convert(Expression.Invoke(compile_base, cast_new_to_signature), typeof(object)) }), object_arr ); return final_expression.Compile() as Func<object[], object[]>; } protected static class SOMDocToLambdaExpression { // TODO: Populate Dictionaries #region ExpressionDictionaries public delegate LambdaExpression CustomFunction(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params); private static readonly Dictionary<string, CustomFunction> MMTtoLambdaMaker = new() { { MMTConstants.InvertRealLit, MakeInvert }, { MMTConstants.Sin, MakeSin }, { MMTConstants.Cos, MakeCos }, { MMTConstants.SquareRoot, MakeRoot }, { MMTConstants.Tuple, MakeTupel }, { MMTConstants.Product, // TODO:Automate MakeTupel }, { MMTConstants.MakeObjectArray, MakeObjArray }, { MMTConstants.ListApplicant, MakeInstantList }, { MMTConstants.ListEnd, MakeListEnd }, { MMTConstants.ListLiteral, InsertFrontListLiteral }, { MMTConstants.ListType, Identity0 }, { MMTConstants.ProjL, ProjLVecTupel }, { MMTConstants.ProjR, ProjRVecTupel }, { MMTConstants.Map, ChainMakes(new[]{ CallAnyFunction(false, "Select", typeof(Enumerable)), CallAnyFunction(false, "ToList", typeof(Enumerable))})}, { MMTConstants.FeedForwardWhile, FeedForwardUntil }, { MMTConstants.FeedForwardWhile2, FeedForwardUntil }, { MMTConstants.PartialAggregate, CallAnyFunction(false, "PartialAggregate", typeof(IEnumerableExtensions)) }, { MMTConstants.ToArray, CallAnyFunction(false, "ToArray", typeof(Enumerable)) }, { MMTConstants.Filter2, ChainMakes(new[]{ CallAnyFunction(false, "Where", typeof(Enumerable)), CallAnyFunction(false, "ToList", typeof(Enumerable))})}, { MMTConstants.Fold, Aggregate}, { MMTConstants.PropertyX, GetPropertyOrField("x") }, { MMTConstants.PropertyY, GetPropertyOrField("y") }, { MMTConstants.PropertyZ, GetPropertyOrField("z") }, { MMTConstants.IndexList, IntCastedIndexer("Item") }, { MMTConstants.IfThenElse, IfThenElse }, { MMTConstants.GetField, GetPropertyOrFieldDynamic }, }; private static readonly Dictionary<string, ExpressionType> MMTtoBinaryExpressionType = new() { { MMTConstants.AddRealLit, ExpressionType.Add}, { "AddAssign", ExpressionType.AddAssign}, { "AddAssignChecked", ExpressionType.AddAssignChecked}, { "AddChecked", ExpressionType.AddChecked}, { "And", ExpressionType.And}, { "AndAlso", ExpressionType.AndAlso}, { "AndAssign", ExpressionType.AndAssign}, { "Assign", ExpressionType.Assign}, { MMTConstants.Divide, ExpressionType.Divide}, { "DivideAssign", ExpressionType.DivideAssign}, { "Equal", ExpressionType.Equal}, { "ExclusiveOr", ExpressionType.ExclusiveOr}, { "ExclusiveOrAssign", ExpressionType.ExclusiveOrAssign}, { "GreaterThan", ExpressionType.GreaterThan}, { "GreaterThanOrEqual", ExpressionType.GreaterThanOrEqual}, { "LeftShift", ExpressionType.LeftShift}, { "LeftShiftAssign", ExpressionType.LeftShiftAssign}, { MMTConstants.LessThan, ExpressionType.LessThan}, { MMTConstants.LEQRealLit, ExpressionType.LessThanOrEqual}, { "Modulo", ExpressionType.Modulo}, { "ModuloAssign", ExpressionType.ModuloAssign}, { MMTConstants.TimesRealLit, ExpressionType.Multiply}, { "MultiplyAssign", ExpressionType.MultiplyAssign}, { "MultiplyAssignChecked", ExpressionType.MultiplyAssignChecked}, { "MultiplyChecked", ExpressionType.MultiplyChecked}, { "NotEqual", ExpressionType.NotEqual}, { "Or", ExpressionType.Or}, { "OrAssign", ExpressionType.OrAssign}, { "OrElse", ExpressionType.OrElse}, { "Power", ExpressionType.Power}, { "PowerAssign", ExpressionType.PowerAssign}, { "RightShift", ExpressionType.RightShift}, { "RightShiftAssign", ExpressionType.RightShiftAssign}, { "Subtract", ExpressionType.Subtract}, { "SubtractAssign", ExpressionType.SubtractAssign}, { "SubtractAssignChecked", ExpressionType.SubtractAssignChecked}, { "SubtractChecked", ExpressionType.SubtractChecked}, }; private static readonly Dictionary<string, ExpressionType> MMTtoUnaryExpressionType = new() { //{ "Constant", // Not Unary // ExpressionType.Constant}, { "Convert", ExpressionType.Convert}, { "ConvertChecked", ExpressionType.ConvertChecked}, { "Decrement", ExpressionType.Decrement}, { "Increment", ExpressionType.Increment}, { MMTConstants.MinusRealLit, ExpressionType.Negate}, { "NegateChecked", ExpressionType.NegateChecked}, { "Not", ExpressionType.Not}, { "OnesComplement", ExpressionType.OnesComplement}, { "PostDecrementAssign", ExpressionType.PostDecrementAssign}, { "PostIncrementAssign", ExpressionType.PostIncrementAssign}, { "PreDecrementAssign", ExpressionType.PreDecrementAssign}, { "PreIncrementAssign", ExpressionType.PreIncrementAssign}, { "UnaryPlus", ExpressionType.UnaryPlus}, }; #endregion ExpressionDictionaries //TODO: case ((f->x)->y) instead of assumed (f->(x->y)) public static LambdaExpression MakeLambdaExpression(string URI, LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { void ThrowArgumentException(ExpressionType expression_cast, int expected) { throw new ArgumentException(string.Format( "\"Wrong number of Arguments. Required: {2}. Supplied: {3}.\\n\\tFor URI:\\\"{0}\\\"\\n\\tmapped to:\\\"{1}\\\"\"", URI, expression_cast, expected, lambda_applicant.Count() )); } ParameterExpression[] lambda_params = lambda_applicant .SelectMany(l => l.Parameters) .ToArray(); //PERF: .ToList().Sort() => .BinarySearch; //Too much overhead? ParameterExpression[] found_bound_params = bound_params .Where(p => lambda_params.Contains(p)) .ToArray(); if (FactRecorder.AllFacts.TryGetValue(URI, out Fact fact)) { Expression lambda_lambda; int ll_params_c; IEnumerable<Type> ll_params; if (fact is not FunctionFact ffact) { MMTFact decl = fact.MakeMMTDeclaration(); SOMDoc df = decl is MMTGeneralFact gf ? gf.defines : (decl as MMTValueFact).lhs; LambdaExpression lambda_orig = df.GetLambdaExpression(); if (lambda_orig.Body is not LambdaExpression lambda_lambda1 || lambda_applicant.Length == 0) return lambda_orig; lambda_lambda = lambda_lambda1; ll_params_c = lambda_lambda1.Parameters.Count(); ll_params = lambda_lambda1.Parameters.Select(p => p.Type); } else { lambda_lambda = ffact.LambdaExpression; ll_params_c = ffact.Signature.Length - 1; ll_params = ffact.Signature.Take(ll_params_c); } int free_params = ll_params_c - lambda_applicant.Length; if (free_params <= 0) return Expression.Lambda( Expression.Invoke( lambda_lambda, lambda_applicant.Select(app => app.Body).Take(ll_params_c)), found_bound_params ); ParameterExpression[] new_params = ll_params .Skip(lambda_applicant.Length) .Select(t => Expression.Parameter(t)) .ToArray(); return Expression.Lambda( Expression.Lambda( Expression.Invoke( lambda_lambda, lambda_applicant.Select(app => app.Body).AppendRange(new_params) ), new_params ), found_bound_params ); } else if (MMTtoUnaryExpressionType.TryGetValue(URI, out var unnary_type)) { if (lambda_applicant.Count() < 1) ThrowArgumentException(unnary_type, 1); Type UnarySecondArgument = lambda_applicant.Count() < 2 ? null : lambda_applicant[1].ReturnType; return Expression.Lambda(Expression.MakeUnary(unnary_type, lambda_applicant[0].Body, UnarySecondArgument), found_bound_params); } else if (MMTtoBinaryExpressionType.TryGetValue(URI, out var binary_type)) { if (lambda_applicant.Count() != 2) ThrowArgumentException(binary_type, 2); return Expression.Lambda(Expression.MakeBinary(binary_type, lambda_applicant[0].Body, lambda_applicant[1].Body), found_bound_params); } else if (MMTtoLambdaMaker.TryGetValue(URI, out CustomFunction lamda_maker)) { return lamda_maker(lambda_applicant, lambda_arguments, found_bound_params); } else if (MMTConstants.OMS_TO_TYPE.TryGetValue(URI, out Type type)) { return Expression.Lambda(Expression.Default(type), null); } throw new NotImplementedException("Could not map URI: \"" + URI + "\""); } public static CustomFunction ChainMakes(CustomFunction[] makes) => (LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => { foreach (var make in makes) lambda_applicant = new[] { make(lambda_applicant, lambda_arguments, bound_params) }; return lambda_applicant[0]; }; public static LambdaExpression ExpresionFuncToLambda(LambdaExpression func, string name, LambdaExpression[] args_lamda, ParameterExpression[] bound_params, uint nTargs_fallback) => Expression.Lambda(Expression.Invoke(func, args_lamda.Select(l => l.Body)), name, bound_params); public static LambdaExpression ParseFuncUUToExpression<U>(Func<U, U> func) => (Expression<Func<U, U>>)((U x) => func(x)); public static LambdaExpression MakeInvert(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda( Expression.MakeBinary(ExpressionType.Divide, Expression.Convert(Expression.Constant(1), lambda_applicant[0].ReturnType), lambda_applicant[0].Body), bound_params ); public static LambdaExpression MakeSin(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => ExpresionFuncToLambda( lambda_applicant[0].ReturnType == typeof(float) ? ParseFuncUUToExpression<float>(MathF.Sin) : lambda_applicant[0].ReturnType == typeof(double) ? ParseFuncUUToExpression<double>(Math.Sin) : throw new NotImplementedException("Sinus for " + lambda_applicant[0].ReturnType), "Sin", lambda_arguments.Length > 0 ? lambda_arguments : lambda_applicant, bound_params, 1 ); public static LambdaExpression MakeCos(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => ExpresionFuncToLambda( lambda_applicant[0].ReturnType == typeof(float) ? ParseFuncUUToExpression<float>(MathF.Cos) : lambda_applicant[0].ReturnType == typeof(double) ? ParseFuncUUToExpression<double>(Math.Cos) : throw new NotImplementedException("Cosinus for " + lambda_applicant[0].ReturnType), "Cos", lambda_arguments.Length > 0 ? lambda_arguments : lambda_applicant, bound_params, 1 ); public static LambdaExpression MakeRoot(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => ExpresionFuncToLambda( lambda_applicant[0].ReturnType == typeof(float) ? ParseFuncUUToExpression<float>(MathF.Sqrt) : lambda_applicant[0].ReturnType == typeof(double) ? ParseFuncUUToExpression<double>(Math.Sqrt) : throw new NotImplementedException("Sqrt for " + lambda_applicant[0].ReturnType), "Sqrt", lambda_arguments.Length > 0 ? lambda_arguments : lambda_applicant, bound_params, 1 ); public static LambdaExpression ProjLVecTupel(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => ( lambda_applicant[0].ReturnType == typeof(Vector3) ? GetPropertyOrField("x") : GetPropertyOrField("Item1") ) (lambda_applicant, lambda_arguments, bound_params); public static LambdaExpression ProjRVecTupel(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { LambdaExpression[] Items_applicant = lambda_applicant[0].ReturnType == typeof(Vector3) ? new string[] { "y", "z" } .Select(prop => GetPropertyOrField(prop)(lambda_applicant, lambda_arguments, bound_params)) .ToArray() : lambda_applicant[0].ReturnType.GetProperties() .OrderBy(fi => fi.Name) .Skip(1) // Item1 .Select(fi => Expression.Lambda( Expression.Property(lambda_applicant[0].Body, fi), bound_params)) .ToArray(); return Items_applicant.Length == 1 ? Items_applicant[0] : MakeTupel(Items_applicant, lambda_arguments, bound_params); } public static LambdaExpression MakeTupel(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { if (lambda_applicant.Length == 3 && lambda_applicant.All(l => l.ReturnType == typeof(float))) return ExpresionFuncToLambda( (Expression<Func<float, float, float, Vector3>>)((x, y, z) => new Vector3(x, y, z)), "UnityEngineVector3", lambda_applicant, bound_params, 3 ); Type[] genericTypes = new Type[lambda_applicant.Length]; for (int i = 0; i < lambda_applicant.Length; i++) genericTypes[i] = Type.MakeGenericMethodParameter(i); MethodInfo create = typeof(Tuple) .GetMethod("Create", genericTypes) .MakeGenericMethod(lambda_applicant.Select(l => l.ReturnType).ToArray()); return Expression.Lambda( Expression.Call(create, lambda_applicant.Select(l => l.Body)), bound_params ); } public static LambdaExpression MakeObjArray(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { if (lambda_applicant.Length == 1 && lambda_applicant[0].ReturnType.IsArray && !typeof(object[]).IsAssignableFrom(lambda_applicant[0].ReturnType)) { ParameterExpression lambda_param = Expression.Parameter(lambda_applicant[0].ReturnType.GetElementType()); return CallAnyFunction(false, "ToArray", typeof(Enumerable))( new[] { CallAnyFunction(false, "Select", typeof(Enumerable), new[] { (1u, Expression.Lambda(Expression.Lambda(Expression.Convert(lambda_param, typeof(object)), lambda_param))) } ) (lambda_applicant, lambda_arguments, bound_params) }, lambda_arguments, bound_params ); } return Expression.Lambda( Expression.NewArrayInit( typeof(object), lambda_applicant.Select(l => Expression.Convert(l.Body, typeof(object))) ), bound_params ); } public static LambdaExpression MakeInstantList(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda( Expression.ListInit( Expression.New(typeof(List<>).MakeGenericType(lambda_applicant[0].ReturnType)), lambda_applicant.Select(l => l.Body) // Expression.Convert(l.Body, lambda_applicant[0].ReturnType)) ), bound_params ); public static LambdaExpression InsertFrontListLiteral(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda( Expression.Call( lambda_applicant[0].Body, lambda_applicant[0].ReturnType.GetMethod("Insert"), Expression.Constant(0, typeof(int)), lambda_applicant[1].Body ), bound_params ); public static LambdaExpression MakeListEnd(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda( Expression.New(typeof(List<>).MakeGenericType(lambda_applicant[0].ReturnType)) ); public static LambdaExpression Identity0(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => lambda_applicant[0]; public static LambdaExpression Index0(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda( Expression.ArrayIndex(lambda_applicant[0].Body, Expression.Constant(0)) ); public static LambdaExpression Tail(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { LambdaExpression enumerated = CallAnyFunction(false, "Skip", typeof(Enumerable), new[] { (1u, Expression.Lambda(Expression.Constant(1, typeof(int)))) } )(lambda_applicant, lambda_arguments, bound_params); return CallAnyFunction(false, "ToArray", typeof(Enumerable))(new[] { enumerated }, null, bound_params); } public static LambdaExpression IfThenElse(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda( // lambda_applicant[0] is ReturnType Expression.Condition(lambda_applicant[1].Body, lambda_applicant[2].Body, lambda_applicant[3].Body), bound_params ); public static LambdaExpression Aggregate(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { lambda_applicant[2] = // switch order of parameters Expression.Lambda( Expression.Lambda( ((LambdaExpression)lambda_applicant[2].Body).Body, ((LambdaExpression)lambda_applicant[2].Body).Parameters.Reverse() ), lambda_applicant[2].Parameters ); return CallAnyFunction(false, "Aggregate", typeof(Enumerable)) (lambda_applicant, lambda_arguments, bound_params); } public static LambdaExpression FeedForwardUntil(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => ChainMakes(new[]{ CallAnyFunction(false, "FeedForwardUntil", typeof(IEnumerableExtensions)), CallAnyFunction(false, "ToList", typeof(Enumerable))} )(lambda_applicant[1..], lambda_arguments, bound_params); // lambda_applicant[0] is ReturnType public static CustomFunction CallAnyFunction(bool self, string method_name, Type type = null, (uint, LambdaExpression)[] lambda_manual = null) => (LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => { type ??= lambda_applicant[0].ReturnType; LambdaExpression[] lambda_args_new = lambda_applicant .Skip(self ? 1 : 0) .AppendRangeAt(lambda_manual) .ToArray(); Expression[] call_args = lambda_args_new .Select(l => l.Body) .ToArray(); Type[] lambda_args_type = lambda_args_new .Select(l => l.ReturnType) .ToArray(); MethodInfo call_method = // type.method_name type.GetMethod(method_name, lambda_args_type); if (call_method == null) { // call_method is overloaded or generic (MethodInfo m, bool Success, Dictionary<string, (Type To, int Dirty)> method_types, Expression[] partials)[] recipe = type.GetMethods() .Where(m => m.Name.Equals(method_name) && m.GetParameters().Length == call_args.Length ).Select(m => { Dictionary<string, (Type To, int Dirty)> method_types = new(); (bool Success, Dictionary<string, (Type To, int Dirty)> GenericParameters, Expression partials)[] test = m.GetParameters() .Zip(lambda_args_new, (par, lamb) => IsCompatibleType(par.ParameterType, lamb.ReturnType, lamb.Body, 0)) .ToArray(); if (!test.All(t => t.Success) || !test.All(t => method_types.TryAddAllFrom(t.GenericParameters))) return (m, false, new(), new LambdaExpression[0]); else return (m, Success: true, method_types, test.Select(t => t.partials).ToArray()); }).Where(t => t.Success) .ToArray(); if (recipe.Length == 0) throw new Exception($"Could not find method \"{method_name}\" in Type \"{type}\" and Type Signature [{string.Join(", ", lambda_args_type.Select(o => o.ToString()))}]"); if (recipe.Length > 1) // AmbiguousMatchException Debug.LogWarning($"Found methods not unique for \"{method_name}\" in Type \"{type}\" and Type Signature [{string.Join(", ", lambda_args_type.Select(o => o.ToString()))}]"); call_method = recipe[0].m; call_args = recipe[0].partials; if (call_method.IsGenericMethod) { call_method = call_method.MakeGenericMethod( call_method.GetGenericArguments() .Select(arg => recipe[0].method_types[arg.Name].To) .ToArray() ); } } return Expression.Lambda( self ? Expression.Call(lambda_applicant[0].Body, call_method, call_args) : Expression.Call(call_method, call_args), bound_params ); static (bool Success, Dictionary<string, (Type To, int Dirty)> GenericParameters, Expression partials) IsCompatibleType(Type generic, Type from_me, Expression source_from_me, int dirty) { Dictionary<string, (Type To, int Dirty)> retDic = new(); if (generic.HasElementType && from_me.HasElementType) { generic = generic.GetElementType(); from_me = from_me.GetElementType(); } if (generic.IsAssignableFrom(from_me)) return (true, new(), source_from_me); if (generic.IsGenericType) { (bool Success, Dictionary<string, (Type To, int Dirty)> GenericParameters, Expression partials)[] recursion; if (generic.IsInterface && !from_me.IsInterface) { if (generic.Equals(typeof(IEnumerable<>)) && from_me.IsArray) // GetInterfaces() drops here the generic type? return IsCompatibleType( generic.GetGenericArguments()[0], from_me.GetElementType(), source_from_me, //will not be Func[], atmost(?) List<Func> dirty ); recursion = generic.GetInterfaces().Select(gi => from_me.GetInterfaces() .Select(fi => IsCompatibleType(gi, fi, source_from_me, dirty)) .FirstOrDefault(t => t.Success) ).ToArray(); } else { if (FuncExtensions.IsFuncType(generic, out int gene_sig) && FuncExtensions.IsFuncType(from_me, out int from_sig) && from_me == source_from_me.Type) // from_me <within_or_equal> source_from_me.Type { // lets pretend C# uses lambda logic like MMT if (gene_sig > from_sig) return (false, new(), source_from_me); bool IsDirty = gene_sig != from_sig; if (IsDirty) dirty++; bool IsParame = source_from_me is ParameterExpression; bool IsLambda = source_from_me is LambdaExpression; if (!IsParame && !IsLambda) { Debug.LogWarning($"Unexpected Expression for Parameter \"{nameof(source_from_me)}\""); if (IsDirty) return (false, new(), source_from_me); else goto GeneralGenericCase; } Expression[] expr_decomp = null; if (IsParame) { if (IsDirty) { Debug.LogWarning( "If you see this message, you have found an example for this branch.\n" + "I have no clue what will happen now. Good Luck!"); // What should it be? // Call(generic)([(from_me)=>generic](from_me)) // Call([(A)=>C]=>...)([([(a,b)=>c]=>...)=>[(A)=>C]=>...]([(a,b)=>c]=>...)) // [(from_me-generic)=>Call(generic)([(from_me)=>generic](from_me))] // //generic: [(A)=>C]=>... //from_me: [(a,b)=>c]=>... //result: [(A)=>[(a,b)=>c](b)]=>... // or?: [(a)=>[(b)=>c]]=>... // or?: [[(a,b)=>c]=>C]=>... // //(from_me)=>generic]: // [[(a,b)=>c]=>...]=>[[(A)=>C]=>...] //Lamb(Call(from_me, (A,b)), A) -> escalate b } Type[] from_args = from_me.GetGenericArguments(); Type partial_type = generic .GetGenericTypeDefinition() .MakeGenericType(!IsDirty ? from_args : from_args[..(gene_sig - 1)] .Append(FuncExtensions.CreateFuncType(from_args[(gene_sig - 1)..])) .ToArray() ); expr_decomp = partial_type.GetGenericArguments() .Select(typ => Expression.Parameter(typ)) .ToArray(); } else if (IsLambda) { LambdaExpression source_lambda = source_from_me as LambdaExpression; ReadOnlyCollection<ParameterExpression> from_para = source_lambda.Parameters; expr_decomp = from_para.Take<Expression>(gene_sig - 1) .Append(!IsDirty ? source_lambda.Body : Expression.Lambda(source_lambda.Body, from_para.Skip(gene_sig - 1))) .ToArray(); } recursion = generic.GetGenericArguments() .Zip(expr_decomp, (par, expr) => IsCompatibleType(par, expr.Type, expr, dirty)) .ToArray(); if (!recursion.All(t => t.Success) || !recursion.All(t => retDic.TryAddAllFrom(t.GenericParameters))) return (false, new(), source_from_me); Expression source_partial = IsParame ? Expression.Parameter( FuncExtensions.CreateFuncType( recursion.Select(t => t.partials.Type).ToArray())) : IsLambda ? Expression.Lambda( recursion[^1].partials, recursion[..^1].Select(t => t.partials as ParameterExpression) ) : null; // For compiler return (true, retDic, source_partial); } GeneralGenericCase: if (!from_me.IsGenericType || !generic.GetGenericTypeDefinition().Equals(from_me.GetGenericTypeDefinition())) return (false, new(), source_from_me); recursion = generic.GetGenericArguments() .Zip(from_me.GetGenericArguments(), (par, typ) => IsCompatibleType(par, typ, source_from_me, dirty)) .ToArray(); } if (!recursion.All(t => t.Success) || !recursion.All(t => retDic.TryAddAllFrom(t.GenericParameters))) return (false, new(), source_from_me); else return (true, retDic, source_from_me); } if (generic.IsGenericParameter) { // TODO? .GetGenericParameterConstraints() return (true, new() { { generic.Name, (from_me, dirty) } }, source_from_me); } return (false, new(), source_from_me); } }; public static LambdaExpression MakeType(KeyValuePair<string, LambdaExpression>[] members, ParameterExpression[] bound_params) => Expression.Lambda( TupleFactory .Create(members.Select(m => new KeyValuePair<string, Type>(m.Key, m.Value.ReturnType))) .MakeNewExpression(members.Select(m => m.Value.Body)), bound_params ); public static LambdaExpression GetPropertyOrFieldDynamic(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { if (lambda_applicant[1].Compile() is not Func<string> name_gen) throw new ArgumentException($"Second element of {nameof(lambda_applicant)} hast to resolve to {typeof(string)}, argumentless!"); return GetPropertyOrField(name_gen()) (lambda_applicant.Where((l, i) => i != 1).ToArray(), lambda_arguments, bound_params); } public static CustomFunction GetPropertyOrField(string property_name) => (LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => lambda_applicant.Length == 1 ? Expression.Lambda( Expression.PropertyOrField(lambda_applicant[0].Body, property_name), bound_params ) : Expression.Lambda( Expression.Property(lambda_applicant[0].Body, property_name, lambda_applicant.Skip(1).Select(l => l.Body).ToArray()), bound_params ); public static CustomFunction IntCastedIndexer(string property_name) => (LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda( Expression.Property(lambda_applicant[0].Body, property_name, lambda_applicant.Skip(1).Select(l => Expression.Convert(l.Body, typeof(int))).ToArray()), bound_params ); } } }