예제 #1
0
        private DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) {
            // TODO: argument count limit depends on the binder!

            // TODO: pass block as the last (before RHS arg?) parameter/ignore block if args not accepting block:
            var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue);
            if (!metaBuilder.Error) {
                MethodInfo postConverter;
                var interopBinder = GetInteropBinder(args.RubyContext, normalizedArgs, out postConverter);
                if (interopBinder != null) {
                    Type resultType;
                    var result = interopBinder.Bind(args.MetaTarget, ArrayUtils.MakeArray(normalizedArgs));

                    metaBuilder.SetMetaResult(result, args);
                    if (postConverter != null) {
                        // TODO: do better?
                        var paramType = postConverter.GetParameters()[0].ParameterType;

                        metaBuilder.Result = Ast.Call(null, postConverter, AstUtils.Convert(metaBuilder.Result, paramType));
                        resultType = postConverter.ReturnType;
                    } else {
                        resultType = ((IInteropBinder)interopBinder).ResultType;
                    }

                    return metaBuilder.CreateMetaObject(interopBinder, resultType);
                } else {
                    metaBuilder.SetError(Ast.New(
                       typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }),
                       Ast.Constant(String.Format("{0} not supported on foreign meta-objects", this))
                    ));
                }
            }
            return metaBuilder.CreateMetaObject(this);
        }
예제 #2
0
        internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
            Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType);

            if (_isSetter) {
                var actualArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1);
                if (!metaBuilder.Error) {
                    metaBuilder.Result = Ast.Assign(
                        Ast.Field(instance, _fieldInfo),
                        Converter.ConvertExpression(
                            actualArgs[0].Expression, 
                            _fieldInfo.FieldType,
                            args.RubyContext, 
                            args.MetaContext.Expression,
                            true
                        )
                    );
                }
            } else {
                RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0);
                if (!metaBuilder.Error) {
                    if (_fieldInfo.IsLiteral) {
                        // TODO: seems like Compiler should correctly handle the literal field case
                        // (if you emit a read to a literal field, you get a NotSupportedExpception from
                        // FieldHandle when we try to emit)
                        metaBuilder.Result = AstUtils.Constant(_fieldInfo.GetValue(null));
                    } else {
                        metaBuilder.Result = Ast.Field(instance, _fieldInfo);
                    }
                }
            }
        }
예제 #3
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     metaBuilder.Result = Methods.GetInstanceVariable.OpCall(
         args.ScopeExpression,
         AstFactory.Box(args.TargetExpression),
         AstUtils.Constant(InstanceVariableName)
     );
 }
        protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) {
            if (TryImplicitConversion(metaBuilder, args)) {
                metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression);
                return true;
            }

            // TODO: this is our meta object, should we add IRubyMetaConvertible interface instead of using interop-binder?
            if (args.Target is IDynamicMetaObjectProvider) {
                metaBuilder.SetMetaResult(args.MetaTarget.BindConvert(new InteropBinder.Convert(args.RubyContext, _type, true)), false);
                return true;
            }

            if (defaultFallback) {
                metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression);

                metaBuilder.SetError(Methods.MakeTypeConversionError.OpCall(
                    args.MetaContext.Expression,
                    AstUtils.Convert(args.TargetExpression, typeof(object)),
                    Ast.Constant(_type)
                ));
                return true;
            }

            return false;
        }
예제 #5
0
        public static DynamicMetaObject TryBind(RubyContext/*!*/ context, GetMemberBinder/*!*/ binder, DynamicMetaObject/*!*/ target) {
            Assert.NotNull(context, target);
            var metaBuilder = new MetaObjectBuilder();
            var contextExpression = AstUtils.Constant(context);

            RubyClass targetClass = context.GetImmediateClassOf(target.Value);
            MethodResolutionResult method;
            RubyMemberInfo methodMissing = null;

            using (targetClass.Context.ClassHierarchyLocker()) {
                metaBuilder.AddTargetTypeTest(target.Value, targetClass, target.Expression, context, contextExpression);

                method = targetClass.ResolveMethodForSiteNoLock(binder.Name, RubyClass.IgnoreVisibility);
                if (method.Found) {
                    methodMissing = targetClass.ResolveMethodForSiteNoLock(Symbols.MethodMissing, RubyClass.IgnoreVisibility).Info;
                }
            }
            
            if (method.Found) {
                // we need to create a bound member:
                metaBuilder.Result = AstUtils.Constant(new RubyMethod(target.Value, method.Info, binder.Name));
            } else {
                // TODO:
                // We need to throw an exception if we don't find method_missing so that our version update optimization works: 
                // This limits interop with other languages. 
                //                   
                // class B           CLR type with method 'foo'
                // class C < B       Ruby class
                // x = C.new
                //
                // 1. x.GET("foo") from Ruby
                //    No method found or CLR method found -> fallback to Python
                //    Python might see its method foo or might just fallback to .NET, 
                //    in any case it will add rule [1] with restriction on type of C w/o Ruby version check.
                // 2. B.define_method("foo") 
                //    This doesn't update C due to the optimization (there is no overridden method foo in C).
                // 3. x.GET("foo") from Ruby
                //    This will not invoke the binder since the rule [1] is still valid.
                //
                object symbol = SymbolTable.StringToId(binder.Name);
                RubyCallAction.BindToMethodMissing(metaBuilder, 
                    new CallArguments(
                        new DynamicMetaObject(contextExpression, BindingRestrictions.Empty, context),
                        new[] { 
                            target,
                            new DynamicMetaObject(AstUtils.Constant(symbol), BindingRestrictions.Empty, symbol) 
                        },
                        RubyCallSignature.Simple(1)
                    ),
                    binder.Name,
                    methodMissing,
                    method.IncompatibleVisibility,
                    false
                );
            }

            // TODO: we should return null if we fail, we need to throw exception for now:
            return metaBuilder.CreateMetaObject(binder, DynamicMetaObject.EmptyMetaObjects);
        }
예제 #6
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     Proc.BuildCall(
         metaBuilder,
         AstUtils.Constant(_lambda),            // proc object
         args.TargetExpression,                 // self
         args
     );
 }
