private QueryOperator UpdateSelect(SelectOperator op, MonadMember src, QueryTree selector)
            {
                if (src != op.Source || selector != op.Selector)
                {
                    return(MakeSelect(op, src, selector));
                }

                return(op);
            }
        /// <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));
        }
Beispiel #3
0
        /// <summary>
        /// Visits a <see cref="SelectOperator" /> node.
        /// </summary>
        /// <param name="op">Node to visit.</param>
        /// <returns>Result of visiting the node.</returns>
        protected internal override QueryOperator VisitSelect(SelectOperator op)
        {
            var src      = VisitAndConvert <MonadMember>(op.Source);
            var selector = Visit(op.Selector);

            if (src != op.Source || selector != op.Selector)
            {
                return(MakeSelect(op, src, selector));
            }

            return(op);
        }
Beispiel #4
0
        /// <summary>
        /// Visits a <see cref="SelectOperator" /> node.
        /// </summary>
        /// <param name="op">Node to visit.</param>
        /// <returns>Result of visiting the node.</returns>
        protected internal override QueryOperator VisitSelect(SelectOperator op)
        {
            var elementType      = VisitType(op.ElementType);
            var inputElementType = VisitType(op.InputElementType);
            var src      = VisitAndConvert <MonadMember>(op.Source);
            var selector = Visit(op.Selector);

            if (src != op.Source || selector != op.Selector || elementType != op.ElementType || inputElementType != op.InputElementType)
            {
                return(MakeSelect(op, elementType, inputElementType, src, selector));
            }

            return(op);
        }
Beispiel #5
0
 /// <summary>
 /// Makes a <see cref="SelectOperator" /> with the given children.
 /// </summary>
 /// <param name="node">Original query expression.</param>
 /// <param name="source">Source query expression.</param>
 /// <param name="selector">Selector query expression.</param>
 /// <returns>Representation of the original query expression.</returns>
 protected sealed override QueryOperator MakeSelect(SelectOperator node, MonadMember source, QueryTree selector)
 {
     return(node.QueryExpressionFactory.Select(node.ElementType, node.InputElementType, source, selector));
 }
Beispiel #6
0
 /// <summary>
 /// Creates a textual representation of the SelectOperator with the given children.
 /// </summary>
 /// <param name="node">Original query expression.</param>
 /// <param name="source">Source query expression.</param>
 /// <param name="selector">Selector query expression.</param>
 /// <returns>Representation of the original query expression.</returns>
 protected override string MakeSelect(SelectOperator node, string source, string selector)
 {
     return(string.Format(CultureInfo.InvariantCulture, "@Select({0}, {1})", source, selector));
 }
            protected internal override QueryOperator VisitSelect(SelectOperator op)
            {
                var src      = VisitAndConvert <MonadMember>(op.Source);
                var selector = Visit(op.Selector);

                if (TryCast <SelectOperator>(src, OperatorType.Select, out SelectOperator select1) &&
                    TryExtractNullaryLambdaBody <LambdaExpression>(select1.Selector, ExpressionType.Lambda, out LambdaExpression selector1) &&
                    TryGetNewAnonymousType(selector1.Body, out NewExpression anonCtor1) &&
                    TryExtractNullaryLambdaBody <LambdaExpression>(selector, ExpressionType.Lambda, out LambdaExpression selector2))
                {
                    if (TryGetNewAnonymousType(selector2.Body, out NewExpression anonCtor2))
                    {
                        if (anonCtor2.Members.Count > 0 && anonCtor2.Arguments[0] == selector2.Parameters[0])
                        {
                            var newArgs = new Expression[anonCtor2.Members.Count];
                            newArgs[0] = anonCtor1;

                            for (var i = 1; i < newArgs.Length; i++)
                            {
                                var visitor = new ValidateMemberAccessesAndInlineVisitor(anonCtor1, selector1.Parameters[0], selector2.Parameters[0]);
                                newArgs[i] = visitor.Visit(anonCtor2.Arguments[i]);
                                if (!visitor.Valid)
                                {
                                    return(UpdateSelect(op, src, selector));
                                }
                            }

                            var updated = anonCtor2.Update(newArgs);
                            var newBody =
                                DefaultQueryExpressionFactory.Instance.LambdaAbstraction(
                                    Expression.Lambda(Expression.Lambda(updated, selector1.Parameters[0])),
                                    Array.Empty <QueryTree>()
                                    );
                            return
                                (op.QueryExpressionFactory.Select(
                                     op.ElementType,
                                     select1.InputElementType,
                                     select1.Source,
                                     newBody
                                     ));
                        }
                    }
                    else
                    {
                        var flatteningValidationVisitor = new ValidateMemberAccessVisitor(anonCtor1, selector2.Parameters[0]);
                        flatteningValidationVisitor.Visit(selector2.Body);
                        if (flatteningValidationVisitor.Valid)
                        {
                            var flattener = new AnonymousTypeFlattener(anonCtor1);
                            if (flattener.TryConstruct(out NewExpression c))
                            {
                                var t                 = c.Type;
                                var newParam          = Expression.Parameter(t);
                                var flatteningVisitor = new InlineFlattenedTypeVisitor(anonCtor1, newParam, selector2.Parameters[0], flattener);
                                var f                 = flatteningVisitor.Visit(selector2.Body);

                                var child =
                                    select1.QueryExpressionFactory.Select(
                                        t,
                                        select1.InputElementType,
                                        select1.Source,
                                        DefaultQueryExpressionFactory.Instance.LambdaAbstraction(
                                            Expression.Lambda(Expression.Lambda(c, selector1.Parameters[0])),
                                            Array.Empty <QueryTree>()
                                            )
                                        );

                                return
                                    (op.QueryExpressionFactory.Select(
                                         op.ElementType,
                                         t,
                                         child,
                                         DefaultQueryExpressionFactory.Instance.LambdaAbstraction(
                                             Expression.Lambda(Expression.Lambda(f, newParam)),
                                             Array.Empty <QueryTree>()
                                             )
                                         ));
                            }
                        }
                    }
                }

                return(UpdateSelect(op, src, selector));
            }
Beispiel #8
0
 /// <summary>
 /// Makes a <see cref="SelectOperator" /> with the given children.
 /// </summary>
 /// <param name="node">Original query expression.</param>
 /// <param name="source">Source query expression.</param>
 /// <param name="elementType">Element type for the resulting operator.</param>
 /// <param name="inputElementType">Input element type for the resulting operator.</param>
 /// <param name="selector">Selector query expression.</param>
 /// <returns>Representation of the original query expression.</returns>
 protected virtual QueryOperator MakeSelect(SelectOperator node, Type elementType, Type inputElementType, MonadMember source, QueryTree selector)
 {
     return(node.QueryExpressionFactory.Select(elementType, inputElementType, source, selector));
 }