/// <summary>
        /// Rewrites the given expression into a CPS-based expression using the specified initial CPS rewrite state.
        /// </summary>
        /// <param name="expression">Expression to rewrite to a CPS-based expression.</param>
        /// <param name="initialState">Initial CPS rewrite state.</param>
        /// <param name="inline">Indicates whether or not to inline invocations when possible. This optimization may defeat evaluation order for specific subclasses, so it can be disabled.</param>
        /// <returns>Rewritten expression in CPS style.</returns>
        protected Expression RewriteCore(Expression expression, TContinuationState initialState, bool inline)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            var res = new Impl(this, initialState).Visit(expression);

            if (inline)
            {
                res = BetaReducer.Reduce(res);
            }

            res = new LambdaParameterRenamer().Visit(res);

            return(res);
        }
        public static void GetConvertAndPredicate <TLeaf, TTarget>(Expression <Func <TLeaf, TTarget> > convert, Expression <Func <TLeaf, bool> > predicate, out Expression <Func <ExpressionTree, TTarget> > convertLambda, out Func <ExpressionTreeBase, TTarget> convertFunction, out Expression <Func <ExpressionTree, bool> > predicateLambda, out Func <ExpressionTreeBase, bool> predicateFunction)
            where TLeaf : Expression
        {
            var expressionProperty = (PropertyInfo)ReflectionHelpers.InfoOf((ExpressionTree et) => et.Expression);

            var convertParameter = Expression.Parameter(typeof(ExpressionTree), convert.Parameters[0].Name);
            var convertLambdaRaw = Expression.Lambda <Func <ExpressionTree, TTarget> >(
                Expression.Invoke(
                    convert,
                    Expression.Convert(
                        Expression.Property(
                            convertParameter,
                            expressionProperty
                            ),
                        typeof(TLeaf)
                        )
                    ),
                convertParameter
                );

            convertLambda = (Expression <Func <ExpressionTree, TTarget> >)BetaReducer.Reduce(convertLambdaRaw, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None);

            var convertFunctionStrong = convertLambda.Compile();

            convertFunction = new Func <ExpressionTreeBase, TTarget>(etb =>
            {
                return(convertFunctionStrong((ExpressionTree)etb));
            });

            var predicateParameter = Expression.Parameter(typeof(ExpressionTree), predicate.Parameters[0].Name);
            var predicateLambdaRaw = Expression.Lambda <Func <ExpressionTree, bool> >(
                Expression.AndAlso(
                    Expression.TypeIs(
                        Expression.Property(
                            predicateParameter,
                            expressionProperty
                            ),
                        typeof(TLeaf)
                        ),
                    Expression.Invoke(
                        predicate,
                        Expression.Convert(
                            Expression.Property(
                                predicateParameter,
                                expressionProperty
                                ),
                            typeof(TLeaf)
                            )
                        )
                    ),
                predicateParameter
                );

            predicateLambda = (Expression <Func <ExpressionTree, bool> >)BetaReducer.Reduce(predicateLambdaRaw, BetaReductionNodeTypes.Unrestricted, BetaReductionRestrictions.None);

            var predicateFunctionStrong = predicateLambda.Compile();

            predicateFunction = new Func <ExpressionTreeBase, bool>(etb =>
            {
                return(etb is ExpressionTree et && predicateFunctionStrong(et));
            });
        }