예제 #7
0
 internal RubyOverloadResolver(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, SelfCallConvention callConvention,
     bool implicitProtocolConversions)
     : base(args.RubyContext.Binder) {
     _args = args;
     _metaBuilder = metaBuilder;
     _callConvention = callConvention;
     _implicitProtocolConversions = implicitProtocolConversions;
 }
예제 #8
0
        protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) {
            // TODO: this is our meta object, should we add IRubyMetaConvertible interface instead of using interop-binder?
            if (args.Target is IDynamicMetaObjectProvider) {
                metaBuilder.SetMetaResult(args.MetaTarget.BindConvert(new InteropBinder.Convert(args.RubyContext, _type, true)), false);
                return true;
            }

            return BuildConversion(metaBuilder, args.MetaTarget, args.MetaContext.Expression, _type, defaultFallback);
        }
예제 #9
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     var visibleOverloads = GetVisibleOverloads(args, MethodBases, false);
     if (visibleOverloads.Count == 0) {
         metaBuilder.SetError(Methods.MakeClrProtectedMethodCalledError.OpCall(
             args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name)
         ));
     } else {
         BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions);
     }
 }
예제 #10
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0);
     if (!metaBuilder.Error) {
         metaBuilder.Result = Methods.GetInstanceVariable.OpCall(
             AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)),
             AstUtils.Box(args.TargetExpression),
             AstUtils.Constant(InstanceVariableName)
         );
     }
 }
예제 #11
0
        protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) {
            RubyModule currentDeclaringModule;
            string currentMethodName;

            var scope = args.Scope;

            object target;
            scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target);

            var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self");
            
            metaBuilder.AddCondition(
                Methods.IsSuperCallTarget.OpCall(
                    AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)),
                    AstUtils.Constant(currentDeclaringModule),
                    AstUtils.Constant(currentMethodName),
                    targetExpression
                )
            );

            args.SetTarget(targetExpression, target);

            Debug.Assert(currentDeclaringModule != null);

            RubyMemberInfo method;
            RubyMemberInfo methodMissing = null;

            // we need to lock the hierarchy of the target class:
            var targetClass = scope.RubyContext.GetImmediateClassOf(target);
            using (targetClass.Context.ClassHierarchyLocker()) {
                // initialize all methods in ancestors:                
                targetClass.InitializeMethodsNoLock();

                // target is stored in a local, therefore it cannot be part of the restrictions:
                metaBuilder.TreatRestrictionsAsConditions = true;
                metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, 
                    new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton
                );
                metaBuilder.TreatRestrictionsAsConditions = false;

                method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info;
                if (method == null) {
                    // MRI: method_missing is called for the targetClass, not for the super:
                    methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None);
                }
            }

            if (method != null) {
                method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule);
            } else {
                return RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback);
            }

            return true;
        }
예제 #12
0
        internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
            Debug.Assert(!args.Signature.HasBlock);

            Proc.SetProcCallRule(
                metaBuilder,
                Ast.Constant(_lambda),            // proc object
                args.TargetExpression,            // self
                Ast.Constant(this),               // this method for super and class_eval
                args
            );
        }
예제 #13
0
        public override DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ scopeOrContextOrTarget, DynamicMetaObject/*!*/[]/*!*/ args) {
            var callArgs = new CallArguments(_context, scopeOrContextOrTarget, args, Signature);
            var metaBuilder = new MetaObjectBuilder(this, args);

            if (IsForeignMetaObject(callArgs.MetaTarget)) {
                return InteropBind(metaBuilder, callArgs);
            } 

            Build(metaBuilder, callArgs, true);
            return metaBuilder.CreateMetaObject(this);
        }
예제 #14
0
        internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {

            var actualArgs = RubyMethodGroupInfo.MakeActualArgs(metaBuilder, args, true, false, false, false);

            metaBuilder.Result = Methods.SetInstanceVariable.OpCall(
                AstFactory.Box(actualArgs[0]),
                AstFactory.Box(actualArgs[1]),
                args.ScopeExpression,
                AstUtils.Constant(InstanceVariableName)
            );
        }
예제 #15
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     var actualArgs = RubyMethodGroupInfo.NormalizeArguments(metaBuilder, args, SelfCallConvention.NoSelf, false, false);
     if (actualArgs.Length == 0) {
         metaBuilder.Result = Methods.GetInstanceVariable.OpCall(
             args.ScopeExpression,
             AstFactory.Box(args.TargetExpression),
             AstUtils.Constant(InstanceVariableName)
         );
     } else {
         metaBuilder.SetWrongNumberOfArgumentsError(actualArgs.Length, 0);
     }
 }
예제 #16
0
        public override DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ context, DynamicMetaObject/*!*/[]/*!*/ args) {
            var callArgs = new CallArguments(context, args, Signature);
            
            // TODO: COM interop
            if (IsForeignMetaObject(callArgs.MetaTarget)) {
                return InteropBind(callArgs);
            }

            var metaBuilder = new MetaObjectBuilder();
            Build(metaBuilder, callArgs);
            return metaBuilder.CreateMetaObject(this);
        }
예제 #17
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     if (args.Signature.HasBlock) {
         metaBuilder.Result = Methods.HookupEvent.OpCall(
             Ast.Convert(Ast.Constant(_eventInfo), typeof(EventInfo)),
             args.TargetExpression,
             Ast.Convert(args.GetBlockExpression(), typeof(Proc))
         );
     } else {
         // TODO: make error
         throw new NotImplementedError("no block given");
     }
 }
예제 #18
0
            public static DynamicMetaObject/*!*/ Bind(RubyContext/*!*/ context, InvokeBinder/*!*/ binder,
                RubyMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, Action<MetaObjectBuilder, CallArguments>/*!*/ buildInvoke) {

                RubyCallSignature callSignature;
                if (RubyCallSignature.TryCreate(binder.CallInfo, out callSignature)) {
                    return binder.FallbackInvoke(target, args);
                }

                var metaBuilder = new MetaObjectBuilder();
                buildInvoke(metaBuilder, new CallArguments(target.CreateMetaContext(), target, args, callSignature));
                return metaBuilder.CreateMetaObject(binder);
            }
