Wraps the arguments of a dynamic call site Includes the actual arguments, the expressions that produced those arguments, and the call signature. These three things are grouped together to ensure that they are all in sync when we want to shift the arguments around during the method binding process.
Example #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);
        }
Example #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);
                    }
                }
            }
        }
        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;
        }
Example #4
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)
     );
 }
Example #5
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     Proc.BuildCall(
         metaBuilder,
         AstUtils.Constant(_lambda),            // proc object
         args.TargetExpression,                 // self
         args
     );
 }
 internal RubyOverloadResolver(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, SelfCallConvention callConvention,
     bool implicitProtocolConversions)
     : base(args.RubyContext.Binder) {
     _args = args;
     _metaBuilder = metaBuilder;
     _callConvention = callConvention;
     _implicitProtocolConversions = implicitProtocolConversions;
 }
        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);
        }
Example #8
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);
     }
 }
Example #9
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)
         );
     }
 }
Example #10
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;
        }
Example #11
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)
            );
        }
Example #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
            );
        }
Example #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);
        }
Example #14
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);
     }
 }
Example #15
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);
        }
Example #16
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");
     }
 }
Example #17
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);
        }
Example #18
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);
            }
        // 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)
            );
        }
Example #20
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)
            );
        }
Example #21
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)));
     }
 }
Example #22
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)
            );
        }
Example #23
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))
                );
            }
        }
Example #24
0
        // Returns true if the call was bound (with success or failure), false if fallback should be performed.
        internal static bool BuildAccess(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args,
                                         bool defaultFallback, bool callClrMethods)
        {
            RubyMemberInfo methodMissing;
            var            method = Resolve(metaBuilder, methodName, args, out methodMissing);

            if (method.Found)
            {
                if (!callClrMethods && !method.Info.IsRubyMember)
                {
                    return(false);
                }

                if (method.Info.IsDataMember)
                {
                    method.Info.BuildCall(metaBuilder, args, methodName);
                }
                else
                {
                    metaBuilder.Result = Methods.CreateBoundMember.OpCall(
                        AstUtils.Convert(args.TargetExpression, typeof(object)),
                        Ast.Constant(method.Info, typeof(RubyMemberInfo)),
                        Ast.Constant(methodName)
                        );
                }
                return(true);
            }
            else
            {
                // Ruby doesn't have "attribute_missing" so we will always use method_missing and return a bound method object:
                return(BuildMethodMissingAccess(metaBuilder, args, methodName, methodMissing, method.IncompatibleVisibility, false, defaultFallback));
            }
        }
        internal override void BuildMethodMissingCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
            var globalScope = args.TargetClass.GlobalScope;
            var context = globalScope.Context;

            if (name.LastCharacter() == '=') {
                var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1);
                if (!metaBuilder.Error) {
                    var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope");

                    metaBuilder.AddInitialization(
                        Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))))
                    );

                    var interopSetter = context.MetaBinderFactory.InteropSetMember(name.Substring(0, name.Length - 1));

                    metaBuilder.SetMetaResult(
                        interopSetter.Bind(
                            new DynamicMetaObject(
                                scopeVar,
                                BindingRestrictions.Empty,
                                globalScope.Scope
                            ),
                            new[] { normalizedArgs[0] }
                        ),
                        true
                    );
                }
            } else {
                RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0);
                Expression errorExpr =  metaBuilder.Error ? Ast.Throw(metaBuilder.Result, typeof(object)) : null;

                var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope");
                var scopeLookupResultVar = metaBuilder.GetTemporary(typeof(object), "#result");
                
                metaBuilder.AddInitialization(
                    Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))))
                );

                Expression scopeLookupResultExpr = errorExpr ?? scopeLookupResultVar;
                Expression fallbackExp;

                if (name == "scope") {
                    fallbackExp = errorExpr ?? args.TargetExpression;
                } else {
                    // super(methodName, ...args...) - ignore argument error:
                    args.InsertMethodName(name);
                    fallbackExp = AstUtils.LightDynamic(
                        context.MetaBinderFactory.Call(Symbols.MethodMissing, 
                            new RubyCallSignature(
                                args.Signature.ArgumentCount + 1,
                                args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall
                            )
                        ),
                        typeof(object),
                        args.GetCallSiteArguments(args.TargetExpression)
                    );
                }

                var scopeLookup = Ast.NotEqual(
                    Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(RubyMetaBinderFactory.InteropTryGetMemberExact(name), typeof(object), scopeVar)),
                    Expression.Constant(OperationFailed.Value)
                );

                string unmanagled = RubyUtils.TryUnmangleMethodName(name);
                if (unmanagled != null) {
                    scopeLookup = Ast.OrElse(
                        scopeLookup,
                        Ast.NotEqual(
                            Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(RubyMetaBinderFactory.InteropTryGetMemberExact(unmanagled), typeof(object), scopeVar)),
                            Expression.Constant(OperationFailed.Value)
                        )
                    );
                }

                metaBuilder.Result = Ast.Condition(
                    scopeLookup,
                    scopeLookupResultExpr,
                    fallbackExp
                );
            }
        }
