/// <summary> /// Adds yield target to the current try statement and returns the label /// to which the outer code must jump to to route properly to this label. /// </summary> internal TargetLabel AddYieldTarget(TargetLabel label, int index) { switch (State) { case TryStatementState.Try: return _statement.AddTryYieldTarget(label, index); case TryStatementState.Handler: return _statement.AddCatchYieldTarget(label, index, _handler); case TryStatementState.Finally: return _statement.AddFinallyYieldTarget(label, index); default: Debug.Assert(false, "Invalid try statement state " + State.ToString()); throw new System.InvalidOperationException(); } }
protected internal override void PostWalk(YieldStatement node) { // Assign the yield statement index for codegen int index = _topTargets.Count; TargetLabel label = new TargetLabel(); node.Target = new YieldTarget(index, label); foreach (ExceptionBlock eb in _tryBlocks) { // The exception statement must determine // the label for the enclosing code to jump to // to return to the given yield target label = eb.AddYieldTarget(label, index); } // Insert the top target to the top yields Debug.Assert(_topTargets.Count == index); _topTargets.Add(new YieldTarget(index, label)); }
public YieldTarget(int index, TargetLabel label) { _index = index; _target = label; }
private TargetLabel EnsureTopTarget() { if (_target == null) { _target = new TargetLabel(); } return _target; }
internal TargetLabel AddTryYieldTarget(TargetLabel label, int index) { // Yield inside try stays inside try block, so we need to // remember the target label. AddYieldTarget(ref _tryYields, label, index); return EnsureTopTarget(); }
internal TargetLabel AddFinallyYieldTarget(TargetLabel label, int index) { // Yields inside finally stay inside finally so we need to keep track // of them. AddYieldTarget(ref _finallyYields, label, index); return EnsureTopTarget(); }
internal TargetLabel AddCatchYieldTarget(TargetLabel label, int index, int handler) { // Yields inside catch blocks are hoisted out of the catch. // If the catch block has a finally, though, it will get wrapped in // another try block, in which case the direct jump is not possible // and code must route through the top target. Debug.Assert(_handlers != null && handler < _handlers.Count); CatchBlock cb = _handlers[handler]; cb.Yield = true; _yieldInCatch = true; if (_finally != null) { AddYieldTarget(ref _catchYields, label, index); return EnsureTopTarget(); } else { return label; } }
internal static void AddYieldTarget(ref List<YieldTarget> list, TargetLabel target, int index) { if (list == null) { list = new List<YieldTarget>(); } list.Add(new YieldTarget(index, target)); }