예제 #19
0
        internal void BuildInvoke(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) {
            Assert.NotNull(metaBuilder, args);
            Debug.Assert(args.Target == this);

            // TODO: we could compare infos here:
            // first argument must be this method:
            metaBuilder.AddRestriction(Ast.Equal(args.TargetExpression, AstUtils.Constant(this)));

            // set the target (becomes self in the called method):
            args.SetTarget(AstUtils.Constant(_target), _target);

            _info.BuildCall(metaBuilder, args, _name);
        }
        // Only used if method_missing() is called directly on the main singleton.
        internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
            var globalScope = args.TargetClass.GlobalScope;

            // TODO: this just calls super for now, so it doesn't look up the scope:
            metaBuilder.Result = AstUtils.LightDynamic(
                new RubyCallAction(globalScope.Context, Symbols.MethodMissing,
                    new RubyCallSignature(
                        args.Signature.ArgumentCount,
                        args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall
                    )
                ),
                typeof(object),
                args.GetCallSiteArguments(args.TargetExpression)
            );
        }
예제 #21
0
            public override MetaObject/*!*/ BindInvoke(InvokeBinder/*!*/ action, MetaObject/*!*/[]/*!*/ args) {
                RubyCallSignature callSignature;
                if (RubyCallSignature.TryCreate(action.Arguments, out callSignature)) {
                    return action.FallbackInvoke(this, args);
                }

                var context = new MetaObject(
                    Methods.GetContextFromProc.OpCall(AstUtils.Convert(Expression, typeof(Proc))),
                    Restrictions.Empty,
                    RubyOps.GetContextFromProc((Proc)Value)
                );

                var metaBuilder = new MetaObjectBuilder();
                Proc.SetCallActionRule(metaBuilder, new CallArguments(context, this, args, callSignature), true);
                return metaBuilder.CreateMetaObject(action, args);
            }
        // Only used if method_missing() is called directly on the main singleton.
        internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
        {
            var globalScope = args.TargetClass.GlobalScope;

            // TODO: this just calls super for now, so it doesn't look up the scope:
            metaBuilder.Result = AstUtils.LightDynamic(
                new RubyCallAction(globalScope.Context, Symbols.MethodMissing,
                                   new RubyCallSignature(
                                       args.Signature.ArgumentCount,
                                       args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall
                                       )
                                   ),
                typeof(object),
                args.GetCallSiteArguments(args.TargetExpression)
                );
        }
예제 #23
0
 internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     if (args.Signature.HasBlock)
     {
         metaBuilder.Result = Methods.HookupEvent.OpCall(
             Ast.Convert(Ast.Constant(_eventInfo), typeof(EventInfo)),
             args.TargetExpression,
             Ast.Convert(args.GetBlockExpression(), typeof(Proc))
             );
     }
     else
     {
         // TODO: make error
         throw new NotImplementedError("no block given");
     }
 }
예제 #24
0
        internal override void BuildSuperCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name, RubyModule /*!*/ declaringModule)
        {
            Assert.NotNull(declaringModule, metaBuilder, args);
            var visibleOverloads = GetVisibleOverloads(args, MethodBases, true);

            if (visibleOverloads.Count == 0)
            {
                metaBuilder.SetError(Methods.MakeClrVirtualMethodCalledError.OpCall(
                                         args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name)
                                         ));
            }
            else
            {
                BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions);
            }
        }
예제 #25
0
            public static DynamicMetaObject /*!*/ Bind(DynamicMetaObject /*!*/ context, GetIndexBinder /*!*/ binder,
                                                       DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ indexes,
                                                       Func <DynamicMetaObject, DynamicMetaObject[], DynamicMetaObject> /*!*/ fallback)
            {
                Debug.Assert(fallback != null);

                var callArgs    = new CallArguments(context, target, indexes, RubyCallSignature.Interop(indexes.Length));
                var metaBuilder = new MetaObjectBuilder(target, indexes);

                if (!RubyCallAction.BuildCall(metaBuilder, "[]", callArgs, false, false))
                {
                    metaBuilder.SetMetaResult(fallback(target, indexes), false);
                }

                return(metaBuilder.CreateMetaObject(binder));
            }
예제 #26
0
            public static DynamicMetaObject /*!*/ Bind(DynamicMetaObject /*!*/ context, SetMemberBinder /*!*/ binder, DynamicMetaObject /*!*/ target,
                                                       DynamicMetaObject /*!*/ value, Func <DynamicMetaObject, DynamicMetaObject, DynamicMetaObject> /*!*/ fallback)
            {
                Debug.Assert(fallback != null);

                var args        = new[] { value };
                var callArgs    = new CallArguments(context, target, args, RubyCallSignature.Interop(1));
                var metaBuilder = new MetaObjectBuilder(target, args);

                if (!RubyCallAction.BuildCall(metaBuilder, binder.Name + "=", callArgs, false, false))
                {
                    metaBuilder.SetMetaResult(fallback(target, value), false);
                }

                return(metaBuilder.CreateMetaObject(binder));
            }
예제 #27
0
            public static DynamicMetaObject /*!*/ Bind(DynamicMetaObject /*!*/ context, GetMemberBinder /*!*/ binder, DynamicMetaObject /*!*/ target,
                                                       Func <DynamicMetaObject, DynamicMetaObject> /*!*/ fallback)
            {
                Debug.Assert(fallback != null);

                var callArgs    = new CallArguments(context, target, DynamicMetaObject.EmptyMetaObjects, RubyCallSignature.Interop(0));
                var metaBuilder = new MetaObjectBuilder(target);

                if (!RubyCallAction.BuildAccess(metaBuilder, binder.Name, callArgs, false, false))
                {
                    // TODO: error suggestion?
                    metaBuilder.SetMetaResult(fallback(target), false);
                }

                return(metaBuilder.CreateMetaObject(binder));
            }