Example #26
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);
            }
        }
Example #27
0
 internal virtual void BuildMethodMissingCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     args.InsertMethodName(name);
     BuildCallNoFlow(metaBuilder, args, Symbols.MethodMissing);
 }
Example #28
0
            public override DynamicMetaObject/*!*/ FallbackInvoke(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, 
                DynamicMetaObject errorSuggestion) {

                // Used in combination with GetMember to compose InvokeMember operation.
                // Gets here only if the target is not a callable meta-object. 

                var metaBuilder = new MetaObjectBuilder(this, target, args);
                var callArgs = new CallArguments(_context, target, args, CallInfo);

                metaBuilder.AddTypeRestriction(target.GetLimitType(), target.Expression);

                var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, callArgs, 0, 0);
                if (!metaBuilder.Error) {
                    // no arguments => just return the target:
                    metaBuilder.Result = target.Expression;
                } else {
                    // any arguments found (expected none):
                    metaBuilder.SetMetaResult(errorSuggestion, false);
                }
                
                return metaBuilder.CreateMetaObject(this);
            }
Example #29
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);
        }
Example #30
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);
        }
Example #31
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
                );
        }
Example #32
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);
        }
Example #33
0
        /// <summary>
        /// Takes current result and wraps it into try-filter(MethodUnwinder)-finally block that ensures correct "break" behavior for
        /// Ruby method calls with a block given in arguments.
        ///
        /// Sets up a RFC frame similarly to MethodDeclaration.
        /// </summary>
        public static void RuleControlFlowBuilder(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            Debug.Assert(args.Signature.HasBlock);
            if (metaBuilder.Error)
            {
                return;
            }

            // TODO (improvement):
            // We don't special case null block here, although we could (we would need a test for that then).
            // We could also statically know (via call-site flag) that the current method is not a proc-converter (passed by ref),
            // which would make such calls faster.
            var rfcVariable    = metaBuilder.GetTemporary(typeof(RuntimeFlowControl), "#rfc");
            var resultVariable = metaBuilder.GetTemporary(typeof(object), "#result");

            MSA.ParameterExpression unwinder;

            metaBuilder.Result = Ast.Block(
                // initialize frame (RFC):
                Ast.Assign(rfcVariable, Methods.CreateRfcForMethod.OpCall(AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)))),
                AstUtils.Try(
                    Ast.Assign(resultVariable, metaBuilder.Result)
                    ).Filter(unwinder = Ast.Parameter(typeof(MethodUnwinder), "#unwinder"),
                             Ast.Equal(Ast.Field(unwinder, MethodUnwinder.TargetFrameField), rfcVariable),

                             // return unwinder.ReturnValue;
                             Ast.Assign(resultVariable, Ast.Field(unwinder, MethodUnwinder.ReturnValueField))

                             ).Finally(
                    // we need to mark the RFC dead snce the block might escape and break later:
                    Methods.LeaveMethodFrame.OpCall(rfcVariable)
                    ),
                resultVariable
                );
        }
Example #34
0
 internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     BuildCallNoFlow(metaBuilder, args, name, MethodBases, CallConvention, ImplicitProtocolConversions);
 }
 public static void InstanceAllocator(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     ((RubyClass)args.Target).BuildObjectAllocation(metaBuilder, args, name);
 }
 internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     _ruleGenerator(metaBuilder, args, name);
 }
Example #37
0
 internal void BuildMethodMissingCall(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     BuildMethodMissingCallNoFlow(metaBuilder, args, name);
     metaBuilder.BuildControlFlow(args);
 }
