internal static void GetParameterCount(OverloadInfo /*!*/ method, SelfCallConvention callConvention, out int mandatory, out int optional)
        {
            mandatory = 0;
            optional  = 0;
            for (int i = GetHiddenParameterCount(method, callConvention); i < method.ParameterCount; i++)
            {
                var info = method.Parameters[i];

                if (method.IsParamArray(i))
                {
                    // TODO: indicate splat args separately?
                    optional++;
                }
                else if (info.IsOutParameter())
                {
                    // Python allows passing of optional "clr.Reference" to capture out parameters
                    // Ruby should allow similar
                    optional++;
                }
                else if (info.IsMandatory())
                {
                    mandatory++;
                }
                else
                {
                    optional++;
                }
            }
        }
示例#2
0
 internal RubyOverloadResolver(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, SelfCallConvention callConvention,
     bool implicitProtocolConversions)
     : base(args.RubyContext.Binder) {
     _args = args;
     _metaBuilder = metaBuilder;
     _callConvention = callConvention;
     _implicitProtocolConversions = implicitProtocolConversions;
 }
 internal RubyOverloadResolver(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, SelfCallConvention callConvention,
                               bool implicitProtocolConversions)
     : base(args.RubyContext.Binder)
 {
     _args           = args;
     _metaBuilder    = metaBuilder;
     _callConvention = callConvention;
     _implicitProtocolConversions = implicitProtocolConversions;
 }
        internal static int GetHiddenParameterCount(OverloadInfo /*!*/ method, SelfCallConvention callConvention)
        {
            int i     = 0;
            var infos = method.Parameters;

            if (callConvention == SelfCallConvention.SelfIsInstance)
            {
                if (method.IsStatic)
                {
                    Debug.Assert(RubyUtils.IsOperator(method) || method.IsExtension);
                    i++;
                }
            }

            while (i < infos.Count && infos[i].ParameterType.IsSubclassOf(typeof(RubyCallSiteStorage)))
            {
                i++;
            }

            if (i < infos.Count)
            {
                var info = infos[i];

                if (info.ParameterType == typeof(RubyScope))
                {
                    i++;
                }
                else if (info.ParameterType == typeof(RubyContext))
                {
                    i++;
                }
                else if (method.IsConstructor && info.ParameterType == typeof(RubyClass))
                {
                    i++;
                }
            }

            if (i < infos.Count && infos[i].ParameterType == typeof(BlockParam))
            {
                i++;
            }

            if (callConvention == SelfCallConvention.SelfIsParameter)
            {
                Debug.Assert(i < infos.Count);
                Debug.Assert(method.IsStatic);
                i++;
            }

            return(i);
        }
