internal static MSA.Expression /*!*/ MakeCallWithBlockRetryable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ invoke,
MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition)
{
Assert.NotNull(invoke);
Debug.Assert((blockArgVariable == null) == (transformedBlock == null));
// see Ruby Language.doc/Control Flow Implementation/Method Call With a Block
MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object));
MSA.ParameterExpression evalUnwinder;
MSA.LabelTarget retryLabel = Ast.Label("retry");
var result = new AstBlock {
Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)),
Ast.Label(retryLabel),
(isBlockDefinition) ? Methods.InitializeBlock.OpCall(blockArgVariable) : null,
AstUtils.Try(
Ast.Assign(resultVariable, invoke)
).Catch(evalUnwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"),
Ast.Assign(
resultVariable,
Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField)
)
),
Ast.IfThen(Ast.TypeEqual(resultVariable, typeof(BlockReturnResult)),
Ast.IfThenElse(Methods.IsRetrySingleton.OpCall(resultVariable),
// retry:
AstUtils.IfThenElse(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable),
RetryStatement.TransformRetry(gen),
Ast.Goto(retryLabel)
),
// return:
gen.Return(ReturnStatement.Propagate(gen, resultVariable))
)
),
resultVariable
};
return(result);
}