Example #38
0
        // Returns true if the call was bound (with success or failure), false if fallback should be performed.
        internal static bool BuildCall(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args,
                                       bool defaultFallback, bool callClrMethods)
        {
            RubyMemberInfo methodMissing;
            var            method = Resolve(metaBuilder, methodName, args, out methodMissing);

            if (method.Found)
            {
                if (!callClrMethods && !method.Info.IsRubyMember)
                {
                    return(false);
                }

                if (args.Signature.ResolveOnly)
                {
                    metaBuilder.Result = AstFactory.True;
                    return(true);
                }

                if (args.Signature.IsVirtualCall && !method.Info.IsRubyMember)
                {
                    metaBuilder.Result = Ast.Field(null, Fields.ForwardToBase);
                    return(true);
                }

                method.Info.BuildCall(metaBuilder, args, methodName);
                return(true);
            }
            else if (args.Signature.ResolveOnly)
            {
                metaBuilder.Result = AstFactory.False;
                return(true);
            }
            else
            {
                return(BuildMethodMissingCall(metaBuilder, args, methodName, methodMissing, method.IncompatibleVisibility, false, defaultFallback));
            }
        }
Example #39
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++;
            }
        }
Example #40
0
 protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback)
 {
     return(BuildCall(metaBuilder, _methodName, args, defaultFallback, true));
 }
Example #41
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);
            }
Example #42
0
        internal override void BuildMethodMissingCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
        {
            var globalScope = args.TargetClass.GlobalScope;
            var context     = globalScope.Context;

            if (name.LastCharacter() == '=')
            {
                var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1);
                if (!metaBuilder.Error)
                {
                    var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope");

                    metaBuilder.AddInitialization(
                        Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))))
                        );

                    var interopSetter = context.MetaBinderFactory.InteropSetMember(name.Substring(0, name.Length - 1));

                    metaBuilder.SetMetaResult(
                        interopSetter.Bind(
                            new DynamicMetaObject(
                                scopeVar,
                                BindingRestrictions.Empty,
                                globalScope.Scope
                                ),
                            new[] { normalizedArgs[0] }
                            ),
                        true
                        );
                }
            }
            else
            {
                RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0);
                Expression errorExpr = metaBuilder.Error ? Ast.Throw(metaBuilder.Result, typeof(object)) : null;

                var scopeVar             = metaBuilder.GetTemporary(typeof(Scope), "#scope");
                var scopeLookupResultVar = metaBuilder.GetTemporary(typeof(object), "#result");

                metaBuilder.AddInitialization(
                    Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))))
                    );

                Expression scopeLookupResultExpr = errorExpr ?? scopeLookupResultVar;
                Expression fallbackExp;

                if (name == "scope")
                {
                    fallbackExp = errorExpr ?? args.TargetExpression;
                }
                else
                {
                    // super(methodName, ...args...) - ignore argument error:
                    args.InsertMethodName(name);
                    fallbackExp = AstUtils.LightDynamic(
                        context.MetaBinderFactory.Call(Symbols.MethodMissing,
                                                       new RubyCallSignature(
                                                           args.Signature.ArgumentCount + 1,
                                                           args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall
                                                           )
                                                       ),
                        typeof(object),
                        args.GetCallSiteArguments(args.TargetExpression)
                        );
                }

                var scopeLookup = Ast.NotEqual(
                    Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(context.MetaBinderFactory.InteropTryGetMemberExact(name), typeof(object), scopeVar)),
                    Expression.Constant(OperationFailed.Value)
                    );

                string unmanagled = RubyUtils.TryUnmangleMethodName(name);
                if (unmanagled != null)
                {
                    scopeLookup = Ast.OrElse(
                        scopeLookup,
                        Ast.NotEqual(
                            Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(context.MetaBinderFactory.InteropTryGetMemberExact(unmanagled), typeof(object), scopeVar)),
                            Expression.Constant(OperationFailed.Value)
                            )
                        );
                }

                metaBuilder.Result = Ast.Condition(
                    scopeLookup,
                    scopeLookupResultExpr,
                    fallbackExp
                    );
            }
        }
Example #43
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)) {
                    metaBuilder.SetMetaResult(fallback(target), false);
                }

                return metaBuilder.CreateMetaObject(binder);
            }
