If() public static method

public static If ( IfStatementTest tests, Expression @else ) : Expression
tests IfStatementTest
@else Expression
return Expression
Ejemplo n.º 1
0
        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(
                            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
                    @finally,

                    // 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);
        }
Ejemplo n.º 2
0
 internal override MSAst.Expression Transform(MSAst.Expression body)
 {
     return(GlobalParent.AddDebugInfoAndVoid(
                AstUtils.If(
                    GlobalParent.Convert(typeof(bool), ConversionResultKind.ExplicitCast, _test),
                    body
                    ),
                Span
                ));
 }
Ejemplo n.º 3
0
        private void CreatePushFrameExpression()
        {
            _pushFrame = Ast.Block(
                Ast.Assign(_framePushed, Ast.Constant(true)),

                // Get thread
                Ast.Assign(
                    _thread,
                    AstUtils.SimpleCallHelper(
                        typeof(RuntimeOps).GetMethod("GetCurrentThread"),
                        _debugContextExpression
                        )
                    ),

                _debugContext.ThreadFactory.CreatePushFrameExpression(_funcInfo, _debugMarker, _verifiedLocals, _variableInfos, _thread)
                );

            _conditionalPushFrame = AstUtils.If(
                Ast.Equal(_framePushed, Ast.Constant(false)),
                _pushFrame
                );
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Transform multiple python except handlers for a try block into a single catch body.
        /// </summary>
        /// <param name="exception">The variable for the exception in the catch block.</param>
        /// <returns>Null if there are no except handlers. Else the statement to go inside the catch handler</returns>
        private MSAst.Expression TransformHandlers(MSAst.ParameterExpression exception)
        {
            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, Target:
                        //          <body>
                        //  into:
                        //      if ((converted = CheckException(exception, Test)) != null) {
                        //          Target = converted;
                        //          traceback-header
                        //          <body>
                        //      }

                        if (converted == null)
                        {
                            converted = Ast.Variable(typeof(object), "$converted");
                        }

                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                Ast.Assign(converted, test),
                                AstUtils.Constant(null)
                                ),
                            Ast.Block(
                                tsh.Target.TransformSet(SourceSpan.None, converted, PythonOperationKind.None),
                                GlobalParent.AddDebugInfo(
                                    GetTracebackHeader(
                                        this,
                                        exception,
                                        tsh.Body
                                        ),
                                    new SourceSpan(tsh.Start, tsh.Header)
                                    ),
                                AstUtils.Empty()
                                )
                            );
                    }
                    else
                    {
                        //  translating:
                        //      except Test:
                        //          <body>
                        //  into:
                        //      if (CheckException(exception, Test) != null) {
                        //          traceback-header
                        //          <body>
                        //      }
                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                test,
                                AstUtils.Constant(null)
                                ),
                            GlobalParent.AddDebugInfo(
                                GetTracebackHeader(
                                    this,
                                    exception,
                                    tsh.Body
                                    ),
                                new SourceSpan(tsh.Start, tsh.Header)
                                )
                            );
                    }

                    // 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 = GlobalParent.AddDebugInfo(
                        GetTracebackHeader(this, exception, tsh.Body),
                        new SourceSpan(tsh.Start, tsh.Header)
                        );
                }
            }

            MSAst.Expression body = null;

            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("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)
            //      < dynamic exception analysis >
            return(Ast.Block(
                       args,
                       Ast.Assign(
                           extracted,
                           Ast.Call(
                               AstMethods.SetCurrentException,
                               Parent.LocalContext,
                               exception
                               )
                           ),
                       body,
                       Ast.Assign(extracted, Ast.Constant(null)),
                       AstUtils.Empty()
                       ));
        }
