// ***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(); }