Example #44
0
        internal static IList <OverloadInfo> /*!*/ GetVisibleOverloads(CallArguments /*!*/ args, IList <OverloadInfo> /*!*/ overloads, bool isSuperCall)
        {
            IList <OverloadInfo> newOverloads = null;

            Debug.Assert(overloads.Count > 0);

            // handle CLR-protected and virtual methods:

            // TODO (opt):
            // We might be able to cache the callable overloads in a MethodGroup.
            // However, the _overloadOwners of that group would need to point to the original overload owners, not the current class, in order
            // to preserve semantics of overload deletion/redefinition (deletion of the protected overload would need to imply deletion
            // of the correpsondig public overload in the cached MethodGroup).
            if (isSuperCall || !args.RubyContext.DomainManager.Configuration.PrivateBinding)
            {
                Type         underlyingType = null;
                BindingFlags bindingFlags   = 0;

                for (int i = 0; i < overloads.Count; i++)
                {
                    var overload = overloads[i];
                    if ((isSuperCall && overload.IsVirtual && !overload.IsFinal) || overload.IsProtected)
                    {
                        if (newOverloads == null)
                        {
                            newOverloads = CollectionUtils.GetRange(overloads, 0, i);

                            RubyClass cls;
                            IRubyType rt = args.Target as IRubyType;
                            if (rt != null)
                            {
                                bindingFlags   = BindingFlags.Instance;
                                underlyingType = args.Target.GetType();
                            }
                            else if ((cls = args.Target as RubyClass) != null && cls.IsRubyClass && !cls.IsSingletonClass)
                            {
                                bindingFlags   = BindingFlags.Static;
                                underlyingType = cls.GetUnderlyingSystemType();
                            }
                        }

                        if (underlyingType != null)
                        {
                            // TODO (opt): we can define a method on the emitted type that does this more efficently:
                            IList <Type> genericArguments = overload.IsGenericMethod ? overload.GenericArguments : null;

                            OverloadInfo visibleMethod = GetMethodOverload(
                                ArrayUtils.ToArray(overload.Parameters, (pi) => pi.ParameterType),
                                genericArguments,
                                underlyingType,
#if FEATURE_REFEMIT // TODO: should we always prefix with #base# ???
                                ClsTypeEmitter.BaseMethodPrefix + overload.Name,
#else
                                overload.Name,
#endif
                                BindingFlags.Public | bindingFlags
                                );

                            Debug.Assert(visibleMethod != null);

                            newOverloads.Add(visibleMethod);
                        }
                    }
                    else if (newOverloads != null)
                    {
                        newOverloads.Add(overload);
                    }
                }
            }

            return(newOverloads ?? overloads);
        }
Example #45
0
 internal virtual void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     throw Assert.Unreachable;
 }
Example #46
0
        private void SetCallRuleArguments(
            Expression/*!*/ blockParameterExpression, // special arg #0
            Expression/*!*/ selfParameterExpression,  // special arg #1
            CallArguments/*!*/ args,                  // user args
            Expression/*!*/ codeContextExpression,
            MetaObjectBuilder/*!*/ rule, 
            ArgsBuilder/*!*/ actualArgs) {

            // mandatory args:
            actualArgs.Add(blockParameterExpression);
            actualArgs.Add(selfParameterExpression);

            int parameterIndex = 0;

            // mimics CompoundLeftValue.TransformWrite //

            // L(1,-)?
            bool leftOneNone = OptionalParamCount == 1 && !HasParamsArray;

            // L(0,*)?
            bool leftNoneSplat = OptionalParamCount == 0 && HasParamsArray;

            // R(0,*)?
            bool rightNoneSplat = !args.Signature.IsSimple && args.Length == 1 && args.GetArgumentKind(0) == ArgumentKind.List;

            // R(1,-)?
            bool rightOneNone = !args.Signature.IsSimple && args.Length == 1 && args.GetArgumentKind(0) == ArgumentKind.Simple
                || args.Signature.IsSimple && args.Length == 1;

            // R(1,*)?
            bool rightOneSplat = !args.Signature.IsSimple && args.Length == 2 &&
                args.GetArgumentKind(0) == ArgumentKind.Simple &&
                args.GetArgumentKind(1) == ArgumentKind.List;

            // R(0,-)?
            bool rightNoneNone = args.Length == 0;

            if (leftOneNone) {
                Expression rvalue;

                if (rightOneNone) {
                    // simple assignment
                    rvalue = args.Expressions[parameterIndex];
                } else if (rightOneSplat && TestEmptyList(rule, args.Values[parameterIndex + 1], args.Expressions[parameterIndex + 1])) {
                    // simple assignment if the splatted value is an empty array:
                    rvalue = args.Expressions[parameterIndex];
                } else if (rightNoneNone) {
                    // nil assignment
                    rvalue = AddWarning(codeContextExpression, Ast.Constant(null));
                } else if (rightNoneSplat) {
                    // Splat(RHS[*]):
                    rvalue = MakeArgumentSplatWithWarning(rule, args.Values[parameterIndex], args.Expressions[parameterIndex], codeContextExpression);
                } else {
                    // more than one argument -> pack to an array + warning

                    // MakeArray(RHS) + SplatAppend(RHS*):
                    List<Expression> arguments = new List<Expression>();
                    AddBlockArguments(rule, arguments, args, parameterIndex);
                    rvalue = AddWarning(codeContextExpression, ArgsBuilder.MakeArgsArray(arguments));
                }

                actualArgs.Add(rvalue);

            } else {

                // R(0,*) || R(1,-) && !L(0,*) ==> CompoundLeftValue.TransformWrite does Unsplat, MakeArray otherwise.
                // 
                // However, we are not constructing a materalized resulting array (contrary to CompoundLeftValue.TransformWrite).
                // The resulting array is comprised of slots on the stack (loaded to the formal parameters of the block #1, ..., #n).
                // Therefore, we effectively need to take items of imaginary Unsplat's result and put them into the actualArgs as arguments.
                //
                // Unsplat of x makes an array containing x if x is not an array, otherwise it returns x.
                // So, we just need to take elements of x and push them onto the stack.
                //

                List<Expression> arguments = new List<Expression>();

                if (rightNoneSplat) {
                    ArgsBuilder.SplatListToArguments(rule, arguments, args.Values[parameterIndex], args.Expressions[parameterIndex], false);
                } else if (rightOneNone && !leftNoneSplat) {
                    ArgsBuilder.SplatListToArguments(rule, arguments, args.Values[parameterIndex], args.Expressions[parameterIndex], true);
                } else {
                    AddBlockArguments(rule, arguments, args, parameterIndex);
                }

                actualArgs.AddRange(arguments);
            }

            actualArgs.AddForEachMissingArgument(delegate() { return Ast.Constant(null); });

            if (HasParamsArray) {
                actualArgs.AddParamsArray();
            }
        }