Ejemplo n.º 5
0
        private MSAst.LambdaExpression CreateOuterLambda(Type lambdaType, MSAst.Expression debuggableBody)
        {
            List <MSAst.Expression> bodyExpressions    = new List <MSAst.Expression>();
            List <MSAst.Expression> tryExpressions     = new List <MSAst.Expression>();
            List <MSAst.Expression> finallyExpressions = new List <MSAst.Expression>();

            Type returnType = lambdaType.GetMethod("Invoke").ReturnType;

            MSAst.LabelTarget returnLabelTarget = Ast.Label(returnType);

            // Init $funcInfo
            tryExpressions.Add(
                Ast.Assign(
                    _funcInfo,
                    Ast.Convert(_functionInfo, typeof(FunctionInfo))
                    )
                );

            // Init $traceLocations
            // $TODO: only do this if we're in TracePoints mode
            tryExpressions.Add(
                Ast.Assign(
                    _traceLocations,
                    Ast.Call(typeof(RuntimeOps).GetMethod("GetTraceLocations"), _funcInfo)
                    )
                );

            // Init sourceFile locals
            foreach (var entry in _sourceFilesMap)
            {
                tryExpressions.Add(
                    Ast.Assign(
                        entry.Value,
                        Ast.Constant(entry.Key, typeof(DebugSourceFile))
                        )
                    );
            }

            if (_noPushFrameOptimization)
            {
                tryExpressions.Add(_pushFrame);
            }

            tryExpressions.Add(Ast.Call(
                                   typeof(RuntimeOps).GetMethod("OnFrameEnterTraceEvent"),
                                   _thread
                                   ));

            var frameExit = AstUtils.If(
                Ast.Equal(
                    _debugMarkerLocationMap.Length > 0 ?
                    Ast.Property(_sourceFilesMap[_debugMarkerLocationMap[0].SourceFile], "Mode") :
                    _globalDebugMode,
                    AstUtils.Constant((int)DebugMode.FullyEnabled)
                    ),
                Ast.Call(
                    typeof(RuntimeOps).GetMethod("OnFrameExitTraceEvent"),
                    _thread,
                    _debugMarker,
                    _retVal != null ? (MSAst.Expression)Ast.Convert(_retVal, typeof(object)) : Ast.Constant(null)
                    )
                );

            // normal exit
            tryExpressions.Add(
                Ast.Block(
                    _retVal != null ? Ast.Assign(_retVal, debuggableBody) : debuggableBody,
                    Ast.Assign(_frameExitException, Ast.Constant(true)),
                    frameExit)
                );

            tryExpressions.Add(
                _retVal != null ? (MSAst.Expression)Ast.Return(returnLabelTarget, _retVal) : Ast.Empty()
                );

            MSAst.Expression[] popFrame = new MSAst.Expression[] {
                AstUtils.If(
                    // Fire thead-exit event if PopFrame returns true
                    Ast.AndAlso(
                        Ast.Equal(Ast.Call(typeof(RuntimeOps).GetMethod("PopFrame"), _thread), Ast.Constant(true)),
                        Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled))
                        ),
                    Ast.Call(
                        typeof(RuntimeOps).GetMethod("OnThreadExitEvent"),
                        _thread
                        )
                    )
            };

            if (_noPushFrameOptimization)
            {
                finallyExpressions.AddRange(popFrame);
            }
            else
            {
                finallyExpressions.Add(
                    AstUtils.If(
                        Ast.Equal(_framePushed, Ast.Constant(true)),
                        popFrame
                        )
                    );
            }

            MSAst.ParameterExpression caughtException;

            // Run the function body
            bodyExpressions.Add(Ast.TryCatchFinally(
                                    Ast.TryCatch(
                                        Ast.Block(
                                            ArrayUtils.Append(tryExpressions.ToArray(), Ast.Default(returnType))
                                            ),
                                        Ast.Catch(
                                            caughtException = Ast.Variable(typeof(Exception), "$caughtException"),
                                            Ast.Block(
                                                // The expressions below will always throw.
                                                // If the exception needs to be cancelled then OnTraceEvent will throw ForceToGeneratorLoopException.
                                                // If the exception is not being cancelled then we'll just rethrow at the end of the catch block.
                                                AstUtils.If(
                                                    Ast.Not(
                                                        Ast.TypeIs(
                                                            caughtException,
                                                            typeof(ForceToGeneratorLoopException)
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(_globalDebugMode, AstUtils.Constant((int)DebugMode.Disabled)),
                                                        _noPushFrameOptimization ? Ast.Empty() : _conditionalPushFrame,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("OnTraceEventUnwind"),
                                                            _thread,
                                                            _debugMarker,
                                                            caughtException
                                                            )
                                                        ),
                                                    // exception exit
                                                    AstUtils.If(
                                                        Ast.Not(_frameExitException),
                                                        frameExit
                                                        )
                                                    ),

                                                Ast.Rethrow(),

                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                )
                                            )
                                        ),
                                    Ast.Block(finallyExpressions),
                                    Ast.Catch(
                                        typeof(ForceToGeneratorLoopException),
                                        Ast.TryFinally(
                                            // Handle ForceToGeneratorLoopException
                                            Ast.Block(
                                                returnType != typeof(void) ? Ast.Block(
                                                    Ast.Assign(
                                                        _retValFromGeneratorLoop,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                            _thread
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(
                                                            _retValFromGeneratorLoop,
                                                            Ast.Constant(null)
                                                            ),
                                                        Ast.Assign(_retVal, Ast.Convert(_retValFromGeneratorLoop, returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Convert(_retValFromGeneratorLoop, returnType)
                                                            )
                                                        ).Else(
                                                        Ast.Assign(_retVal, Ast.Default(returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Default(returnType)
                                                            )
                                                        )
                                                    ) :
                                                Ast.Block(
                                                    Ast.Call(
                                                        typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                        _thread
                                                        ),
                                                    Ast.Return(returnLabelTarget)
                                                    )
                                                ,
                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                ),
                                            // Make sure that the debugMarker is up-to-date after the generator loop
                                            Ast.Assign(
                                                _debugMarker,
                                                Ast.Call(
                                                    typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForLeafGeneratorFrame"),
                                                    _thread
                                                    )
                                                )
                                            )
                                        )
                                    ));

            MSAst.Expression body = Ast.Block(bodyExpressions);

            if (body.Type == typeof(void) && returnType != typeof(void))
            {
                body = Ast.Block(body, Ast.Default(returnType));
            }

            return(Ast.Lambda(
                       lambdaType,
                       Ast.Block(
                           _lambdaVars,
                           Ast.Label(returnLabelTarget, body)
                           ),
                       _alias,
                       _lambdaParams));
        }
Ejemplo n.º 6
0
        protected override MSAst.Expression VisitTry(MSAst.TryExpression node)
        {
            MSAst.Expression b = Visit(node.Body);
            ReadOnlyCollection <MSAst.CatchBlock> h = Visit(node.Handlers, VisitCatchBlock);

            MSAst.Expression y = Visit(node.Finally);
            MSAst.Expression f;

            _insideConditionalBlock = true;
            try {
                f = Visit(node.Fault);
            } finally {
                _insideConditionalBlock = false;
            }

            node = Ast.MakeTry(node.Type, b, y, f, h);

            List <MSAst.CatchBlock> newHandlers = null;

            MSAst.Expression newFinally = null;

            // If the TryStatement has any Catch blocks we need to insert the exception
            // event as a first statement so that we can be notified of first-chance exceptions.
            if (node.Handlers != null && node.Handlers.Count > 0)
            {
                newHandlers = new List <MSAst.CatchBlock>();

                foreach (var catchBlock in node.Handlers)
                {
                    MSAst.ParameterExpression exceptionVar = catchBlock.Variable != null ? catchBlock.Variable : Ast.Parameter(catchBlock.Test, null);

                    MSAst.Expression debugMarker, thread;
                    if (_transformToGenerator)
                    {
                        debugMarker = Ast.Call(
                            typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForGeneratorFrame"),
                            _frame
                            );

                        thread = Ast.Call(typeof(RuntimeOps).GetMethod("GetThread"), _frame);
                    }
                    else
                    {
                        debugMarker = _debugMarker;
                        thread      = _thread;
                    }

                    MSAst.Expression exceptionEvent = Ast.Block(
                        // Rethrow ForceToGeneratorLoopException
                        AstUtils.If(
                            Ast.TypeIs(
                                exceptionVar,
                                typeof(ForceToGeneratorLoopException)
                                ),
                            Ast.Throw(exceptionVar)
                            ),
                        AstUtils.If(
                            Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled)),
                            (_pushFrame != null) ? _pushFrame : Ast.Empty(),
                            Ast.Call(
                                typeof(RuntimeOps).GetMethod("OnTraceEvent"),
                                thread,
                                debugMarker,
                                exceptionVar
                                )
                            )
                        );

                    newHandlers.Add(Ast.MakeCatchBlock(
                                        catchBlock.Test,
                                        exceptionVar,
                                        Ast.Block(
                                            exceptionEvent,
                                            catchBlock.Body
                                            ),
                                        catchBlock.Filter
                                        ));
                }
            }

            if (!_transformToGenerator && node.Finally != null)
            {
                // Prevent the user finally block from running if the frame is currently remapping to generator
                newFinally = AstUtils.If(
                    Ast.Not(
                        Ast.Call(
                            typeof(RuntimeOps).GetMethod("IsCurrentLeafFrameRemappingToGenerator"),
                            _thread
                            )
                        ),
                    node.Finally
                    );
            }

            if (newHandlers != null || newFinally != null)
            {
                node = Ast.MakeTry(
                    node.Type,
                    node.Body,
                    newFinally != null ? newFinally : node.Finally,
                    node.Fault,
                    newHandlers != null ? newHandlers : newHandlers
                    );
            }

            return(node);
        }
