LeaveRescueClause() public method

public LeaveRescueClause ( ) : void
return void
Esempio n. 1
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);
        }
Esempio n. 2
0
        private MSA.Expression/*!*/ TransformExceptionHandling(AstGenerator/*!*/ gen, ResultOperation resultOperation) {
            Assert.NotNull(gen);

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

            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)
                    ),
                    AstUtils.Empty()
                );
            } 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 setInRescueFlag = null, clearInRescueFlag = null;
            var breakLabel = Ast.Label();
            var continueLabel = Ast.Label();

            // make rescue clause:
            MSA.Expression transformedRescue;
            if (_rescueClauses != null) {
                // outer-most EH blocks sets and clears runtime flag RuntimeFlowControl.InTryRescue:
                if (gen.CurrentRescue == null) {
                    setInRescueFlag = Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InRescueField), AstUtils.Constant(true));
                    clearInRescueFlag = Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InRescueField), AstUtils.Constant(false));
                } else {
                    setInRescueFlag = clearInRescueFlag = AstUtils.Empty();
                }

                gen.EnterRescueClause(retryingVariable, breakLabel, continueLabel);

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

                transformedRescue = Ast.Block(
                    setInRescueFlag,
                    AstUtils.Try(
                        AstUtils.If(handlers, Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)))
                    ).Filter(evalUnwinder, Ast.Equal(Ast.Field(evalUnwinder, EvalUnwinder.ReasonField), AstUtils.Constant(BlockReturnReason.Retry)),
                        Ast.Block(
                            Ast.Assign(retryingVariable, AstUtils.Constant(true)),
                            Ast.Continue(continueLabel),
                            AstUtils.Empty()
                        )
                    )
                );

                gen.LeaveRescueClause();

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

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

            var result = AstFactory.Infinite(breakLabel, continueLabel,
                Ast.Assign(exceptionThrownVariable, AstUtils.Constant(false)),
                Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(false)),
                Ast.Assign(retryingVariable, AstUtils.Constant(false)),

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

                        AstUtils.Try(
                            Ast.Block(transformedBody, AstUtils.Empty())
                        ).Filter(exceptionVariable, Methods.CanRescue.OpCall(gen.CurrentRfcVariable, exceptionVariable),
                            Ast.Assign(exceptionThrownVariable, AstUtils.Constant(true)),
                            Methods.SetCurrentExceptionAndStackTrace.OpCall(gen.CurrentScopeVariable, exceptionVariable),
                            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)
                            ),
                            clearInRescueFlag
                        ),

                        // unless (exception_thrown) do <else-statements> end
                        transformedElse,
                        AstUtils.Empty()
                    )
                ).FilterIf((_rescueClauses != null || _elseStatements != null),
                    exceptionVariable, Methods.CanRescue.OpCall(gen.CurrentRfcVariable, exceptionVariable),
                    Ast.Block(
                        Methods.SetCurrentExceptionAndStackTrace.OpCall(gen.CurrentScopeVariable, exceptionVariable),
                        Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)),
                        AstUtils.Empty()
                    )
                ).Finally(
                    AstUtils.Unless(retryingVariable, transformedEnsure)
                ),

                Ast.Break(breakLabel)
            );

            return result;
        }