Example #47
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);
            }
        }
Example #48
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)) {
                    metaBuilder.SetMetaResult(fallback(target, args), false);
                }
                return metaBuilder.CreateMetaObject(binder);
            }
Example #49
0
        private static MethodMissingBinding BindToKernelMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName,
                                                                      RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall)
        {
            // TODO: better specialization of method_missing methods
            if (methodMissing == null ||
                methodMissing.DeclaringModule == methodMissing.Context.KernelModule && methodMissing is RubyLibraryMethodInfo)
            {
                if (isSuperCall)
                {
                    metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName)));
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Private)
                {
                    metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Protected)
                {
                    metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else
                {
                    return(MethodMissingBinding.Fallback);
                }

                return(MethodMissingBinding.Error);
            }

            return(MethodMissingBinding.Custom);
        }
Example #50
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);
            }
Example #51
0
        // Returns true if the call was bound (with success or failure), false if fallback should be performed.
        internal static bool BuildMethodMissingAccess(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName,
                                                      RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall, bool defaultFallback)
        {
            switch (BindToKernelMethodMissing(metaBuilder, args, methodName, methodMissing, incompatibleVisibility, isSuperCall))
            {
            case MethodMissingBinding.Custom:
                // we pretend we found the member and return a method that calls method_missing:
                Debug.Assert(!metaBuilder.Error);
                metaBuilder.Result = Methods.CreateBoundMissingMember.OpCall(
                    AstUtils.Convert(args.TargetExpression, typeof(object)),
                    Ast.Constant(methodMissing, typeof(RubyMemberInfo)),
                    Ast.Constant(methodName)
                    );
                return(true);

            case MethodMissingBinding.Error:
                // method_missing is defined in Kernel, error has been reported:
                return(true);

            case MethodMissingBinding.Fallback:
                // method_missing is defined in Kernel:
                if (defaultFallback)
                {
                    metaBuilder.SetError(Methods.MakeMissingMemberError.OpCall(Ast.Constant(methodName)));
                    return(true);
                }
                return(false);
            }
            throw Assert.Unreachable;
        }
 public static void MethodCall(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     ((RubyMethod)args.Target).BuildInvoke(metaBuilder, args);
 }
Example #53
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);
        }
 protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) {
     Debug.Assert(defaultFallback, "custom fallback not supported");
     ProtocolConversionAction.BuildConversion(metaBuilder, args, _resultType, _conversions);
     return true;
 }
 internal override void ApplyBlockFlowHandling(MetaObjectBuilder metaBuilder, CallArguments args)
 {
     // nop
 }