protected override Expression LookupOther(string id, Type type, Type funcType) { if (!externalFunctions.TryGetValue(id, out var expr)) { return(base.LookupOther(id, type, funcType)); } var typeMap = funcType.UnifyExact(expr.Type); var substitutor = new TypeSubstitutionExpressionVisitor(typeMap); var unifiedExpr = substitutor.Visit(expr); return(unifiedExpr); }
public void Evaluate(Expression expression) { var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { typeof(IQubjectFactory <>), typeof(ISubjectFactory <>) }, { typeof(IQubject <>), typeof(ISubject <>) }, { typeof(IQbservable <>), typeof(IObservable <>) }, { typeof(IQbserver <>), typeof(IObserver <>) }, { typeof(IQubscription), typeof(IDisposable) }, }); var expr = subst.Visit(expression); var fvs = FreeVariableScanner.Scan(expr); var map = new Dictionary <ParameterExpression, Expression>(); foreach (var fv in fvs) { if (_registry.TryGetValue(fv.Name, out var res)) { if (res is Expression e) { var u = e.Type.UnifyExact(fv.Type); var f = new TypeSubstitutionExpressionVisitor(u).Visit(e); map.Add(fv, f); continue; } else { e = Expression.Constant(res, fv.Type); map.Add(fv, e); continue; } } throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Could not bind '{0}'.", fv.Name)); } var bound = new Binder(map).Bind(expr); if (bound.Type == typeof(void)) { // TODO: Evaluate method could be more forgiving for void-returning delegates (no automatic coercion to object) bound = Expression.Block(bound, Expression.Default(typeof(object))); } bound.Evaluate(); }
/// <summary> /// Visits and substitutes types of an expression which is the body of a lambda abstraction. /// </summary> /// <param name="body">The expression to visit.</param> /// <returns>Result of visiting the expression.</returns> protected override LambdaExpression VisitLambdaAbstractionBody(LambdaExpression body) { return((LambdaExpression)_lambdaBodyConverter.Visit(body)); }