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

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