예제 #28
0
            public static DynamicMetaObject /*!*/ Bind(DynamicMetaObject /*!*/ context, string /*!*/ methodName, CallInfo /*!*/ callInfo,
                                                       DynamicMetaObjectBinder /*!*/ binder, DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args,
                                                       Func <DynamicMetaObject, DynamicMetaObject[], DynamicMetaObject> /*!*/ fallback)
            {
                Debug.Assert(fallback != null);

                var callArgs    = new CallArguments(context, target, args, RubyCallSignature.Interop(callInfo.ArgumentCount));
                var metaBuilder = new MetaObjectBuilder(target, args);

                if (!RubyCallAction.BuildCall(metaBuilder, methodName, callArgs, false, false))
                {
                    // TODO: error suggestion?
                    metaBuilder.SetMetaResult(fallback(target, args), false);
                }
                return(metaBuilder.CreateMetaObject(binder));
            }
예제 #29
0
            public static DynamicMetaObject /*!*/ Bind(InvokeBinder /*!*/ binder,
                                                       RubyMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args, Action <MetaObjectBuilder, CallArguments> /*!*/ buildInvoke)
            {
                RubyCallSignature callSignature;

                if (RubyCallSignature.TryCreate(binder.CallInfo, out callSignature))
                {
                    return(binder.FallbackInvoke(target, args));
                }

                var callArgs    = new CallArguments(target.CreateMetaContext(), target, args, callSignature);
                var metaBuilder = new MetaObjectBuilder(target, args);

                buildInvoke(metaBuilder, callArgs);
                return(metaBuilder.CreateMetaObject(binder));
            }
예제 #30
0
        internal static MethodResolutionResult Resolve(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args,
                                                       out RubyMemberInfo methodMissing)
        {
            MethodResolutionResult method;
            var targetClass       = args.TargetClass;
            var visibilityContext = GetVisibilityContext(args.Signature, args.Scope);

            using (targetClass.Context.ClassHierarchyLocker()) {
                metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext,
                                              new[] { methodName, Symbols.MethodMissing }
                                              );

                if (args.Signature.IsSuperCall)
                {
                    Debug.Assert(!args.Signature.IsVirtualCall && args.Signature.HasImplicitSelf);
                    method = targetClass.ResolveSuperMethodNoLock(methodName, targetClass).InvalidateSitesOnOverride();
                }
                else
                {
                    var options = args.Signature.IsVirtualCall ? MethodLookup.Virtual : MethodLookup.Default;
                    method = targetClass.ResolveMethodForSiteNoLock(methodName, visibilityContext, options);
                }

                if (!method.Found)
                {
                    methodMissing = targetClass.ResolveMethodMissingForSite(methodName, method.IncompatibleVisibility);
                }
                else
                {
                    methodMissing = null;
                }
            }

            // Whenever the current self's class changes we need to invalidate the rule, if a protected method is being called.
            if (method.Info != null && method.Info.IsProtected && visibilityContext.Class != null)
            {
                // We don't need to compare versions, just the class objects (super-class relationship cannot be changed).
                // Since we don't want to hold on a class object (to make it collectible) we compare references to the version handlers.
                metaBuilder.AddCondition(Ast.Equal(
                                             Methods.GetSelfClassVersionHandle.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))),
                                             Ast.Constant(visibilityContext.Class.Version)
                                             ));
            }

            return(method);
        }
예제 #31
0
        public static MetaObject TryBind(RubyContext/*!*/ context, GetMemberBinder/*!*/ binder, MetaObject/*!*/ target) {
            Assert.NotNull(context, target);
            var metaBuilder = new MetaObjectBuilder();
            var contextExpression = Ast.Constant(context);

            metaBuilder.AddTargetTypeTest(target.Value, target.Expression, context, contextExpression);

            RubyMemberInfo method = context.ResolveMethod(target.Value, binder.Name, true).InvalidateSitesOnOverride();
            if (method != null && RubyModule.IsMethodVisible(method, false)) {
                // we need to create a bound member:
                metaBuilder.Result = Ast.Constant(new RubyMethod(target.Value, method, binder.Name));
            } else {
                // TODO:
                // We need to throw an exception if we don't find method_missing so that our version update optimization works: 
                // This limits interop with other languages. 
                //                   
                // class B           CLR type with method 'foo'
                // class C < B       Ruby class
                // x = C.new
                //
                // 1. x.GET("foo") from Ruby
                //    No method found or CLR method found -> fallback to Python
                //    Python might see its method foo or might just fallback to .NET, 
                //    in any case it will add rule [1] with restriction on type of C w/o Ruby version check.
                // 2. B.define_method("foo") 
                //    This doesn't update C due to the optimization (there is no overridden method foo in C).
                // 3. x.GET("foo") from Ruby
                //    This will not invoke the binder since the rule [1] is still valid.
                //
                object symbol = SymbolTable.StringToId(binder.Name);
                RubyCallAction.BindToMethodMissing(metaBuilder, binder.Name,
                    new CallArguments(
                        new MetaObject(contextExpression, Restrictions.Empty, context),
                        new[] { 
                            target,
                            new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol) 
                        },
                        RubyCallSignature.Simple(1)
                    ), 
                    method != null
                );
            }

            // TODO: we should return null if we fail, we need to throw exception for now:
            return metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects);
        }
예제 #32
0
        public override DynamicMetaObject /*!*/ Bind(DynamicMetaObject /*!*/ scopeOrContextOrTargetOrArgArray, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "Ruby: " + GetType().Name + Signature.ToString() + ": Bind");

            var callArgs    = new CallArguments(_context, scopeOrContextOrTargetOrArgArray, args, Signature);
            var metaBuilder = new MetaObjectBuilder(this, args);

            DynamicMetaObject interopBinding;

            if (IsForeignMetaObject(callArgs.MetaTarget) && (interopBinding = InteropBind(metaBuilder, callArgs)) != null)
            {
                return(interopBinding);
            }

            Build(metaBuilder, callArgs, true);
            return(metaBuilder.CreateMetaObject(this));
        }
예제 #33
0
        protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            if (args.Target == null)
            {
                metaBuilder.Result = Ast.Constant(null);
                return(true);
            }

            var convertedTarget = args.Target as TTargetType;

            if (convertedTarget != null)
            {
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(TTargetType));
                return(true);
            }
            return(false);
        }