示例#5
0
        /// <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 <OverloadInfo> /*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions)
        {
            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, implicitProtocolConversions, out resolver);

            if (bindingTarget.Success)
            {
                // TODO: create a custom overload info:
                if (ReferenceEquals(bindingTarget.Overload.ReflectionInfo, Methods.CreateDefaultInstance))
                {
                    Debug.Assert(args.TargetClass.TypeTracker.Type.IsValueType);
                    metaBuilder.Result = Ast.New(args.TargetClass.TypeTracker.Type);
                }
                else if (args.Signature.IsVirtualCall && bindingTarget.Overload.IsVirtual)
                {
                    // Virtual methods that have been detached from the CLR type and
                    // defined on the corresponding Ruby class or its subclass are not
                    // directly invoked from a dynamic virtual call to prevent recursion.
                    // Instead the base call is performed.
                    //
                    // Example:
                    // class C < ArrayList
                    //   define_method(:Add, instance_method(:Add))
                    // end
                    //
                    // C.new.Add(1)
                    //
                    // C.new.Add dispatches to the virtual ArrayList::Add, which in turn dispatches to the auto-generated override C$1::Add.
                    // That gets here since the defined method is a Ruby method (a detached CLR method group). If we called it directly
                    // it would invoke the C$1::Add override again leading to a stack overflow. So we need to use a base call instead.
                    metaBuilder.Result = Ast.Field(null, Fields.ForwardToBase);
                }
                else
                {
                    metaBuilder.Result = bindingTarget.MakeExpression();
                }
            }
            else
            {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
示例#6
0
        // TODO: OBSOLETE
        private static Expression[]/*!*/ MakeActualArgs(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args,
            SelfCallConvention callConvention, bool calleeHasBlockParam, bool injectMissingBlockParam) {

            var actualArgs = new List<Expression>();

            // self (instance):
            if (callConvention == SelfCallConvention.SelfIsInstance) {
                // test already added by method resolver
                Debug.Assert(args.TargetExpression != null);
                AddArgument(actualArgs, args.Target, args.TargetExpression);
            }

            // block:
            if (calleeHasBlockParam) {
                if (args.Signature.HasBlock) {
                    if (args.GetBlock() == null) {
                        // the user explicitly passed nil as a block arg:
                        actualArgs.Add(AstUtils.Constant(null));
                    } else {
                        // pass BlockParam:
                        Debug.Assert(metaBuilder.BfcVariable != null);
                        actualArgs.Add(metaBuilder.BfcVariable);
                    }
                } else {
                    // no block passed into a method with a BlockParam:
                    actualArgs.Add(AstUtils.Constant(null));
                }
            } else if (injectMissingBlockParam) {
                // no block passed into a method w/o a BlockParam (we still need to fill the missing block argument):
                actualArgs.Add(AstUtils.Constant(null));
            }

            // self (non-instance):
            if (callConvention == SelfCallConvention.SelfIsParameter) {
                // test already added by method resolver
                AddArgument(actualArgs, args.Target, args.TargetExpression);
            }

            // simple arguments:
            for (int i = 0; i < args.SimpleArgumentCount; i++) {
                var value = args.GetSimpleArgument(i);
                var expr = args.GetSimpleArgumentExpression(i);

                // TODO: overload-resolution restrictions
                metaBuilder.AddObjectTypeRestriction(value, expr);
                AddArgument(actualArgs, value, expr);
            }

            // splat argument:
            int listLength;
            ParameterExpression listVariable;
            if (args.Signature.HasSplattedArgument) {
                object splattedArg = args.GetSplattedArgument();
                Expression splattedArgExpression = args.GetSplattedArgumentExpression();

                if (metaBuilder.AddSplattedArgumentTest(splattedArg, splattedArgExpression, out listLength, out listVariable)) {

                    // AddTestForListArg only returns 'true' if the argument is a List<object>
                    var list = (List<object>)splattedArg;

                    // get arguments, add tests
                    for (int j = 0; j < listLength; j++) {
                        var value = list[j];
                        var expr = Ast.Call(listVariable, typeof(List<object>).GetMethod("get_Item"), AstUtils.Constant(j));

                        // TODO: overload-resolution restrictions
                        metaBuilder.AddObjectTypeCondition(value, expr);
                        AddArgument(actualArgs, value, expr);
                    }

                } else {
                    // argument is not an array => add the argument itself:
                    AddArgument(actualArgs, splattedArg, splattedArgExpression);
                }
            }

            // rhs argument:
            if (args.Signature.HasRhsArgument) {
                var value = args.GetRhsArgument();
                var expr = args.GetRhsArgumentExpression();

                // TODO: overload-resolution restrictions
                metaBuilder.AddObjectTypeRestriction(value, expr);
                AddArgument(actualArgs, value, expr);
            }

            return actualArgs.ToArray();
        }
示例#7
0
        /// <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) {

            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, out resolver);
            if (bindingTarget.Success) {
                metaBuilder.Result = bindingTarget.MakeExpression();
            } else {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
示例#8
0
        internal static void GetParameterCount(MethodBase/*!*/ method, ParameterInfo/*!*/[]/*!*/ parameterInfos, SelfCallConvention callConvention, 
            out int mandatory, out int optional) {

            mandatory = 0;
            optional = 0;
            for (int i = GetHiddenParameterCount(method, parameterInfos, callConvention); i < parameterInfos.Length; i++) {
                var info = parameterInfos[i];

                if (CompilerHelpers.IsParamArray(info)) {
                    // TODO: indicate splat args separately?
                    optional++;
                } else if (CompilerHelpers.IsOutParameter(info)) {
                    // Python allows passing of optional "clr.Reference" to capture out parameters
                    // Ruby should allow similar
                    optional++;
                } else if (CompilerHelpers.IsMandatoryParameter(info)) {
                    mandatory++;
                } else {
                    optional++;
                }
            }
        }
示例#9
0
        internal static int GetHiddenParameterCount(MethodBase/*!*/ method, ParameterInfo/*!*/[]/*!*/ infos, SelfCallConvention callConvention) {
            int i = 0;

            if (callConvention == SelfCallConvention.SelfIsInstance) {
                if (CompilerHelpers.IsStatic(method)) {
                    Debug.Assert(RubyUtils.IsOperator(method) || CompilerHelpers.IsExtension(method));
                    i++;
                }
            }

            while (i < infos.Length && infos[i].ParameterType.IsSubclassOf(typeof(RubyCallSiteStorage))) {
                i++;
            }

            if (i < infos.Length) {
                var info = infos[i];

                if (info.ParameterType == typeof(RubyScope)) {
                    i++;
                } else if (info.ParameterType == typeof(RubyContext)) {
                    i++;
                } else if (method.IsConstructor && info.ParameterType == typeof(RubyClass)) {
                    i++;
                }
            }

            if (i < infos.Length && infos[i].ParameterType == typeof(BlockParam)) {
                i++;
            }

            if (callConvention == SelfCallConvention.SelfIsParameter) {
                Debug.Assert(i < infos.Length);
                Debug.Assert(CompilerHelpers.IsStatic(method));
                i++;
            }

            return i;
        }
示例#10
0
        internal static void GetParameterCount(OverloadInfo/*!*/ method, SelfCallConvention callConvention, out int mandatory, out int optional) {
            mandatory = 0;
            optional = 0;
            for (int i = GetHiddenParameterCount(method, callConvention); i < method.ParameterCount; i++) {
                var info = method.Parameters[i];

                if (method.IsParamArray(i)) {
                    // TODO: indicate splat args separately?
                    optional++;
                } else if (info.IsOutParameter()) {
                    // Python allows passing of optional "clr.Reference" to capture out parameters
                    // Ruby should allow similar
                    optional++;
                } else if (info.IsMandatory()) {
                    mandatory++;
                } else {
                    optional++;
                }
            }
        }
示例#11
0
        internal static int GetHiddenParameterCount(OverloadInfo/*!*/ method, SelfCallConvention callConvention) {
            int i = 0;
            var infos = method.Parameters;

            if (callConvention == SelfCallConvention.SelfIsInstance) {
                if (method.IsStatic) {
                    Debug.Assert(RubyUtils.IsOperator(method) || method.IsExtension);
                    i++;
                }
            }

            while (i < infos.Count && infos[i].ParameterType.IsSubclassOf(typeof(RubyCallSiteStorage))) {
                i++;
            }

            if (i < infos.Count) {
                var info = infos[i];

                if (info.ParameterType == typeof(RubyScope)) {
                    i++;
                } else if (info.ParameterType == typeof(RubyContext)) {
                    i++;
                } else if (method.IsConstructor && info.ParameterType == typeof(RubyClass)) {
                    i++;
                }
            }

            if (i < infos.Count && infos[i].ParameterType == typeof(BlockParam)) {
                i++;
            }

            if (callConvention == SelfCallConvention.SelfIsParameter) {
                Debug.Assert(i < infos.Count);
                Debug.Assert(method.IsStatic);
                i++;
            }

            return i;
        }
示例#12
0
        /// <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<OverloadInfo>/*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions) {

            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, implicitProtocolConversions, out resolver);
            if (bindingTarget.Success) {
                // TODO: create a custom overload info:
                if (ReferenceEquals(bindingTarget.Overload.ReflectionInfo, Methods.CreateDefaultInstance)) {
                    Debug.Assert(args.TargetClass.TypeTracker.Type.IsValueType);
                    metaBuilder.Result = Ast.New(args.TargetClass.TypeTracker.Type);
                } else if (args.Signature.IsVirtualCall && bindingTarget.Overload.IsVirtual) {
                    // Virtual methods that have been detached from the CLR type and 
                    // defined on the corresponding Ruby class or its subclass are not
                    // directly invoked from a dynamic virtual call to prevent recursion.
                    // Instead the base call is performed. 
                    //
                    // Example:
                    // class C < ArrayList           
                    //   define_method(:Add, instance_method(:Add))          
                    // end
                    // 
                    // C.new.Add(1)
                    // 
                    // C.new.Add dispatches to the virtual ArrayList::Add, which in turn dispatches to the auto-generated override C$1::Add.
                    // That gets here since the defined method is a Ruby method (a detached CLR method group). If we called it directly
                    // it would invoke the C$1::Add override again leading to a stack overflow. So we need to use a base call instead.
                    metaBuilder.Result = Ast.Field(null, Fields.ForwardToBase);
                } else {
                    metaBuilder.Result = bindingTarget.MakeExpression();
                }
            } else {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
示例#13
0
        internal static BindingTarget/*!*/ ResolveOverload(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name,
            IList<OverloadInfo>/*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions, 
            out RubyOverloadResolver/*!*/ resolver) {

            resolver = new RubyOverloadResolver(metaBuilder, args, callConvention, implicitProtocolConversions);
            var bindingTarget = resolver.ResolveOverload(name, overloads, NarrowingLevel.None, NarrowingLevel.All);

            bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Overload);
            
            // 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 && calleeHasBlockParam) {
                metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder;
            }

            // add restrictions used for overload resolution:
            resolver.AddArgumentRestrictions(metaBuilder, bindingTarget);
            
            return bindingTarget;
        }
