/// <summary> /// Mezcla dos matches, devuelve null si los matches tienen parametros con valores diferentes entre sí. /// Si alguno de los dos es null, devuelve null /// </summary> public static PartialMatch Merge(PartialMatch a, PartialMatch b) { var argDic = MergeDic(a?.Args, b?.Args, CompareExpr.ExprEquals); var typeDic = MergeDic(a?.Types, b?.Types, CompareExpr.TypeEquals); if (argDic == null || typeDic == null) { return(null); } return(new PartialMatch(typeDic, argDic)); }
/// <summary> /// Un partial match de un parámetro, devuelve un match si el parametro tiene un tipo AnyType o si el tipo de la expresión es igual al tipo del parametro. /// Si el tipo del parametro no encaja devuelve null /// </summary> public static PartialMatch FromParam(ParameterExpression param, Expression expr) { var paramType = param.Type; var argDic = new Dictionary <ParameterExpression, Expression> { { param, expr } }; var valueMatch = new PartialMatch(EmptyTypes, argDic); var typeMatch = FromType(param.Type, expr.Type); var ret = Merge(valueMatch, typeMatch); return(ret); }
/// <summary> /// Convierte un PartialMatch a un Match. Devuelve null si el PartialMatch no esta completo /// </summary> public static Match ToFullMatch(PartialMatch match, IEnumerable <ParameterExpression> parameters) { if (match == null) { return(null); } var ret = parameters.Select(x => { if (match.Args.TryGetValue(x, out Expression value)) { return(value); } return(null); }).ToList(); if (ret.Any(x => x == null)) { return(null); } return(new Match(match.Types, ret.ToList())); }
/// <summary> /// Devuelve el resultado de aplicar una regla al niver superior de la expresión o la expresión original si la regla no se pudo aplicar a la expresión /// </summary> public static Expression GlobalApplyRule(Expression expr, RewriteRule rule, Func <Expression, Expression> visit) { if (rule.DebugName == "convertFromParam" || rule.DebugName == "fromParam") { ; } var parameters = rule.Find.Parameters; var pattBody = rule.Find.Body; PartialMatch partialMatch; try { partialMatch = GlobalMatch(expr, parameters, pattBody); } catch (Exception ex) { throw new ApplyRuleException("Error al obtener el match", rule.DebugName, expr, ex); } var match = PartialMatch.ToFullMatch(partialMatch, parameters); if (match == null) { return(expr); } if (rule.Condition != null && !rule.Condition(match, expr)) { return(expr); } //Sustituir la expresión: var ret = expr; var replaceLambda = rule.Replace; if (replaceLambda != null) { var subDic = replaceLambda.Parameters .Select((x, i) => (par: x, value: match.Args[i])) .ToDictionary(x => (Expression)x.par, x => x.value) ; Expression repRet; try { repRet = ReplaceVisitor.Replace(replaceLambda.Body, subDic, match.Types, x => false); } catch (Exception ex) { throw new ApplyRuleException("Error al reemplazar", rule.DebugName, expr, ex); } ret = repRet; } //Aplicar los transforms: { Expression nextRet; try { nextRet = ReplaceVisitor.Replace(ret, ex => { if (ex is MethodCallExpression call && call.Method.DeclaringType == typeof(RewriteSpecial) && call.Method.Name == nameof(RewriteSpecial.Transform)) { //Aplica el transform a la expresión: var arg = call.Arguments[0]; var func = ExprEval.EvalExpr <Func <Expression, Expression> >(call.Arguments[1]); var tResult = func.Value(arg); return(tResult); } return(ex); }); }