public void BetaReducer_Defaults_None2() { var e = Expression.Invoke(Expression.Constant(new Func <int, int>(x => x)), Expression.Constant(42)); var r = BetaReducer.Reduce(e); Assert.AreSame(e, r); }
public void UnifyingSerializationHelpers_Roundtrip_WithEnums() { var metadata = new MetadataMock(); var uri1 = new Uri("test://id/1"); var uri2 = new Uri("test://id/2"); metadata.Observables.Add(uri1, new MockObservable <EntityEnum>(uri1)); metadata.Observables.Add(uri2, new MockObservable <TypeWithEnum>(uri2)); Expression <Func <IAsyncReactiveQbservable <EntityEnum>, IAsyncReactiveQbservable <TypeWithEnum>, IAsyncReactiveQbservable <TypeWithEnum> > > f = (io1, io2) => Concat(Select(io1, x => new TypeWithEnum { Enum = x }), io2); var invoked = BetaReducer.Reduce( Expression.Invoke( f, Expression.Parameter(typeof(IAsyncReactiveQbservable <EntityEnum>), uri1.ToCanonicalString()), Expression.Parameter(typeof(IAsyncReactiveQbservable <TypeWithEnum>), uri2.ToCanonicalString()))); var normalized = new ReactiveExpressionServices(typeof(object)).Normalize(invoked); var clientSerializer = new ClientSerializationHelpers(); var serviceSerializer = new UnifyingSerializationHelpers(metadata); var bonsai = clientSerializer.Serialize(normalized); var roundtrip = serviceSerializer.Deserialize <Expression>(bonsai); Assert.AreEqual(typeof(IAsyncReactiveQbservable <TypeWithEnum>), roundtrip.Type); }
#pragma warning restore CA1062 #pragma warning restore IDE0079 /// <summary> /// Reduces the current node to an equivalent <see cref="System.Linq.Expressions.Expression"/>. /// </summary> /// <returns>This node's equivalent <see cref="System.Linq.Expressions.Expression"/>.</returns> public override Expression Reduce() { var cnt = Parameters.Count; var reducedParameters = new Expression[cnt]; for (var i = 0; i < cnt; i++) { reducedParameters[i] = Parameters[i].Reduce(); } // The first reduction is to fill in the holes that the converter created var reduced = Body; for (var i = 0; i < cnt; i++) { // TODO Make replacement visitor take multiple replacements reduced = Expression.Lambda(new ReplacementVisitor(reduced.Parameters[i], reducedParameters[i]).Visit(reduced.Body), reduced.Parameters); } var body = reduced.Body; // After filling in the holes, we might get new opportunities for reductions, so go ahead and do that. // TODO this step won't be needed if we maintain the invariant that no LambdaAbstraction nodes have LambdaAbstraction subnodes. return(BetaReducer.Reduce(body, BetaReductionNodeTypes.Atoms, BetaReductionRestrictions.None)); }
public void BetaReducer_Defaults_None1() { var e = Expression.Constant(42); var r = BetaReducer.Reduce(e); Assert.AreSame(e, r); }
protected override TResult Execute <TResult>(Expression expression) { var pars = FreeVariableScanner.Scan(expression).Distinct().ToArray(); var args = new Expression[pars.Length]; for (var i = 0; i < pars.Length; i++) { var par = pars[i]; var queryableType = par.Type; args[i] = par.Name switch { "rx://metadata/observables" => Expression.Constant(new EnumerableQueryableDictionary <Uri, IReactiveObservableDefinition>(Observables), queryableType), "rx://metadata/observers" => Expression.Constant(new EnumerableQueryableDictionary <Uri, IReactiveObserverDefinition>(Observers), queryableType), "rx://metadata/streams" => Expression.Constant(new EnumerableQueryableDictionary <Uri, IReactiveStreamProcess>(Streams), queryableType), _ => throw new NotSupportedException(), }; } var bound = Expression.Invoke(Expression.Lambda(expression, pars), args); var reduced = BetaReducer.ReduceEager(bound, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None, throwOnCycle: false); var res = reduced.Evaluate <TResult>(); return(res); }
public override Expression Normalize(Expression expression) { var res = base.Normalize(expression); res = BetaReducer.ReduceEager(res, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None, throwOnCycle: false); return(res); }
public static Expression BetaReduce(this Expression expression) { return(BetaReducer.ReduceEager( expression, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None, true)); }
public void BetaReducer_Advanced_AllNodes_ExactlyOnce() { var e = Expression.Negate(Expression.Constant(42)); var x = Expression.Parameter(typeof(int)); var f = Expression.Invoke(Expression.Lambda(Expression.Add(x, x), x), e); Assert.ThrowsException <InvalidOperationException>(() => BetaReducer.Reduce(f, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.ExactlyOnce)); }
public void BetaReducer_Defaults_Constant_Identity() { var e = Expression.Constant(42); var x = Expression.Parameter(typeof(int)); var f = Expression.Invoke(Expression.Lambda(x, x), e); var r = BetaReducer.Reduce(f); Assert.AreSame(e, r); }
/// <summary> /// Visits a <see cref="WhereOperator" /> and coalesces it with any possible child operators. /// </summary> /// <param name="op">The operator to visit.</param> /// <returns>The coalesced operator.</returns> protected internal override QueryOperator VisitWhere(WhereOperator op) { var source = VisitAndConvert <MonadMember>(op.Source); var predicate = Visit(op.Predicate); var srcOperator = source.QueryNodeType == QueryNodeType.Operator ? (QueryOperator)source : null; var srcWhere = srcOperator != null && srcOperator.NodeType == OperatorType.Where ? (WhereOperator)srcOperator : null; if (srcWhere != null && op.ElementType == srcWhere.ElementType) { var p = Expression.Parameter(op.ElementType); if (TryExtractNullaryLambdaBody(srcWhere.Predicate, out Expression predicate1) && TryExtractNullaryLambdaBody(predicate, out Expression predicate2)) { var reduced1 = BetaReducer.Reduce(Expression.Invoke(predicate1, p)); var reduced2 = BetaReducer.Reduce(Expression.Invoke(predicate2, p)); return(op.QueryExpressionFactory.Where( op.ElementType, srcWhere.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda( Expression.Lambda( Expression.AndAlso(reduced1, reduced2), p ) ), Array.Empty <QueryTree>() ) )); } var predicateType = typeof(Func <,>).MakeGenericType(p.Type, typeof(bool)); var p1 = Expression.Parameter(predicateType); var p2 = Expression.Parameter(predicateType); return(op.QueryExpressionFactory.Where( op.ElementType, srcWhere.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda( Expression.Lambda( Expression.AndAlso( Expression.Invoke(p1, p), Expression.Invoke(p2, p) ), p ), p1, p2 ), new[] { srcWhere.Predicate, predicate } ) )); } return(op.Update(source, predicate)); }
public override Expression Normalize(Expression expression) { var normalized = base.Normalize(expression); return(BetaReducer.ReduceEager( normalized, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None, true)); }
public void BetaReducer_Defaults_Constant_Nested_Complex() { var e = Expression.Constant(42); var x = Expression.Parameter(typeof(int)); var f = Expression.Invoke(Expression.Lambda(Expression.Lambda(x, x), x), e); var r = BetaReducer.Reduce(f); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(Expression.Lambda(x, x), r)); }
public void BetaReducer_Defaults_Parameter_MultipleUses() { var e = Expression.Parameter(typeof(int)); var x = Expression.Parameter(typeof(int)); var f = Expression.Invoke(Expression.Lambda(Expression.Add(x, x), x), e); var r = BetaReducer.Reduce(f); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(Expression.Add(e, e), r)); }
public void BetaReducer_Advanced_AllNodes_MoreThanOnce() { var e = Expression.Negate(Expression.Constant(42)); var x = Expression.Parameter(typeof(int)); var f = Expression.Invoke(Expression.Lambda(Expression.Add(x, x), x), e); var r = BetaReducer.Reduce(f, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(Expression.Add(e, e), r)); }
/// <summary> /// Visits a <see cref="SelectOperator" /> and coalesces it with any possible child operators. /// </summary> /// <param name="op">The operator to visit.</param> /// <returns>The coalesced operator.</returns> protected internal override QueryOperator VisitSelect(SelectOperator op) { var source = VisitAndConvert <MonadMember>(op.Source); var selector = Visit(op.Selector); var srcOperator = source.QueryNodeType == QueryNodeType.Operator ? (QueryOperator)source : null; var srcSelect = srcOperator != null && srcOperator.NodeType == OperatorType.Select ? (SelectOperator)srcOperator : null; if (srcSelect != null && op.InputElementType == srcSelect.ElementType) { var p = Expression.Parameter(srcSelect.InputElementType); // Optimization when both lambda abstractions don't abstract over anything if (TryExtractNullaryLambdaBody(srcSelect.Selector, out Expression selector1) && TryExtractNullaryLambdaBody(selector, out Expression selector2)) { var reduced = BetaReducer.Reduce(Expression.Invoke(selector2, Expression.Invoke(selector1, p))); return(op.QueryExpressionFactory.Select( op.ElementType, srcSelect.InputElementType, srcSelect.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda( Expression.Lambda( reduced, p ) ), Array.Empty <QueryTree>() ) )); } var p1 = Expression.Parameter(typeof(Func <,>).MakeGenericType(srcSelect.InputElementType, srcSelect.ElementType)); var p2 = Expression.Parameter(typeof(Func <,>).MakeGenericType(op.InputElementType, op.ElementType)); return(op.QueryExpressionFactory.Select( op.ElementType, srcSelect.InputElementType, srcSelect.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda( Expression.Lambda( Expression.Invoke(p2, Expression.Invoke(p1, p)), p ), p1, p2 ), new[] { srcSelect.Selector, selector } ) )); } return(op.Update(source, selector)); }
public void BetaReducer_Defaults_Quote_Nested() { var e = Expression.Quote(Expression.Lambda(Expression.Constant("foo"))); var x = Expression.Parameter(typeof(Expression)); var y = Expression.Parameter(typeof(int)); var f = Expression.Invoke(Expression.Lambda(Expression.Lambda(x, y), x), e); var r = BetaReducer.Reduce(f); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(Expression.Lambda <Func <int, Expression> >(e, y), r)); }
public Expression Apply(Expression expression, ParameterExpression self) { if (expression is InvocationExpression asOperator) { if (asOperator.Expression is ParameterExpression operatorId && operatorId.Name == "where") // NOTE: Delegation targets know about identifiers and are loosely coupled { var source = asOperator.Arguments[0]; var operand = asOperator.Arguments[1].Unquote(); if (source == self && operand.NodeType == ExpressionType.Lambda) { var predicate = operand; if (predicate.Parameters.Count == 1) { // // TODO: match predicate based on // - supported keys passed to the factory upon stream creation (an array of lambdas a la person => person.Name) // - supported equality checks (==, Equals, etc.) // var filter = predicate.Body; if (filter.NodeType == ExpressionType.Equal) { var equal = (BinaryExpression)filter; var member = equal.Left as MemberExpression; var constant = equal.Right as ConstantExpression; if (constant == null && member == null) { member = equal.Right as MemberExpression; constant = equal.Left as ConstantExpression; } if (constant != null && member != null) { if (member.Expression == predicate.Parameters[0]) { var newPartition = (Expression <Func <MemberInfo, object, PartitionObservable> >)((MemberInfo key, object value) => new PartitionObservable(this, key, value)); var partition = BetaReducer.Reduce(Expression.Invoke(newPartition, Expression.Constant(member.Member), Expression.Constant(constant.Value, typeof(object)))); return(partition); } } } } } } } return(expression); }
private void AssertExpression <TKey, TValue, TResult>(IDictionary <TKey, TValue> data, Action <QueryableDictionaryBase <TKey, TValue> > action, Expression <Func <TestQueryableDictionary <TKey, TValue>, TResult> > expected) { var thisParameter = Expression.Parameter(typeof(TestQueryableDictionary <TKey, TValue>), "this"); void assert(Expression expr) { var invoked = BetaReducer.Reduce(Expression.Invoke(expected, thisParameter)); Assert.IsTrue(new ExpressionEqualityComparer().Equals(invoked, expr)); } var queryableDictionary = new TestQueryableDictionary <TKey, TValue>(thisParameter, data, assert); action(queryableDictionary); }
/// <summary> /// Normalizes the specified expression. This method is typically used to process expressions prior to further processing by a service. /// </summary> /// <param name="expression">Expression to normalize.</param> /// <returns>Normalized expression.</returns> public virtual Expression Normalize(Expression expression) { if (expression == null) { throw new ArgumentNullException(nameof(expression)); } var inlinedExpressions = new ExpressionInliner(this).Inline(expression); var uriBased = _knownResourceRewriter.Rewrite(inlinedExpressions); var simplified = SimplifyUriForms(uriBased); var convertsRewritten = new ConvertedGlobalParameterRewriter().Visit(simplified); var betaReduced = BetaReducer.Reduce(convertsRewritten); return(betaReduced); }
private static T SetupInnerSubscribable(INotification <string> @event) { var elementType = typeof(T).FindGenericType(typeof(ISubscribable <>)).GenericTypeArguments[0]; var timelineType = typeof(TimelineObservable <>).MakeGenericType(elementType); var timelineCtor = timelineType.GetConstructor(new[] { typeof(Uri), typeof(bool) }); var expression = (InvocationExpression)BetaReducer.Reduce(Deserialize <Expression>(@event.Value)); var parameter = (ParameterExpression)expression.Expression; var timelineUri = (Uri)expression.Arguments[0].Evaluate(); Expression subscribableExpression = parameter.Name switch { Constants.Test.ColdTimelineObservable.String => Expression.New(timelineCtor, Expression.Constant(timelineUri), Expression.Constant(true)), Constants.Test.HotTimelineObservable.String => Expression.New(timelineCtor, Expression.Constant(timelineUri), Expression.Constant(true)), _ => throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unexpected subscribable type '{0}'.", parameter.Name)), }; var quotedSubscribableType = typeof(QuotedSubscribable <>).MakeGenericType(elementType); var quotedSubscribableCtor = quotedSubscribableType.GetConstructor(new[] { typeof(Expression) }); return((T)quotedSubscribableCtor.Invoke(new object[] { subscribableExpression })); }
private static Expression CreateQuery <T, R>(string collection, Expression <Func <IQueryable <KeyValuePair <Uri, T> >, R> > expression) { return(BetaReducer.Reduce(Expression.Invoke(expression, Expression.Parameter(typeof(IQueryable <KeyValuePair <Uri, T> >), collection)))); }
/// <summary> /// Applies the specified expression. /// </summary> /// <param name="expression">The expression.</param> /// <param name="arguments">The arguments.</param> /// <returns>the reduced expression</returns> public static Expression Apply(this LambdaExpression expression, params Expression[] arguments) { return(BetaReducer.Reduce(Expression.Invoke(expression, arguments))); }
public static IAsyncReactiveQbservable <TSource> DoHttp <TSource>( this IAsyncReactiveQbservable <TSource> source, Expression <Func <TSource, string> > getMethod, Expression <Func <TSource, Uri> > getOnNext, Expression <Func <TSource, string> > getBody, Expression <Func <TSource, Tuple <string, string>[]> > getHeaders, Expression <Func <TSource, RetryData> > getRetryData, Expression <Func <TSource, TimeSpan> > getTimeout) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (getMethod == null) { throw new ArgumentNullException(nameof(getMethod)); } if (getOnNext == null) { throw new ArgumentNullException(nameof(getOnNext)); } if (getBody == null) { throw new ArgumentNullException(nameof(getBody)); } if (getHeaders == null) { throw new ArgumentNullException(nameof(getHeaders)); } if (getRetryData == null) { throw new ArgumentNullException(nameof(getRetryData)); } if (getTimeout == null) { throw new ArgumentNullException(nameof(getTimeout)); } Expression <Func <string, string, Tuple <string, string>[], Uri, RetryData, TimeSpan, HttpData> > newHttpDataTemplate = (body, method, headers, onNext, retryData, timeout) => new HttpData { Body = body, Method = method, Headers = headers, OnNext = onNext, RetryData = retryData, Timeout = timeout, }; var item = Expression.Parameter(typeof(TSource)); var newHttpData = BetaReducer.Reduce(Expression.Invoke(newHttpDataTemplate, getBody.Apply(item), getMethod.Apply(item), getHeaders.Apply(item), getOnNext.Apply(item), getRetryData.Apply(item), getTimeout.Apply(item)), BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.ExactlyOnce); var getHttpData = Expression.Lambda <Func <TSource, HttpData> >(newHttpData, item); var poster = source.Provider.CreateQbserver <HttpData>(Expression.Parameter( typeof(IAsyncReactiveQbserver <HttpData>), Constants.Observer.Action.Http.String)); return(source.Do(getHttpData, poster)); }
public void Optimizer_SelectCoalescing() { var cmp = new ExpressionEqualityComparer(); { var e = Infer(() => new int[0].Select(i => i.ToString()).Select(s => int.Parse(s))).Body; var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); Assert.AreEqual(ExpressionType.Call, o.NodeType); var select = (MethodCallExpression)o; Assert.AreEqual(ReflectionHelpers.InfoOf((IEnumerable <int> enumerable) => enumerable.Select(default(Func <int, int>))), select.Method); var selector = (Expression <Func <int, int> >)select.Arguments[1]; var x = Expression.Parameter(typeof(int)); var y = Expression.Parameter(typeof(string)); var expectedCoalesced = Expression.Lambda( Expression.Invoke( Expression.Lambda( Expression.Call( null, (MethodInfo)ReflectionHelpers.InfoOf((string s) => int.Parse(s)), y ), y ), Expression.Call( x, (MethodInfo)ReflectionHelpers.InfoOf((int i) => i.ToString()) ) ), x ); Assert.IsTrue(cmp.Equals( expectedCoalesced, selector)); } { var e = Infer(() => new int[0].Select(i => i.ToString()).Select(i => int.Parse(i))).Body; var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); var r = BetaReducer.Reduce( Expression.Invoke( Infer((Func <string, int> f) => new int[0].Select(i => f(i.ToString()))), Infer((string i) => int.Parse(i)) ), BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None ); Assert.IsTrue(cmp.Equals( r, o)); } { var e = Infer(() => new int[0].Select(new[] { (Func <int, string>)(i => i.ToString()) }.First()).Select(i => int.Parse(i))).Body; var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); var r = BetaReducer.Reduce( Expression.Invoke( Infer((Func <string, int> g, Func <int, string> f) => new int[0].Select(i => g(f(i)))), Infer((string i) => int.Parse(i)), Infer(() => new[] { (Func <int, string>)(i => i.ToString()) }.First()).Body ), BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None ); Assert.IsTrue(cmp.Equals( r, o)); } { var e = Infer(() => new int[0].Select(i => i.ToString()).Select(new[] { (Func <string, int>)(i => int.Parse(i)) }.First())).Body; var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); var r = BetaReducer.ReduceEager( Expression.Invoke( Infer((Func <string, int> g, Func <int, string> f) => new int[0].Select(i => g(f(i)))), Infer(() => new[] { (Func <string, int>)(i => int.Parse(i)) }.First()).Body, Infer((int i) => i.ToString()) ), BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None, false ); Assert.IsTrue(cmp.Equals( r, o)); } }
public void Optimizer_WhereCoalescing() { var cmp = new ExpressionEqualityComparer(); { var e = Infer(() => new int[0].Where(x => x >= 0).Where(x => x <= 0)).Body; var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); Assert.IsTrue(cmp.Equals( Infer(() => new int[0].Where(x => x >= 0 && x <= 0)).Body, o)); } { Expression <Func <Func <int, bool>, Func <int, bool> > > id = _ => _; var e = BetaReducer.Reduce( Expression.Invoke( Infer((Func <Func <int, bool>, Func <int, bool> > f) => new int[0].Where(f(x => x >= 0)).Where(x => x <= 0)), id ), BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None ); var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); Assert.IsTrue(cmp.Equals( BetaReducer.Reduce( Expression.Invoke( Infer((Func <Func <int, bool>, Func <int, bool> > f) => new int[0].Where(y => f(x => x >= 0)(y) && y <= 0)), id ), BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None ), o)); } { var e = Infer(() => new int[0].Where(Enumerable.Range(0, 1).Select(_ => (Func <int, bool>)(x => x >= 0)).Single()).Where(x => x <= 0)).Body; var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); Assert.IsTrue(cmp.Equals( Infer(() => new int[0].Where(x => Enumerable.Range(0, 1).Select(_ => (Func <int, bool>)(y => y >= 0)).Single()(x) && x <= 0)).Body, o)); } { var e = Infer(() => new int[0].Where(x => x >= 0).Where(Enumerable.Range(0, 1).Select(_ => (Func <int, bool>)(x => x <= 0)).Single())).Body; var q = new EnumerableToQueryTreeConverter().Convert(e); var c = new CoalescingOptimizer().Optimize(q); var o = c.Reduce(); Assert.IsTrue(cmp.Equals( Infer(() => new int[0].Where(x => x >= 0 && Enumerable.Range(0, 1).Select(_ => (Func <int, bool>)(y => y <= 0)).Single()(x))).Body, o)); } }
public void BetaReducer_ArgumentChecking() { AssertEx.ThrowsException <ArgumentNullException>(() => BetaReducer.Reduce(expression: null), ex => Assert.AreEqual("expression", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => BetaReducer.Reduce(expression: null, BetaReductionNodeTypes.Atoms, BetaReductionRestrictions.None), ex => Assert.AreEqual("expression", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => BetaReducer.ReduceEager(expression: null, BetaReductionNodeTypes.Atoms, BetaReductionRestrictions.None, throwOnCycle: false), ex => Assert.AreEqual("expression", ex.ParamName)); }