示例#14
0
        internal static BindingTarget/*!*/ ResolveOverload(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name,
            IList<MethodBase>/*!*/ overloads, SelfCallConvention callConvention, out RubyOverloadResolver/*!*/ resolver) {

            resolver = new RubyOverloadResolver(metaBuilder, args, callConvention);
            var bindingTarget = resolver.ResolveOverload(name, overloads, NarrowingLevel.None, NarrowingLevel.All);

            bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Method);
            
            // 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) {
                    Debug.Assert(metaBuilder.BfcVariable != null);
                    metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder;
                }

                // Overload resolution might not need to distinguish between nil and non-nil block.
                // However, we still do since we construct CF only for non-nil blocks.
                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)));
                }
            }

            // add restrictions used for overload resolution:
            resolver.AddArgumentRestrictions(metaBuilder, bindingTarget);
            
            return bindingTarget;
        }
示例#15
0
        internal static BindingTarget /*!*/ ResolveOverload(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name,
                                                            IList <OverloadInfo> /*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions,
                                                            out RubyOverloadResolver /*!*/ resolver)
        {
            resolver = new RubyOverloadResolver(metaBuilder, args, callConvention, implicitProtocolConversions);
            var bindingTarget = resolver.ResolveOverload(name, overloads, NarrowingLevel.None, NarrowingLevel.All);

            bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Overload);

            // 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 && calleeHasBlockParam)
            {
                metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder;
            }

            // add restrictions used for overload resolution:
            resolver.AddArgumentRestrictions(metaBuilder, bindingTarget);

            return(bindingTarget);
        }
