Inheritance: IronRuby.Runtime.Calls.RubyMetaBinder, IExpressionSerializable
Esempio n. 1
0
            public override DynamicMetaObject /*!*/ FallbackGetMember(DynamicMetaObject /*!*/ target, DynamicMetaObject errorSuggestion)
            {
                if (_unmangled != null)
                {
                    // TODO: errorSuggestion?
                    return(_unmangled.Bind(target, DynamicMetaObject.EmptyMetaObjects));
                }

#if !SILVERLIGHT
                DynamicMetaObject result;
                if (Microsoft.Scripting.ComInterop.ComBinder.TryBindGetMember(this, target, out result))
                {
                    return(result);
                }
#endif

                var metaBuilder = new MetaObjectBuilder(target);
                var callArgs    = new CallArguments(_context, target, DynamicMetaObject.EmptyMetaObjects, _CallInfo);

                if (!RubyCallAction.BuildAccess(metaBuilder, _originalName ?? Name, callArgs, errorSuggestion == null, true))
                {
                    Debug.Assert(errorSuggestion != null);
                    metaBuilder.SetMetaResult(errorSuggestion, false);
                }

                return(metaBuilder.CreateMetaObject(this));
            }
Esempio n. 2
0
            public override DynamicMetaObject /*!*/ FallbackGetMember(DynamicMetaObject /*!*/ target, DynamicMetaObject errorSuggestion)
            {
#if !SILVERLIGHT
                DynamicMetaObject result;
                if (Microsoft.Scripting.ComInterop.ComBinder.TryBindGetMember(this, target, out result))
                {
                    return(result);
                }
#endif

                var metaBuilder = new MetaObjectBuilder(target);
                var callArgs    = new CallArguments(_context, target, DynamicMetaObject.EmptyMetaObjects, _CallInfo);

                // See InvokeMember binder for explanation.
                bool tryAlternateBinding = _unmangled != null && errorSuggestion == null;

                if (!RubyCallAction.BuildAccess(metaBuilder, _originalName ?? Name, callArgs, errorSuggestion == null && !tryAlternateBinding, true))
                {
                    Debug.Assert(errorSuggestion != null || tryAlternateBinding);
                    if (tryAlternateBinding)
                    {
                        metaBuilder.SetMetaResult(target.BindGetMember(_unmangled), true);
                    }
                    else
                    {
                        // method wasn't found so we didn't do any operation with arguments that would require restrictions converted to conditions:
                        metaBuilder.SetMetaResult(errorSuggestion, false);
                    }
                }

                return(metaBuilder.CreateMetaObject(this));
            }
Esempio n. 3
0
            internal static DynamicMetaObject FallbackInvokeMember(IInteropBinder /*!*/ binder, string /*!*/ methodName, CallInfo /*!*/ callInfo,
                                                                   DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args, DynamicMetaObject errorSuggestion, InvokeMember alternateBinder)
            {
                var metaBuilder = new MetaObjectBuilder(binder, target, args);
                var callArgs    = new CallArguments(binder.Context, target, args, callInfo);

                //
                // If we are called with no errorSuggestion we attempt to bind the alternate name since the current binding failed
                // (unless we successfully bind to a COM object method or Ruby/CLR method defined on the target meta-object).
                // If we already have an errorSuggestion we use it as it represents a valid binding and no alternate name lookups are thus necessary.
                //
                // For example, DynamicObject InvokeMember calls our FallbackInvokeMember 4 times:
                //
                // 1) binder.fallback(..., errorSuggestion: null)
                //    -> DynamicObject.BindInvokeMember(altBinder)
                //       2) altBinder.fallback(..., errorSuggestion: null)
                //          -> [[ error ]]
                //
                //       3) altBinder.fallback(..., errorSuggestion: [[
                //                                                     TryInvokeMember(altName, out result)
                //                                                       ? result
                //                                                       : TryGetMember(altName, out result)
                //                                                           ? altBinder.FallbackInvoke(result)
                //                                                           : [[ error ]]
                //                                                   ]])
                //          -> errorSuggestion
                //
                // 4) binder.fallback(..., errorSuggestion: [[
                //                                            TryInvokeMember(name, out result)
                //                                              ? result
                //                                              : TryGetMember(name, out result)
                //                                                  ? binder.FallbackInvoke(result)
                //                                                    TryInvokeMember(altName, out result)
                //                                                      ? result
                //                                                      : TryGetMember(altName, out result)
                //                                                          ? altBinder.FallbackInvoke(result)
                //                                                          : [[ error ]]
                //
                //                                          ]])
                // -> errorSuggestion
                //
                bool tryAlternateBinding = alternateBinder != null && errorSuggestion == null;

                if (!RubyCallAction.BuildCall(metaBuilder, methodName, callArgs, errorSuggestion == null && !tryAlternateBinding, true))
                {
                    Debug.Assert(errorSuggestion != null || tryAlternateBinding);
                    if (tryAlternateBinding)
                    {
                        metaBuilder.SetMetaResult(target.BindInvokeMember(alternateBinder, args), true);
                    }
                    else
                    {
                        // method wasn't found so we didn't do any operation with arguments that would require restrictions converted to conditions:
                        metaBuilder.SetMetaResult(errorSuggestion, false);
                    }
                }

                return(metaBuilder.CreateMetaObject((DynamicMetaObjectBinder)binder));
            }
Esempio n. 4
0
        public RubyCallAction /*!*/ Call(string /*!*/ methodName, RubyCallSignature signature)
        {
            var key = Key.Create(methodName, signature);

            lock (_callActions) {
                RubyCallAction result;
                if (!_callActions.TryGetValue(key, out result))
                {
                    _callActions.Add(key, result = new RubyCallAction(_context, methodName, signature));
                }
                return(result);
            }
        }
