Newer
Older
using System.Collections.Generic;
using System.Linq.Expressions;
using System;
using System.Linq;
using UnityEngine;
MaZiFAU
committed
using UnityEditor;
using System.Collections.ObjectModel;
namespace REST_JSON_API
{
abstract public partial class SOMDoc
{
MaZiFAU
committed
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();
MaZiFAU
committed
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();
MaZiFAU
committed
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])
MaZiFAU
committed
? Expression.Invoke(compile_base, cast_new_to_signature)
MaZiFAU
committed
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()
{
MaZiFAU
committed
{ MMTConstants.InvertRealLit,
MakeInvert },
{ MMTConstants.Sin,
MakeSin },
{ MMTConstants.Cos,
MakeCos },
{ MMTConstants.SquareRoot,
{ MMTConstants.Tuple,
MakeTupel },
MaZiFAU
committed
{ MMTConstants.Product, // TODO:Automate
MakeTupel },
{ MMTConstants.MakeObjectArray,
MakeObjArray },
MaZiFAU
committed
{ MMTConstants.ListApplicant,
MakeInstantList },
{ MMTConstants.ListEnd,
MakeListEnd },
{ MMTConstants.ListLiteral,
InsertFrontListLiteral },
{ MMTConstants.ListType,
Identity0 },
MaZiFAU
committed
ProjLVecTupel },
MaZiFAU
committed
ProjRVecTupel },
{ MMTConstants.Map,
ChainMakes(new[]{
CallAnyFunction(false, "Select", typeof(Enumerable)),
CallAnyFunction(false, "ToList", typeof(Enumerable))})},
FeedForwardUntil },
{ MMTConstants.FeedForwardWhile2,
FeedForwardUntil },
{ MMTConstants.PartialAggregate,
CallAnyFunction(false, "PartialAggregate", typeof(IEnumerableExtensions)) },
{ MMTConstants.ToArray,
CallAnyFunction(false, "ToArray", typeof(Enumerable)) },
MaZiFAU
committed
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()
{
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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.LEQRealLit,
ExpressionType.LessThanOrEqual},
{ "Modulo",
ExpressionType.Modulo},
{ "ModuloAssign",
ExpressionType.ModuloAssign},
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},
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
{ "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();
MaZiFAU
committed
if (FactRecorder.AllFacts.TryGetValue(URI, out Fact fact))
{
MaZiFAU
committed
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;
MaZiFAU
committed
MaZiFAU
committed
LambdaExpression lambda_orig = df.GetLambdaExpression();
if (lambda_orig.Body is not LambdaExpression lambda_lambda1
|| lambda_applicant.Length == 0)
return lambda_orig;
MaZiFAU
committed
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);
}
MaZiFAU
committed
int free_params = ll_params_c - lambda_applicant.Length;
if (free_params <= 0)
return Expression.Lambda(
MaZiFAU
committed
lambda_lambda,
lambda_applicant.Select(app => app.Body).Take(ll_params_c)),
found_bound_params
);
ParameterExpression[] new_params =
MaZiFAU
committed
ll_params
MaZiFAU
committed
.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
);
MaZiFAU
committed
}
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 + "\"");
}
MaZiFAU
committed
=> (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));
MaZiFAU
committed
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)
{
if (lambda_applicant[0].Body is MethodCallExpression meth
&& meth.Method.DeclaringType == typeof(Tuple)
&& meth.Method.Name == "Create") // Access Values Directly
{
return Expression.Lambda(meth.Arguments.First(), bound_params);
}
return (
lambda_applicant[0].ReturnType == typeof(Vector3)
? GetPropertyOrField("x")
: GetPropertyOrField("Item1")
)
(lambda_applicant, lambda_arguments, bound_params);
}
MaZiFAU
committed
public static LambdaExpression ProjRVecTupel(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params)
LambdaExpression[] Items_applicant;
if (lambda_applicant[0].Body is MethodCallExpression meth
&& meth.Method.DeclaringType == typeof(Tuple)
&& meth.Method.Name == "Create") // Access Values Directly
{
Items_applicant = meth.Arguments
.Skip(1)
.Select(arg => Expression.Lambda(arg, bound_params))
MaZiFAU
committed
.ToArray();
}
else
{
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();
}
MaZiFAU
committed
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)
MaZiFAU
committed
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)
MaZiFAU
committed
{
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,
MaZiFAU
committed
}
return Expression.Lambda(
Expression.NewArrayInit(
typeof(object),
lambda_applicant.Select(l => Expression.Convert(l.Body, typeof(object)))
),
bound_params
);
MaZiFAU
committed
}
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)),
MaZiFAU
committed
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(
MaZiFAU
committed
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.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);
}
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
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)
MaZiFAU
committed
{ // call_method is overloaded or generic
(MethodInfo m, bool Success, Dictionary<string, (Type To, int Dirty)> method_types, Expression[] partials)[] recipe =
MaZiFAU
committed
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]);
MaZiFAU
committed
else
return (m, Success: true, method_types, test.Select(t => t.partials).ToArray());
MaZiFAU
committed
}).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()))}]");
MaZiFAU
committed
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()))}]");
MaZiFAU
committed
call_method = recipe[0].m;
MaZiFAU
committed
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
);
MaZiFAU
committed
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
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
}
MaZiFAU
committed
Type[] from_args = from_me.GetGenericArguments();
Type partial_type = generic
.GetGenericTypeDefinition()
.MakeGenericType(!IsDirty
? from_args
: from_args[..(gene_sig - 1)]
MaZiFAU
committed
.Append(FuncExtensions.CreateFuncType(from_args[(gene_sig - 1)..]))
.ToArray()
);
MaZiFAU
committed
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
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 =
MaZiFAU
committed
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
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
);
=> (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