示例#16
0
        // Normalizes arguments: inserts self, expands splats, and inserts rhs arg. 
        // Adds any restrictions/conditions applied to the arguments to the given meta-builder.
        internal static DynamicMetaObject[]/*!*/ NormalizeArguments(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args,
            SelfCallConvention callConvention, bool calleeHasBlockParam, bool injectMissingBlockParam) {

            var result = new List<DynamicMetaObject>();

            // self (instance):
            if (callConvention == SelfCallConvention.SelfIsInstance) {
                result.Add(args.MetaTarget);
            }

            // block:
            if (calleeHasBlockParam) {
                if (args.Signature.HasBlock) {
                    if (args.GetMetaBlock() == null) {
                        // the user explicitly passed nil as a block arg:
                        result.Add(RubyBinder.NullMetaObject);
                    } else {
                        // pass BlockParam:
                        Debug.Assert(metaBuilder.BfcVariable != null);
                        result.Add(new DynamicMetaObject(metaBuilder.BfcVariable, BindingRestrictions.Empty));
                    }
                } else {
                    // no block passed into a method with a BlockParam:
                    result.Add(RubyBinder.NullMetaObject);
                }
            } else if (injectMissingBlockParam) {
                // no block passed into a method w/o a BlockParam (we still need to fill the missing block argument):
                result.Add(RubyBinder.NullMetaObject);
            }

            // self (parameter):
            if (callConvention == SelfCallConvention.SelfIsParameter) {
                result.Add(args.MetaTarget);
            }

            // simple arguments:
            for (int i = 0; i < args.SimpleArgumentCount; i++) {
                result.Add(args.GetSimpleMetaArgument(i));
            }

            // splat argument:
            int listLength;
            ParameterExpression listVariable;
            if (args.Signature.HasSplattedArgument) {
                var splatted = args.GetSplattedMetaArgument();

                if (metaBuilder.AddSplattedArgumentTest(splatted.Value, splatted.Expression, out listLength, out listVariable)) {

                    // AddTestForListArg only returns 'true' if the argument is a List<object>
                    var list = (List<object>)splatted.Value;

                    // get arguments, add tests
                    for (int j = 0; j < listLength; j++) {
                        result.Add(DynamicMetaObject.Create(
                            list[j], 
                            Ast.Call(listVariable, typeof(List<object>).GetMethod("get_Item"), AstUtils.Constant(j))
                        ));
                    }

                } else {
                    // argument is not an array => add the argument itself:
                    result.Add(splatted);
                }
            }

            // rhs argument:
            if (args.Signature.HasRhsArgument) {
                result.Add(args.GetRhsMetaArgument());
            }

            return result.ToArray();
        }
