123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using Luticate2.Auth.Utils.Dbo;
- using Luticate2.Auth.Utils.Dbo.Result;
- using Luticate2.Auth.Utils.Exceptions;
- using Luticate2.Auth.Utils.Interfaces;
-
- namespace Luticate2.Auth.Utils.Business.ExpressionConverter
- {
- public class LuExpressionConverterVisitor : ExpressionVisitor
- {
- public LuExpressionConverterOptions Options { get; }
-
- protected IServiceProvider ServiceProvider { get; }
-
- public LuExpressionConverterVisitor(LuExpressionConverterOptions options, IServiceProvider serviceProvider)
- {
- Options = options;
- ServiceProvider = serviceProvider;
- }
-
- protected LuResult<Stack<Expression>> StackSimpleExpression(Expression expression, Stack<Expression> stack)
- {
- stack.Push(expression);
- if (expression is MemberExpression memberExpression)
- {
- if (memberExpression.Expression != null)
- {
- var result = StackSimpleExpression(memberExpression.Expression, stack);
- return result;
- }
- return LuResult<Stack<Expression>>.Ok(stack);
- }
- else if (expression is MethodCallExpression methodCallExpression)
- {
- if (methodCallExpression.Object != null)
- {
- var result = StackSimpleExpression(methodCallExpression.Object, stack);
- return result;
- }
- return LuResult<Stack<Expression>>.Ok(stack);
- }
- else
- {
- return LuResult<Stack<Expression>>.Ok(stack);
- }
- }
-
- protected ILuObjectConverterDescriptor GetConverterDescriptor(Type typeFrom, Type typeTo)
- {
- var type = typeof(ILuObjectConverterDescriptor<,>);
- var gtype = type.MakeGenericType(typeFrom, typeTo);
- var descriptor = (ILuObjectConverterDescriptor) ServiceProvider.GetService(gtype);
- if (descriptor == null && typeFrom == typeTo)
- {
- descriptor = (ILuObjectConverterDescriptor) ServiceProvider.GetService(typeof(ILuObjectConverterDescriptorIdentity));
- }
- return descriptor;
- }
-
- protected LuResult<Expression> ConvertMemberExpression(MemberExpression memberExpression, Expression newExpression, Type typeTo)
- {
- var typeFrom = memberExpression.Expression == null ? memberExpression.Member.DeclaringType : memberExpression.Expression.Type;
- var descriptor = GetConverterDescriptor(typeFrom, typeTo);
- if (descriptor == null)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Could not find converter descriptor for {typeFrom} => {typeTo}");
- }
-
- var valueExpression = descriptor.GetMemberValueExpression(memberExpression.Member, Options.Types);
- if (valueExpression == null)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Could not find converter descriptor lambda for {typeFrom} => {typeTo} => {memberExpression.Member}");
- }
- if (valueExpression.Parameters[0].Type != typeTo)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Invalid conversion lambda for {typeFrom} => {typeTo}");
- }
-
- if (newExpression != null)
- {
- Options.Parameters.Add(valueExpression.Parameters[0], newExpression);
- }
-
- var visitor = new LuExpressionParamReplaceVisitor(Options);
- var replacedExpression = visitor.Visit(valueExpression.Body);
- newExpression = LuExpressionUtils.GetFromConvert(replacedExpression);
-
- if (newExpression != null)
- {
- Options.Parameters.Remove(valueExpression.Parameters[0]);
- }
-
- return LuResult<Expression>.Ok(newExpression);
- }
-
- protected LuResult<Expression> ConvertMethodCallExpression(MethodCallExpression methodCallExpression, Expression newExpression, Type typeTo)
- {
- var typeFrom = methodCallExpression.Object == null ? methodCallExpression.Method.DeclaringType : methodCallExpression.Object.Type;
- var descriptor = GetConverterDescriptor(typeFrom, typeTo);
- if (descriptor == null)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Could not find converter descriptor for {typeFrom} => {typeTo}");
- }
-
- var valueExpression = descriptor.GetMethodValueExpression(methodCallExpression.Method, Options.Types);
- if (valueExpression == null)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Could not find converter descriptor lambda for {typeFrom} => {typeTo} => {methodCallExpression.Method}");
- }
- if (valueExpression.Parameters.Count != methodCallExpression.Arguments.Count + 1)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Converter descriptor lambda has incorrect number of arguments for {typeFrom} => {typeTo} => {methodCallExpression.Method}");
- }
- if (valueExpression.Parameters[0].Type != typeTo)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Invalid conversion lambda for {typeFrom} => {typeTo}");
- }
-
- var visitorConverter = new LuExpressionConverterVisitor(Options, ServiceProvider);
- for (var i = 0; i < methodCallExpression.Arguments.Count; ++i)
- {
- var convertedArgument = visitorConverter.Visit(methodCallExpression.Arguments[i]);
- Options.Parameters.Add(valueExpression.Parameters[i + 1], convertedArgument);
- }
- Options.Parameters.Add(valueExpression.Parameters[0], newExpression);
- var visitor = new LuExpressionParamReplaceVisitor(Options);
- var replacedExpression = visitor.Visit(valueExpression.Body);
- newExpression = LuExpressionUtils.GetFromConvert(replacedExpression);
- Options.Parameters.Remove(valueExpression.Parameters[0]);
-
- return LuResult<Expression>.Ok(newExpression);
- }
-
- protected LuResult<Expression> ReplaceExpression(Expression expression)
- {
- var stackResult = StackSimpleExpression(expression, new Stack<Expression>());
- if (!stackResult)
- {
- return stackResult.To<Expression>();
- }
-
- Expression newExpression;
- var currentExp = stackResult.Data.Pop();
-
- if (currentExp is ParameterExpression parameterExpression)
- {
- if (!Options.Parameters.ContainsKey(parameterExpression))
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Could not find a conversion for parameter {parameterExpression}");
- }
- newExpression = Options.Parameters[parameterExpression];
- }
- else if (currentExp is MemberExpression memberExpression)
- {
- var typeFrom = memberExpression.Member.DeclaringType;
- var typeTo = Options.Types.ContainsKey(typeFrom) ? Options.Types[typeFrom] : typeFrom;
-
- var convertResult = ConvertMemberExpression(memberExpression, null, typeTo);
- if (!convertResult)
- {
- return convertResult;
- }
-
- newExpression = convertResult.Data;
- }
- else if (currentExp is MethodCallExpression methodCallExpression)
- {
- var typeFrom = methodCallExpression.Method.DeclaringType;
- var typeTo = Options.Types.ContainsKey(typeFrom) ? Options.Types[typeFrom] : typeFrom;
-
- var convertResult = ConvertMethodCallExpression(methodCallExpression, null, typeTo);
- if (!convertResult)
- {
- return convertResult;
- }
-
- newExpression = convertResult.Data;
- }
- else
- {
- var visitor = new LuExpressionConverterVisitor(Options, ServiceProvider);
- newExpression = visitor.Visit(currentExp);
- }
-
- if (newExpression == null)
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Invalid simple expression first member: {currentExp}", "");
- }
-
- while (stackResult.Data.Any())
- {
- currentExp = stackResult.Data.Pop();
-
- if (currentExp is MemberExpression memberExpression)
- {
- var typeTo = newExpression.Type;
-
- var convertResult = ConvertMemberExpression(memberExpression, newExpression, typeTo);
- if (!convertResult)
- {
- return convertResult;
- }
-
- newExpression = convertResult.Data;
- }
- else if (currentExp is MethodCallExpression methodCallExpression)
- {
- var typeTo = newExpression.Type;
-
- var convertResult = ConvertMethodCallExpression(methodCallExpression, newExpression, typeTo);
- if (!convertResult)
- {
- return convertResult;
- }
-
- newExpression = convertResult.Data;
- }
- else
- {
- return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Unknown expression type (should not happen) {currentExp}");
- }
- }
-
- return LuResult<Expression>.Ok(newExpression);
- }
-
- protected override Expression VisitMember(MemberExpression node)
- {
- return ReplaceExpression(node).ThrowIfNotSuccess().Data;
- }
-
- protected override Expression VisitMethodCall(MethodCallExpression node)
- {
- return ReplaceExpression(node).ThrowIfNotSuccess().Data;
- }
-
- protected override Expression VisitParameter(ParameterExpression node)
- {
- if (!Options.Parameters.ContainsKey(node))
- {
- LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
- $"Could not find a conversion for parameter {node}").Throw();
- }
- return Options.Parameters[node];
- }
-
- protected override Expression VisitLambda<T>(Expression<T> node)
- {
- var convertedParams = new List<ParameterExpression>();
- foreach (var parameter in node.Parameters)
- {
- // TODO check Options.Types[parameter.Type] access
- var convertedParam = Expression.Parameter(Options.Types[parameter.Type]);
- Options.Parameters.Add(parameter, convertedParam);
- convertedParams.Add(convertedParam);
- }
- var convertedBody = Visit(node.Body);
- foreach (var parameter in node.Parameters)
- {
- Options.Parameters.Remove(parameter);
- }
-
- var convertedLambda = Expression.Lambda(convertedBody, convertedParams);
- return convertedLambda;
- }
- }
- }
|