internal override MSAst.Expression Transform(AstGenerator ag) { MSAst.Expression raiseExpression; if (_type == null && _value == null && _traceback == null) { raiseExpression = Ast.Call( AstGenerator.GetHelperMethod("MakeRethrownException"), ag.LocalContext ); if (!ag._isEmittingFinally) { raiseExpression = Ast.Block( ag.UpdateLineUpdated(true), raiseExpression ); } } else { raiseExpression = Ast.Call( AstGenerator.GetHelperMethod("MakeException"), ag.LocalContext, ag.TransformOrConstantNull(_type, typeof(object)), ag.TransformOrConstantNull(_value, typeof(object)), ag.TransformOrConstantNull(_traceback, typeof(object)) ); } return ag.AddDebugInfo( Ast.Throw(raiseExpression), Span ); }
internal ScriptCode/*!*/ TransformToAst(CompilationMode mode, CompilerContext/*!*/ context) { // Create the ast generator // Use the PrintExpression value for the body (global level code) PythonCompilerOptions pco = context.Options as PythonCompilerOptions; Debug.Assert(pco != null); string name; if (!context.SourceUnit.HasPath || (pco.Module & ModuleOptions.ExecOrEvalCode) != 0) { name = "<module>"; } else { name = context.SourceUnit.Path; } AstGenerator ag = new AstGenerator(mode, context, _body.Span, name, false, _printExpressions); MSAst.Expression body = Ast.Block( Ast.Call( AstGenerator.GetHelperMethod("ModuleStarted"), ag.LocalContext, AstUtils.Constant(ag.BinderState, typeof(object)), AstUtils.Constant(_languageFeatures) ), ag.UpdateLineNumber(0), ag.UpdateLineUpdated(false), ag.WrapScopeStatements(Transform(ag)), // new ComboActionRewriter().VisitNode(Transform(ag)) AstUtils.Empty() ); if (_isModule) { string moduleName = pco.ModuleName; if (moduleName == null) { #if !SILVERLIGHT if (context.SourceUnit.HasPath && context.SourceUnit.Path.IndexOfAny(Path.GetInvalidFileNameChars()) == -1) { moduleName = Path.GetFileNameWithoutExtension(context.SourceUnit.Path); #else if (context.SourceUnit.HasPath) { moduleName = context.SourceUnit.Path; #endif } else { moduleName = "<module>"; } } Debug.Assert(moduleName != null); body = Ast.Block( ag.Globals.Assign(ag.Globals.GetVariable(ag, _fileVariable), Ast.Constant(name)), ag.Globals.Assign(ag.Globals.GetVariable(ag, _nameVariable), Ast.Constant(moduleName)), body // already typed to void ); if ((pco.Module & ModuleOptions.Initialize) != 0) { MSAst.Expression tmp = ag.HiddenVariable(typeof(object), "$originalModule"); // TODO: Should be try/fault body = AstUtils.Try( Ast.Assign(tmp, Ast.Call(AstGenerator.GetHelperMethod("PublishModule"), ag.LocalContext, Ast.Constant(moduleName))), body ).Catch( typeof(Exception), Ast.Call(AstGenerator.GetHelperMethod("RemoveModule"), ag.LocalContext, Ast.Constant(moduleName), tmp), Ast.Rethrow(body.Type) ); } } body = ag.AddProfiling(body); body = ag.AddReturnTarget(body); if (body.Type == typeof(void)) { body = Ast.Block(body, Ast.Constant(null)); } return ag.MakeScriptCode(body, context, this); }
private MSAst.Expression AddFinally(AstGenerator/*!*/ ag, MSAst.Expression/*!*/ body, MSAst.ParameterExpression noNestedException) { if (_finally != null) { Debug.Assert(noNestedException != null); MSAst.ParameterExpression nestedFrames = ag.GetTemporary("$nestedFrames", typeof(List<DynamicStackFrame>)); bool inFinally = ag.InFinally; ag.InFinally = true; MSAst.Expression @finally = ag.Transform(_finally); ag.InFinally = inFinally; if (@finally == null) { // error reported during compilation return null; } if (ag.TrackLines) { // lots is going on here. We need to consider: // 1. Exceptions propagating out of try/except/finally. Here we need to save the line # // from the exception block and not save the # from the finally block later. // 2. Exceptions propagating out of the finally block. Here we need to report the line number // from the finally block and leave the existing stack traces cleared. // 3. Returning from the try block: Here we need to run the finally block and not update the // line numbers. body = AstUtils.Try(// we use a filter to know when we have an exception and when control leaves normally (via // either a return or the body completing successfully). AstUtils.Try( ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Span.Start, _header)), Ast.Assign(noNestedException, Ast.Constant(true)), body ).Filter( typeof(Exception), // condition is never true, just note the exception and let it propagate Ast.Equal( Ast.Assign(noNestedException, Ast.Constant(false)), Ast.Constant(true) ), Ast.Default(body.Type) ) ).Finally( // if we had an exception save the line # that was last executing during the try AstUtils.If( Ast.Not(noNestedException), ag.GetLineNumberUpdateExpression(false) ), // clear the frames incase thae finally throws, and allow line number // updates to proceed ag.UpdateLineUpdated(false), Ast.Assign( nestedFrames, Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames")) ), // run the finally code @finally, // if the finally exits normally restore any previous exception info Ast.Call( AstGenerator.GetHelperMethod("SetDynamicStackFrames"), nestedFrames ), ag.UpdateLineUpdated(true) ); ag.FreeTemp(nestedFrames); ag.FreeTemp(noNestedException); } else { body = AstUtils.Try(body).Finally( Ast.Assign( nestedFrames, Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames")) ), // run the finally code @finally, // if the finally exits normally restore any previous exception info Ast.Call( AstGenerator.GetHelperMethod("SetDynamicStackFrames"), nestedFrames ) ); } } return body; }
private MSAst.Expression AddFinally(AstGenerator/*!*/ ag, MSAst.Expression/*!*/ body, MSAst.ParameterExpression nestedException) { if (_finally != null) { bool isEmitting = ag._isEmittingFinally; ag._isEmittingFinally = true; int loopId = ++ag._loopOrFinallyId; ag.LoopOrFinallyIds.Add(loopId, true); try { Debug.Assert(nestedException != null); MSAst.ParameterExpression nestedFrames = ag.GetTemporary("$nestedFrames", typeof(List<DynamicStackFrame>)); bool inFinally = ag.InFinally; ag.InFinally = true; MSAst.Expression @finally = ag.Transform(_finally); ag.InFinally = inFinally; if (@finally == null) { // error reported during compilation return null; } // lots is going on here. We need to consider: // 1. Exceptions propagating out of try/except/finally. Here we need to save the line # // from the exception block and not save the # from the finally block later. // 2. Exceptions propagating out of the finally block. Here we need to report the line number // from the finally block and leave the existing stack traces cleared. // 3. Returning from the try block: Here we need to run the finally block and not update the // line numbers. body = AstUtils.Try( // we use a fault to know when we have an exception and when control leaves normally (via // either a return or the body completing successfully). AstUtils.Try( ag.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)), Ast.Assign(nestedException, AstUtils.Constant(false)), body ).Fault( // fault Ast.Assign(nestedException, AstUtils.Constant(true)) ) ).FinallyWithJumps( // if we had an exception save the line # that was last executing during the try AstUtils.If( nestedException, ag.GetSaveLineNumberExpression(false) ), // clear the frames incase thae finally throws, and allow line number // updates to proceed ag.UpdateLineUpdated(false), Ast.Assign( nestedFrames, Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames")) ), // run the finally code @finally, // if the finally exits normally restore any previous exception info Ast.Call( AstGenerator.GetHelperMethod("SetDynamicStackFrames"), nestedFrames ), // if we took an exception in the try block we have saved the line number. Otherwise // we have no line number saved and will need to continue saving them if // other exceptions are thrown. AstUtils.If( nestedException, ag.UpdateLineUpdated(true) ) ); ag.FreeTemp(nestedFrames); ag.FreeTemp(nestedException); } finally { ag._isEmittingFinally = isEmitting; ag.LoopOrFinallyIds.Remove(loopId); } } return body; }
/// <summary> /// WithStatement is translated to the DLR AST equivalent to /// the following Python code snippet (from with statement spec): /// /// mgr = (EXPR) /// exit = mgr.__exit__ # Not calling it yet /// value = mgr.__enter__() /// exc = True /// try: /// VAR = value # Only if "as VAR" is present /// BLOCK /// except: /// # The exceptional case is handled here /// exc = False /// if not exit(*sys.exc_info()): /// raise /// # The exception is swallowed if exit() returns true /// finally: /// # The normal and non-local-goto cases are handled here /// if exc: /// exit(None, None, None) /// /// </summary> internal override MSAst.Expression Transform(AstGenerator ag) { MSAst.ParameterExpression lineUpdated = ag.GetTemporary("$lineUpdated_with", typeof(bool)); // Five statements in the result... MSAst.Expression[] statements = new MSAst.Expression[6]; //****************************************************************** // 1. mgr = (EXPR) //****************************************************************** MSAst.ParameterExpression manager = ag.GetTemporary("with_manager"); statements[0] = ag.MakeAssignment( manager, ag.Transform(_contextManager), new SourceSpan(Start, _header) ); //****************************************************************** // 2. exit = mgr.__exit__ # Not calling it yet //****************************************************************** MSAst.ParameterExpression exit = ag.GetTemporary("with_exit"); statements[1] = ag.MakeAssignment( exit, ag.Get( typeof(object), "__exit__", manager ) ); //****************************************************************** // 3. value = mgr.__enter__() //****************************************************************** MSAst.ParameterExpression value = ag.GetTemporary("with_value"); statements[2] = ag.AddDebugInfo( ag.MakeAssignment( value, ag.Invoke( typeof(object), new CallSignature(0), ag.Get( typeof(object), "__enter__", manager ) ) ), new SourceSpan(Start, _header) ); //****************************************************************** // 4. exc = True //****************************************************************** MSAst.ParameterExpression exc = ag.GetTemporary("with_exc", typeof(bool)); statements[3] = ag.MakeAssignment( exc, AstUtils.Constant(true) ); //****************************************************************** // 5. The final try statement: // // try: // VAR = value # Only if "as VAR" is present // BLOCK // except: // # The exceptional case is handled here // exc = False // if not exit(*sys.exc_info()): // raise // # The exception is swallowed if exit() returns true // finally: // # The normal and non-local-goto cases are handled here // if exc: // exit(None, None, None) //****************************************************************** MSAst.ParameterExpression exception = ag.GetTemporary("exception", typeof(Exception)); MSAst.ParameterExpression nestedFrames = ag.GetTemporary("$nestedFrames", typeof(List<DynamicStackFrame>)); statements[4] = // try: AstUtils.Try( AstUtils.Try(// try statement body ag.PushLineUpdated(false, lineUpdated), _var != null ? ag.AddDebugInfo( Ast.Block( // VAR = value _var.TransformSet(ag, SourceSpan.None, value, PythonOperationKind.None), // BLOCK ag.Transform(_body), AstUtils.Empty() ), _body.Span ) : // BLOCK ag.Transform(_body) // except:, // try statement location ).Catch(exception, // Python specific exception handling code TryStatement.GetTracebackHeader( ag, exception, ag.AddDebugInfo( Ast.Block( // exc = False ag.MakeAssignment( exc, AstUtils.Constant(false) ), Ast.Assign( nestedFrames, Ast.Call(AstGenerator.GetHelperMethod("GetAndClearDynamicStackFrames")) ), // if not exit(*sys.exc_info()): // raise AstUtils.IfThen( ag.Convert( typeof(bool), ConversionResultKind.ExplicitCast, ag.Operation( typeof(bool), PythonOperationKind.Not, MakeExitCall(ag, exit, exception) ) ), ag.UpdateLineUpdated(true), Ast.Call( AstGenerator.GetHelperMethod("SetDynamicStackFrames"), nestedFrames ), Ast.Rethrow() ) ), _body.Span ) ), Ast.Call( AstGenerator.GetHelperMethod("SetDynamicStackFrames"), nestedFrames ), ag.PopLineUpdated(lineUpdated), Ast.Empty() ) // finally: ).Finally( // if exc: // exit(None, None, None) AstUtils.IfThen( exc, ag.AddDebugInfo( Ast.Block( Ast.Dynamic( ag.BinderState.Invoke( new CallSignature(3) // signature doesn't include function ), typeof(object), new MSAst.Expression[] { ag.LocalContext, exit, AstUtils.Constant(null), AstUtils.Constant(null), AstUtils.Constant(null) } ), Ast.Empty() ), _contextManager.Span ) ) ); statements[4] = ag.AddDebugInfo(statements[4], Span); statements[5] = AstUtils.Empty(); return ag.AddDebugInfo(Ast.Block(statements), _body.Span); }
internal MSAst.LambdaExpression/*!*/ TransformToAst(CompilerContext context) { // Create the ast generator // Use the PrintExpression value for the body (global level code) PythonCompilerOptions pco = context.Options as PythonCompilerOptions; Debug.Assert(pco != null); string name; if (!context.SourceUnit.HasPath || (pco.Module & ModuleOptions.ExecOrEvalCode) != 0) { name = "<module>"; } else { name = context.SourceUnit.Path; } AstGenerator ag = new AstGenerator(context, _body.Span, name, false, _printExpressions); ag.Block.Global = true; ag.Block.Body = Ast.Block( Ast.Call( AstGenerator.GetHelperMethod("ModuleStarted"), AstUtils.CodeContext(), Ast.Constant(ag.BinderState, typeof(object)), Ast.Constant(_languageFeatures) ), ag.UpdateLineNumber(0), ag.UpdateLineUpdated(false), ag.WrapScopeStatements(Transform(ag)), // new ComboActionRewriter().VisitNode(Transform(ag)) Ast.Empty() ); if (_isModule) { Debug.Assert(pco.ModuleName != null); ag.Block.Body = Ast.Block( AstUtils.Assign(_fileVariable.Variable, Ast.Constant(name)), AstUtils.Assign(_nameVariable.Variable, Ast.Constant(pco.ModuleName)), ag.Block.Body // already typed to void ); if ((pco.Module & ModuleOptions.Initialize) != 0) { MSAst.Expression tmp = ag.Block.HiddenVariable(typeof(object), "$originalModule"); // TODO: Should be try/fault ag.Block.Body = AstUtils.Try( Ast.Assign(tmp, Ast.Call(AstGenerator.GetHelperMethod("PublishModule"), AstUtils.CodeContext(), Ast.Constant(pco.ModuleName))), ag.Block.Body ).Catch( typeof(Exception), Ast.Call(AstGenerator.GetHelperMethod("RemoveModule"), AstUtils.CodeContext(), Ast.Constant(pco.ModuleName), tmp), Ast.Rethrow(ag.Block.Body.Type) ); } } ag.Block.Body = ag.AddReturnTarget(ag.Block.Body); DisableInterpreter = ag.DisableInterpreter; return ag.Block.MakeLambda(); }