예제 #34
0
        public static DynamicMetaObject TryBind(RubyContext/*!*/ context, InvokeMemberBinder/*!*/ binder, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args) {
            Assert.NotNull(context, target);

            var metaBuilder = new MetaObjectBuilder();
            
            RubyCallAction.Bind(metaBuilder, binder.Name,
                new CallArguments(
                    new DynamicMetaObject(AstUtils.Constant(context), BindingRestrictions.Empty, context),
                    target, 
                    args, 
                    RubyCallSignature.Simple(binder.CallInfo.ArgumentCount)
                )
            );

            // TODO: we should return null if we fail, we need to throw exception for now:
            return metaBuilder.CreateMetaObject(binder, DynamicMetaObject.EmptyMetaObjects);
        }
예제 #35
0
        public static DynamicMetaObject TryBind(RubyContext/*!*/ context, CreateInstanceBinder/*!*/ binder, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args) {
            Assert.NotNull(context, binder, target, args);
            
            var metaBuilder = new MetaObjectBuilder();

            RubyCallAction.Bind(metaBuilder, "new", 
                new CallArguments(
                    new DynamicMetaObject(AstUtils.Constant(context), BindingRestrictions.Empty, context),
                    target, 
                    args, 
                    RubyCallSignature.Simple(args.Length)
                )
            );

            // TODO: we should return null if we fail, we need to throw exception due to version update optimization:
            return metaBuilder.CreateMetaObject(binder, DynamicMetaObject.EmptyMetaObjects);
        }
예제 #36
0
            public override DynamicMetaObject/*!*/ BindInvoke(InvokeBinder/*!*/ action, DynamicMetaObject/*!*/[]/*!*/ args) {
                RubyCallSignature callSignature;
                if (RubyCallSignature.TryCreate(action.Arguments, out callSignature)) {
                    return action.FallbackInvoke(this, args);
                }

                var self = (RubyMethod)Value;

                var context = new DynamicMetaObject(
                    Methods.GetContextFromMethod.OpCall(AstUtils.Convert(Expression, typeof(RubyMethod))),
                    BindingRestrictions.Empty,
                    RubyOps.GetContextFromMethod(self)
                );

                var metaBuilder = new MetaObjectBuilder();
                Method.SetRuleForCall(metaBuilder, new CallArguments(context, this, args, callSignature));
                return metaBuilder.CreateMetaObject(action, args);
            }
        public static MetaObject TryBind(RubyContext /*!*/ context, CreateInstanceBinder /*!*/ binder, MetaObject /*!*/ target, MetaObject /*!*/[] /*!*/ args)
        {
            Assert.NotNull(context, binder, target, args);

            var metaBuilder = new MetaObjectBuilder();

            RubyCallAction.Bind(metaBuilder, "new",
                                new CallArguments(
                                    new MetaObject(Ast.Constant(context), Restrictions.Empty, context),
                                    target,
                                    args,
                                    RubyCallSignature.Simple(args.Length)
                                    )
                                );

            // TODO: we should return null if we fail, we need to throw exception due to version update optimization:
            return(metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects));
        }
예제 #38
0
        internal override void BuildSuperCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name, RubyModule /*!*/ declaringModule)
        {
            Assert.NotNull(declaringModule, metaBuilder, args);

            IList <MethodBase> methods;

            if (!declaringModule.IsSingletonClass)
            {
                Type associatedType = GetAssociatedSystemType(declaringModule);
                methods = GetStaticDispatchMethods(associatedType, name);
            }
            else
            {
                methods = MethodBases;
            }

            BuildCallNoFlow(metaBuilder, args, name, methods, !_isClrStatic, !_isRubyMethod);
        }
예제 #39
0
        protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            object target = args.Target;

            if (args.Target == null)
            {
                metaBuilder.Result = Ast.Constant(false);
                return(true);
            }

            if (target is bool)
            {
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(bool));
                return(true);
            }

            return(true);
        }
예제 #40
0
        public static MetaObject TryBind(RubyContext /*!*/ context, InvokeMemberBinder /*!*/ binder, MetaObject /*!*/ target, MetaObject /*!*/[] /*!*/ args)
        {
            Assert.NotNull(context, target);

            var metaBuilder = new MetaObjectBuilder();

            RubyCallAction.Bind(metaBuilder, binder.Name,
                                new CallArguments(
                                    new MetaObject(Ast.Constant(context), Restrictions.Empty, context),
                                    target,
                                    args,
                                    RubyCallSignature.Simple(binder.Arguments.Count)
                                    )
                                );

            // TODO: we should return null if we fail, we need to throw exception for now:
            return(metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects));
        }
예제 #41
0
        /// <summary>
        /// Takes current result and wraps it into try-filter(MethodUnwinder)-finally block that ensures correct "break" behavior for
        /// library method calls with block given in bfcVariable (BlockParam).
        /// </summary>
        public static void RuleControlFlowBuilder(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            if (metaBuilder.Error)
            {
                return;
            }

            var metaBlock = args.GetMetaBlock();

            Debug.Assert(metaBlock != null, "RuleControlFlowBuilder should only be used if the signature has a block");

            // We construct CF only for non-nil blocks thus we need a test for it:
            if (metaBlock.Value == null)
            {
                metaBuilder.AddRestriction(Ast.Equal(metaBlock.Expression, AstUtils.Constant(null)));
                return;
            }

            // 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)));
            Expression bfcVariable = metaBuilder.BfcVariable;

            Debug.Assert(bfcVariable != null);

            // Method call with proc can invoke control flow that returns an arbitrary value from the call, so we need to type result to Object.
            // Otherwise, the result could only be result of targetExpression unless its return type is void.
            Expression          resultVariable = metaBuilder.GetTemporary(typeof(object), "#result");
            ParameterExpression unwinder;

            metaBuilder.Result = Ast.Block(
                Ast.Assign(bfcVariable, Methods.CreateBfcForLibraryMethod.OpCall(AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)))),
                AstUtils.Try(
                    Ast.Assign(resultVariable, AstUtils.Convert(metaBuilder.Result, typeof(object)))
                    ).Filter(unwinder = Ast.Parameter(typeof(MethodUnwinder), "#unwinder"),
                             Methods.IsProcConverterTarget.OpCall(bfcVariable, unwinder),

                             Ast.Assign(resultVariable, Ast.Field(unwinder, MethodUnwinder.ReturnValueField)),
                             AstUtils.Default(typeof(object))
                             ).Finally(
                    Methods.LeaveProcConverter.OpCall(bfcVariable)
                    ),
                resultVariable
                );
        }
