You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LuExpressionConverterVisitor.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using Luticate2.Auth.Utils.Business.Converters;
  6. using Luticate2.Auth.Utils.Dbo;
  7. using Luticate2.Auth.Utils.Dbo.Result;
  8. using Luticate2.Auth.Utils.Exceptions;
  9. using Luticate2.Auth.Utils.Interfaces;
  10. namespace Luticate2.Auth.Utils.Business.ExpressionConverter
  11. {
  12. public interface ILuExpressionConverterVisitorOptions
  13. {
  14. IDictionary<ParameterExpression, Expression> Parameters { get; }
  15. ILuConvertersTypeConverter TypeConverter { get; }
  16. ILuObjectConverterDescriptorOptions DescriptorOptions { get; }
  17. ILuExpressionParamReplaceVisitorOptions VisitorOptions { get; }
  18. }
  19. public class LuExpressionConverterVisitor : ExpressionVisitor
  20. {
  21. public ILuExpressionConverterVisitorOptions Options { get; }
  22. protected IServiceProvider ServiceProvider { get; }
  23. public LuExpressionConverterVisitor(ILuExpressionConverterVisitorOptions options, IServiceProvider serviceProvider)
  24. {
  25. Options = options;
  26. ServiceProvider = serviceProvider;
  27. }
  28. protected LuResult<Stack<Expression>> StackSimpleExpression(Expression expression, Stack<Expression> stack)
  29. {
  30. stack.Push(expression);
  31. if (expression is MemberExpression memberExpression)
  32. {
  33. if (memberExpression.Expression != null)
  34. {
  35. var result = StackSimpleExpression(memberExpression.Expression, stack);
  36. return result;
  37. }
  38. return LuResult<Stack<Expression>>.Ok(stack);
  39. }
  40. else if (expression is MethodCallExpression methodCallExpression)
  41. {
  42. if (methodCallExpression.Object != null)
  43. {
  44. var result = StackSimpleExpression(methodCallExpression.Object, stack);
  45. return result;
  46. }
  47. return LuResult<Stack<Expression>>.Ok(stack);
  48. }
  49. else
  50. {
  51. return LuResult<Stack<Expression>>.Ok(stack);
  52. }
  53. }
  54. protected ILuObjectConverterDescriptor GetConverterDescriptor(Type typeFrom, Type typeTo)
  55. {
  56. var type = typeof(ILuObjectConverterDescriptor<,>);
  57. var gtype = type.MakeGenericType(typeFrom, typeTo);
  58. var descriptor = (ILuObjectConverterDescriptor) ServiceProvider.GetService(gtype);
  59. if (descriptor == null && typeFrom == typeTo)
  60. {
  61. descriptor = (ILuObjectConverterDescriptor) ServiceProvider.GetService(typeof(ILuObjectConverterDescriptorIdentity));
  62. }
  63. return descriptor;
  64. }
  65. protected LuResult<Expression> ConvertMemberExpression(MemberExpression memberExpression, Expression newExpression, Type typeTo)
  66. {
  67. var typeFrom = memberExpression.Expression == null ? memberExpression.Member.DeclaringType : memberExpression.Expression.Type;
  68. var descriptor = GetConverterDescriptor(typeFrom, typeTo);
  69. if (descriptor == null)
  70. {
  71. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  72. $"Could not find converter descriptor for {typeFrom} => {typeTo}");
  73. }
  74. var valueExpression = descriptor.GetMemberValueExpression(memberExpression.Member, Options.DescriptorOptions);
  75. if (valueExpression == null)
  76. {
  77. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  78. $"Could not find converter descriptor lambda for {typeFrom} => {typeTo} => {memberExpression.Member}");
  79. }
  80. if (valueExpression.Parameters[0].Type != typeTo)
  81. {
  82. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  83. $"Invalid conversion lambda for {typeFrom} => {typeTo}");
  84. }
  85. if (newExpression != null)
  86. {
  87. Options.Parameters.Add(valueExpression.Parameters[0], newExpression);
  88. }
  89. var visitor = new LuExpressionParamReplaceVisitor(Options.VisitorOptions);
  90. newExpression = visitor.Visit(valueExpression.Body);
  91. if (newExpression != null)
  92. {
  93. Options.Parameters.Remove(valueExpression.Parameters[0]);
  94. }
  95. return LuResult<Expression>.Ok(newExpression);
  96. }
  97. protected LuResult<Expression> ConvertMethodCallExpression(MethodCallExpression methodCallExpression, Expression newExpression, Type typeTo)
  98. {
  99. var typeFrom = methodCallExpression.Object == null ? methodCallExpression.Method.DeclaringType : methodCallExpression.Object.Type;
  100. var descriptor = GetConverterDescriptor(typeFrom, typeTo);
  101. if (descriptor == null)
  102. {
  103. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  104. $"Could not find converter descriptor for {typeFrom} => {typeTo}");
  105. }
  106. var valueExpression = descriptor.GetMethodValueExpression(methodCallExpression.Method, Options.DescriptorOptions);
  107. if (valueExpression == null)
  108. {
  109. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  110. $"Could not find converter descriptor lambda for {typeFrom} => {typeTo} => {methodCallExpression.Method}");
  111. }
  112. if (valueExpression.Parameters.Count != methodCallExpression.Arguments.Count + 1)
  113. {
  114. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  115. $"Converter descriptor lambda has incorrect number of arguments for {typeFrom} => {typeTo} => {methodCallExpression.Method}");
  116. }
  117. if (valueExpression.Parameters[0].Type != typeTo)
  118. {
  119. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  120. $"Invalid conversion lambda for {typeFrom} => {typeTo}");
  121. }
  122. var visitorConverter = new LuExpressionConverterVisitor(Options, ServiceProvider);
  123. for (var i = 0; i < methodCallExpression.Arguments.Count; ++i)
  124. {
  125. var convertedArgument = visitorConverter.Visit(methodCallExpression.Arguments[i]);
  126. Options.Parameters.Add(valueExpression.Parameters[i + 1], convertedArgument);
  127. }
  128. Options.Parameters.Add(valueExpression.Parameters[0], newExpression);
  129. var visitor = new LuExpressionParamReplaceVisitor(Options.VisitorOptions);
  130. newExpression = visitor.Visit(valueExpression.Body);
  131. Options.Parameters.Remove(valueExpression.Parameters[0]);
  132. return LuResult<Expression>.Ok(newExpression);
  133. }
  134. protected LuResult<Expression> ReplaceExpression(Expression expression)
  135. {
  136. var stackResult = StackSimpleExpression(expression, new Stack<Expression>());
  137. if (!stackResult)
  138. {
  139. return stackResult.To<Expression>();
  140. }
  141. Expression newExpression;
  142. var currentExp = stackResult.Data.Pop();
  143. if (currentExp is ParameterExpression parameterExpression)
  144. {
  145. if (!Options.Parameters.ContainsKey(parameterExpression))
  146. {
  147. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  148. $"Could not find a conversion for parameter {parameterExpression}");
  149. }
  150. newExpression = Options.Parameters[parameterExpression];
  151. }
  152. else if (currentExp is MemberExpression memberExpression)
  153. {
  154. var typeFrom = memberExpression.Member.DeclaringType;
  155. var typeTo = Options.TypeConverter.ConvertType(typeFrom);
  156. var convertResult = ConvertMemberExpression(memberExpression, null, typeTo);
  157. if (!convertResult)
  158. {
  159. return convertResult;
  160. }
  161. newExpression = convertResult.Data;
  162. }
  163. else if (currentExp is MethodCallExpression methodCallExpression)
  164. {
  165. var typeFrom = methodCallExpression.Method.DeclaringType;
  166. var typeTo = Options.TypeConverter.ConvertType(typeFrom);
  167. var convertResult = ConvertMethodCallExpression(methodCallExpression, null, typeTo);
  168. if (!convertResult)
  169. {
  170. return convertResult;
  171. }
  172. newExpression = convertResult.Data;
  173. }
  174. else
  175. {
  176. var visitor = new LuExpressionConverterVisitor(Options, ServiceProvider);
  177. newExpression = visitor.Visit(currentExp);
  178. }
  179. if (newExpression == null)
  180. {
  181. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  182. $"Invalid simple expression first member: {currentExp}", "");
  183. }
  184. while (stackResult.Data.Any())
  185. {
  186. currentExp = stackResult.Data.Pop();
  187. if (currentExp is MemberExpression memberExpression)
  188. {
  189. var typeTo = newExpression.Type;
  190. var convertResult = ConvertMemberExpression(memberExpression, newExpression, typeTo);
  191. if (!convertResult)
  192. {
  193. return convertResult;
  194. }
  195. newExpression = convertResult.Data;
  196. }
  197. else if (currentExp is MethodCallExpression methodCallExpression)
  198. {
  199. var typeTo = newExpression.Type;
  200. var convertResult = ConvertMethodCallExpression(methodCallExpression, newExpression, typeTo);
  201. if (!convertResult)
  202. {
  203. return convertResult;
  204. }
  205. newExpression = convertResult.Data;
  206. }
  207. else
  208. {
  209. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  210. $"Unknown expression type (should not happen) {currentExp}");
  211. }
  212. }
  213. return LuResult<Expression>.Ok(newExpression);
  214. }
  215. protected override Expression VisitMember(MemberExpression node)
  216. {
  217. return ReplaceExpression(node).ThrowIfNotSuccess().Data;
  218. }
  219. protected override Expression VisitMethodCall(MethodCallExpression node)
  220. {
  221. return ReplaceExpression(node).ThrowIfNotSuccess().Data;
  222. }
  223. protected override Expression VisitParameter(ParameterExpression node)
  224. {
  225. if (!Options.Parameters.ContainsKey(node))
  226. {
  227. LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  228. $"Could not find a conversion for parameter {node}").Throw();
  229. }
  230. return Options.Parameters[node];
  231. }
  232. protected override Expression VisitLambda<T>(Expression<T> node)
  233. {
  234. var convertedParams = new List<ParameterExpression>();
  235. foreach (var parameter in node.Parameters)
  236. {
  237. var convertedParam = Expression.Parameter(Options.TypeConverter.ConvertType(parameter.Type));
  238. Options.Parameters.Add(parameter, convertedParam);
  239. convertedParams.Add(convertedParam);
  240. }
  241. var convertedBody = Visit(node.Body);
  242. foreach (var parameter in node.Parameters)
  243. {
  244. Options.Parameters.Remove(parameter);
  245. }
  246. var convertedLambda = Expression.Lambda(convertedBody, convertedParams);
  247. return convertedLambda;
  248. }
  249. }
  250. }