From 0e30a6442c47b01e6329dd7fde9253118d12ac77 Mon Sep 17 00:00:00 2001 From: MaZiFAU <63099053+MaZiFAU@users.noreply.github.com> Date: Sat, 10 Jun 2023 22:35:18 +0200 Subject: [PATCH] OMDoc to C# dynamic function builder 1.0 --- Assets/Scripts/JSONManager.cs | 179 +++++++++++++++++----------------- GlobalSuppressions.cs | 3 + 2 files changed, 94 insertions(+), 88 deletions(-) diff --git a/Assets/Scripts/JSONManager.cs b/Assets/Scripts/JSONManager.cs index 3565766f..1c676387 100644 --- a/Assets/Scripts/JSONManager.cs +++ b/Assets/Scripts/JSONManager.cs @@ -59,11 +59,14 @@ public static class MMTURIs public static class MMTtoLambdaExpression<T> { - private static LambdaExpression @default = Expression.Lambda(Expression.Default(typeof(T)), null); + public static readonly LambdaExpression @default = Expression.Lambda(Expression.Default(typeof(T)), null); + + private static uint param_counter = 0; //for better debugs + // TODO: Populate Dictionaries #region ExpressionDictionaries - private static Dictionary<string, Func<LambdaExpression>> MMTtoLambdaMaker = new() + private static readonly Dictionary<string, Func<LambdaExpression[], LambdaExpression>> MMTtoLambdaMaker = new() { { "sin", MakeSin}, @@ -71,7 +74,7 @@ public static class MMTtoLambdaExpression<T> MakeCos}, }; - private static Dictionary<string, ExpressionType> MMTtoBinaryExpressionType = new() + private static readonly Dictionary<string, ExpressionType> MMTtoBinaryExpressionType = new() { { "Add", ExpressionType.Add}, @@ -149,10 +152,14 @@ public static class MMTtoLambdaExpression<T> ExpressionType.SubtractChecked}, }; - private static Dictionary<string, ExpressionType> MMTtoUnaryExpressionType = new() + private static readonly Dictionary<string, ExpressionType> MMTtoUnaryExpressionType = new() { //{ "Constant", // Not Unary // ExpressionType.Constant}, + { "Convert", + ExpressionType.Convert}, + { "ConvertChecked", + ExpressionType.ConvertChecked}, { "Decrement", ExpressionType.Decrement}, { "Increment", @@ -179,71 +186,97 @@ public static class MMTtoLambdaExpression<T> #endregion ExpressionDictionaries - public static LambdaExpression MakeLambdaExpression(string URI) + public static LambdaExpression MakeLambdaExpression(string URI, LambdaExpression[] args_lamda = null) { + 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, args_lamda.Count() + )); + } + + ParameterExpression[] args_param = args_lamda?.SelectMany(l => l.Parameters).ToArray(); + if (MMTtoUnaryExpressionType.TryGetValue(URI, out var unnary_type)) { - ParameterExpression[] args = new ParameterExpression[] { - Expression.Parameter(typeof(T)) - }; - return Expression.Lambda(Expression.MakeUnary(unnary_type, args[0], typeof(T)), args); + if (args_lamda == null) { + ParameterExpression[] args = new ParameterExpression[] { + Expression.Parameter(typeof(T), "PNamed_" + (++param_counter).ToString()), + }; + return Expression.Lambda(Expression.MakeUnary(unnary_type, args[0], typeof(T)), args); + } + else { + if (args_lamda.Count() < 1) + ThrowArgumentException(unnary_type, 1); + + Type UnarySecondArgument = args_lamda.Count() < 2 ? null : args_lamda[1].ReturnType; + + return Expression.Lambda(Expression.MakeUnary(unnary_type, args_lamda[0].Body, UnarySecondArgument), args_param); + } } else if (MMTtoBinaryExpressionType.TryGetValue(URI, out var binary_type)) { - ParameterExpression[] args = new ParameterExpression[] { - Expression.Parameter(typeof(T)), - Expression.Parameter(typeof(T)) - }; - return Expression.Lambda(Expression.MakeBinary(binary_type, args[0], args[1]), args); + if (args_lamda == null) { + ParameterExpression[] args = new ParameterExpression[] { + Expression.Parameter(typeof(T), "PNamed_" + (++param_counter).ToString()), + Expression.Parameter(typeof(T), "PNamed_" + (++param_counter).ToString()), + }; + return Expression.Lambda(Expression.MakeBinary(binary_type, args[0], args[1]), args); + } + else { + if (args_lamda.Count() != 2) + ThrowArgumentException(binary_type, 2); + + return Expression.Lambda(Expression.MakeBinary(binary_type, args_lamda[0].Body, args_lamda[1].Body), args_param); + } } else if (MMTtoLambdaMaker.TryGetValue(URI, out var lamda_maker)) { - return lamda_maker(); + return lamda_maker(args_lamda ?? null); //args_lamda == null ok } throw new NotImplementedException("Could not map URI: \"" + URI + "\""); } - private static Expression<Func<T, T>> ParseFuncTUUT<U>(Func<U,U> func) - => (T x) => - (T) Convert.ChangeType( - func( - (U) Convert.ChangeType( - x, - typeof(U) - ) - ), - typeof(T) - ); - - private static LambdaExpression ExpresionFuncToLambda(Expression func, uint nTargs) + private static LambdaExpression ExpresionFuncToLambda(Expression func, string name, uint nTargs) { ParameterExpression[] args = new ParameterExpression[nTargs]; for (int i = 0; i < nTargs; i++) args[i] = Expression.Parameter(typeof(T)); - return Expression.Lambda(Expression.Invoke(func, args), args); + return Expression.Lambda(Expression.Invoke(func, args), name, args); } - //TODO? more general/generics - private static LambdaExpression ParseFuncTUUTToLambda<U>(Func<U, U> func) - => ExpresionFuncToLambda(ParseFuncTUUT<U>(func), 1); - - private static LambdaExpression MakeSin() - => default(T) switch // TODO? cleaner switch - { - float => ParseFuncTUUTToLambda<float>(MathF.Sin), - double => ParseFuncTUUTToLambda<double>(Math.Sin), - _ => throw new NotImplementedException("Sinus for " + typeof(T)) - }; - - private static LambdaExpression MakeCos() - => default(T) switch - { - float => ParseFuncTUUTToLambda<float>(MathF.Cos), - double => ParseFuncTUUTToLambda<double>(Math.Cos), - _ => throw new NotImplementedException("Sinus for " + typeof(T)) - }; + private static LambdaExpression ExpresionFuncToLambda(Expression func, string name, LambdaExpression[] args_lamda, uint nTargs_fallback) + => args_lamda == null || args_lamda.Count() == 0 + ? ExpresionFuncToLambda(func, name, nTargs_fallback) + : Expression.Lambda(Expression.Invoke(func, args_lamda.Select(l => l.Body)), name, args_lamda.SelectMany(l => l.Parameters)); + + private static Expression<Func<U, U>> ParseFuncUUToExpression<U>(Func<U, U> func) + => (Expression<Func<U, U>>) ((x) => func(x)); + + private static LambdaExpression MakeSin(LambdaExpression[] args_lamda) + => ExpresionFuncToLambda( + default(T) switch // TODO? cleaner switch + { + float => ParseFuncUUToExpression<float>(MathF.Sin), + double => ParseFuncUUToExpression<double>(Math.Sin), + _ => throw new NotImplementedException("Sinus for " + typeof(T)) + }, + "Sin", args_lamda, 1 + ); + + private static LambdaExpression MakeCos(LambdaExpression[] args_lamda) + => ExpresionFuncToLambda( + default(T) switch // TODO? cleaner switch + { + float => ParseFuncUUToExpression<float>(MathF.Cos), + double => ParseFuncUUToExpression<double>(Math.Cos), + _ => throw new NotImplementedException("Cosinus for " + typeof(T)) + }, + "Cos", args_lamda, 1 + ); } @@ -262,7 +295,7 @@ public class MMTTerm { string kind; - virtual public LambdaExpression GetLambdaExpression() + virtual public LambdaExpression GetLambdaExpression(LambdaExpression[] args = null) => Expression.Lambda(Expression.Empty(), null); } @@ -278,37 +311,8 @@ public OMA(MMTTerm applicant, List<MMTTerm> arguments) this.arguments = arguments; } - override public LambdaExpression GetLambdaExpression() - { - // local variable for each arguments - ParameterExpression[] line_variable = new ParameterExpression[arguments.Count]; - - // expression of computing arguments and assigning to corresponding variable - Expression[] line_expression = new Expression[arguments.Count + 1]; - - // unbound parameters a.k.a. all params of arguments - List<ParameterExpression> father_param = new(); - - for (int i = 0; i < arguments.Count; i++) - { - LambdaExpression - child_lambda = arguments[i].GetLambdaExpression(); - List<ParameterExpression> - child_params = child_lambda.Parameters.ToList(); - - line_variable[i] = Expression.Variable(child_lambda.ReturnType); - line_expression[i] = Expression.Assign(line_variable[i], Expression.Invoke(child_lambda, child_params)); - - foreach (ParameterExpression arg in child_params) - father_param.Add(arg); - } - - // invoke applicant with computed arguments - line_expression[arguments.Count] = Expression.Invoke(applicant.GetLambdaExpression(), line_variable); - - // compile all this into LambdaExpression - return Expression.Lambda(Expression.Block(line_variable, line_expression), father_param); - } + override public LambdaExpression GetLambdaExpression(LambdaExpression[] args = null) + => applicant.GetLambdaExpression(arguments?.Select(mmt => mmt.GetLambdaExpression()).ToArray()); } public class OMS : MMTTerm @@ -321,8 +325,8 @@ public OMS(string uri) this.uri = uri; } - override public LambdaExpression GetLambdaExpression() - => MMTtoLambdaExpression<float>.MakeLambdaExpression(uri); + override public LambdaExpression GetLambdaExpression(LambdaExpression[] args) + => MMTtoLambdaExpression<float>.MakeLambdaExpression(uri, args); } public class OMSTR : MMTTerm @@ -336,7 +340,7 @@ public OMSTR(string s) this.s = s; } - override public LambdaExpression GetLambdaExpression() + override public LambdaExpression GetLambdaExpression(LambdaExpression[] args = null) => Expression.Lambda(Expression.Constant(s, typeof(string)), null); } @@ -351,10 +355,11 @@ public OMF(float f) this.f = f; } - override public LambdaExpression GetLambdaExpression() + override public LambdaExpression GetLambdaExpression(LambdaExpression[] args = null) => Expression.Lambda(Expression.Constant(f, typeof(float)), null); } + public class MMTDeclaration { public string label; @@ -362,16 +367,14 @@ public class MMTDeclaration public static MMTDeclaration FromJson(string json) { MMTDeclaration mmtDecl = JsonConvert.DeserializeObject<MMTDeclaration>(json); - if (mmtDecl.label == null) - mmtDecl.label = string.Empty; + mmtDecl.label ??= string.Empty; return mmtDecl; } public static string ToJson(MMTDeclaration mmtDecl) { - if (mmtDecl.label == null) - mmtDecl.label = string.Empty; + mmtDecl.label ??= string.Empty; string json = JsonConvert.SerializeObject(mmtDecl); return json; diff --git a/GlobalSuppressions.cs b/GlobalSuppressions.cs index 30971bbb..d7cde694 100644 --- a/GlobalSuppressions.cs +++ b/GlobalSuppressions.cs @@ -12,3 +12,6 @@ //Local [assembly: SuppressMessage("Style", "IDE0018:Inlinevariablendeklaration", Justification = "Readability", Scope = "member", Target = "~M:Math3d.GetLineSplineIntersections(UnityEngine.Vector2[],UnityEngine.Vector2[])")] [assembly: SuppressMessage("Style", "IDE0018:Inlinevariablendeklaration", Justification = "Readability", Scope = "member", Target = "~M:Math3d.AreLineSegmentsCrossing(UnityEngine.Vector3,UnityEngine.Vector3,UnityEngine.Vector3,UnityEngine.Vector3)~System.Boolean")] + +[assembly: SuppressMessage("Style", "IDE0044:Modifizierer \"readonly\" hinzufügen", Justification = "Must not be for De/Serialzer", Scope = "member", Target = "~F:JSONManager.MMTTerm.kind")] +[assembly: SuppressMessage("CodeQuality", "IDE0051:Nicht verwendete private Member entfernen", Justification = "Needed for De/Serialzer", Scope = "member", Target = "~F:JSONManager.MMTTerm.kind")] -- GitLab