Ejemplo n.º 7
0
        private MSA.Expression /*!*/ TransformExceptionHandling(AstGenerator /*!*/ gen, ResultOperation resultOperation)
        {
            Assert.NotNull(gen);

            MSA.Expression exceptionThrownVariable  = gen.CurrentScope.DefineHiddenVariable("#exception-thrown", typeof(bool));
            MSA.Expression exceptionRethrowVariable = gen.CurrentScope.DefineHiddenVariable("#exception-rethrow", typeof(bool));
            MSA.Expression retryingVariable         = gen.CurrentScope.DefineHiddenVariable("#retrying", typeof(bool));
            MSA.Expression oldExceptionVariable     = gen.CurrentScope.DefineHiddenVariable("#old-exception", typeof(Exception));

            MSA.ParameterExpression unwinder, exceptionVariable;
            MSA.Expression          transformedBody;
            MSA.Expression          transformedEnsure;
            MSA.Expression          transformedElse;

            if (_ensureStatements != null)
            {
                transformedEnsure = Ast.Block(
                    // ensure:
                    Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),
                    gen.TransformStatements(_ensureStatements, ResultOperation.Ignore),
                    Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable),

                    // rethrow:
                    AstUtils.IfThen(
                        Ast.AndAlso(
                            exceptionRethrowVariable,
                            Ast.NotEqual(oldExceptionVariable, AstUtils.Constant(null))
                            ),
                        Ast.Throw(oldExceptionVariable)
                        )
                    );
            }
            else
            {
                // rethrow:
                transformedEnsure = AstUtils.IfThen(
                    Ast.AndAlso(
                        exceptionRethrowVariable,
                        Ast.NotEqual(
                            Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),
                            AstUtils.Constant(null, typeof(Exception)))
                        ),
                    Ast.Throw(oldExceptionVariable)
                    );
            }

            if (_elseStatements != null)
            {
                transformedElse = gen.TransformStatements(_elseStatements, resultOperation);
            }
            else
            {
                transformedElse = AstUtils.Empty();
            }

            // body should do return, but else-clause is present => we cannot do return from the guarded statements:
            // (the value of the last expression in the body cannot be the last executed expression statement => we can ignore it):
            transformedBody = gen.TransformStatements(_statements, (_elseStatements != null) ? ResultOperation.Ignore : resultOperation);

            MSA.Expression enterRescue = null, leaveRescue = null;
            var            retryLabel = Ast.Label("retry");

            // make rescue clause:
            MSA.Expression transformedRescue;
            if (_rescueClauses != null)
            {
                // outer-most EH blocks sets and clears runtime flag RuntimeFlowControl.InTryRescue:
                if (gen.CurrentRescue == null)
                {
                    enterRescue = Methods.EnterRescue.OpCall(gen.CurrentScopeVariable);
                    leaveRescue = Methods.LeaveRescue.OpCall(gen.CurrentScopeVariable);
                }
                else
                {
                    enterRescue = leaveRescue = AstUtils.Empty();
                }

                gen.EnterRescueClause(retryingVariable, retryLabel);

                var handlers = new IfStatementTest[_rescueClauses.Count];
                for (int i = 0; i < handlers.Length; i++)
                {
                    handlers[i] = _rescueClauses[i].Transform(gen, resultOperation);
                }

                transformedRescue =
                    AstUtils.Try(
                        enterRescue,
                        AstUtils.If(handlers, Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)))
                        ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"),
                                 Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstUtils.Constant(BlockReturnReason.Retry)),

                                 Ast.Block(
                                     Ast.Assign(retryingVariable, AstUtils.Constant(true)),
                                     Ast.Continue(retryLabel),
                                     AstUtils.Empty()
                                     )
                                 );


                gen.LeaveRescueClause();
            }
            else
            {
                transformedRescue = Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true));
            }

            if (_elseStatements != null)
            {
                transformedElse = AstUtils.Unless(exceptionThrownVariable, transformedElse);
            }

            var result = Ast.Block(
                Ast.Label(retryLabel),
                AstUtils.Try(
                    Ast.Assign(exceptionThrownVariable, AstUtils.Constant(false)),
                    Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(false)),
                    Ast.Assign(retryingVariable, AstUtils.Constant(false)),

                    // save exception (old_$! is not used unless there is a rescue clause):
                    (_rescueClauses == null) ? (MSA.Expression)AstUtils.Empty() :
                    Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),

                    AstUtils.Try(
                        Ast.Block(transformedBody, AstUtils.Empty())
                        ).Filter(exceptionVariable = Ast.Parameter(typeof(Exception), "#e"),
                                 Methods.CanRescue.OpCall(gen.CurrentScopeVariable, exceptionVariable),

                                 Ast.Assign(exceptionThrownVariable, AstUtils.Constant(true)),
                                 transformedRescue,
                                 AstUtils.Empty()
                                 ).FinallyIf((_rescueClauses != null),
                                             // restore previous exception if the current one has been handled:
                                             AstUtils.Unless(exceptionRethrowVariable,
                                                             Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable)
                                                             ),
                                             leaveRescue
                                             ),

                    // unless (exception_thrown) do <else-statements> end
                    transformedElse,
                    AstUtils.Empty()
                    ).FilterIf((_rescueClauses != null || _elseStatements != null),
                               exceptionVariable = Ast.Parameter(typeof(Exception), "#e"),
                               Methods.CanRescue.OpCall(gen.CurrentScopeVariable, exceptionVariable),

                               Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)),
                               AstUtils.Empty()
                               ).FinallyWithJumps(
                    AstUtils.Unless(retryingVariable, transformedEnsure)
                    )
                );

            return(result);
        }
Ejemplo n.º 8
0
        private MSAst.Expression AddFinally(MSAst.Expression /*!*/ body, MSAst.ParameterExpression nestedException)
        {
            if (_finally != null)
            {
                Debug.Assert(nestedException != null);

                MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List <DynamicStackFrame>), "$nestedFrames");

                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, _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,
                        Parent.GetSaveLineNumberExpression(false)
                        ),

                    // clear the frames incase thae finally throws, and allow line number
                    // updates to proceed
                    UpdateLineUpdated(false),
                    Ast.Assign(
                        nestedFrames,
                        Ast.Call(AstMethods.GetAndClearDynamicStackFrames)
                        ),

                    // run the finally code
                    @finally,

                    // if the finally exits normally restore any previous exception info
                    Ast.Call(
                        AstMethods.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,
                        UpdateLineUpdated(true)
                        )
                    );

                body = Ast.Block(new[] { nestedFrames }, body);
            }
            return(body);
        }