private TransformStatements ( Statements statements, ResultOperation resultOperation ) : |
||
statements | Statements | |
resultOperation | ResultOperation | |
return |
private void TransformBody(AstGenerator /*!*/ gen) { ScopeBuilder scope = DefineLocals(); var scopeVariable = gen.TopLevelScope.Builder.DefineHiddenVariable("#scope", typeof(RubyScope)); gen.EnterFileInitializer( scope, gen.TopLevelScope.SelfVariable, scopeVariable ); // visit nested initializers depth-first: var body = gen.TransformStatements(_statements, ResultOperation.Ignore); gen.LeaveFileInitializer(); gen.AddFileInitializer( scope.CreateScope( scopeVariable, Methods.CreateFileInitializerScope.OpCall( scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), gen.TopLevelScope.RuntimeScopeVariable ), body ) ); }
private void TransformBody(AstGenerator/*!*/ gen) { ScopeBuilder scope = DefineLocals(); var scopeVariable = gen.TopLevelScope.Builder.DefineHiddenVariable("#scope", typeof(RubyScope)); gen.EnterFileInitializer( scope, gen.TopLevelScope.SelfVariable, scopeVariable ); // visit nested initializers depth-first: var body = gen.TransformStatements(_statements, ResultOperation.Ignore); gen.LeaveFileInitializer(); gen.AddFileInitializer( scope.CreateScope( scopeVariable, Methods.CreateFileInitializerScope.OpCall( scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), gen.TopLevelScope.RuntimeScopeVariable ), body ) ); }
// // rescue stmts ... if (StandardError === $!) { stmts; } // rescue <types> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; } // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; } // internal IfStatementTest /*!*/ Transform(AstGenerator /*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); MSA.Expression condition; if (_types.Length != 0) { var comparisonSiteStorage = Ast.Constant(new BinaryOpStorage(gen.Context)); if (_types.Length == 1) { condition = MakeCompareException(gen, comparisonSiteStorage, _types[0].TransformRead(gen), _types[0] is SplattedArgument); } else { // forall{i}: <temps[i]> = evaluate type[i] var temps = new MSA.Expression[_types.Length]; var exprs = new BlockBuilder(); for (int i = 0; i < _types.Length; i++) { var t = _types[i].TransformRead(gen); var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, t.Type); temps[i] = tmp; exprs.Add(Ast.Assign(tmp, t)); } // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>) condition = MakeCompareException(gen, comparisonSiteStorage, temps[0], _types[0] is SplattedArgument); for (int i = 1; i < _types.Length; i++) { condition = Ast.OrElse(condition, MakeCompareException(gen, comparisonSiteStorage, temps[i], _types[i] is SplattedArgument)); } // (temps[0] = type[0], ..., temps[n] == type[n], condition) exprs.Add(condition); condition = exprs; } } else { condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable); } return(AstUtils.IfCondition(condition, gen.TransformStatements( // <lvalue> = e; (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null, // body: _statements, resultOperation ) )); }
internal override MSA.Expression /*!*/ TransformResult(AstGenerator /*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); if (HasExceptionHandling) { return(TransformExceptionHandling(gen, resultOperation)); } else { return(gen.TransformStatements(_statements, resultOperation)); } }
// // rescue stmts ... if (StandardError === $!) { stmts; } // rescue <types> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; } // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; } // internal IfStatementTest/*!*/ Transform(AstGenerator/*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); MSA.Expression condition; if (_types.Length != 0 || _splatType != null) { var comparisonSiteStorage = Ast.Constant(new BinaryOpStorage(gen.Context)); if (_types.Length == 0) { // splat only: condition = MakeCompareSplattedExceptions(gen, comparisonSiteStorage, TransformSplatType(gen)); } else if (_types.Length == 1 && _splatType == null) { condition = MakeCompareException(gen, comparisonSiteStorage, _types[0].TransformRead(gen)); } else { // forall{i}: <temps[i]> = evaluate type[i] var temps = new MSA.Expression[_types.Length + (_splatType != null ? 1 : 0)]; var exprs = new MSA.Expression[temps.Length + 1]; int i = 0; while (i < _types.Length) { var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object)); temps[i] = tmp; exprs[i] = Ast.Assign(tmp, _types[i].TransformRead(gen)); i++; } if (_splatType != null) { var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object)); temps[i] = tmp; exprs[i] = Ast.Assign(tmp, TransformSplatType(gen)); i++; } Debug.Assert(i == temps.Length); // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>) i = 0; condition = MakeCompareException(gen, comparisonSiteStorage, temps[i++]); while (i < _types.Length) { condition = Ast.OrElse(condition, MakeCompareException(gen, comparisonSiteStorage, temps[i++])); } if (_splatType != null) { condition = Ast.OrElse(condition, MakeCompareSplattedExceptions(gen, comparisonSiteStorage, temps[i++])); } Debug.Assert(i == temps.Length); // (temps[0] = type[0], ..., temps[n] == type[n], condition) exprs[exprs.Length - 1] = condition; condition = AstFactory.Block(exprs); } } else { condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable); } return AstUtils.IfCondition(condition, gen.TransformStatements( // <lvalue> = e; (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null, // body: _statements, resultOperation ) ); }
internal MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen, bool isLambda) { ScopeBuilder scope = DefineLocals(gen.CurrentScope); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.ParameterExpression blockParameter, selfParameter; var parameters = DefineParameters(out selfParameter, out blockParameter); MSA.ParameterExpression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder, filterVariable; MSA.Expression traceCall, traceReturn; if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body.First.Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body.Last.Location.End.Line : Location.End.Line; traceCall = Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(firstStatementLine)); traceReturn = Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(lastStatementLine)); } else { traceCall = traceReturn = Ast.Empty(); } MSA.Expression body = AstUtils.Try( paramInit, traceCall, Ast.Label(redoLabel), AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Goto(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ).Filter(filterVariable = Ast.Parameter(typeof(Exception), "#e"), Methods.FilterBlockException.OpCall(scopeVariable, filterVariable) ).Finally( traceReturn, Ast.Empty() ); body = gen.AddReturnTarget( scope.CreateScope( scopeVariable, Methods.CreateBlockScope.OpCall(new AstExpressions { scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), blockParameter, selfParameter, EnterInterpretedFrameExpression.Instance }), body ) ); gen.LeaveBlockDefinition(); int parameterCount = ParameterCount; var attributes = _parameters.GetBlockSignatureAttributes(); var dispatcher = Ast.Constant( BlockDispatcher.Create(parameterCount, attributes, gen.SourcePath, Location.Start.Line), typeof(BlockDispatcher) ); return(Ast.Coalesce( (isLambda ? Methods.InstantiateLambda : Methods.InstantiateBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher), (isLambda ? Methods.DefineLambda : Methods.DefineBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher, BlockDispatcher.CreateLambda( body, RubyStackTraceBuilder.EncodeMethodName(gen.CurrentMethod.MethodName, gen.SourcePath, Location, gen.DebugMode), parameters, parameterCount, attributes ) ) )); }
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); }
internal MSA.Expression <T> /*!*/ Transform <T>(AstGenerator /*!*/ gen) { Debug.Assert(gen != null); ScopeBuilder scope = new ScopeBuilder(); MSA.ParameterExpression[] parameters; MSA.Expression selfVariable; MSA.Expression rfcVariable; MSA.Expression parentScope; MSA.Expression language; MSA.Expression runtimeScopeVariable; MSA.Expression moduleVariable; MSA.Expression blockParameter; MSA.Expression currentMethodVariable; if (gen.CompilerOptions.IsEval) { parameters = new MSA.ParameterExpression[6]; parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope"); selfVariable = parameters[1] = Ast.Parameter(typeof(object), "#self"); parameters[2] = Ast.Parameter(typeof(RubyModule), "#module"); blockParameter = parameters[3] = Ast.Parameter(typeof(Proc), "#block"); currentMethodVariable = parameters[4] = Ast.Parameter(typeof(RubyMethodInfo), "#method"); rfcVariable = parameters[5] = Ast.Parameter(typeof(RuntimeFlowControl), "#rfc"); if (gen.CompilerOptions.IsModuleEval) { runtimeScopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyScope)); parentScope = parameters[0]; moduleVariable = parameters[2]; } else { runtimeScopeVariable = parameters[0]; moduleVariable = null; parentScope = null; } language = null; } else { parameters = new MSA.ParameterExpression[2]; parentScope = parameters[0] = Ast.Parameter(typeof(Scope), "#globalScope"); language = parameters[1] = Ast.Parameter(typeof(LanguageContext), "#language"); selfVariable = scope.DefineHiddenVariable("#self", typeof(object)); rfcVariable = scope.DefineHiddenVariable("#rfc", typeof(RuntimeFlowControl)); runtimeScopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyScope)); blockParameter = null; currentMethodVariable = null; moduleVariable = null; } gen.EnterSourceUnit( scope, selfVariable, runtimeScopeVariable, blockParameter, rfcVariable, currentMethodVariable, gen.CompilerOptions.TopLevelMethodName, // method name null // parameters ); _definedScope.TransformLocals(scope); MSA.Expression scopeFactoryCall; if (gen.CompilerOptions.IsEval) { if (gen.CompilerOptions.IsModuleEval) { scopeFactoryCall = Methods.CreateModuleEvalScope.OpCall( scope.VisibleVariables(), parentScope, selfVariable, moduleVariable ); } else { scopeFactoryCall = null; } } else if (!gen.CompilerOptions.IsIncluded) { scopeFactoryCall = Methods.CreateMainTopLevelScope.OpCall(scope.VisibleVariables(), parentScope, language, selfVariable, rfcVariable, Ast.Constant(gen.SourceUnit.Path, typeof(string)), Ast.Constant(_dataOffset)); } else if (gen.CompilerOptions.IsWrapped) { scopeFactoryCall = Methods.CreateWrappedTopLevelScope.OpCall(scope.VisibleVariables(), parentScope, language, selfVariable, rfcVariable); } else { scopeFactoryCall = Methods.CreateTopLevelScope.OpCall(scope.VisibleVariables(), parentScope, language, selfVariable, rfcVariable); } MSA.Expression prologue, body; if (scopeFactoryCall != null) { prologue = Ast.Assign(runtimeScopeVariable, scopeFactoryCall); } else { prologue = null; } if (gen.SourceUnit.Kind == SourceCodeKind.InteractiveCode) { var resultVariable = scope.DefineHiddenVariable("#result", typeof(object)); var epilogue = Methods.PrintInteractiveResult.OpCall(runtimeScopeVariable, Ast.Dynamic(ConvertToSAction.Instance, typeof(MutableString), gen.CurrentScopeVariable, Ast.Dynamic(RubyCallAction.Make("inspect", RubyCallSignature.WithScope(0)), typeof(object), gen.CurrentScopeVariable, resultVariable ) ) ); body = gen.TransformStatements(prologue, _statements, epilogue, ResultOperation.Store(resultVariable)); } else { body = gen.TransformStatements(prologue, _statements, ResultOperation.Return); } body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveSourceUnit(); return(Ast.Lambda <T>( body, RubyExceptionData.TopLevelMethodName, parameters )); }
internal MSA.Expression <T> /*!*/ Transform <T>(AstGenerator /*!*/ gen) { Debug.Assert(gen != null); ScopeBuilder scope = DefineLocals(); MSA.ParameterExpression[] parameters; MSA.ParameterExpression selfVariable; MSA.ParameterExpression runtimeScopeVariable; MSA.ParameterExpression blockParameter; if (gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.None || gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.ModuleEval) { parameters = new MSA.ParameterExpression[4]; runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope"); selfVariable = parameters[1] = Ast.Parameter(typeof(object), "#self"); parameters[2] = Ast.Parameter(typeof(RubyModule), "#module"); blockParameter = parameters[3] = Ast.Parameter(typeof(Proc), "#block"); } else { parameters = new MSA.ParameterExpression[2]; runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope"); selfVariable = parameters[1] = Ast.Parameter(typeof(object), "#self"); blockParameter = null; } gen.EnterSourceUnit( scope, selfVariable, runtimeScopeVariable, blockParameter, gen.CompilerOptions.TopLevelMethodName, // method name for blocks null // parameters for super calls ); MSA.Expression body; if (_statements.Count > 0) { if (gen.PrintInteractiveResult) { var resultVariable = scope.DefineHiddenVariable("#result", typeof(object)); var epilogue = Methods.PrintInteractiveResult.OpCall(runtimeScopeVariable, AstUtils.LightDynamic(ConvertToSAction.Make(gen.Context), typeof(MutableString), CallSiteBuilder.InvokeMethod(gen.Context, "inspect", RubyCallSignature.WithScope(0), gen.CurrentScopeVariable, resultVariable ) ) ); body = gen.TransformStatements(null, _statements, epilogue, ResultOperation.Store(resultVariable)); } else { body = gen.TransformStatements(_statements, ResultOperation.Return); } // TODO: var exceptionVariable = Ast.Parameter(typeof(Exception), "#exception"); body = AstUtils.Try( body ).Filter(exceptionVariable, Methods.TraceTopLevelCodeFrame.OpCall(runtimeScopeVariable, exceptionVariable), Ast.Empty() ); } else { body = AstUtils.Constant(null); } // scope initialization: MSA.Expression prologue; switch (gen.CompilerOptions.FactoryKind) { case TopScopeFactoryKind.None: case TopScopeFactoryKind.ModuleEval: prologue = Methods.InitializeScopeNoLocals.OpCall(runtimeScopeVariable, EnterInterpretedFrameExpression.Instance); break; case TopScopeFactoryKind.Hosted: case TopScopeFactoryKind.File: case TopScopeFactoryKind.WrappedFile: prologue = Methods.InitializeScope.OpCall( runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), EnterInterpretedFrameExpression.Instance ); break; case TopScopeFactoryKind.Main: prologue = Methods.InitializeScope.OpCall( runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), EnterInterpretedFrameExpression.Instance ); if (_dataOffset >= 0) { prologue = Ast.Block( prologue, Methods.SetDataConstant.OpCall( runtimeScopeVariable, gen.SourcePathConstant, AstUtils.Constant(_dataOffset) ) ); } break; default: throw Assert.Unreachable; } // BEGIN blocks: if (gen.FileInitializers != null) { var b = new AstBlock(); b.Add(prologue); b.Add(gen.FileInitializers); b.Add(body); body = b; } body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveSourceUnit(); return(Ast.Lambda <T>(body, GetEncodedName(gen), parameters)); }
internal override MSA.Expression/*!*/ TransformResult(AstGenerator/*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); if (HasExceptionHandling) { return TransformExceptionHandling(gen, resultOperation); } else { return gen.TransformStatements(_statements, resultOperation); } }
// // rescue stmts ... if (StandardError === $!) { stmts; } // rescue <types> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; } // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; } // /*!*/ internal IfStatementTest Transform(AstGenerator/*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); MSA.Expression condition; if (_types.Length != 0) { var comparisonSiteStorage = Ast.Constant(new BinaryOpStorage(gen.Context)); if (_types.Length == 1) { condition = MakeCompareException(gen, comparisonSiteStorage, _types[0].TransformRead(gen), _types[0] is SplattedArgument); } else { // forall{i}: <temps[i]> = evaluate type[i] var temps = new MSA.Expression[_types.Length]; var exprs = new BlockBuilder(); for (int i = 0; i < _types.Length; i++) { var t = _types[i].TransformRead(gen); var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, t.Type); temps[i] = tmp; exprs.Add(Ast.Assign(tmp, t)); } // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>) condition = MakeCompareException(gen, comparisonSiteStorage, temps[0], _types[0] is SplattedArgument); for (int i = 1; i < _types.Length; i++) { condition = Ast.OrElse(condition, MakeCompareException(gen, comparisonSiteStorage, temps[i], _types[i] is SplattedArgument)); } // (temps[0] = type[0], ..., temps[n] == type[n], condition) exprs.Add(condition); condition = exprs; } } else { condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable); } return AstUtils.IfCondition(condition, gen.TransformStatements( // <lvalue> = e; (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null, // body: _statements, resultOperation ) ); }
// // rescue stmts ... if (StandardError === $!) { stmts; } // rescue <types> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; } // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; } // internal IfStatementTest /*!*/ Transform(AstGenerator /*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); MSA.Expression condition; if (_types.Count != 0 || _splatType != null) { if (_types.Count == 0) { // splat only: condition = MakeCompareSplattedExceptions(gen, TransformSplatType(gen)); } else if (_types.Count == 1 && _splatType == null) { condition = MakeCompareException(gen, _types[0].TransformRead(gen)); } else { // forall{i}: <temps[i]> = evaluate type[i] var temps = new MSA.Expression[_types.Count + (_splatType != null ? 1 : 0)]; var exprs = new MSA.Expression[temps.Length + 1]; int i = 0; while (i < _types.Count) { var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object)); temps[i] = tmp; exprs[i] = Ast.Assign(tmp, _types[i].TransformRead(gen)); i++; } if (_splatType != null) { var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object)); temps[i] = tmp; exprs[i] = Ast.Assign(tmp, TransformSplatType(gen)); i++; } Debug.Assert(i == temps.Length); // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>) i = 0; condition = MakeCompareException(gen, temps[i++]); while (i < _types.Count) { condition = Ast.OrElse(condition, MakeCompareException(gen, temps[i++])); } if (_splatType != null) { condition = Ast.OrElse(condition, MakeCompareSplattedExceptions(gen, temps[i++])); } Debug.Assert(i == temps.Length); // (temps[0] = type[0], ..., temps[n] == type[n], condition) exprs[exprs.Length - 1] = condition; condition = AstFactory.Block(exprs); } } else { condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable); } return(AstUtils.IfCondition(condition, gen.TransformStatements( // <lvalue> = e; (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null, // body: _statements, resultOperation ) )); }
internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression parentScope = gen.CurrentScopeVariable; ScopeBuilder scope = new ScopeBuilder(); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.Expression blockParameter, selfParameter; MSA.ParameterExpression[] parameters = DefineParameters(out selfParameter, out blockParameter); MSA.Expression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); if (_definedScope != null) { _definedScope.TransformLocals(scope); } MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder = scope.DefineHiddenVariable("#unwinder", typeof(BlockUnwinder)); MSA.Expression loop = AstFactory.Infinite(null, redoLabel, AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder, // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Continue(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ); if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body[0].Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body[_body.Count - 1].Location.End.Line : Location.End.Line; loop = Ast.TryFinally( Ast.Block( Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(firstStatementLine)), loop ), Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(lastStatementLine)) ); } MSA.Expression body = Ast.Block( Ast.Assign(scopeVariable, Methods.CreateBlockScope.OpCall(scope.VisibleVariables(), parentScope, blockParameter, selfParameter) ), paramInit, loop, Ast.Empty() ); body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveBlockDefinition(); int parameterCount = _parameters.LeftValues.Count; var attributes = _parameters.GetBlockSignatureAttributes(); return(Methods.DefineBlock.OpCall( gen.CurrentScopeVariable, gen.CurrentRfcVariable, gen.CurrentSelfVariable, Ast.Lambda( BlockDispatcher.GetDelegateType(parameterCount, attributes), body, gen.EncodeMethodName(gen.CurrentMethod.MethodName, Location), new ReadOnlyCollection <MSA.ParameterExpression>(parameters) ), Ast.Constant(parameterCount), Ast.Constant(attributes) )); }
internal override MSA.Expression/*!*/ Transform(AstGenerator/*!*/ gen) { MSA.Expression parentScope = gen.CurrentScopeVariable; ScopeBuilder scope = new ScopeBuilder(); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.Expression blockParameter, selfParameter; MSA.ParameterExpression[] parameters = DefineParameters(out selfParameter, out blockParameter); MSA.ParameterExpression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); if (_definedScope != null) { _definedScope.TransformLocals(scope); } MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder = scope.DefineHiddenVariable("#unwinder", typeof(BlockUnwinder)); MSA.ParameterExpression filterVariable = scope.DefineHiddenVariable("#e", typeof(Exception)); MSA.Expression traceCall, traceReturn; if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body.First.Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body.Last.Location.End.Line : Location.End.Line; traceCall = Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, Ast.Convert(AstUtils.Constant(gen.SourceUnit.Path), typeof(string)), AstUtils.Constant(firstStatementLine)); traceReturn = Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, Ast.Convert(AstUtils.Constant(gen.SourceUnit.Path), typeof(string)), AstUtils.Constant(lastStatementLine)); } else { traceCall = traceReturn = Ast.Empty(); } MSA.Expression body = AstUtils.Try( Ast.Assign(scopeVariable, Methods.CreateBlockScope.OpCall( scope.VisibleVariables(), parentScope, blockParameter, selfParameter, EnterInterpretedFrameExpression.Instance ) ), paramInit, traceCall, Ast.Label(redoLabel), AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder, // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Goto(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ).Filter(filterVariable, Methods.FilterBlockException.OpCall(scopeVariable, filterVariable) ).Finally( traceReturn, Methods.LeaveBlockFrame.OpCall(scopeVariable), LeaveInterpretedFrameExpression.Instance ); body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveBlockDefinition(); int parameterCount = _parameters.LeftValues.Count; var attributes = _parameters.GetBlockSignatureAttributes(); return Methods.DefineBlock.OpCall( gen.CurrentScopeVariable, gen.CurrentRfcVariable, gen.CurrentSelfVariable, BlockDispatcher.CreateLambda( body, RubyExceptionData.EncodeMethodName(gen.SourceUnit, gen.CurrentMethod.MethodName, Location), new ReadOnlyCollection<MSA.ParameterExpression>(parameters), parameterCount, attributes ), AstUtils.Constant(parameterCount), AstUtils.Constant(attributes) ); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/While-Until internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#loop-result", typeof(object)); MSA.Expression redoVariable = gen.CurrentScope.DefineHiddenVariable("#skip-condition", typeof(bool)); MSA.ParameterExpression unwinder; bool isInnerLoop = gen.CurrentLoop != null; MSA.LabelTarget breakLabel = Ast.Label(); MSA.LabelTarget continueLabel = Ast.Label(); gen.EnterLoop(redoVariable, resultVariable, breakLabel, continueLabel); MSA.Expression transformedBody = gen.TransformStatements(_statements, ResultOperation.Ignore); MSA.Expression transformedCondition = _condition.TransformCondition(gen, true); gen.LeaveLoop(); MSA.Expression conditionPositiveStmt, conditionNegativeStmt; if (_isWhileLoop) { conditionPositiveStmt = AstUtils.Empty(); conditionNegativeStmt = Ast.Break(breakLabel); } else { conditionPositiveStmt = Ast.Break(breakLabel); conditionNegativeStmt = AstUtils.Empty(); } // make the loop first: MSA.Expression loop = new AstBlock { gen.ClearDebugInfo(), Ast.Assign(redoVariable, AstUtils.Constant(_isPostTest)), AstFactory.Infinite(breakLabel, continueLabel, AstUtils.Try( AstUtils.If(redoVariable, Ast.Assign(redoVariable, AstUtils.Constant(false)) ).ElseIf(transformedCondition, conditionPositiveStmt ).Else( conditionNegativeStmt ), transformedBody, AstUtils.Empty() ).Catch(unwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo = u.IsRedo Ast.Assign(redoVariable, Ast.Field(unwinder, BlockUnwinder.IsRedoField)), AstUtils.Empty() ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"), Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak), // result = unwinder.ReturnValue Ast.Assign(resultVariable, Ast.Field(unwinder, EvalUnwinder.ReturnValueField)), Ast.Break(breakLabel) ) ), gen.ClearDebugInfo(), AstUtils.Empty(), }; // wrap it to try finally that updates RFC state: if (!isInnerLoop) { loop = AstUtils.Try( Methods.EnterLoop.OpCall(gen.CurrentScopeVariable), loop ).Finally( Methods.LeaveLoop.OpCall(gen.CurrentScopeVariable) ); } return(Ast.Block(loop, resultVariable)); }
internal MSA.Expression/*!*/ Transform(AstGenerator/*!*/ gen, bool isLambda) { ScopeBuilder scope = DefineLocals(gen.CurrentScope); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.ParameterExpression blockParameter, selfParameter; var parameters = DefineParameters(out selfParameter, out blockParameter); MSA.ParameterExpression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder, filterVariable; MSA.Expression traceCall, traceReturn; if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body.First.Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body.Last.Location.End.Line : Location.End.Line; traceCall = Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(firstStatementLine)); traceReturn = Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(lastStatementLine)); } else { traceCall = traceReturn = Ast.Empty(); } MSA.Expression body = AstUtils.Try( paramInit, traceCall, Ast.Label(redoLabel), AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Goto(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ).Filter(filterVariable = Ast.Parameter(typeof(Exception), "#e"), Methods.FilterBlockException.OpCall(scopeVariable, filterVariable) ).Finally( traceReturn, Ast.Empty() ); body = gen.AddReturnTarget( scope.CreateScope( scopeVariable, Methods.CreateBlockScope.OpCall(new AstExpressions { scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), blockParameter, selfParameter, EnterInterpretedFrameExpression.Instance }), body ) ); gen.LeaveBlockDefinition(); int parameterCount = ParameterCount; var attributes = _parameters.GetBlockSignatureAttributes(); var dispatcher = Ast.Constant( BlockDispatcher.Create(parameterCount, attributes, gen.SourcePath, Location.Start.Line), typeof(BlockDispatcher) ); return Ast.Coalesce( (isLambda ? Methods.InstantiateLambda : Methods.InstantiateBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher), (isLambda ? Methods.DefineLambda : Methods.DefineBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher, BlockDispatcher.CreateLambda( body, RubyStackTraceBuilder.EncodeMethodName(gen.CurrentMethod.MethodName, gen.SourcePath, Location, gen.DebugMode), parameters, parameterCount, attributes ) ) ); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/While-Until internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#loop-result", typeof(object)); MSA.Expression redoVariable = gen.CurrentScope.DefineHiddenVariable("#skip-condition", typeof(bool)); MSA.ParameterExpression unwinder; bool isInnerLoop = gen.CurrentLoop != null; MSA.LabelTarget breakLabel = Ast.Label(); MSA.LabelTarget continueLabel = Ast.Label(); gen.EnterLoop(redoVariable, resultVariable, breakLabel, continueLabel); MSA.Expression transformedBody = gen.TransformStatements(_statements, ResultOperation.Ignore); MSA.Expression transformedCondition = _condition.TransformCondition(gen, true); gen.LeaveLoop(); MSA.Expression conditionPositiveStmt, conditionNegativeStmt; if (_isWhileLoop) { conditionPositiveStmt = AstUtils.Empty(); conditionNegativeStmt = Ast.Break(breakLabel); } else { conditionPositiveStmt = Ast.Break(breakLabel); conditionNegativeStmt = AstUtils.Empty(); } // make the loop first: MSA.Expression loop = new AstBlock { gen.ClearDebugInfo(), Ast.Assign(redoVariable, AstUtils.Constant(_isPostTest)), AstFactory.Infinite(breakLabel, continueLabel, AstUtils.Try( AstUtils.If(redoVariable, Ast.Assign(redoVariable, AstUtils.Constant(false)) ).ElseIf(transformedCondition, conditionPositiveStmt ).Else( conditionNegativeStmt ), transformedBody, AstUtils.Empty() ).Catch(unwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo = u.IsRedo Ast.Assign(redoVariable, Ast.Field(unwinder, BlockUnwinder.IsRedoField)), AstUtils.Empty() ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"), Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak), // result = unwinder.ReturnValue Ast.Assign(resultVariable, Ast.Field(unwinder, EvalUnwinder.ReturnValueField)), Ast.Break(breakLabel) ) ), gen.ClearDebugInfo(), AstUtils.Empty(), }; // wrap it to try finally that updates RFC state: if (!isInnerLoop) { loop = AstUtils.Try( Methods.EnterLoop.OpCall(gen.CurrentScopeVariable), loop ).Finally( Methods.LeaveLoop.OpCall(gen.CurrentScopeVariable) ); } return Ast.Block(loop, resultVariable); }
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; }