internal MSA.LambdaExpression/*!*/ TransformBody(AstGenerator/*!*/ gen, RubyScope/*!*/ declaringScope, RubyModule/*!*/ declaringModule) {
string encodedName = RubyExceptionData.EncodeMethodName(_name, gen.SourcePath, Location);
AstParameters parameters;
ScopeBuilder scope = DefineLocals(out parameters);
var scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyMethodScope));
var selfParameter = parameters[0];
var blockParameter = parameters[1];
// exclude block parameter even if it is explicitly specified:
int visiblePrameterCountAndSignatureFlags = (parameters.Count - 2) << 2;
if (_parameters.Block != null) {
visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasBlockFlag;
}
if (_parameters.Array != null) {
visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasUnsplatFlag;
}
gen.EnterMethodDefinition(
scope,
selfParameter,
scopeVariable,
blockParameter,
_name,
_parameters
);
// profiling:
MSA.Expression profileStart, profileEnd;
if (gen.Profiler != null) {
int profileTickIndex = gen.Profiler.GetTickIndex(encodedName);
var stampVariable = scope.DefineHiddenVariable("#stamp", typeof(long));
profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall());
profileEnd = Methods.UpdateProfileTicks.OpCall(AstUtils.Constant(profileTickIndex), stampVariable);
} else {
profileStart = profileEnd = AstUtils.Empty();
}
// tracing:
MSA.Expression traceCall, traceReturn;
if (gen.TraceEnabled) {
traceCall = Methods.TraceMethodCall.OpCall(
scopeVariable,
gen.SourcePathConstant,
AstUtils.Constant(Location.Start.Line)
);
traceReturn = Methods.TraceMethodReturn.OpCall(
gen.CurrentScopeVariable,
gen.SourcePathConstant,
AstUtils.Constant(Location.End.Line)
);
} else {
traceCall = traceReturn = AstUtils.Empty();
}
MSA.ParameterExpression unwinder;
MSA.Expression body = AstUtils.Try(
profileStart,
_parameters.TransformOptionalsInitialization(gen),
traceCall,
Body.TransformResult(gen, ResultOperation.Return)
).Filter(unwinder = Ast.Parameter(typeof(Exception), "#u"), Methods.IsMethodUnwinderTargetFrame.OpCall(scopeVariable, unwinder),
Ast.Return(gen.ReturnLabel, Methods.GetMethodUnwinderReturnValue.OpCall(unwinder))
).Finally(
// leave frame:
Methods.LeaveMethodFrame.OpCall(scopeVariable),
Ast.Empty(),
profileEnd,
traceReturn
);
body = gen.AddReturnTarget(
scope.CreateScope(
scopeVariable,
Methods.CreateMethodScope.OpCall(new AstExpressions {
scope.MakeLocalsStorage(),
scope.GetVariableNamesExpression(),
Ast.Constant(visiblePrameterCountAndSignatureFlags),
Ast.Constant(declaringScope, typeof(RubyScope)),
Ast.Constant(declaringModule, typeof(RubyModule)),
Ast.Constant(_name),
selfParameter, blockParameter,
EnterInterpretedFrameExpression.Instance
}),
body
)
);
gen.LeaveMethodDefinition();
return CreateLambda(encodedName, parameters, body);
}