private void EmitWithCatchBlock(CodeGen cg, Slot exc, Slot exit) { cg.BeginCatchBlock(typeof(Exception)); // Extract state from the carrier exception cg.EmitCallerContext(); cg.EmitCall(typeof(Ops), "ExtractException", new Type[] { typeof(Exception), typeof(ICallerContext) }); cg.Emit(OpCodes.Pop); // except body cg.PushExceptionBlock(Targets.TargetBlockType.Catch, null, null); cg.EmitConstantBoxed(false); exc.EmitSet(cg); cg.EmitCallerContext(); exit.EmitGet(cg); cg.EmitObjectArray(new Expression[0]); cg.EmitCallerContext(); cg.EmitCall(typeof(Ops), "ExtractSysExcInfo"); cg.EmitCall(typeof(Ops), "CallWithArgsTupleAndContext", new Type[] { typeof(ICallerContext), typeof(object), typeof(object[]), typeof(object) }); Label afterRaise = cg.DefineLabel(); cg.EmitTestTrue(); cg.Emit(OpCodes.Brtrue, afterRaise); cg.EmitCall(typeof(Ops), "Raise", new Type[0]); //, new Type[] { typeof(object), typeof(SymbolId) }); cg.MarkLabel(afterRaise); cg.EmitCallerContext(); cg.EmitCall(typeof(Ops), "ClearException", new Type[] { typeof(ICallerContext) }); cg.PopTargets(); }
// ***WITH STATEMENT CODE GENERATION ALGORITHM*** // //GRAMMAR := //with EXPR as VAR: // BLOCK // //CODE GEN := // //mgr = (EXPR) //exit = mgr.__exit__ # Not calling it yet //value = mgr.__enter__() //exc = True //isTryYielded = False //try: // // VAR = value # Only if "as VAR" is present // BLOCK // // if yield happens in the Block, // // then isTryYielded is set to True by Yield's Code Gen //except: // # The exceptional case is handled here // exc = False // if not exit(*sys.exc_info()): // raise // # The exception is consumed if exit() returns true //finally: // # The normal and non-local-goto cases are handled here // if isTryYielded = False && exc == True : // exit(None, None, None) internal override void Emit(CodeGen cg) { Slot exc = null; Slot isTryYielded = null; Slot exit = null; if (cg.IsGenerator()) { exc = cg.Names.GetTempSlot("with", typeof(object)); isTryYielded = cg.Names.GetTempSlot("with", typeof(object)); exit = cg.Names.GetTempSlot("with", typeof(object)); } else { exc = cg.GetLocalTmp(typeof(object)); isTryYielded = cg.GetLocalTmp(typeof(object)); exit = cg.GetLocalTmp(typeof(object)); } // mgr = (EXPR) Slot mgr = cg.GetLocalTmp(typeof(object)); contextManager.Emit(cg); mgr.EmitSet(cg); // exit = mgr.__exit__ # not calling it yet cg.EmitCallerContext(); mgr.EmitGet(cg); cg.EmitSymbolId("__exit__"); cg.EmitCall(typeof(Ops), "GetAttr"); exit.EmitSet(cg); mgr.EmitGet(cg); cg.FreeLocalTmp(mgr); cg.EmitSymbolId("__enter__"); cg.EmitObjectArray(new Expression[0]); cg.EmitCall(typeof(Ops), "Invoke", new Type[] { typeof(object), typeof(SymbolId), typeof(object[]) }); Slot value = cg.GetLocalTmp(typeof(object)); value.EmitSet(cg); // exc = True cg.EmitConstantBoxed(true); exc.EmitSet(cg); Slot choiceVar = null; if (yieldTargets != null && yieldTargets.Count > 0) { Label startOfBlock = cg.DefineLabel(); choiceVar = cg.GetLocalTmp(typeof(int)); cg.EmitInt(-1); choiceVar.EmitSet(cg); cg.Emit(OpCodes.Br, startOfBlock); int index = 0; foreach (YieldTarget yt in yieldTargets) { cg.MarkLabel(yt.TopBranchTarget); cg.EmitInt(index++); choiceVar.EmitSet(cg); cg.Emit(OpCodes.Br, startOfBlock); } cg.MarkLabel(startOfBlock); } cg.EmitConstantBoxed(false); isTryYielded.EmitSet(cg); Label beforeFinally = cg.DefineLabel(); cg.PushWithTryBlock(isTryYielded); cg.BeginExceptionBlock(); if (yieldTargets != null && yieldTargets.Count > 0) { int index = 0; foreach (YieldTarget yt in yieldTargets) { choiceVar.EmitGet(cg); cg.EmitInt(index); cg.Emit(OpCodes.Beq, yt.YieldContinuationTarget); index++; } cg.FreeLocalTmp(choiceVar); } if (var != null) { value.EmitGet(cg); var.EmitSet(cg); } body.Emit(cg); EmitWithCatchBlock(cg, exc, exit); cg.PopTargets(); EmitWithFinallyBlock(cg, exc, exit, isTryYielded); cg.EndExceptionBlock(); if (yieldTargets != null) yieldTargets.Clear(); }