Newer
Older
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
MaZiFAU
committed
using UnityEditor;
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 },
{ MMTConstants.ScalarProduct,
CallAnyFunction(false, "Dot", typeof(Vector3)) },
{ MMTConstants.VecCross,
CallAnyFunction(false, "Cross", typeof(Vector3)) },
//{ MMTConstants.VecMultI,
// CallAnyFunction(false, "Scale", typeof(Vector3)) },
MaZiFAU
committed
ProjLVecTupel },
MaZiFAU
committed
ProjRVecTupel },
{ MMTConstants.Map,
ChainMakes(new[]{
CallAnyFunction(false, "Select", typeof(Enumerable)),
CallAnyFunction(false, "ToList", typeof(Enumerable))})},
{ MMTConstants.FeedForwardWhileT2,
FeedForwardUntil },
{ MMTConstants.PartialAggregate,
CallAnyFunction(false, "PartialAggregate", typeof(IEnumerableExtensions)) },
{ MMTConstants.ToArray,
CallAnyFunction(false, "ToArray", typeof(Enumerable)) },
{ MMTConstants.Filter,
ChainMakes(new[]{
CallAnyFunction(false, "Where", typeof(Enumerable)),
CallAnyFunction(false, "ToList", typeof(Enumerable))})},
MaZiFAU
committed
CallAnyFunction(false, "Where", typeof(Enumerable)),
{ MMTConstants.FilterT2,
ChainMakes(new[]{
CallAnyFunction(false, "Where", typeof(Enumerable)),
CallAnyFunction(false, "ToList", typeof(Enumerable))})},
{ MMTConstants.PropertyX,
GetPropertyOrField("x") },
{ MMTConstants.PropertyY,
GetPropertyOrField("y") },
{ MMTConstants.PropertyZ,
GetPropertyOrField("z") },
{ MMTConstants.IndexList,
IntCastedIndexer("Item") },
{ MMTConstants.IfThenElse,
IfThenElse },
{ MMTConstants.GetField,
GetPropertyOrFieldDynamic },
{ MMTConstants.Invoke,
PartialInvoke },
};
private static readonly Dictionary<string, ExpressionType> MMTtoBinaryExpressionType = new()
{
{ MMTConstants.PointAddI,
ExpressionType.Add},
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
{ "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},
{ MMTConstants.VecMultI,
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},
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},
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
{ "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)
ParameterExpression[] found_bound_params =
bound_params
.Where(p => lambda_params.Contains(p))
.ToArray();
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);
}
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
else // Last entree to avoid stack-overflow:
if (FactRecorder.AllFacts.TryGetValue(URI, out Fact fact))
{
type = fact.CompiledValue.GetType();
Expression lambda_orig =
Expression.Constant(fact.CompiledValue, type);
if (FuncExtensions.IsFuncType(type, out int signature_count))
{ // has to be LambdaExpression!
ParameterExpression[] invoke_params = type
.GetGenericArguments()
.Take(signature_count - 1)
.Select(t => Expression.Parameter(t))
.ToArray();
lambda_orig = Expression.Lambda(
Expression.Invoke(lambda_orig, invoke_params),
invoke_params
);
}
if (lambda_applicant.Length == 0)
return Expression.Lambda(lambda_orig, null);
else
return _PartialInvoke(lambda_orig, lambda_applicant, found_bound_params);
}
throw new NotImplementedException("Could not map URI: \"" + URI + "\"");
}
#pragma warning disable IDE0060 // Nicht verwendete Parameter entfernen // Signatures given by CustomFunction
public static LambdaExpression PartialInvoke(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params)
=> _PartialInvoke(lambda_applicant[0].Body, lambda_arguments, bound_params);
public static LambdaExpression _PartialInvoke(Expression func, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params)
{
if (!FuncExtensions.IsFuncType(func.Type, out int signature_count))
throw new ArgumentException($"{nameof(func)} has to be Func");
int params_count = signature_count - 1;
IEnumerable<Type> params_type = func.Type.GetGenericArguments().Take(params_count);
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
int free_params = params_count - lambda_arguments.Length;
if (free_params <= 0)
return Expression.Lambda(
Expression.Invoke(
func,
lambda_arguments.Select(app => app.Body).Take(params_count)),
bound_params
);
ParameterExpression[] new_params =
params_type
.Skip(lambda_arguments.Length)
.Select(t => Expression.Parameter(t))
.ToArray();
return Expression.Lambda(
Expression.Lambda(
Expression.Invoke(
func,
lambda_arguments.Select(app => app.Body).AppendRange(new_params)
),
new_params
),
bound_params
);
}
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);
}
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
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
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
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
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
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
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
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
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
#pragma warning restore IDE0060 // Nicht verwendete Parameter entfernen // Signatures given by CustomFunction