public DynamicMetaObject DoOperation(string operation, OverloadResolverFactory resolverFactory, params DynamicMetaObject[] args) {
            ContractUtils.RequiresNotNull(operation, "operation");
            ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory");
            ContractUtils.RequiresNotNullItems(args, "args");

            return MakeGeneralOperatorRule(operation, resolverFactory, args);   // Then try comparison / other ExpressionType
        }
Example #2
0
        public override Ast ConvertExpression(Ast expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory)
        {
            Type exprType = expr.Type;
            Type visType = CompilerHelpers.GetVisibleType(toType);

            if (typeof(IFn).IsAssignableFrom(exprType) && typeof(Delegate).IsAssignableFrom(visType))
                return Ast.Call(typeof(Converter).GetMethod("ConvertToDelegate"), Ast.Convert(expr, typeof(IFn)), Expression.Constant(visType));

            // Follow through on our promise to convert IEnumerable<Object> or IEnumerable to IEnumerable<T> for any T
            if (toType.IsGenericType && ! toType.IsAssignableFrom(expr.Type))
            {
                // The following is inspired by IronPython.Runtime.Binding.Python.ConversionBinder.FallbackConvert
                Type genTo = toType.GetGenericTypeDefinition();
                if ( genTo == typeof(IList<>))
                {
                    return MakeToGenericConversion(expr,toType,typeof(IList<object>),typeof(ListGenericWrapper<>));
                }
                else if (genTo == typeof(IDictionary<,>))
                {
                    return MakeToGenericConversion(expr,toType,typeof(IDictionary<object,object>),typeof(DictionaryGenericWrapper<,>));
                }
                else if (genTo == typeof(IEnumerable<>))
                {   
                    return MakeToGenericConversion(expr, toType, typeof(IEnumerable),typeof(IEnumerableOfTWrapper<>));
                }
            }

            return base.ConvertExpression(expr, toType, kind, resolverFactory);
        }
 protected override DynamicMetaObject SetBoundValue(OverloadResolverFactory factory, ActionBinder binder, Type type, DynamicMetaObject value, DynamicMetaObject instance, DynamicMetaObject errorSuggestion) {
     return new DynamicMetaObject(
         Expression.Condition(
             Ast.Call(
                 typeof(PythonOps).GetMethod("SlotTrySetValue"),
                 ((PythonOverloadResolverFactory)factory)._codeContext,
                 AstUtils.Constant(GetSlot(), typeof(PythonTypeSlot)),
                 AstUtils.Convert(
                     instance.Expression,
                     typeof(object)
                 ),
                 AstUtils.Constant(DynamicHelpers.GetPythonTypeFromType(type)),
                 value.Expression
             ),
             AstUtils.Convert(value.Expression, typeof(object)),
             errorSuggestion != null ?
                 errorSuggestion.Expression :
                 Expression.Throw(
                     Expression.Call(
                         typeof(PythonOps).GetMethod("AttributeErrorForMissingAttribute", new Type[] { typeof(object), typeof(string) }),
                         instance.Expression,
                         Expression.Constant(Name)
                     ),
                     typeof(object)
                 )
         ),
         BindingRestrictions.Empty
     );
 }
        /// <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>
        public DynamicMetaObject SetIndex(OverloadResolverFactory resolverFactory, DynamicMetaObject[] args) {
            if (args[0].LimitType.IsArray) {
                return MakeArrayIndexRule(resolverFactory, IndexType.Set, args);
            }

            return MakeMethodIndexRule(IndexType.Set, resolverFactory, args);
        }
Example #5
0
        public override Expression ConvertExpression(Expression expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory)
        {
            ContractUtils.RequiresNotNull(expr, "expr");
            ContractUtils.RequiresNotNull(toType, "toType");

            Type exprType = expr.Type;

            if (toType == typeof(object))
            {
                if (exprType.IsValueType())
                    return Utils.Convert(expr, toType);
                else
                    return expr;
            }

            if (toType.IsAssignableFrom(exprType))
                return expr;

            Type visType = Context.Binder.PrivateBinding ? toType : CompilerHelpers.GetVisibleType(toType);

            return Binders.Convert(
                _context,
                visType,
                kind,
                expr
            );
        }
Example #6
0
        /// <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="resolverFactory">Overload resolver factory.</param>
        /// <param name="errorSuggestion">The result should the object be uncallable.</param>
        /// <returns>A MetaObject representing the call or the error.</returns>
        public DynamicMetaObject Call(CallSignature signature, DynamicMetaObject errorSuggestion, OverloadResolverFactory resolverFactory,ClrMethod method, DynamicMetaObject target, params DynamicMetaObject[] args)
        {
            ContractUtils.RequiresNotNullItems(args, "args");
            ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory");

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

            if (targetInfo != null)
            {
                // we're calling a well-known MethodBase
                DynamicMetaObject res = MakeMetaMethodCall(signature, resolverFactory, targetInfo);
                if (res.Expression.Type.IsValueType)
                {
                    if (res.Expression.Type == Types.Void)
                        res = new DynamicMetaObject(
                            Expression.Block(Types.Object[0],
                                res.Expression,
                                Expression.Constant(null)),
                            res.Restrictions
                        );
                    else
                        res = new DynamicMetaObject(
                            Expression.Convert(res.Expression, typeof(object)),
                            res.Restrictions
                    );
                }

                return res;
            }
            else
            {
                // we can't call this object
                return errorSuggestion ?? MakeCannotCallRule(target, target.GetLimitType());
            }
        }
        public DynamicMetaObject ConvertTo(Type toType, ConversionResultKind kind, DynamicMetaObject arg, OverloadResolverFactory resolverFactory, DynamicMetaObject errorSuggestion) {
            ContractUtils.RequiresNotNull(toType, "toType");
            ContractUtils.RequiresNotNull(arg, "arg");

            Type knownType = arg.GetLimitType();

            // try all the conversions - first look for conversions against the expression type,
            // these can be done w/o any additional tests.  Then look for conversions against the 
            // restricted type.
            BindingRestrictions typeRestrictions = arg.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg.Expression, arg.GetLimitType()));

            DynamicMetaObject res = 
                TryConvertToObject(toType, arg.Expression.Type, arg, typeRestrictions) ??
                TryAllConversions(resolverFactory, toType, kind, arg.Expression.Type, typeRestrictions, arg) ??
                TryAllConversions(resolverFactory, toType, kind, arg.GetLimitType(), typeRestrictions, arg) ??
                errorSuggestion ??
                MakeErrorTarget(toType, kind, typeRestrictions, arg);

            if ((kind == ConversionResultKind.ExplicitTry || kind == ConversionResultKind.ImplicitTry) && toType.IsValueType) {
                res = new DynamicMetaObject(
                    AstUtils.Convert(
                        res.Expression,
                        typeof(object)
                    ),
                    res.Restrictions
                );
            }
            return res;
        }
 /// <summary>
 /// Checks if any conversions are available and if so builds the target for that conversion.
 /// </summary>
 private DynamicMetaObject TryAllConversions(OverloadResolverFactory factory, Type toType, ConversionResultKind kind, Type knownType, BindingRestrictions restrictions, DynamicMetaObject 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(factory, toType, kind, knownType, restrictions, arg) ??   // null -> Nullable<T> or T -> Nullable<T>
         TryNullConversion(toType, knownType, restrictions);                             // null -> reference type
 }
 /// <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="resolverFactory">
 /// Provides overload resolution and method binding for any calls which need to be performed for the GetMember.
 /// </param>
 /// <returns>
 /// Returns a DynamicMetaObject which represents the value that will be returned when the member is accessed.
 /// 
 /// The returned DynamicMetaObject may be strongly typed to a value type which needs boxing before being
 /// returned from a standard DLR GetMemberBinder.  The language is responsible for performing any boxing
 /// so that it has an opportunity to perform custom boxing.
 /// </returns>
 public DynamicMetaObject GetMember(string name, DynamicMetaObject target, OverloadResolverFactory resolverFactory) {
     return GetMember(
         name,
         target,
         resolverFactory,
         false,
         null
     );
 }
Example #10
0
        public override Ast ConvertExpression(Ast expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory)
        {
            Type exprType = expr.Type;
            Type visType = CompilerHelpers.GetVisibleType(toType);

            if (typeof(IFn).IsAssignableFrom(exprType) && typeof(Delegate).IsAssignableFrom(visType))
                return Ast.Call(typeof(Converter).GetMethod("ConvertToDelegate"), Ast.Convert(expr, typeof(IFn)), Expression.Constant(visType));

            return base.ConvertExpression(expr, toType, kind, resolverFactory);
        }
        /// <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="resolverFactory">
        /// rovides overload resolution and method binding for any calls which need to be performed for the SetMember.
        /// </param>
        public DynamicMetaObject SetMember(string name, DynamicMetaObject target, DynamicMetaObject value, OverloadResolverFactory resolverFactory) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");
            ContractUtils.RequiresNotNull(value, "value");
            ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory");

            return MakeSetMemberTarget(
                new SetOrDeleteMemberInfo(name, resolverFactory),
                target,
                value
            );
        }
        public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, OverloadResolverFactory resolutionFactory) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");

            return MakeDeleteMemberTarget(
                new SetOrDeleteMemberInfo(
                    name,
                    resolutionFactory
                ),
                target.Restrict(target.GetLimitType())
            );
        }
Example #13
0
        /// <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="resolverFactory">Overload resolver factory.</param>
        /// <returns>A MetaObject representing the call or the error.</returns>
        public DynamicMetaObject Call(CallSignature signature, OverloadResolverFactory resolverFactory, DynamicMetaObject target, params DynamicMetaObject[] args) {
            ContractUtils.RequiresNotNullItems(args, "args");
            ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory");

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

            if (targetInfo != null) {
                // we're calling a well-known MethodBase
                return MakeMetaMethodCall(signature, resolverFactory, targetInfo);
            } else {
                // we can't call this object
                return MakeCannotCallRule(target, target.GetLimitType());
            }
        }
 protected override DynamicMetaObject GetBoundValue(OverloadResolverFactory factory, ActionBinder binder, Type type, DynamicMetaObject instance) {
     return new DynamicMetaObject(
         Ast.Call(
             typeof(PythonOps).GetMethod("SlotGetValue"),
             ((PythonOverloadResolverFactory)factory)._codeContext,
             AstUtils.Constant(GetSlot(), typeof(PythonTypeSlot)),
             AstUtils.Convert(
                 instance.Expression,
                 typeof(object)
             ),
             AstUtils.Constant(DynamicHelpers.GetPythonTypeFromType(type))
         ),
         BindingRestrictions.Empty
     );
 }
        /// <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="resolverFactory">
        /// An OverloadResolverFactory which can be used for performing overload resolution and method binding.
        /// </param>
        /// <param name="isNoThrow">
        /// True if the operation should return Operation.Failed on failure, false if it
        /// should return the exception produced by MakeMissingMemberError.
        /// </param>
        /// <param name="errorSuggestion">
        /// The meta object to be used if the get results in an error.
        /// </param>
        public DynamicMetaObject GetMember(string name, DynamicMetaObject target, OverloadResolverFactory resolverFactory, bool isNoThrow, DynamicMetaObject errorSuggestion) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");
            ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory");

            return MakeGetMemberTarget(
                new GetMemberInfo(
                    name,
                    resolverFactory,
                    isNoThrow,
                    errorSuggestion
                ),
                target
            );
        }
