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()
{
145
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
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},
234
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
{ "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)
MaZiFAU
committed
=> (
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)
MaZiFAU
committed
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();
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);
}
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
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
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
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
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
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
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
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
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