예제 #42
0
        internal void SetRule(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            RubyModule currentDeclaringModule;
            string     currentMethodName;

            var scope = args.Scope;

            object target;

            scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target);

            var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self");

            metaBuilder.AddCondition(
                Methods.IsSuperCallTarget.OpCall(
                    AstUtils.Convert(args.ScopeExpression, typeof(RubyScope)),
                    Ast.Constant(currentDeclaringModule),
                    AstUtils.Constant(currentMethodName),
                    targetExpression
                    )
                );

            args.SetTarget(targetExpression, target);

            Debug.Assert(currentDeclaringModule != null);

            // target is stored in a local, therefore it cannot be part of the restrictions:
            metaBuilder.TreatRestrictionsAsConditions = true;
            metaBuilder.AddTargetTypeTest(target, targetExpression, scope.RubyContext, args.ContextExpression);
            metaBuilder.TreatRestrictionsAsConditions = false;

            RubyMemberInfo method = scope.RubyContext.ResolveSuperMethod(target, currentMethodName, currentDeclaringModule);

            // super calls don't go to method_missing
            if (method == null)
            {
                metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(Ast.Constant(currentMethodName)));
            }
            else
            {
                method.InvalidateSitesOnOverride = true;
                method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule);
            }
        }
예제 #43
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);
            }
        }
예제 #44
0
        /// <exception cref="MissingMethodException">The resolved method is Kernel#method_missing.</exception>
        internal static void Bind(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args)
        {
            metaBuilder.AddTargetTypeTest(args);

            RubyMemberInfo method = args.RubyContext.ResolveMethod(args.Target, methodName, true).InvalidateSitesOnOverride();

            if (method != null && RubyModule.IsMethodVisible(method, args.Signature.HasImplicitSelf))
            {
                method.BuildCall(metaBuilder, args, methodName);
            }
            else
            {
                // insert the method name argument into the args
                object symbol = SymbolTable.StringToId(methodName);
                args.InsertSimple(0, new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol));

                BindToMethodMissing(metaBuilder, methodName, args, method != null);
            }
        }
예제 #45
0
        internal static void BuildConversion(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args)
        {
            const string ToS = "to_s";

            if (TryImplicitConversion(metaBuilder, args)) {
                metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression);
                return;
            }

            RubyMemberInfo conversionMethod, methodMissing = null;

            RubyClass targetClass = args.RubyContext.GetImmediateClassOf(args.Target);
            using (targetClass.Context.ClassHierarchyLocker()) {
                metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext,
                    new[] { ToS, Symbols.MethodMissing }
                );

                conversionMethod = targetClass.ResolveMethodForSiteNoLock(ToS, VisibilityContext.AllVisible).Info;

                // find method_missing - we need to add "to_s" method to the missing methods table:
                if (conversionMethod == null) {
                    methodMissing = targetClass.ResolveMethodMissingForSite(ToS, RubyMethodVisibility.None);
                }
            }

            // invoke target.to_s and if successful convert the result to string unless it is already:
            if (conversionMethod != null) {
                conversionMethod.BuildCall(metaBuilder, args, ToS);
            } else {
                RubyCallAction.BuildMethodMissingCall(metaBuilder, args, ToS, methodMissing, RubyMethodVisibility.None, false, true);
            }

            if (metaBuilder.Error) {
                return;
            }

            metaBuilder.Result = Methods.ToSDefaultConversion.OpCall(
                AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)),
                AstUtils.Box(args.TargetExpression),
                AstUtils.Box(metaBuilder.Result)
            );
        }
예제 #46
0
            public static DynamicMetaObject /*!*/ Bind(DynamicMetaObject /*!*/ context, SetIndexBinder /*!*/ binder,
                                                       DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ indexes, DynamicMetaObject /*!*/ value,
                                                       Func <DynamicMetaObject, DynamicMetaObject[], DynamicMetaObject, DynamicMetaObject> /*!*/ fallback)
            {
                Debug.Assert(fallback != null);

                var args     = ArrayUtils.Append(indexes, value);
                var callArgs = new CallArguments(context, target, args,
                                                 new RubyCallSignature(indexes.Length, RubyCallFlags.IsInteropCall | RubyCallFlags.HasRhsArgument)
                                                 );

                var metaBuilder = new MetaObjectBuilder(target, args);

                if (!RubyCallAction.BuildCall(metaBuilder, "[]=", callArgs, false, false))
                {
                    metaBuilder.SetMetaResult(fallback(target, indexes, value), false);
                }

                return(metaBuilder.CreateMetaObject(binder));
            }
예제 #47
0
            public override DynamicMetaObject /*!*/ FallbackConvert(DynamicMetaObject /*!*/ target, DynamicMetaObject errorSuggestion)
            {
#if !SILVERLIGHT
                DynamicMetaObject result;
                if (Microsoft.Scripting.ComInterop.ComBinder.TryConvert(this, target, out result))
                {
                    return(result);
                }
#endif
                var metaBuilder = new MetaObjectBuilder(this, target, DynamicMetaObject.EmptyMetaObjects);

                if (!GenericConversionAction.BuildConversion(metaBuilder, target, Ast.Constant(_context), Type, errorSuggestion == null))
                {
                    Debug.Assert(errorSuggestion != null);
                    // no conversion applicable so we didn't do any operation with arguments that would require restrictions converted to conditions:
                    metaBuilder.SetMetaResult(errorSuggestion, false);
                }

                return(metaBuilder.CreateMetaObject(this));
            }
