/// <summary> /// Resolves an library method overload and builds call expression. /// The resulting expression on meta-builder doesn't handle block control flow yet. /// </summary> internal static void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, IList<MethodBase>/*!*/ overloads, bool includeSelf, bool selfIsInstance) { var bindingTarget = ResolveOverload(name, overloads, args, includeSelf, selfIsInstance); if (bindingTarget.Success) { bool calleeHasBlockParam = HasBlockParameter(bindingTarget.Method); // Allocates a variable holding BlockParam. At runtime the BlockParam is created with a new RFC instance that // identifies the library method frame as a proc-converter target of a method unwinder triggered by break from a block. // // NOTE: We check for null block here -> test fore that fact is added in MakeActualArgs if (metaBuilder.BfcVariable == null && args.Signature.HasBlock && args.GetBlock() != null && calleeHasBlockParam) { metaBuilder.BfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc"); } var actualArgs = MakeActualArgs(metaBuilder, args, includeSelf, selfIsInstance, calleeHasBlockParam, true); var parameterBinder = new RubyParameterBinder(args.RubyContext.Binder, args.MetaContext.Expression, args.Signature.HasScope); var targetExpression = bindingTarget.MakeExpression(parameterBinder, actualArgs); metaBuilder.Result = targetExpression; } else { metaBuilder.SetError( Methods.MakeInvalidArgumentTypesError.OpCall(Ast.Constant(name)) ); } }
/// <summary> /// Resolves an library method overload and builds call expression. /// The resulting expression on meta-builder doesn't handle block control flow yet. /// </summary> internal static void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, IList<MethodBase>/*!*/ overloads, SelfCallConvention callConvention) { var bindingTarget = ResolveOverload(name, overloads, args, callConvention); bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Method); // Allocates a variable holding BlockParam. At runtime the BlockParam is created with a new RFC instance that // identifies the library method frame as a proc-converter target of a method unwinder triggered by break from a block. if (args.Signature.HasBlock) { var metaBlock = args.GetMetaBlock(); if (metaBlock.Value != null && calleeHasBlockParam) { if (metaBuilder.BfcVariable == null) { metaBuilder.BfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc"); } metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder; } // Block test - we need to test for a block regardless of whether it is actually passed to the method or not // since the information that the block is not null is used for overload resolution. if (metaBlock.Value == null) { metaBuilder.AddRestriction(Ast.Equal(metaBlock.Expression, AstUtils.Constant(null))); } else { // don't need to test the exact type of the Proc since the code is subclass agnostic: metaBuilder.AddRestriction(Ast.NotEqual(metaBlock.Expression, AstUtils.Constant(null))); } } var actualArgs = MakeActualArgs(metaBuilder, args, callConvention, calleeHasBlockParam, true); if (bindingTarget.Success) { var parameterBinder = new RubyParameterBinder(args.RubyContext.Binder, args.MetaContext.Expression, args.Signature.HasScope); metaBuilder.Result = bindingTarget.MakeExpression(parameterBinder, actualArgs); } else { metaBuilder.SetError(args.RubyContext.RubyBinder.MakeInvalidParametersError(bindingTarget).Expression); } }