示例#17
0
        /// <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);
            }
        }
示例#18
0
        internal static BindingTarget/*!*/ ResolveOverload(string/*!*/ name, IList<MethodBase>/*!*/ overloads, CallArguments/*!*/ args, 
            SelfCallConvention callConvention) {

            var methodBinder = MethodBinder.MakeBinder(args.RubyContext.Binder, name, overloads, ArrayUtils.EmptyStrings, NarrowingLevel.None, NarrowingLevel.All);
            var argTypes = GetSignatureToMatch(args, callConvention);
            return methodBinder.MakeBindingTarget(CallTypes.None, argTypes);
        }
示例#19
0
 public RubyOverloadResolver(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, SelfCallConvention callConvention)
     : base(args.RubyContext.Binder) {
     _args = args;
     _metaBuilder = metaBuilder;
     _callConvention = callConvention;
 }
示例#20
0
        /// <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);
            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 for that fact is added in MakeActualArgs
                if (args.Signature.HasBlock && args.GetBlock() != null && calleeHasBlockParam) {
                    if (metaBuilder.BfcVariable == null) {
                        metaBuilder.BfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc");
                    }
                    metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder;
                }

                var actualArgs = MakeActualArgs(metaBuilder, args, callConvention, 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(args.RubyContext.RubyBinder.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
示例#21
0
        // TODO: OBSOLETE
        private static Type[]/*!*/ GetSignatureToMatch(CallArguments/*!*/ args, SelfCallConvention callConvention) {
            var result = new List<Type>(args.ExplicitArgumentCount);

            // self (instance):
            if (callConvention == SelfCallConvention.SelfIsInstance) {
                result.Add(CompilerHelpers.GetType(args.Target));
            }

            // block:
            if (args.Signature.HasBlock) {
                // use None to let binder know that [NotNull]BlockParam is not applicable
                result.Add(args.GetBlock() != null ? typeof(BlockParam) : typeof(DynamicNull));
            } else {
                result.Add(typeof(MissingBlockParam));
            }

            // self (non-instance):
            if (callConvention == SelfCallConvention.SelfIsParameter) {
                result.Add(CompilerHelpers.GetType(args.Target));
            }

            // simple args:
            for (int i = 0; i < args.SimpleArgumentCount; i++) {
                result.Add(CompilerHelpers.GetType(args.GetSimpleArgument(i)));
            }

            // splat arg:
            if (args.Signature.HasSplattedArgument) {
                object splattedArg = args.GetSplattedArgument();
                
                var list = splattedArg as List<object>;
                if (list != null) {
                    foreach (object obj in list) {
                        result.Add(CompilerHelpers.GetType(obj));
                    }
                } else {
                    result.Add(CompilerHelpers.GetType(splattedArg));
                }
            }

            // rhs arg:
            if (args.Signature.HasRhsArgument) {
                result.Add(CompilerHelpers.GetType(args.GetRhsArgument()));
            }

            return result.ToArray();
        }
示例#22
0
        /// <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, bool implicitProtocolConversions) {

            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, implicitProtocolConversions, out resolver);
            if (bindingTarget.Success) {
                if (ReferenceEquals(bindingTarget.Method, Methods.CreateDefaultInstance)) {
                    Debug.Assert(args.TargetClass.TypeTracker.Type.IsValueType);
                    metaBuilder.Result = Ast.New(args.TargetClass.TypeTracker.Type);
                } else {
                    metaBuilder.Result = bindingTarget.MakeExpression();
                }
            } else {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }