Exemple #1
0
 /// <summary>
 /// Creates a new BindingTarget when the method binding has succeeded
 /// </summary>
 internal BindingTarget(string name, int actualArgumentCount, MethodTarget target, NarrowingLevel level, MetaObject[] restrictedArgs) {
     _name = name;
     _target = target;
     _restrictedArgs = restrictedArgs;
     _level = level;
     _actualArgs = actualArgumentCount;
 }
Exemple #2
0
 public static bool TryBindInvokeMember(InvokeMemberBinder binder, ref MetaObject instance, MetaObject[] args) {
     if (TryGetMetaObject(ref instance)) {
         instance = instance.BindInvokeMember(binder, args);
         return true;
     }
     return false;
 }
Exemple #3
0
        private MetaObject[] GetArguments(MetaObject[] args, IList<MetaObject> results, int metaBinderIndex) {
            BinderMappingInfo indices = _metaBinders[metaBinderIndex];

            MetaObject[] res = new MetaObject[indices.MappingInfo.Count];
            for (int i = 0; i < res.Length; i++) {
                ParameterMappingInfo mappingInfo = indices.MappingInfo[i];

                if (mappingInfo.IsAction) {
                    // input is the result of a previous bind
                    res[i] = results[mappingInfo.ActionIndex];
                } else if (mappingInfo.IsParameter) {
                    // input is one of the original arguments
                    res[i] = args[mappingInfo.ParameterIndex];
                } else {
                    // input is a constant
                    res[i] = new MetaObject(
                        mappingInfo.Constant,
                        Restrictions.Empty,
                        mappingInfo.Constant.Value
                    );
                }
            }

            return res;
        }
Exemple #4
0
 public static bool TryBindSetIndex(SetIndexBinder binder, ref MetaObject instance, MetaObject[] args, MetaObject value) {
     if (TryGetMetaObject(ref instance)) {
         instance = instance.BindSetIndex(binder, args, value);
         return true;
     }
     return false;
 }
        public override MetaObject BindInvokeMember(InvokeMemberBinder binder, MetaObject[] args) {
            ContractUtils.RequiresNotNull(binder, "binder");

            if (args.Any(arg => ComBinderHelpers.IsStrongBoxArg(arg))) {
                return ComBinderHelpers.RewriteStrongBoxAsRef(binder, this, args);
            }

            ComMethodDesc methodDesc;

            if (_wrapperType.Funcs.TryGetValue(binder.Name, out methodDesc) ||
                  _self.TryGetMemberMethodExplicit(binder.Name, out methodDesc)) {
                return new ComInvokeBinder(
                    binder.Arguments,
                    args,
                    IDispatchRestriction(),
                    Expression.Constant(methodDesc),
                    Expression.Property(
                        Expression.Convert(Expression, typeof(IDispatchComObject)),
                        typeof(IDispatchComObject).GetProperty("DispatchObject")
                    ),
                    methodDesc
                ).Invoke();
            }

            return base.BindInvokeMember(binder, args);
        }
Exemple #6
0
 public static bool TryBindSetMember(SetMemberBinder binder, ref MetaObject instance, MetaObject value) {
     if (TryGetMetaObject(ref instance)) {
         instance = instance.BindSetMember(binder, value);
         return true;
     }
     return false;
 }
        public sealed override MetaObject Bind(MetaObject target, MetaObject[] args) {
            ContractUtils.RequiresNotNull(target, "target");
            ContractUtils.RequiresNotNullItems(args, "args");
            ContractUtils.Requires(args.Length == 1);

            return target.BindSetMember(this, args[0]);
        }
        public sealed override Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel) {
            if (args.Length == 0) {
                throw new InvalidOperationException();
            }

            MetaObject[] mos;
            if (args.Length != 1) {
                mos = new MetaObject[args.Length - 1];
                for (int i = 1; i < args.Length; i++) {
                    mos[i - 1] = MetaObject.ObjectToMetaObject(args[i], parameters[i]);
                }
            } else {
                mos = MetaObject.EmptyMetaObjects;
            }

            MetaObject binding = Bind(
                MetaObject.ObjectToMetaObject(args[0], parameters[0]),
                mos
            );

            if (binding == null) {
                throw Error.BindingCannotBeNull();
            }

            return GetMetaObjectRule(binding, returnLabel);
        }
 /// <summary>
 /// Builds a MetaObject for performing a member get.  Supports all built-in .NET members, the OperatorMethod 
 /// GetBoundMember, and StrongBox instances.
 /// </summary>
 /// <param name="name">
 /// The name of the member to retrieve.  This name is not processed by the DefaultBinder and
 /// is instead handed off to the GetMember API which can do name mangling, case insensitive lookups, etc...
 /// </param>
 /// <param name="target">
 /// The MetaObject from which the member is retrieved.
 /// </param>
 /// <param name="codeContext">
 /// An expression which provides access to the CodeContext if its required for 
 /// accessing the member (e.g. for an extension property which takes CodeContext).  By default this
 /// a null CodeContext object is passed.
 /// </param>
 public MetaObject GetMember(string name, MetaObject target, Expression codeContext) {
     return GetMember(
         name,
         target,
         codeContext,
         false
     );
 }
        public override MetaObject/*!*/ FallbackGetMember(MetaObject/*!*/ self, MetaObject/*!*/ onBindingError) {
            var result = TryBind(_context, this, self);
            if (result != null) {
                return result; 
            }

            // TODO: remove CodeContext
            return ((DefaultBinder)_context.Binder).GetMember(Name, self, Ast.Constant(null, typeof(CodeContext)), true);
        }
        /// <summary>
        /// Checks if the conversion can be handled by a simple cast.
        /// </summary>
        private static MetaObject TryAssignableConversion(Type toType, Type type, Restrictions restrictions, MetaObject arg) {
            if (toType.IsAssignableFrom(type) ||
                (type == typeof(Null) && (toType.IsClass || toType.IsInterface))) {
                // MakeSimpleConversionTarget handles the ConversionResultKind check
                return MakeSimpleConversionTarget(toType, restrictions, arg);
            }

            return null;
        }
 /// <summary>
 /// Checks if any conversions are available and if so builds the target for that conversion.
 /// </summary>
 private MetaObject TryAllConversions(Type toType, ConversionResultKind kind, Type knownType, Restrictions restrictions, MetaObject arg) {
     return
         TryAssignableConversion(toType, knownType, restrictions, arg) ??           // known type -> known type
         TryExtensibleConversion(toType, knownType, restrictions, arg) ??           // Extensible<T> -> Extensible<T>.Value
         TryUserDefinedConversion(kind, toType, knownType, restrictions, arg) ??    // op_Implicit
         TryImplicitNumericConversion(toType, knownType, restrictions, arg) ??      // op_Implicit
         TryNullableConversion(toType, kind, knownType, restrictions, arg) ??       // null -> Nullable<T> or T -> Nullable<T>
         TryNullConversion(toType, knownType, restrictions);                        // null -> reference type
 }
        public override MetaObject/*!*/ FallbackInvokeMember(MetaObject/*!*/ self, MetaObject/*!*/[]/*!*/ args, MetaObject/*!*/ onBindingError) {
            var result = TryBind(_context, this, self, args);
            if (result != null) {
                return result;
            }

            // TODO: return ((DefaultBinder)_context.Binder).GetMember(Name, self, Ast.Null(typeof(CodeContext)), true);
            throw new NotImplementedException();
        }
 public override MetaObject BindSetIndex(SetIndexBinder binder, MetaObject[] indexes, MetaObject value) {
     if (_callable.ComMethodDesc.IsPropertyPut) {
         if (indexes.Any(arg => ComBinderHelpers.IsStrongBoxArg(arg))) {
             return ComBinderHelpers.RewriteStrongBoxAsRef(binder, this, indexes.AddLast(value));
         }
         return BindComInvoke(binder.Arguments, indexes.AddLast(value));
     }
     return base.BindSetIndex(binder, indexes, value);
 }
 /// <summary>
 /// Checks if the conversion is to object and produces a target if it is.
 /// </summary>
 private static MetaObject TryConvertToObject(Type toType, Type knownType, MetaObject arg) {
     if (toType == typeof(object)) {
         if (knownType.IsValueType) {
             return MakeBoxingTarget(arg);
         } else {
             return arg;
         }
     }
     return null;
 }
        public override MetaObject/*!*/ FallbackCreateInstance(MetaObject/*!*/ target, MetaObject/*!*/[]/*!*/ args, MetaObject errorSuggestion) {
            var result = TryBind(_context, this, target, args);
            if (result != null) {
                return result;
            }

            throw new NotImplementedException();
            // TODO:
            //return ((DefaultBinder)_context.Binder).Create(.GetMember(Name, self, Ast.Null(typeof(CodeContext)), true);
        }
        /// <summary>
        /// Builds a MetaObject for performing a member delete.  Supports all built-in .NET members, the OperatorMethod 
        /// DeleteMember, and StrongBox instances.
        /// </summary>
        public MetaObject DeleteMember(string name, MetaObject target) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");

            return DeleteMember(
                name,
                target,
                Ast.Constant(null, typeof(CodeContext))
            );
        }
 private MetaObject MakeComparisonRule(OperatorInfo info, Expression codeContext, MetaObject[] args) {
     return
         TryComparisonMethod(info, codeContext, args[0], args) ??   // check the first type if it has an applicable method
         TryComparisonMethod(info, codeContext, args[0], args) ??   // then check the second type
         TryNumericComparison(info, args) ??           // try Compare: cmp(x,y) (>, <, >=, <=, ==, !=) 0
         TryInvertedComparison(info, args[0], args) ?? // try inverting the operator & result (e.g. if looking for Equals try NotEquals, LessThan for GreaterThan)...
         TryInvertedComparison(info, args[0], args) ?? // inverted binding on the 2nd type
         TryNullComparisonRule(args) ??                // see if we're comparing to null w/ an object ref or a Nullable<T>
         TryPrimitiveCompare(info, args) ??            // see if this is a primitive type where we're comparing the two values.
         MakeOperatorError(info, args);                // no comparisons are possible            
 }
        /// <summary>
        /// Creates the MetaObject for indexing directly into arrays or indexing into objects which have
        /// default members.  Returns null if we're not an indexing operation.
        /// </summary>
        private MetaObject MakeDefaultMemberRule(string oper, MetaObject[] args) {
            if (oper == StandardOperators.GetItem || oper == StandardOperators.SetItem) {
                if (args[0].LimitType.IsArray) {
                    return MakeArrayIndexRule(oper, args);
                }

                return MakeMethodIndexRule(oper, args);
            }

            return null;
        }
 public override MetaObject BindCreateInstance(CreateInstanceBinder binder, MetaObject[] args) {
     return new MetaObject(
         Expression.Call(
             AstUtils.Convert(Expression, typeof(ComTypeClassDesc)),
             typeof(ComTypeClassDesc).GetMethod("CreateInstance")
         ),
         Restrictions.Combine(args).Merge(
             Restrictions.GetTypeRestriction(Expression, typeof(ComTypeClassDesc))
         )
     );
 }
        /// <summary>
        /// Creates the meta object for the rest of the operations: comparisons and all other
        /// operators.  If the operation cannot be completed a MetaObject which indicates an
        /// error will be returned.
        /// </summary>
        private MetaObject MakeGeneralOperatorRule(string operation, Expression codeContext, MetaObject[] args) {
            OperatorInfo info = OperatorInfo.GetOperatorInfo(operation);
            MetaObject res;

            if (CompilerHelpers.IsComparisonOperator(operation)) {
                res = MakeComparisonRule(info, codeContext, args);
            } else {
                res = MakeOperatorRule(info, codeContext, args);
            }

            return res;
        }
        /// <summary>
        /// Builds a MetaObject for performing a member get.  Supports all built-in .NET members, the OperatorMethod 
        /// GetBoundMember, and StrongBox instances.
        /// </summary>
        /// <param name="name">
        /// The name of the member to retrieve.  This name is not processed by the DefaultBinder and
        /// is instead handed off to the GetMember API which can do name mangling, case insensitive lookups, etc...
        /// </param>
        /// <param name="target">
        /// The MetaObject from which the member is retrieved.
        /// </param>
        /// <param name="value">
        /// The value being assigned to the target member.
        /// </param>
        /// <param name="codeContext">
        /// An expression which provides access to the CodeContext if its required for 
        /// accessing the member (e.g. for an extension property which takes CodeContext).  By default this
        /// a null CodeContext object is passed.
        /// </param>
        public MetaObject SetMember(string name, MetaObject target, MetaObject value, Expression codeContext) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");
            ContractUtils.RequiresNotNull(value, "value");
            ContractUtils.RequiresNotNull(codeContext, "codeContext");

            return MakeSetMemberTarget(
                new SetOrDeleteMemberInfo(name, codeContext),
                target,
                value
            );
        }
        public MetaObject DeleteMember(string name, MetaObject target, Expression codeContext) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");

            return MakeDeleteMemberTarget(
                new SetOrDeleteMemberInfo(
                    name,
                    codeContext
                ),
                target.Restrict(target.LimitType)
            );
        }
        public sealed override MetaObject Bind(MetaObject target, MetaObject[] args) {
            ContractUtils.RequiresNotNull(target, "target");
            ContractUtils.RequiresNotNullItems(args, "args");

            // Try to call BindOperation
            var emo = target as OperationMetaObject;
            if (emo != null) {
                return emo.BindOperation(this, args);
            }

            // Otherwise just fall back (it's as if they didn't override BindOperation)
            return FallbackOperation(target, args);
        }
        /// <summary>
        /// Provides default binding for performing a call on the specified meta objects.
        /// </summary>
        /// <param name="signature">The signature describing the call</param>
        /// <param name="target">The meta object to be called.</param>
        /// <param name="args">
        /// Additional meta objects are the parameters for the call as specified by the CallSignature in the CallAction.
        /// </param>
        /// <param name="parameterBinder">ParameterBinder used to map arguments to parameters.</param>
        /// <returns>A MetaObject representing the call or the error.</returns>
        public MetaObject Call(CallSignature signature, ParameterBinder parameterBinder, MetaObject target, params MetaObject[] args) {
            ContractUtils.RequiresNotNullItems(args, "args");
            ContractUtils.RequiresNotNull(parameterBinder, "parameterBinder");

            TargetInfo targetInfo = GetTargetInfo(signature, target, args);

            if (targetInfo != null) {
                // we're calling a well-known MethodBase
                return MakeMetaMethodCall(signature, parameterBinder, targetInfo);
            } else {
                // we can't call this object
                return MakeCannotCallRule(target, target.LimitType);
            }
        }
        internal static MetaObject RewriteStrongBoxAsRef(CallSiteBinder action, MetaObject target, MetaObject[] args) {
            Debug.Assert(action != null && target != null && args != null);

            var restrictions = target.Restrictions.Merge(Restrictions.Combine(args));

            Expression[] argExpressions = new Expression[args.Length + 1];
            Type[] signatureTypes = new Type[args.Length + 3]; // args + CallSite, target, returnType

            signatureTypes[0] = typeof(CallSite);

            //TODO: we are not restricting on target type here, but in theory we could. 
            //It is a tradeoff between rule reuse and higher polymorphism of the site. 
            argExpressions[0] = target.Expression;
            signatureTypes[1] = target.Expression.Type;

            for (int i = 0; i < args.Length; i++) {
                MetaObject currArgument = args[i];
                if (IsStrongBoxArg(currArgument)) {
                    restrictions = restrictions.Merge(Restrictions.GetTypeRestriction(currArgument.Expression, currArgument.LimitType));

                    // we have restricted this argument to LimitType so we can convert and conversion will be trivial cast.
                    Expression boxedValueAccessor = Expression.Field(
                        Helpers.Convert(
                            currArgument.Expression,
                            currArgument.LimitType
                        ),
                        currArgument.LimitType.GetField("Value")
                    );

                    argExpressions[i + 1] = boxedValueAccessor;
                    signatureTypes[i + 2] = boxedValueAccessor.Type.MakeByRefType();
                } else {
                    argExpressions[i + 1] = currArgument.Expression;
                    signatureTypes[i + 2] = currArgument.Expression.Type;
                }
            }

            // Last signatureType is the return value
            signatureTypes[signatureTypes.Length - 1] = typeof(object);

            return new MetaObject(
                Expression.MakeDynamic(
                    Expression.GetDelegateType(signatureTypes),
                    action,
                    argExpressions
                ),
                restrictions
            );
        }
        public MetaObject Defer(MetaObject target, params MetaObject[] args) {
            ContractUtils.RequiresNotNull(target, "target");

            if (args == null) {
                return MakeDeferred(
                        target.Restrictions,
                        target
                );
            } else {
                return MakeDeferred(
                        target.Restrictions.Merge(Restrictions.Combine(args)),
                        args.AddFirst(target)
                );
            }
        }
Exemple #28
0
            public override MetaObject/*!*/ BindInvoke(InvokeBinder/*!*/ action, MetaObject/*!*/[]/*!*/ args) {
                RubyCallSignature callSignature;
                if (RubyCallSignature.TryCreate(action.Arguments, out callSignature)) {
                    return action.FallbackInvoke(this, args);
                }

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

                var metaBuilder = new MetaObjectBuilder();
                Proc.SetCallActionRule(metaBuilder, new CallArguments(context, this, args, callSignature), true);
                return metaBuilder.CreateMetaObject(action, args);
            }
        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);
        }
        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);
        }
Exemple #31
0
 public MetaObject FallbackDeleteIndex(MetaObject target, MetaObject[] indexes)
 {
     return(FallbackDeleteIndex(target, indexes, null));
 }
Exemple #32
0
 public MetaObject FallbackConvert(MetaObject target)
 {
     return(FallbackConvert(target, null));
 }
 public MetaObject FallbackBinaryOperation(MetaObject target, MetaObject arg)
 {
     return(FallbackBinaryOperation(target, arg, null));
 }
Exemple #34
0
 public abstract MetaObject FallbackDeleteIndex(MetaObject target, MetaObject[] indexes, MetaObject errorSuggestion);