Esempio n. 5
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));
        }
Esempio n. 6
0
            internal static DynamicMetaObject FallbackInvokeMember(IInteropBinder /*!*/ binder, string /*!*/ methodName, CallInfo /*!*/ callInfo,
                                                                   DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args, DynamicMetaObject errorSuggestion)
            {
                var metaBuilder = new MetaObjectBuilder(binder, target, args);
                var callArgs    = new CallArguments(binder.Context, target, args, callInfo);

                if (!RubyCallAction.BuildCall(metaBuilder, methodName, callArgs, errorSuggestion == null, true))
                {
                    Debug.Assert(errorSuggestion != null);
                    // method wasn't found so we didn't do any operation with arguments that would require restrictions converted to conditions:
                    metaBuilder.SetMetaResult(errorSuggestion, false);
                }

                return(metaBuilder.CreateMetaObject((DynamicMetaObjectBinder)binder));
            }
Esempio n. 7
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));
            }
Esempio n. 8
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));
            }
Esempio n. 9
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));
            }
Esempio n. 10
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));
            }
        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));
        }
        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));
        }
Esempio n. 13
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));
            }
Esempio n. 14
0
        internal void SetRule(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            Assert.NotNull(metaBuilder, args);
            Debug.Assert(args.SimpleArgumentCount == 0 && !args.Signature.HasBlock && !args.Signature.HasSplattedArgument && !args.Signature.HasRhsArgument);
            Debug.Assert(args.Signature.HasScope);

            var ec = args.RubyContext;

            // implicit conversions should only depend on a static type:
            if (TryImplicitConversion(metaBuilder, args))
            {
                if (args.Target == null)
                {
                    metaBuilder.AddRestriction(Ast.Equal(args.TargetExpression, Ast.Constant(null, args.TargetExpression.Type)));
                }
                else
                {
                    metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression);
                }
                return;
            }

            // check for type version:
            metaBuilder.AddTargetTypeTest(args);

            string     toMethodName            = ToMethodName;
            Expression targetClassNameConstant = Ast.Constant(ec.GetClassOf(args.Target).Name);

            // Kernel#respond_to? method is not overridden => we can optimize
            RubyMemberInfo respondToMethod = ec.ResolveMethod(args.Target, Symbols.RespondTo, true).InvalidateSitesOnOverride();

            if (respondToMethod == null ||
                // the method is defined in library, hasn't been replaced by user defined method (TODO: maybe we should make this check better)
                (respondToMethod.DeclaringModule == ec.KernelModule && respondToMethod is RubyMethodGroupInfo))
            {
                RubyMemberInfo conversionMethod = ec.ResolveMethod(args.Target, toMethodName, false).InvalidateSitesOnOverride();
                if (conversionMethod == null)
                {
                    // error:
                    SetError(metaBuilder, targetClassNameConstant, args);
                    return;
                }
                else
                {
                    // invoke target.to_xxx() and validate it; returns an instance of TTargetType:
                    conversionMethod.BuildCall(metaBuilder, args, toMethodName);

                    if (!metaBuilder.Error && ConversionResultValidator != null)
                    {
                        metaBuilder.Result = ConversionResultValidator.OpCall(targetClassNameConstant, AstFactory.Box(metaBuilder.Result));
                    }
                    return;
                }
            }
            else if (!RubyModule.IsMethodVisible(respondToMethod, false))
            {
                // respond_to? is private:
                SetError(metaBuilder, targetClassNameConstant, args);
                return;
            }

            // slow path: invoke respond_to?, to_xxx and result validation:

            var conversionCallSite = Ast.Dynamic(
                RubyCallAction.Make(toMethodName, RubyCallSignature.WithScope(0)),
                typeof(object),
                args.ScopeExpression, args.TargetExpression
                );

            Expression opCall;

            metaBuilder.Result = Ast.Condition(
                // If

                // respond_to?()
                Methods.IsTrue.OpCall(
                    Ast.Dynamic(
                        RubyCallAction.Make(Symbols.RespondTo, RubyCallSignature.WithScope(1)),
                        typeof(object),
                        args.ScopeExpression, args.TargetExpression, Ast.Constant(SymbolTable.StringToId(toMethodName))
                        )
                    ),

                // Then

                // to_xxx():
                opCall = (ConversionResultValidator == null) ? conversionCallSite :
                         ConversionResultValidator.OpCall(targetClassNameConstant, conversionCallSite),

                // Else

                AstUtils.Convert(
                    (ConversionResultValidator == null) ? args.TargetExpression :
                    Ast.Convert(
                        Ast.Throw(Methods.CreateTypeConversionError.OpCall(targetClassNameConstant, Ast.Constant(TargetTypeName))),
                        typeof(object)
                        ),
                    opCall.Type
                    )
                );
        }
Esempio n. 15
0
        protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback)
        {
            RubyModule currentDeclaringModule;
            string     currentMethodName;

            var scope     = args.Scope;
            var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope));

            RubyScope targetScope;
            int       scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope);

            if (scopeNesting == -1)
            {
                metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr));
                metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall());
                return(true);
            }

            object target           = targetScope.SelfObject;
            var    targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self");
            var    assignTarget     = Ast.Assign(
                targetExpression,
                Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting))
                );

            if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod)
            {
                metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate)));
                metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall());
                return(true);
            }

            // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail:
            metaBuilder.AddInitialization(assignTarget);

            args.SetTarget(targetExpression, target);

            Debug.Assert(currentDeclaringModule != null);

            RubyMemberInfo method;
            RubyMemberInfo methodMissing = null;

            // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C
            // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419.

            // 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 (_signature.ResolveOnly)
                {
                    metaBuilder.Result = AstUtils.Constant(method != null);
                    return(true);
                }

                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);
        }