예제 #48
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     // TODO: splat, rhs, ...
     if (args.Signature.ArgumentCount == 0) {
         if (args.Signature.HasBlock) {
             metaBuilder.Result = Methods.HookupEvent.OpCall(
                 AstUtils.Constant(this),
                 args.TargetExpression,
                 Ast.Convert(args.GetBlockExpression(), typeof(Proc))
             );
         } else {
             metaBuilder.Result = Methods.CreateEvent.OpCall(
                 AstUtils.Constant(this),
                 args.TargetExpression,
                 AstUtils.Constant(name)
             );
         }
     } else {
         metaBuilder.SetError(Methods.MakeWrongNumberOfArgumentsError.OpCall(Ast.Constant(args.Signature.ArgumentCount), Ast.Constant(0)));
     }
 }
예제 #49
0
        protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            object target           = args.Target;
            var    targetExpression = args.TargetExpression;

            if (args.Target == null)
            {
                metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(Ast.Constant("nil"), Ast.Constant(TargetTypeName)));
                return(true);
            }

            var str = target as MutableString;

            if (str != null)
            {
                metaBuilder.Result = Methods.ConvertMutableStringToSymbol.OpCall(AstUtils.Convert(targetExpression, typeof(MutableString)));
                return(true);
            }

            var sym = target as string;

            if (sym != null)
            {
                metaBuilder.Result = AstUtils.Convert(targetExpression, typeof(string));
                return(true);
            }

            if (target is SymbolId)
            {
                metaBuilder.Result = Methods.ConvertSymbolIdToSymbol.OpCall(AstUtils.Convert(targetExpression, typeof(SymbolId)));
                return(true);
            }

            if (target is int)
            {
                metaBuilder.Result = Methods.ConvertFixnumToSymbol.OpCall(args.ContextExpression, AstUtils.Convert(targetExpression, typeof(int)));
                return(true);
            }

            return(false);
        }
예제 #50
0
        protected override void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) {
            const string ToS = "to_s";

            // no conversion for a subclass of string:
            var stringTarget = args.Target as MutableString;
            if (stringTarget != null) {
                metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression);
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(MutableString));
                return;
            }

            RubyMemberInfo conversionMethod, methodMissing = null;

            RubyClass targetClass = args.RubyContext.GetImmediateClassOf(args.Target);
            using (targetClass.Context.ClassHierarchyLocker()) {
                metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext);
                conversionMethod = targetClass.ResolveMethodForSiteNoLock(ToS, RubyClass.IgnoreVisibility).Info;

                // find method_missing - we need to add "to_xxx" methods to the missing methods table:
                if (conversionMethod == null) {
                    methodMissing = targetClass.ResolveMethodMissingForSite(ToS, RubyMethodVisibility.None);
                }
            }
            
            // invoke target.to_s and if successful convert the result to string unless it is already:
            if (conversionMethod != null) {
                conversionMethod.BuildCall(metaBuilder, args, ToS);

                if (metaBuilder.Error) {
                    return;
                }
            } else {
                RubyCallAction.BindToMethodMissing(metaBuilder, args, ToS, methodMissing, RubyMethodVisibility.None, false, true);
            }

            metaBuilder.Result = Methods.ToSDefaultConversion.OpCall(
                AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), 
                AstFactory.Box(args.TargetExpression), 
                AstFactory.Box(metaBuilder.Result)
            );
        }
예제 #51
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);
        }
예제 #52
0
        private void AddBlockArguments(MetaObjectBuilder/*!*/ rule, List<Expression>/*!*/ actualArgs, CallArguments/*!*/ args, int parameterIndex) {

            while (parameterIndex < args.Length) {
                switch (args.GetArgumentKind(parameterIndex)) {
                    case ArgumentKind.Simple:
                        actualArgs.Add(args.Expressions[parameterIndex]);
                        break;

                    case ArgumentKind.List:
                        ArgsBuilder.SplatListToArguments(rule, actualArgs, args.Values[parameterIndex], args.Expressions[parameterIndex], false);
                        break;

                    case ArgumentKind.Instance:
                    case ArgumentKind.Block:
                    default:
                        throw new NotImplementedException();
                }

                parameterIndex++;
            }
        }
예제 #53
0
        private DynamicMetaObject InteropBind(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            // TODO: argument count limit depends on the binder!

            // TODO: pass block as the last (before RHS arg?) parameter/ignore block if args not accepting block:
            var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue);

            if (!metaBuilder.Error)
            {
                MethodInfo postConverter;
                var        interopBinder = GetInteropBinder(args.RubyContext, normalizedArgs, out postConverter);
                if (interopBinder != null)
                {
                    Type resultType;
                    var  result = interopBinder.Bind(args.MetaTarget, ArrayUtils.MakeArray(normalizedArgs));

                    metaBuilder.SetMetaResult(result, args);
                    if (postConverter != null)
                    {
                        // TODO: do better?
                        var paramType = postConverter.GetParameters()[0].ParameterType;

                        metaBuilder.Result = Ast.Call(null, postConverter, AstUtils.Convert(metaBuilder.Result, paramType));
                        resultType         = postConverter.ReturnType;
                    }
                    else
                    {
                        resultType = interopBinder.ReturnType;
                    }

                    return(metaBuilder.CreateMetaObject(interopBinder, resultType));
                }
                else
                {
                    // interop protocol not supported for this binder -> ignore IDO and treat it as a CLR object:
                    return(null);
                }
            }
            return(metaBuilder.CreateMetaObject(this));
        }
예제 #54
0
        internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
        {
            Assert.NotNull(metaBuilder, args, name);

            // 2 implicit args: self, block
            var argsBuilder = new ArgsBuilder(2, Parameters.Mandatory.Length, Parameters.LeadingMandatoryCount, Parameters.Optional.Length, Parameters.Unsplat != null);

            argsBuilder.SetImplicit(0, AstUtils.Box(args.TargetExpression));
            argsBuilder.SetImplicit(1, args.Signature.HasBlock ? AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)) : AstFactory.NullOfProc);
            argsBuilder.AddCallArguments(metaBuilder, args);

            if (metaBuilder.Error)
            {
                return;
            }

            // box explicit arguments:
            var boxedArguments = argsBuilder.GetArguments();

            for (int i = 2; i < boxedArguments.Length; i++)
            {
                boxedArguments[i] = AstUtils.Box(boxedArguments[i]);
            }

            var method = GetDelegate();

            if (method.GetType() == ParamsArrayDelegateType)
            {
                // Func<object, Proc, object[], object>
                metaBuilder.Result = AstFactory.CallDelegate(method, new[] {
                    boxedArguments[0],
                    boxedArguments[1],
                    Ast.NewArrayInit(typeof(object), ArrayUtils.ShiftLeft(boxedArguments, 2))
                });
            }
            else
            {
                metaBuilder.Result = AstFactory.CallDelegate(method, boxedArguments);
            }
        }
