Beispiel #1
0
        /// <summary>
        /// Begins a catch block for the given exception type in the given exception block.
        ///
        /// The given exception block must still be open.
        /// </summary>
        public CatchBlock BeginCatchBlock(ExceptionBlock forTry, Type exceptionType)
        {
            if (exceptionType == null)
            {
                throw new ArgumentNullException("exceptionType");
            }

            if (forTry == null)
            {
                throw new ArgumentNullException("forTry");
            }

            if (((IOwned)forTry).Owner != this)
            {
                FailOwnership(forTry);
            }

            if (CurrentExceptionBlock.Count > 0 && forTry != CurrentExceptionBlock.Peek())
            {
                throw new InvalidOperationException("Cannot start CatchBlock on " + forTry + " while inner ExceptionBlock is still open");
            }

            if (!typeof(Exception).IsAssignableFrom(exceptionType))
            {
                throw new ArgumentException("BeginCatchBlock expects a type descending from Exception, found " + exceptionType, "exceptionType");
            }

            var currentlyOpen = CatchBlocks.Where(c => c.Key.ExceptionBlock == forTry && c.Value.Item2 == -1).Select(s => s.Key).SingleOrDefault();

            if (currentlyOpen != null)
            {
                throw new InvalidOperationException("Cannot start a new catch block, " + currentlyOpen + " has not been ended");
            }

            if (MustMark)
            {
                MarkLabel(DefineLabel(AutoNamer.Next(this, "__autolabel")));
            }

            UpdateState(Wrap(new[] { new StackTransition(0) }, "BeginCatchBlock"));

            var tryBlock = TryBlocks[forTry];

            if (tryBlock.Item2 != -1)
            {
                throw new SigilVerificationException("BeginCatchBlock expects an unclosed exception block, but " + forTry + " is already closed", IL.Instructions(AllLocals));
            }

            IL.BeginCatchBlock(exceptionType);

            UpdateState(Wrap(StackTransition.Push(exceptionType), "BeginCatchBlock"));

            var ret = new CatchBlock(exceptionType, forTry);

            CatchBlocks[ret] = SigilTuple.Create(IL.Index, -1);

            return(ret);
        }
Beispiel #2
0
        /// <summary>
        /// Begins a finally block on the given exception block.
        ///
        /// Only one finally block can be defined per exception block, and the block cannot appear within a catch block.
        ///
        /// The given exception block must still be open.
        /// </summary>
        public FinallyBlock BeginFinallyBlock(ExceptionBlock forTry)
        {
            if (forTry == null)
            {
                throw new ArgumentNullException("forTry");
            }

            if (((IOwned)forTry).Owner != this)
            {
                FailOwnership(forTry);
            }

            var tryBlock = TryBlocks[forTry];

            if (tryBlock.Item2 != -1)
            {
                throw new InvalidOperationException("BeginFinallyBlock expects an unclosed exception block, but " + forTry + " is already closed");
            }

            if (CurrentExceptionBlock.Count > 0 && forTry != CurrentExceptionBlock.Peek())
            {
                throw new InvalidOperationException("Cannot begin FinallyBlock on " + forTry + " while inner ExceptionBlock " + CurrentExceptionBlock.Peek() + " is still open");
            }

            if (FinallyBlocks.Any(kv => kv.Key.ExceptionBlock == forTry))
            {
                throw new InvalidOperationException("There can only be one finally block per ExceptionBlock, and one is already defined for " + forTry);
            }

            if (MustMark)
            {
                MarkLabel(DefineLabel(AutoNamer.Next(this, "__autolabel")));
            }

            UpdateState(Wrap(new[] { new StackTransition(0) }, "BeginFinallyBlock"));

            var ret = new FinallyBlock(forTry);

            IL.BeginFinallyBlock();

            FinallyBlocks[ret] = SigilTuple.Create(IL.Index, -1);

            return(ret);
        }
Beispiel #3
0
        /// <summary>
        /// Start a new exception block.  This is roughly analogous to a `try` block in C#, but an exception block contains it's catch and finally blocks.
        /// </summary>
        public ExceptionBlock BeginExceptionBlock()
        {
            if (MustMark)
            {
                MarkLabel(DefineLabel(AutoNamer.Next(this, "__autolabel")));
            }

            UpdateState(Wrap(new[] { new StackTransition(0) }, "BeginExceptionBlock"));

            var labelDel = IL.BeginExceptionBlock();
            var label    = new Label(this, labelDel, AutoNamer.Next(this, "__exceptionBlockEnd"));

            CurrentLabels[label.Name] = label;

            var ret = new ExceptionBlock(label);

            TryBlocks[ret] = SigilTuple.Create(IL.Index, -1);

            CurrentExceptionBlock.Push(ret);

            return(ret);
        }
Beispiel #4
0
        /// <summary>
        /// Ends the given exception block.
        ///
        /// All catch and finally blocks associated with the given exception block must be ended before this method is called.
        /// </summary>
        public Emit <DelegateType> EndExceptionBlock(ExceptionBlock forTry)
        {
            if (forTry == null)
            {
                throw new ArgumentNullException("forTry");
            }

            if (((IOwned)forTry).Owner != this)
            {
                FailOwnership(forTry);
            }

            var location = TryBlocks[forTry];

            // Can't close the same exception block twice
            if (location.Item2 != -1)
            {
                throw new InvalidOperationException("ExceptionBlock has already been ended");
            }

            if (CurrentExceptionBlock.Count > 0 && forTry != CurrentExceptionBlock.Peek())
            {
                throw new InvalidOperationException("Cannot end outer ExceptionBlock " + forTry + " while inner EmitExceptionBlock " + CurrentExceptionBlock.Peek() + " is open");
            }

            // Can't close an exception block while there are outstanding catch blocks
            foreach (var kv in CatchBlocks.AsEnumerable())
            {
                if (kv.Key.ExceptionBlock != forTry)
                {
                    continue;
                }

                if (kv.Value.Item2 == -1)
                {
                    throw new InvalidOperationException("Cannot end ExceptionBlock, CatchBlock " + kv.Key + " has not been ended");
                }
            }

            foreach (var kv in FinallyBlocks.AsEnumerable())
            {
                if (kv.Key.ExceptionBlock != forTry)
                {
                    continue;
                }

                if (kv.Value.Item2 == -1)
                {
                    throw new InvalidOperationException("Cannot end ExceptionBlock, FinallyBlock " + kv.Key + " has not been ended");
                }
            }

            if (!CatchBlocks.Any(k => k.Key.ExceptionBlock == forTry) && !FinallyBlocks.Any(k => k.Key.ExceptionBlock == forTry))
            {
                throw new InvalidOperationException("Cannot end ExceptionBlock without defining at least one of a catch or finally block");
            }

            IL.EndExceptionBlock();

            TryBlocks[forTry] = SigilTuple.Create(location.Item1, IL.Index);

            Marks[forTry.Label] = IL.Index;

            CurrentExceptionBlock.Pop();

            if (MustMark)
            {
                MarkLabel(DefineLabel(AutoNamer.Next(this, "__autolabel")));
            }

            return(this);
        }