private Expression RewriteFaultHandler(TryExpression node)
        {
            //
            // 0. Recurse into the children.
            //
            var body  = Visit(node.Body);
            var fault = Visit(node.Fault);

            //
            // 1. Initialize rewriter.
            //
            var rewriter = new HandlerRewriter();

            //
            // 2. Rewrite body and handler.
            //
            var rewrittenTry          = rewriter.Rewrite(body)();
            var rewrittenTryHandler   = Expression.Lambda <Func <LeaveHandlerData> >(rewrittenTry);
            var rewrittenFaultHandler = Expression.Lambda <Action>(fault);

            //
            // 3. Emit call to TryFault helper.
            //
            var tryFault = Expression.Call(s_tryFault, rewrittenTryHandler, rewrittenFaultHandler);

            //
            // 4. Create resulting expression.
            //
            return(CreateRewrittenTry(node, rewriter, tryFault));
        }
        private static Expression CreateRewrittenTry(TryExpression node, HandlerRewriter rewriter, Expression call)
        {
            var assignLeaveResult = Expression.Assign(rewriter.LeaveResult, call);
            var leaveResultValue  = Expression.PropertyOrField(rewriter.LeaveResult, "Value");

            //
            // 1. Create jump table.
            //
            var dispatch = rewriter.GetDispatchTable();

            //
            // 2. Count number of expressions needed in resulting block.
            //
            var n          = (node.Type == typeof(void) ? 0 : 1) + (dispatch != null ? 1 : 0) + 1;
            var statements = new Expression[n];

            //
            // 3. Store result of call in temporary.
            //
            var i = 0;

            statements[i++] = assignLeaveResult;

            //
            // 4. For non-emptyu dispatch tables, emit the dispatch.
            //
            if (dispatch != null)
            {
                statements[i++] = dispatch;
            }

            //
            // 5. For non-null nodes, extract the result.
            //
            if (node.Type != typeof(void))
            {
                statements[i++] = Expression.Convert(leaveResultValue, node.Type);
            }

            //
            // 6. Put everything together in a block.
            //
            var res = Expression.Block(node.Type, new[] { rewriter.LeaveResult }, statements);

            return(res);
        }
        private Expression RewriteFilterHandler(TryExpression node)
        {
            if (node.Handlers.Count == 1 && node.Finally == null)
            {
                //
                // 0. Recurse into the children.
                //
                var body    = Visit(node.Body);
                var handler = VisitCatchBlock(node.Handlers[0]);

                //
                // 1. Initialize rewriter.
                //
                var rewriter = new HandlerRewriter();

                //
                // 2. Obtain rewriters for the body and the handler.
                //
                var bodyRewriter  = rewriter.Rewrite(body);
                var catchRewriter = rewriter.Rewrite(handler.Body); // TODO: verify we can't jump out of the filter

                //
                // 3. Rewrite body, handler, and filter.
                //
                var rewrittenTry           = bodyRewriter();
                var rewrittenTryHandler    = Expression.Lambda <Func <LeaveHandlerData> >(rewrittenTry);
                var rewrittenCatch         = catchRewriter();
                var rewrittenCatchHandler  = Expression.Lambda(rewrittenCatch, handler.Variable);
                var rewrittenFilterHandler = Expression.Lambda(handler.Filter, handler.Variable);

                //
                // 4. Emit call to TryFilter helper.
                //
                var tryFilter = Expression.Call(s_tryFilter.MakeGenericMethod(handler.Test), rewrittenTryHandler, rewrittenFilterHandler, rewrittenCatchHandler);

                //
                // 4. Create resulting expression.
                //
                return(CreateRewrittenTry(node, rewriter, tryFilter));
            }
            else
            {
                return(Visit(Expand(node)));
            }
        }
        private Expression RewriteFilterHandler(TryExpression node)
        {
            if (node.Handlers.Count == 1 && node.Finally == null)
            {
                //
                // 0. Recurse into the children.
                //
                var body = Visit(node.Body);
                var handler = VisitCatchBlock(node.Handlers[0]);

                //
                // 1. Initialize rewriter.
                //
                var rewriter = new HandlerRewriter();

                //
                // 2. Obtain rewriters for the body and the handler.
                //
                var bodyRewriter = rewriter.Rewrite(body);
                var catchRewriter = rewriter.Rewrite(handler.Body); // TODO: verify we can't jump out of the filter

                //
                // 3. Rewrite body, handler, and filter.
                //
                var rewrittenTry = bodyRewriter();
                var rewrittenTryHandler = Expression.Lambda<Func<LeaveHandlerData>>(rewrittenTry);
                var rewrittenCatch = catchRewriter();
                var rewrittenCatchHandler = Expression.Lambda(rewrittenCatch, handler.Variable);
                var rewrittenFilterHandler = Expression.Lambda(handler.Filter, handler.Variable);

                //
                // 4. Emit call to TryFilter helper.
                //
                var tryFilter = Expression.Call(s_tryFilter.MakeGenericMethod(handler.Test), rewrittenTryHandler, rewrittenFilterHandler, rewrittenCatchHandler);

                //
                // 4. Create resulting expression.
                //
                return CreateRewrittenTry(node, rewriter, tryFilter);
            }
            else
            {
                return Visit(Expand(node));
            }
        }
        private Expression RewriteFaultHandler(TryExpression node)
        {
            //
            // 0. Recurse into the children.
            //
            var body = Visit(node.Body);
            var fault = Visit(node.Fault);

            //
            // 1. Initialize rewriter.
            //
            var rewriter = new HandlerRewriter();

            //
            // 2. Rewrite body and handler.
            //
            var rewrittenTry = rewriter.Rewrite(body)();
            var rewrittenTryHandler = Expression.Lambda<Func<LeaveHandlerData>>(rewrittenTry);
            var rewrittenFaultHandler = Expression.Lambda<Action>(fault);

            //
            // 3. Emit call to TryFault helper.
            //
            var tryFault = Expression.Call(s_tryFault, rewrittenTryHandler, rewrittenFaultHandler);

            //
            // 4. Create resulting expression.
            //
            return CreateRewrittenTry(node, rewriter, tryFault);
        }
        private static Expression CreateRewrittenTry(TryExpression node, HandlerRewriter rewriter, Expression call)
        {
            var assignLeaveResult = Expression.Assign(rewriter.LeaveResult, call);
            var leaveResultValue = Expression.PropertyOrField(rewriter.LeaveResult, "Value");

            //
            // 1. Create jump table.
            //
            var dispatch = rewriter.GetDispatchTable();

            //
            // 2. Count number of expressions needed in resulting block.
            //
            var n = (node.Type == typeof(void) ? 0 : 1) + (dispatch != null ? 1 : 0) + 1;
            var statements = new Expression[n];

            //
            // 3. Store result of call in temporary.
            //
            var i = 0;
            statements[i++] = assignLeaveResult;

            //
            // 4. For non-emptyu dispatch tables, emit the dispatch.
            //
            if (dispatch != null)
            {
                statements[i++] = dispatch;
            }

            //
            // 5. For non-null nodes, extract the result.
            //
            if (node.Type != typeof(void))
            {
                statements[i++] = Expression.Convert(leaveResultValue, node.Type);
            }

            //
            // 6. Put everything together in a block.
            //
            var res = Expression.Block(node.Type, new[] { rewriter.LeaveResult }, statements);
            return res;
        }