예제 #55
0
        internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
        {
            Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType);

            if (_isSetter)
            {
                var actualArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1);
                if (!metaBuilder.Error)
                {
                    metaBuilder.Result = Ast.Assign(
                        Ast.Field(instance, _fieldInfo),
                        Converter.ConvertExpression(
                            actualArgs[0].Expression,
                            _fieldInfo.FieldType,
                            args.RubyContext,
                            args.MetaContext.Expression,
                            true
                            )
                        );
                }
            }
            else
            {
                RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0);
                if (!metaBuilder.Error)
                {
                    if (_fieldInfo.IsLiteral)
                    {
                        // TODO: seems like Compiler should correctly handle the literal field case
                        // (if you emit a read to a literal field, you get a NotSupportedExpception from
                        // FieldHandle when we try to emit)
                        metaBuilder.Result = AstUtils.Constant(_fieldInfo.GetValue(null));
                    }
                    else
                    {
                        metaBuilder.Result = Ast.Field(instance, _fieldInfo);
                    }
                }
            }
        }
예제 #56
0
        internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
            Expression expr = null;
            Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType);

            if (_isSetter) {
                // parameters should be: instance/type, value
                if (args.SimpleArgumentCount == 0 && args.Signature.HasRhsArgument) {
                    expr = Ast.Assign(
                        Ast.Field(instance, _fieldInfo),
                        Converter.ConvertExpression(
                            args.GetRhsArgumentExpression(), 
                            _fieldInfo.FieldType,
                            args.RubyContext, 
                            args.MetaContext.Expression,
                            true
                        )
                    );
                }
            } else {
                // parameter should be: instance/type
                if (args.SimpleArgumentCount == 0) {
                    if (_fieldInfo.IsLiteral) {
                        // TODO: seems like Compiler should correctly handle the literal field case
                        // (if you emit a read to a literal field, you get a NotSupportedExpception from
                        // FieldHandle when we try to emit)
                        expr = AstUtils.Constant(_fieldInfo.GetValue(null));
                    } else {
                        expr = Ast.Field(instance, _fieldInfo);
                    }
                }
            }

            if (expr != null) {
                metaBuilder.Result = expr;
            } else {
                metaBuilder.SetError(
                    Methods.MakeInvalidArgumentTypesError.OpCall(AstUtils.Constant(_isSetter ? name + "=" : name))
                );
            }
        }
예제 #57
0
        public void AddCallArguments(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            // simple args:
            for (int i = 0; i < args.SimpleArgumentCount; i++)
            {
                Add(args.GetSimpleArgumentExpression(i));
            }

            // splat arg:
            if (args.Signature.HasSplattedArgument)
            {
                AddSplatted(metaBuilder, args);
            }

            // rhs arg:
            if (args.Signature.HasRhsArgument)
            {
                Add(args.GetRhsArgumentExpression());
            }

            if (HasTooFewArguments)
            {
                metaBuilder.SetWrongNumberOfArgumentsError(_explicitArgCount, _mandatoryParamCount);
                return;
            }

            if (HasTooManyArguments)
            {
                metaBuilder.SetWrongNumberOfArgumentsError(_explicitArgCount, _mandatoryParamCount);
                return;
            }

            // add optional placeholders:
            FillMissingArguments();

            if (_hasUnsplatParameter)
            {
                AddUnsplat();
            }
        }
예제 #58
0
        internal static void BindToMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args, bool privateMethod)
        {
            // args already contain method name:
            var method = args.RubyContext.ResolveMethod(args.Target, Symbols.MethodMissing, true).InvalidateSitesOnOverride();

            // TODO: better check for builtin method
            if (method == null ||
                method.DeclaringModule == args.RubyContext.KernelModule && method is RubyMethodGroupInfo)
            {
                // throw an exception immediately, do not cache the rule:
                if (privateMethod)
                {
                    throw RubyExceptions.CreatePrivateMethodCalled(args.RubyContext, args.Target, methodName);
                }
                else
                {
                    throw RubyExceptions.CreateMethodMissing(args.RubyContext, args.Target, methodName);
                }
            }

            method.BuildCall(metaBuilder, args, methodName);
        }
예제 #59
0
        public void AddSplatted(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            var arg = args.GetSplattedMetaArgument();

            int listLength;
            ParameterExpression listVariable;

            metaBuilder.AddSplattedArgumentTest((IList)arg.Value, arg.Expression, out listLength, out listVariable);
            if (listLength > 0)
            {
                for (int i = 0; i < listLength; i++)
                {
                    Add(
                        Ast.Call(
                            listVariable,
                            typeof(IList).GetMethod("get_Item"),
                            AstUtils.Constant(i)
                            )
                        );
                }
            }
        }
예제 #60
0
        internal static bool BuildConversion(MetaObjectBuilder/*!*/ metaBuilder, DynamicMetaObject/*!*/ target, Expression/*!*/ contextExpression, 
            Type/*!*/ toType, bool defaultFallback) {

            Expression expr = TryImplicitConversion(target, toType);
            if (expr != null) {
                metaBuilder.Result = expr;
                metaBuilder.AddObjectTypeRestriction(target.Value, target.Expression);
                return true;
            }

            if (defaultFallback) {
                metaBuilder.AddObjectTypeRestriction(target.Value, target.Expression);

                metaBuilder.SetError(Methods.MakeTypeConversionError.OpCall(
                    contextExpression,
                    AstUtils.Convert(target.Expression, typeof(object)),
                    Ast.Constant(toType)
                ));
                return true;
            }

            return false;
        }