public override void VisitTry(BoundTry node)
            {
                // Rules for try/catch:
                // * Try stays the default;
                // * Catch becomes a fork (it's only taken when an exception is
                //   thrown);
                // * Finally is treated special. It's also executed on the default
                //   branch, but it's also executed from break/continue/throw/return's,
                //   because these flow through the finally. We don't do this here,
                //   but in JoinOnBlock.

                var block = new Block(_branch, null, false, false, node.Finally);

                PushBlock(block);

                Visit(node.Try);

                if (node.Catch != null)
                {
                    // Create a block for the catch.

                    var catchBlock = new Block(block.Branch, null, false, false, null);

                    PushBlock(catchBlock);

                    _branch = catchBlock.Branch.Fork();

                    Visit(node.Catch);

                    catchBlock.JoinBranch(_branch);

                    // Create an empty fork to tell the Join algorithm that the
                    // Catch was an optional branch.

                    catchBlock.JoinBranch(catchBlock.Branch.Fork());

                    PopBlock(catchBlock);
                }

                Visit(node.Finally);

                PopBlock(block);
            }
Example #2
0
 public virtual void VisitTry(BoundTry node)
 {
     DefaultVisit(node);
 }
Example #3
0
        private void EmitTry(BoundTry node)
        {
            _scope.EntryTryCatch();

            IL.BeginExceptionBlock();

            EmitStatement(node.Try);

            // Emit the catch block.

            if (node.Catch != null)
            {
                IL.BeginCatchBlock(typeof(Exception));

                if (node.Catch.Target == null)
                {
                    IL.Emit(OpCodes.Pop);
                }
                else
                {
                    // Store the unwrapped exception in a local.
                    var exceptionTarget = IL.DeclareLocal(typeof(Exception));
                    IL.Emit(OpCodes.Stloc, exceptionTarget);

                    // Wrap the exception.
                    _scope.EmitLoad(SpecialLocal.Runtime);
                    IL.Emit(OpCodes.Ldloc, exceptionTarget);
                    IL.EmitCall(_runtimeWrapException);

                    // Assign the exception to a local.
                    var wrappedExceptionTarget = IL.DeclareLocal(typeof(object));
                    IL.Emit(OpCodes.Stloc, wrappedExceptionTarget);

                    // Assign the wrapped exception to the target.
                    EmitSetVariable(
                        node.Catch.Target,
                        new BoundEmitExpression(
                            BoundValueType.Unknown,
                            () => IL.Emit(OpCodes.Ldloc, wrappedExceptionTarget)
                        )
                    );
                }

                // Emit the body for the catch.
                EmitStatement(node.Catch.Body);
            }

            // Emit the finally block.

            if (node.Finally != null)
            {
                IL.BeginFinallyBlock();

                EmitStatement(node.Finally.Body);
            }

            IL.EndExceptionBlock();

            _scope.LeaveTryCatch();
        }