Example #16
0
        private DynamicMetaObject MakeMetaMethodCall(CallSignature signature, OverloadResolverFactory resolverFactory, TargetInfo targetInfo) {
            BindingRestrictions restrictions = BindingRestrictions.Combine(targetInfo.Arguments).Merge(targetInfo.Restrictions);
            if (targetInfo.Instance != null) {
                restrictions = targetInfo.Instance.Restrictions.Merge(restrictions);
            }

            DynamicMetaObject[] args;
            CallTypes callType;
            if (targetInfo.Instance != null) {
                args = ArrayUtils.Insert(targetInfo.Instance, targetInfo.Arguments);
                callType = CallTypes.ImplicitInstance;
            } else {
                args = targetInfo.Arguments;
                callType = CallTypes.None;
            }

            return CallMethod(resolverFactory.CreateOverloadResolver(args, signature, callType), targetInfo.Targets, restrictions);
        }
Example #17
0
        public override DynamicMetaObject GetValue(OverloadResolverFactory resolverFactory, ActionBinder binder, Type type) {
            if (!IsStatic || GetIndexParameters().Length > 0) {
                // need to bind to a value or parameters to get the value.
                return binder.ReturnMemberTracker(type, this);
            }

            MethodInfo getter = ResolveGetter(binder.PrivateBinding);
            if (getter == null || getter.ContainsGenericParameters) {
                // no usable getter
                return null;
            }

            if (getter.IsPublic && getter.DeclaringType.IsPublic) {
                return binder.MakeCallExpression(resolverFactory, getter);
            }

            // private binding is just a call to the getter method...
            return MemberTracker.FromMemberInfo(getter).Call(resolverFactory, binder);
        }
Example #18
0
        /// <summary>
        /// Called when the user is accessing a protected or private member on a get.
        /// 
        /// The default implementation allows access to the fields or properties using reflection.
        /// </summary>
        public virtual ErrorInfo MakeNonPublicMemberGetError(OverloadResolverFactory resolverFactory, MemberTracker member, Type type, DynamicMetaObject instance) {
            switch (member.MemberType) {
                case TrackerTypes.Field:
                    FieldTracker ft = (FieldTracker)member;

                    return ErrorInfo.FromValueNoError(
                        Ast.Call(
                            AstUtils.Convert(AstUtils.Constant(ft.Field), typeof(FieldInfo)),
                            typeof(FieldInfo).GetMethod("GetValue"),
                            AstUtils.Convert(instance.Expression, typeof(object))
                        )
                    );
                case TrackerTypes.Property:
                    PropertyTracker pt = (PropertyTracker)member;

                    return ErrorInfo.FromValueNoError(
                        MemberTracker.FromMemberInfo(pt.GetGetMethod(true)).Call(resolverFactory, this, instance).Expression
                    );
                default:
                    throw new InvalidOperationException();
            }
        }
Example #19
0
        /// <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="resolverFactory">Overload resolver factory.</param>
        /// <returns>A MetaObject representing the call or the error.</returns>
        public DynamicMetaObject Call(CallSignature signature, OverloadResolverFactory resolverFactory, DynamicMetaObject target, params DynamicMetaObject[] args) {
            ContractUtils.RequiresNotNullItems(args, "args");
            ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory");

            TargetInfo targetInfo = GetTargetInfo(target, args);

            if (targetInfo != null) {
                // we're calling a well-known MethodBase
                DynamicMetaObject res =  MakeMetaMethodCall(signature, resolverFactory, targetInfo);
                if (res.Expression.Type.IsValueType) {
                    res = new DynamicMetaObject(
                        AstUtils.Convert(res.Expression, typeof(object)),
                        res.Restrictions
                    );
                }

                return res;
            } else {
                // we can't call this object
                return MakeCannotCallRule(target, target.GetLimitType());
            }
        }
