public override MSAst.Expression Reduce() { if (_statements.Length == 0) { return(GlobalParent.AddDebugInfoAndVoid(AstUtils.Empty(), Span)); } ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(); int curStart = -1; foreach (var statement in _statements) { // CPython debugging treats multiple statements on the same line as a single step, we // match that behavior here. int newline = GlobalParent.IndexToLocation(statement.StartIndex).Line; if (newline == curStart) { statements.Add(new DebugInfoRemovalExpression(statement, curStart)); } else { if (statement.CanThrow && newline != -1) { statements.Add(UpdateLineNumber(newline)); } statements.Add(statement); } curStart = newline; } return(Ast.Block(statements.ToReadOnlyCollection())); }
public override MSAst.Expression Reduce() { Debug.Assert(PythonVariable != null, "Shouldn't be called by lambda expression"); MSAst.Expression function = MakeFunctionExpression(); return(GlobalParent.AddDebugInfoAndVoid( AssignValue(Parent.GetVariableExpression(PythonVariable), function), new SourceSpan(GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(HeaderIndex)) )); }
private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert) { // Only the body is "in the loop" for the purposes of break/continue // The "else" clause is outside ConstantExpression constTest = _test as ConstantExpression; if (constTest != null && constTest.Value is int) { // while 0: / while 1: int val = (int)constTest.Value; if (val == 0) { // completely optimize the loop away if (_else == null) { return(MSAst.Expression.Empty()); } else { return(_else); } } MSAst.Expression test = MSAst.Expression.Constant(true); MSAst.Expression res = AstUtils.While( test, _body, _else, _break, _continue ); if (GlobalParent.IndexToLocation(_test.StartIndex).Line != GlobalParent.IndexToLocation(_body.StartIndex).Line) { res = GlobalParent.AddDebugInfoAndVoid(res, _test.Span); } return(res); } return(AstUtils.While( GlobalParent.AddDebugInfo( optimizeDynamicConvert ? TransformAndDynamicConvert(_test, typeof(bool)) : GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, _test), Header ), _body, _else, _break, _continue )); }
public override MSAst.Expression Reduce() { var codeObj = GetOrMakeFunctionCode(); var funcCode = GlobalParent.Constant(codeObj); FuncCodeExpr = funcCode; MSAst.Expression lambda; if (EmitDebugSymbols) { lambda = GetLambda(); } else { lambda = NullLambda; ThreadPool.QueueUserWorkItem((x) => { // class defs are almost always run, so start // compiling the code now so it might be ready // when we actually go and execute it codeObj.UpdateDelegate(PyContext, true); }); } MSAst.Expression classDef = Ast.Call( AstMethods.MakeClass, funcCode, lambda, Parent.LocalContext, AstUtils.Constant(_name), Ast.NewArrayInit( typeof(object), ToObjectArray(_bases) ), Metaclass is null ? AstUtils.Constant(null, typeof(object)) : AstUtils.Convert(Metaclass, typeof(object)), AstUtils.Constant(FindSelfNames()) ); classDef = AddDecorators(classDef, Decorators); return(GlobalParent.AddDebugInfoAndVoid( AssignValue(Parent.GetVariableExpression(PythonVariable), classDef), new SourceSpan( GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(HeaderIndex) ) )); }
/// <summary> /// Creates the LambdaExpression which implements the body of the function. /// /// The functions signature is either "object Function(PythonFunction, ...)" /// where there is one object parameter for each user defined parameter or /// object Function(PythonFunction, object[]) for functions which take more /// than PythonCallTargets.MaxArgs arguments. /// </summary> private LightLambdaExpression CreateFunctionLambda() { bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs; Type delegateType = GetDelegateType(_parameters, needsWrapperMethod, out _); MSAst.ParameterExpression localContext = null; ReadOnlyCollectionBuilder <MSAst.ParameterExpression> locals = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(); if (NeedsLocalContext) { localContext = LocalCodeContextVariable; locals.Add(localContext); } MSAst.ParameterExpression[] parameters = CreateParameters(needsWrapperMethod, locals); List <MSAst.Expression> init = new List <MSAst.Expression>(); foreach (var param in _parameters) { if (GetVariableExpression(param.PythonVariable) is IPythonVariableExpression pyVar) { var varInit = pyVar.Create(); if (varInit != null) { init.Add(varInit); } } } // Transform the parameters. init.Add(Ast.ClearDebugInfo(GlobalParent.Document)); locals.Add(PythonAst._globalContext); init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContext))); GlobalParent.PrepareScope(locals, init); // Create variables and references. Since references refer to // parameters, do this after parameters have been created. CreateFunctionVariables(locals, init); // Initialize parameters - unpack tuples. // Since tuples unpack into locals, this must be done after locals have been created. InitializeParameters(init, needsWrapperMethod, parameters); List <MSAst.Expression> statements = new List <MSAst.Expression>(); // add beginning sequence point var start = GlobalParent.IndexToLocation(StartIndex); statements.Add(GlobalParent.AddDebugInfo( AstUtils.Empty(), new SourceSpan(new SourceLocation(0, start.Line, start.Column), new SourceLocation(0, start.Line, int.MaxValue)))); // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close(). // The exception traceback needs to come from the generator's method body, and so we must do the check and throw // from inside the generator. if (IsGenerator) { MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(SourceSpan.None); statements.Add(s1); } if (Body.CanThrow && !(Body is SuiteStatement) && Body.StartIndex != -1) { statements.Add(UpdateLineNumber(GlobalParent.IndexToLocation(Body.StartIndex).Line)); } statements.Add(Body); MSAst.Expression body = Ast.Block(statements); if (Body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames) { body = AddFrame(LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty(nameof(PythonFunction.__code__))), body); locals.Add(FunctionStackVariable); } body = AddProfiling(body); body = WrapScopeStatements(body, Body.CanThrow); body = Ast.Block(body, AstUtils.Empty()); body = AddReturnTarget(body); MSAst.Expression bodyStmt = body; if (localContext != null) { var createLocal = CreateLocalContext(_parentContext); init.Add( Ast.Assign( localContext, createLocal ) ); } init.Add(bodyStmt); bodyStmt = Ast.Block(init); // wrap a scope if needed bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt); return(AstUtils.LightLambda( typeof(object), delegateType, AddDefaultReturn(bodyStmt, typeof(object)), Name + "$" + Interlocked.Increment(ref _lambdaId), parameters )); }
/// <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> public override MSAst.Expression Reduce() { // Five statements in the result... ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(6); ReadOnlyCollectionBuilder <MSAst.ParameterExpression> variables = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(6); MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with"); variables.Add(lineUpdated); //****************************************************************** // 1. mgr = (EXPR) //****************************************************************** MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager"); variables.Add(manager); statements.Add( GlobalParent.AddDebugInfo( Ast.Assign( manager, _contextManager ), new SourceSpan(GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(_headerIndex)) ) ); //****************************************************************** // 2. exit = mgr.__exit__ # Not calling it yet //****************************************************************** MSAst.ParameterExpression exit = Ast.Variable(typeof(object), "with_exit"); variables.Add(exit); statements.Add( MakeAssignment( exit, GlobalParent.Get( "__exit__", manager ) ) ); //****************************************************************** // 3. value = mgr.__enter__() //****************************************************************** MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value"); variables.Add(value); statements.Add( GlobalParent.AddDebugInfoAndVoid( MakeAssignment( value, Parent.Invoke( new CallSignature(0), Parent.LocalContext, GlobalParent.Get( "__enter__", manager ) ) ), new SourceSpan(GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(_headerIndex)) ) ); //****************************************************************** // 4. exc = True //****************************************************************** MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc"); variables.Add(exc); statements.Add( 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) //****************************************************************** var previousException = Ast.Variable(typeof(Exception), "$previousException"); variables.Add(previousException); MSAst.ParameterExpression exception; statements.Add( // try: AstUtils.Try( AstUtils.Try(// try statement body PushLineUpdated(false, lineUpdated), Ast.Assign(previousException, Ast.Call(AstMethods.SaveCurrentException)), _var != null ? (MSAst.Expression)Ast.Block( // VAR = value _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None), // BLOCK _body, AstUtils.Empty() ) : // BLOCK (MSAst.Expression)_body // except:, // try statement location ).Catch(exception = Ast.Variable(typeof(Exception), "exception"), // Python specific exception handling code TryStatement.GetTracebackHeader( this, exception, GlobalParent.AddDebugInfoAndVoid( Ast.Block( Ast.Call(AstMethods.SetCurrentException, Parent.LocalContext, exception), // exc = False MakeAssignment( exc, AstUtils.Constant(false) ), // if not exit(*sys.exc_info()): // raise AstUtils.IfThen( GlobalParent.Convert( typeof(bool), ConversionResultKind.ExplicitCast, GlobalParent.Operation( typeof(bool), PythonOperationKind.IsFalse, MakeExitCall(exit, exception) ) ), UpdateLineUpdated(true), Ast.Throw( Ast.Call( AstMethods.MakeRethrowExceptionWorker, exception ) ) ) ), _body.Span ) ), PopLineUpdated(lineUpdated), Ast.Empty() ) // finally: ).Finally( Ast.Call(AstMethods.RestoreCurrentException, previousException), // if exc: // exit(None, None, None) AstUtils.IfThen( exc, GlobalParent.AddDebugInfoAndVoid( Ast.Block( MSAst.DynamicExpression.Dynamic( GlobalParent.PyContext.Invoke( new CallSignature(3) // signature doesn't include function ), typeof(object), new MSAst.Expression[] { Parent.LocalContext, exit, AstUtils.Constant(null), AstUtils.Constant(null), AstUtils.Constant(null) } ), Ast.Empty() ), _contextManager.Span ) ) ) ); statements.Add(AstUtils.Empty()); return(Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection())); }
/// <summary> /// Creates the LambdaExpression which implements the body of the function. /// /// The functions signature is either "object Function(PythonFunction, ...)" /// where there is one object parameter for each user defined parameter or /// object Function(PythonFunction, object[]) for functions which take more /// than PythonCallTargets.MaxArgs arguments. /// </summary> private LightLambdaExpression CreateFunctionLambda() { bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs; Delegate originalDelegate; Type delegateType = GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate); MSAst.ParameterExpression localContext = null; ReadOnlyCollectionBuilder <MSAst.ParameterExpression> locals = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(); if (NeedsLocalContext) { localContext = LocalCodeContextVariable; locals.Add(localContext); } MSAst.ParameterExpression[] parameters = CreateParameters(needsWrapperMethod, locals); List <MSAst.Expression> init = new List <MSAst.Expression>(); foreach (var param in _parameters) { IPythonVariableExpression pyVar = GetVariableExpression(param.PythonVariable) as IPythonVariableExpression; if (pyVar != null) { var varInit = pyVar.Create(); if (varInit != null) { init.Add(varInit); } } } // Transform the parameters. init.Add(Ast.ClearDebugInfo(GlobalParent.Document)); locals.Add(PythonAst._globalContext); init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContext))); GlobalParent.PrepareScope(locals, init); // Create variables and references. Since references refer to // parameters, do this after parameters have been created. CreateFunctionVariables(locals, init); // If the __class__ variable is used the a class method then we need to initialize it. // This must be done before parameter initialization (in case one of the parameters is called __class__). ClassDefinition parent = FindParentOfType <ClassDefinition>(); PythonVariable pVar; if (parent != null && TryGetVariable("__class__", out pVar)) { init.Add( AssignValue( GetVariableExpression(pVar), Ast.Call(AstMethods.LookupName, parent.Parent.LocalContext, Ast.Constant(parent.Name)) ) ); } // Initialize parameters - unpack tuples. // Since tuples unpack into locals, this must be done after locals have been created. InitializeParameters(init, needsWrapperMethod, parameters); List <MSAst.Expression> statements = new List <MSAst.Expression>(); // add beginning sequence point var start = GlobalParent.IndexToLocation(StartIndex); statements.Add(GlobalParent.AddDebugInfo( AstUtils.Empty(), new SourceSpan(new SourceLocation(0, start.Line, start.Column), new SourceLocation(0, start.Line, Int32.MaxValue)))); // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close(). // The exception traceback needs to come from the generator's method body, and so we must do the check and throw // from inside the generator. if (IsGenerator) { MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(SourceSpan.None); statements.Add(s1); } MSAst.ParameterExpression extracted = null; if (!IsGenerator && _canSetSysExcInfo) { // need to allocate the exception here so we don't share w/ exceptions made & freed // during the body. extracted = Ast.Parameter(typeof(Exception), "$ex"); locals.Add(extracted); } if (_body.CanThrow && !(_body is SuiteStatement) && _body.StartIndex != -1) { statements.Add(UpdateLineNumber(GlobalParent.IndexToLocation(_body.StartIndex).Line)); } statements.Add(Body); MSAst.Expression body = Ast.Block(statements); // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish. // // Wrap in // $temp = PythonOps.SaveCurrentException() // <body> // PythonOps.RestoreCurrentException($temp) // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class // before it's invoked. This is because the restoration must occur at every place the function returns from // a yield point. That's different than the finally semantics in a generator. if (extracted != null) { MSAst.Expression s = AstUtils.Try( Ast.Assign( extracted, Ast.Call(AstMethods.SaveCurrentException) ), body ).Finally( Ast.Call( AstMethods.RestoreCurrentException, extracted ) ); body = s; } if (_body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames) { body = AddFrame(LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty("__code__")), body); locals.Add(FunctionStackVariable); } body = AddProfiling(body); body = WrapScopeStatements(body, _body.CanThrow); body = Ast.Block(body, AstUtils.Empty()); body = AddReturnTarget(body); MSAst.Expression bodyStmt = body; if (localContext != null) { var createLocal = CreateLocalContext(_parentContext); init.Add( Ast.Assign( localContext, createLocal ) ); } init.Add(bodyStmt); bodyStmt = Ast.Block(init); // wrap a scope if needed bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt); return(AstUtils.LightLambda( typeof(object), delegateType, AddDefaultReturn(bodyStmt, typeof(object)), Name + "$" + Interlocked.Increment(ref _lambdaId), parameters )); }
public override MSAst.Expression Reduce() { // allocated all variables here so they won't be shared w/ other // locals allocated during the body or except blocks. MSAst.ParameterExpression?lineUpdated = null; MSAst.ParameterExpression?runElse = null; MSAst.ParameterExpression?previousExceptionContext = null; if (Else != null || _handlers.Length > 0) { lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_try"); if (Else != null) { runElse = Ast.Variable(typeof(bool), "run_else"); } } // don't allocate locals below here... MSAst.Expression body = Body; MSAst.Expression? @else = Else; MSAst.Expression? @catch; MSAst.Expression result; MSAst.ParameterExpression?exception; if (_handlers.Length > 0) { previousExceptionContext = Ast.Variable(typeof(Exception), "$previousException"); exception = Ast.Variable(typeof(Exception), "$exception"); @catch = TransformHandlers(exception, previousExceptionContext); } else if (Finally != null) { exception = Ast.Variable(typeof(Exception), "$exception"); @catch = null; } else { exception = null; @catch = null; } // We have else clause, must generate guard around it if (@else != null) { Debug.Assert(@catch != null); // run_else = true; // try { // try_body // } catch ( ... ) { // run_else = false; // catch_body // } // if (run_else) { // else_body // } result = Ast.Block( Ast.Assign(runElse, AstUtils.Constant(true)), // save existing line updated, we could choose to do this only for nested exception handlers. PushLineUpdated(false, lineUpdated), LightExceptions.RewriteExternal( AstUtils.Try( Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(HeaderIndex))), Ast.Assign(previousExceptionContext, Ast.Call(AstMethods.SaveCurrentException)), body, AstUtils.Constant(null) ).Catch(exception, Ast.Assign(runElse, AstUtils.Constant(false)), @catch, // restore existing line updated after exception handler completes PopLineUpdated(lineUpdated), Ast.Assign(exception, Ast.Constant(null, typeof(Exception))), AstUtils.Constant(null) ) ), AstUtils.IfThen(runElse, @else ), AstUtils.Empty() ); } else if (@catch != null) // no "else" clause // try { // <try body> // } catch (Exception e) { // ... catch handling ... // } // { result = LightExceptions.RewriteExternal( AstUtils.Try( GlobalParent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(HeaderIndex))), // save existing line updated PushLineUpdated(false, lineUpdated), Ast.Assign(previousExceptionContext, Ast.Call(AstMethods.SaveCurrentException)), body, AstUtils.Constant(null) ).Catch(exception, @catch, // restore existing line updated after exception handler completes PopLineUpdated(lineUpdated), Ast.Assign(exception, Ast.Constant(null, typeof(Exception))), AstUtils.Constant(null) ) ); } else { result = body; } return(Ast.Block( GetVariables(lineUpdated, runElse, previousExceptionContext), AddFinally(result), AstUtils.Default(typeof(void)) )); }
private MSAst.Expression TransformHandlers(MSAst.ParameterExpression exception, MSAst.ParameterExpression previousException) { Assert.NotEmpty(_handlers); MSAst.ParameterExpression extracted = Ast.Variable(typeof(object), "$extracted"); var tests = new List <Microsoft.Scripting.Ast.IfStatementTest>(_handlers.Length); MSAst.ParameterExpression?converted = null; MSAst.Expression? catchAll = null; for (int index = 0; index < _handlers.Length; index++) { TryStatementHandler tsh = _handlers[index]; if (tsh.Test != null) { Microsoft.Scripting.Ast.IfStatementTest ist; // translating: // except Test ... // // generate following AST for the Test (common part): // CheckException(exception, Test) MSAst.Expression test = Ast.Call( AstMethods.CheckException, Parent.LocalContext, extracted, AstUtils.Convert(tsh.Test, typeof(object)) ); if (tsh.Target != null) { // translating: // except Test as Target: // <body> // into: // if ((converted = CheckException(exception, Test)) != null) { // try { // Target = converted; // traceback-header // <body> // } // finally { // del Target // } // } if (converted == null) { converted = Ast.Variable(typeof(object), "$converted"); } ist = AstUtils.IfCondition( Ast.NotEqual( Ast.Assign(converted, test), AstUtils.Constant(null) ), Ast.TryFinally( Ast.Block( tsh.Target.TransformSet(SourceSpan.None, converted, PythonOperationKind.None), GlobalParent.AddDebugInfo( GetTracebackHeader(this, exception, tsh.Body), new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex)) ), AstUtils.Empty() ), Ast.Block( Ast.Call(AstMethods.RestoreCurrentException, previousException), tsh.Target.TransformSet(SourceSpan.None, AstUtils.Constant(null), PythonOperationKind.None), tsh.Target.TransformDelete() ) ) ); } else { // translating: // except Test: // <body> // into: // if (CheckException(exception, Test) != null) { // traceback-header // <body> // } ist = AstUtils.IfCondition( Ast.NotEqual( test, AstUtils.Constant(null) ), Ast.TryFinally( GlobalParent.AddDebugInfo( GetTracebackHeader(this, exception, tsh.Body), new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex)) ), Ast.Call(AstMethods.RestoreCurrentException, previousException) ) ); } // Add the test to the if statement test cascade tests.Add(ist); } else { Debug.Assert(index == _handlers.Length - 1); Debug.Assert(catchAll == null); // translating: // except: // <body> // into: // { // traceback-header // <body> // } catchAll = Ast.TryFinally( GlobalParent.AddDebugInfo( GetTracebackHeader(this, exception, tsh.Body), new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex)) ), Ast.Call(AstMethods.RestoreCurrentException, previousException) ); } } MSAst.Expression body; if (tests.Count > 0) { // rethrow the exception if we have no catch-all block if (catchAll == null) { catchAll = Ast.Block( Parent.GetSaveLineNumberExpression(exception, true), Ast.Throw( Ast.Call( typeof(ExceptionHelpers).GetMethod(nameof(ExceptionHelpers.UpdateForRethrow)), exception ) ) ); } body = AstUtils.If( tests.ToArray(), catchAll ); } else { Debug.Assert(catchAll != null); body = catchAll !; } IList <MSAst.ParameterExpression> args; if (converted != null) { args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> { converted, extracted }; } else { args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> { extracted }; } // Codegen becomes: // extracted = PythonOps.SetCurrentException(exception) // try: // < dynamic exception analysis > // extracted = None return(Ast.Block( args, Ast.Assign( extracted, Ast.Call(AstMethods.SetCurrentException, Parent.LocalContext, exception) ), body, Ast.Assign(extracted, Ast.Constant(null)), AstUtils.Empty() )); }
private MSAst.Expression AddFinally(MSAst.Expression /*!*/ body) { if (Finally != null) { MSAst.ParameterExpression tryThrows = Ast.Variable(typeof(Exception), "$tryThrows"); MSAst.ParameterExpression locException = Ast.Variable(typeof(Exception), "$localException"); MSAst.Expression? @finally = Finally; // 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( Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(HeaderIndex))), Ast.Assign(tryThrows, AstUtils.Constant(null, typeof(Exception))), body, AstUtils.Empty() ).Catch( locException, Expression.Block( // If there was no except block, or the except block threw, then the // exception has not yet been properly set, so we need to set the // currently handled exception when we catch it Ast.Call(AstMethods.SetCurrentException, Parent.LocalContext, locException), Ast.Assign(tryThrows, locException), Expression.Rethrow() ) ) ).FinallyWithJumps( // if we had an exception save the line # that was last executing during the try AstUtils.If( Expression.NotEqual(tryThrows, Expression.Default(typeof(Exception))), Parent.GetSaveLineNumberExpression(tryThrows, false) ), // clear the frames incase thae finally throws, and allow line number // updates to proceed UpdateLineUpdated(false), // run the finally code // if the finally block reraises the same exception we have been handling, // mark it as already updated AstUtils.Try( @finally ).Catch( locException, AstUtils.If( Expression.Equal(locException, tryThrows), UpdateLineUpdated(true) ), Expression.Rethrow() ), // 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( Expression.NotEqual(tryThrows, Expression.Default(typeof(Exception))), UpdateLineUpdated(true) ) ); body = Ast.Block(new[] { tryThrows }, body); } return(body); }
internal override MSAst.Expression Transform(MSAst.Expression body) { MSAst.ParameterExpression temp = Ast.Parameter(typeof(KeyValuePair <IEnumerator, IDisposable>), "list_comprehension_for"); return(Ast.Block( new[] { temp }, ForStatement.TransformFor(Parent, temp, _list, _lhs, body, null, Span, GlobalParent.IndexToLocation(_lhs.EndIndex), null, null, false) )); }
public override MSAst.Expression Reduce() { // Temporary variable for the IEnumerator object MSAst.ParameterExpression enumerator = Ast.Variable(typeof(KeyValuePair <IEnumerator, IDisposable>), "foreach_enumerator"); return(Ast.Block(new[] { enumerator }, TransformFor(Parent, enumerator, _list, _left, _body, _else, Span, GlobalParent.IndexToLocation(_headerIndex), _break, _continue, true))); }
private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert) { MSAst.Expression result; if (_tests.Length > 100) { // generate: // if(x) { // body // goto end // } else { // } // elseBody // end: // // to avoid deeply recursive trees which can stack overflow. BlockBuilder builder = new BlockBuilder(); var label = Ast.Label(); for (int i = 0; i < _tests.Length; i++) { IfStatementTest ist = _tests[i]; builder.Add( Ast.Condition( optimizeDynamicConvert ? TransformAndDynamicConvert(ist.Test, typeof(bool)) : GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test), Ast.Block( TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)), Ast.Goto(label) ), Utils.Empty() ) ); } if (_else != null) { builder.Add(_else); } builder.Add(Ast.Label(label)); result = builder.ToExpression(); } else { // Now build from the inside out if (_else != null) { result = _else; } else { result = AstUtils.Empty(); } int i = _tests.Length; while (i-- > 0) { IfStatementTest ist = _tests[i]; result = GlobalParent.AddDebugInfoAndVoid( Ast.Condition( optimizeDynamicConvert ? TransformAndDynamicConvert(ist.Test, typeof(bool)) : GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test), TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)), result ), new SourceSpan(GlobalParent.IndexToLocation(ist.StartIndex), GlobalParent.IndexToLocation(ist.HeaderIndex)) ); } } return(result); }
public override MSAst.Expression Reduce() { // Temporary variable for the IEnumerator object MSAst.ParameterExpression enumerator = Ast.Variable(typeof(KeyValuePair <IEnumerator, IDisposable>), "foreach_enumerator"); return(Ast.Block(new[] { enumerator }, TransformFor(Parent, enumerator, List, Left, Body, Else, Span, GlobalParent.IndexToLocation(HeaderIndex), ((ILoopStatement)this).BreakLabel, ((ILoopStatement)this).ContinueLabel, true))); }