private void ValidateTryCatchFinallyBlocks() { foreach (var kv in TryBlocks.AsEnumerable()) { if (kv.Value.Item2 == -1) { throw new SigilVerificationException( "Unended ExceptionBlock " + kv.Key, IL.Instructions(AllLocals) ); } } foreach (var kv in CatchBlocks.AsEnumerable()) { if (kv.Value.Item2 == -1) { throw new Exception("Invalid State, all ExceptionBlocks are ended but CatchBlock " + kv.Key + " isn't ended"); } } foreach (var kv in FinallyBlocks.AsEnumerable()) { if (kv.Value.Item2 == -1) { throw new Exception("Invalid State, all ExceptionBlocks are ended but FinallyBlock " + kv.Key + " isn't ended"); } } }
/// <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); }