Example #20
0
        public virtual ErrorInfo MakeEventValidation(MemberGroup members, DynamicMetaObject eventObject, DynamicMetaObject value, OverloadResolverFactory resolverFactory) {
            EventTracker ev = (EventTracker)members[0];

            // handles in place addition of events - this validates the user did the right thing.
            return ErrorInfo.FromValueNoError(
                Expression.Call(
                    typeof(BinderOps).GetMethod("SetEvent"),
                    AstUtils.Constant(ev),
                    value.Expression
                )
            );
        }
        private Expression ConvertIfNeeded(OverloadResolverFactory factory, Expression expression, Type type) {
            Assert.NotNull(expression, type);

            if (expression.Type != type) {
                return ConvertExpression(expression, type, ConversionResultKind.ExplicitCast, factory);
            }
            return expression;
        }
        private DynamicMetaObject TryMakeInvertedBindingTarget(OverloadResolverFactory resolverFactory, MethodBase[] targets, DynamicMetaObject[] args) {
            var resolver = resolverFactory.CreateOverloadResolver(args, new CallSignature(args.Length), CallTypes.None);
            BindingTarget target = resolver.ResolveOverload(targets[0].Name, targets, NarrowingLevel.None, NarrowingLevel.All);
            if (target.Success) {
                return new DynamicMetaObject(
                    Ast.Not(target.MakeExpression()),
                    target.RestrictedArguments.GetAllRestrictions()
                );
            }

            return null;
        }
        private DynamicMetaObject MakeArrayIndexRule(OverloadResolverFactory factory, IndexType oper, DynamicMetaObject[] args) {
            if (CanConvertFrom(GetArgType(args, 1), typeof(int), false, NarrowingLevel.All)) {
                BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[0].Expression, args[0].GetLimitType()).Merge(BindingRestrictions.Combine(args));

                if (oper == IndexType.Get) {
                    return new DynamicMetaObject(
                        Ast.ArrayAccess(
                            args[0].Expression,
                            ConvertIfNeeded(factory, args[1].Expression, typeof(int))
                        ),
                        restrictions
                    );
                } else {
                    return new DynamicMetaObject(
                        Ast.Assign(
                            Ast.ArrayAccess(
                                args[0].Expression,
                                ConvertIfNeeded(factory, args[1].Expression, typeof(int))
                            ),
                            ConvertIfNeeded(factory, args[2].Expression, args[0].GetLimitType().GetElementType())
                        ),
                        restrictions.Merge(args[1].Restrictions)
                    );
                }
            }

            return null;
        }
        private DynamicMetaObject MakeMethodIndexRule(IndexType oper, OverloadResolverFactory resolverFactory, DynamicMetaObject[] args) {
            MethodInfo[] defaults = GetMethodsFromDefaults(args[0].GetLimitType().GetDefaultMembers(), oper);
            if (defaults.Length != 0) {
                DynamicMetaObject[] selfWithArgs = args;
                ParameterExpression arg2 = null;

                if (oper == IndexType.Set) {
                    Debug.Assert(args.Length >= 2);

                    // need to save arg2 in a temp because it's also our result
                    arg2 = Ast.Variable(args[2].Expression.Type, "arg2Temp");

                    args[2] = new DynamicMetaObject(
                        Ast.Assign(arg2, args[2].Expression),
                        args[2].Restrictions
                    );
                }

                BindingRestrictions restrictions = BindingRestrictions.Combine(args);

                var resolver = resolverFactory.CreateOverloadResolver(selfWithArgs, new CallSignature(selfWithArgs.Length), CallTypes.ImplicitInstance);
                BindingTarget target = resolver.ResolveOverload(oper == IndexType.Get ? "get_Item" : "set_Item", defaults, NarrowingLevel.None, NarrowingLevel.All);
                if (target.Success) {
                    if (oper == IndexType.Get) {
                        return new DynamicMetaObject(
                            target.MakeExpression(),
                            restrictions.Merge(target.RestrictedArguments.GetAllRestrictions())
                        );
                    } else {
                        return new DynamicMetaObject(
                            Ast.Block(
                                new ParameterExpression[] { arg2 },
                                target.MakeExpression(),
                                arg2
                            ),
                            restrictions.Merge(target.RestrictedArguments.GetAllRestrictions())
                        );
                    }
                }

                return MakeError(
                    resolver.MakeInvalidParametersError(target),
                    restrictions,
                    typeof(object)
                );
            }

            return null;
        }
        private DynamicMetaObject TryReverseOperator(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject[] args) {
            // we need a special conversion for the return type on MemberNames
            if (args.Length > 0) {
                MethodInfo[] targets = GetApplicableMembers(args[0].LimitType, info);
                if (targets.Length > 0) {
                    return TryMakeBindingTarget(resolverFactory, targets, args, BindingRestrictions.Empty);
                }
            }

            return null;
        }
        private DynamicMetaObject TryForwardOperator(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject[] args) {
            MethodInfo[] targets = GetApplicableMembers(args[0].GetLimitType(), info);
            BindingRestrictions restrictions = BindingRestrictions.Empty;

            if (targets.Length > 0) {
                return TryMakeBindingTarget(resolverFactory, targets, args, restrictions);
            }

            return null;
        }
 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] // TODO: fix
 private DynamicMetaObject MakeOperatorRule(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject[] args) {
     return
         TryForwardOperator(info, resolverFactory, args) ??
         TryReverseOperator(info, resolverFactory, args) ??
         TryPrimitiveOperator(info, args) ??
         TryMakeDefaultUnaryRule(info, args) ??
         MakeOperatorError(info, args);
 }
        private DynamicMetaObject TryInvertedComparison(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject target, DynamicMetaObject[] args) {
            ExpressionType revOp = GetInvertedOperator(info.Operator);
            OperatorInfo revInfo = OperatorInfo.GetOperatorInfo(revOp);
            Debug.Assert(revInfo != null);

            // try the 1st type's opposite function result negated 
            MethodBase[] targets = GetApplicableMembers(target.GetLimitType(), revInfo);
            if (targets.Length > 0) {
                return TryMakeInvertedBindingTarget(resolverFactory, targets, args);
            }

            return null;
        }
        private DynamicMetaObject TryNumericComparison(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject[] args) {
            MethodInfo[] targets = FilterNonMethods(
                args[0].GetLimitType(),
                GetMember(
                    MemberRequestKind.Operation,
                    args[0].GetLimitType(),
                    "Compare"
                )
            );

            if (targets.Length > 0) {
                var resolver = resolverFactory.CreateOverloadResolver(args, new CallSignature(args.Length), CallTypes.None);
                BindingTarget target = resolver.ResolveOverload(targets[0].Name, targets, NarrowingLevel.None, NarrowingLevel.All);
                if (target.Success) {
                    Expression call = AstUtils.Convert(target.MakeExpression(), typeof(int));
                    switch (info.Operator) {
                        case ExpressionType.GreaterThan: call = Ast.GreaterThan(call, AstUtils.Constant(0)); break;
                        case ExpressionType.LessThan: call = Ast.LessThan(call, AstUtils.Constant(0)); break;
                        case ExpressionType.GreaterThanOrEqual: call = Ast.GreaterThanOrEqual(call, AstUtils.Constant(0)); break;
                        case ExpressionType.LessThanOrEqual: call = Ast.LessThanOrEqual(call, AstUtils.Constant(0)); break;
                        case ExpressionType.Equal: call = Ast.Equal(call, AstUtils.Constant(0)); break;
                        case ExpressionType.NotEqual: call = Ast.NotEqual(call, AstUtils.Constant(0)); break;
                    }

                    return new DynamicMetaObject(
                        call,
                        target.RestrictedArguments.GetAllRestrictions()
                    );
                }
            }

            return null;
        }
        private DynamicMetaObject TryComparisonMethod(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject target, DynamicMetaObject[] args) {
            MethodInfo[] targets = GetApplicableMembers(target.GetLimitType(), info);
            if (targets.Length > 0) {
                return TryMakeBindingTarget(resolverFactory, targets, args, BindingRestrictions.Empty);
            }

            return null;
        }