OperatorInfo provides a mapping from DLR ExpressionType to their associated .NET methods.
 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            
 }
示例#2
0
        private static DynamicMetaObject TryMakeDefaultUnaryRule(OperatorInfo info, DynamicMetaObject[] args)
        {
            if (args.Length == 1)
            {
                BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[0].Expression, args[0].GetLimitType()).Merge(BindingRestrictions.Combine(args));
                switch (info.Operator)
                {
                case ExpressionType.IsTrue:
                    if (args[0].GetLimitType() == typeof(bool))
                    {
                        return(args[0]);
                    }
                    break;

                case ExpressionType.Negate:
                    if (args[0].GetLimitType().IsArithmetic())
                    {
                        return(new DynamicMetaObject(
                                   Expression.Negate(args[0].Expression),
                                   restrictions
                                   ));
                    }
                    break;

                case ExpressionType.Not:
                    if (args[0].GetLimitType().IsIntegerOrBool())
                    {
                        return(new DynamicMetaObject(
                                   Expression.Not(args[0].Expression),
                                   restrictions
                                   ));
                    }
                    break;
                }
            }
            return(null);
        }
        /// <summary>
        /// Gets alternate members which are specially recognized by the DLR for specific types when
        /// all other member lookup fails.
        /// </summary>
        private MethodInfo[] GetFallbackMembers(Type t, OperatorInfo info)
        {
            // if we have an event we need to make a strongly-typed event handler

            if (t == typeof(EventTracker))
            {
                EventTracker et = ((EventTracker)_args[0]);
                if (info.Operator == Operators.InPlaceAdd)
                {
                    return(new MethodInfo[] { typeof(BinderOps).GetMethod("EventTrackerInPlaceAdd").MakeGenericMethod(et.Event.EventHandlerType) });
                }
                else if (info.Operator == Operators.InPlaceSubtract)
                {
                    return(new MethodInfo[] { typeof(BinderOps).GetMethod("EventTrackerInPlaceRemove").MakeGenericMethod(et.Event.EventHandlerType) });
                }
            }
            else if (t == typeof(BoundMemberTracker))
            {
                BoundMemberTracker bmt = ((BoundMemberTracker)_args[0]);
                if (bmt.BoundTo.MemberType == TrackerTypes.Event)
                {
                    EventTracker et = ((EventTracker)bmt.BoundTo);

                    if (info.Operator == Operators.InPlaceAdd)
                    {
                        return(new MethodInfo[] { typeof(BinderOps).GetMethod("BoundEventTrackerInPlaceAdd").MakeGenericMethod(et.Event.EventHandlerType) });
                    }
                    else if (info.Operator == Operators.InPlaceSubtract)
                    {
                        return(new MethodInfo[] { typeof(BinderOps).GetMethod("BoundEventTrackerInPlaceRemove").MakeGenericMethod(et.Event.EventHandlerType) });
                    }
                }
            }

            return(new MethodInfo[0]);
        }
 private static DynamicMetaObject TryMakeDefaultUnaryRule(OperatorInfo info, DynamicMetaObject[] args) {
     if (args.Length == 1) {
         BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[0].Expression, args[0].GetLimitType()).Merge(BindingRestrictions.Combine(args));
         switch (info.Operator) {
             case ExpressionType.IsTrue:
                 if (args[0].GetLimitType() == typeof(bool)) {
                     return args[0];
                 }
                 break;
             case ExpressionType.Negate:
                 if (TypeUtils.IsArithmetic(args[0].GetLimitType())) {
                     return new DynamicMetaObject(
                         Ast.Negate(args[0].Expression),
                         restrictions
                     );
                 }
                 break;
             case ExpressionType.Not:
                 if (TypeUtils.IsIntegerOrBool(args[0].GetLimitType())) {
                     return new DynamicMetaObject(
                         Ast.Not(args[0].Expression),
                         restrictions
                     );
                 }
                 break;
         }
     }
     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 static DynamicMetaObject MakeOperatorError(OperatorInfo info, DynamicMetaObject[] args) {
     return new DynamicMetaObject(
         Ast.Throw(
             AstUtils.ComplexCallHelper(
                 typeof(BinderOps).GetMethod("BadArgumentsForOperation"),
                 ArrayUtils.Insert((Expression)AstUtils.Constant(info.Operator), DynamicUtils.GetExpressions(args))
             )
         ),
         BindingRestrictions.Combine(args)
     );
 }
示例#9
0
        /// <summary>
        /// Creates the meta object for the rest of the operations: comparisons and all other
        /// ExpressionType.  If the operation cannot be completed a MetaObject which indicates an
        /// error will be returned.
        /// </summary>
        private DynamicMetaObject MakeGeneralOperatorRule(ExpressionType operation, OverloadResolverFactory resolverFactory, DynamicMetaObject[] args)
        {
            OperatorInfo info = OperatorInfo.GetOperatorInfo(operation);

            return(MakeGeneratorOperatorRule(resolverFactory, args, info));
        }
        /// <summary>
        /// Gets alternate members which are specially recognized by the DLR for specific types when
        /// all other member lookup fails.
        /// </summary>
        private static MethodInfo[] GetFallbackMembers(Type t, OperatorInfo info, MetaObject[] args, out Restrictions restrictions) {
            // if we have an event we need to make a strongly-typed event handler

            // TODO: Events, we need to look in the args and pull out the real values

            if (t == typeof(EventTracker)) {
                EventTracker et = ((EventTracker)args[0].Value);
                if (info.Operator == Operators.InPlaceAdd) {
                    restrictions = GetFallbackRestrictions(t, et, args[0]);
                    return new MethodInfo[] { typeof(BinderOps).GetMethod("EventTrackerInPlaceAdd").MakeGenericMethod(et.Event.EventHandlerType) };
                } else if (info.Operator == Operators.InPlaceSubtract) {
                    restrictions = GetFallbackRestrictions(t, et, args[0]);
                    return new MethodInfo[] { typeof(BinderOps).GetMethod("EventTrackerInPlaceRemove").MakeGenericMethod(et.Event.EventHandlerType) };
                }
            } else if (t == typeof(BoundMemberTracker)) {
                BoundMemberTracker bmt = ((BoundMemberTracker)args[0].Value);
                if (bmt.BoundTo.MemberType == TrackerTypes.Event) {
                    EventTracker et = ((EventTracker)bmt.BoundTo);

                    if (info.Operator == Operators.InPlaceAdd) {
                        restrictions = GetFallbackRestrictions(t, et, args[0]);
                        return new MethodInfo[] { typeof(BinderOps).GetMethod("BoundEventTrackerInPlaceAdd").MakeGenericMethod(et.Event.EventHandlerType) };
                    } else if (info.Operator == Operators.InPlaceSubtract) {
                        restrictions = GetFallbackRestrictions(t, et, args[0]);
                        return new MethodInfo[] { typeof(BinderOps).GetMethod("BoundEventTrackerInPlaceRemove").MakeGenericMethod(et.Event.EventHandlerType) };
                    }
                }
            }

            restrictions = Restrictions.Empty;
            return new MethodInfo[0];
        }
        private static MetaObject TryMakeDefaultUnaryRule(OperatorInfo info, Expression codeContext, MetaObject[] args) {
            if (args.Length == 1) {
                Restrictions restrictions = Restrictions.GetTypeRestriction(args[0].Expression, args[0].LimitType).Merge(Restrictions.Combine(args));
                switch (info.Operator) {
                    case Operators.IsTrue:
                        if (args[0].LimitType == typeof(bool)) {
                            return args[0];
                        }
                        break;
                    case Operators.Negate:
                        if (TypeUtils.IsArithmetic(args[0].LimitType)) {
                            return new MetaObject(
                                Ast.Negate(args[0].Expression),
                                restrictions
                            );
                        }
                        break;
                    case Operators.Not:
                        if (TypeUtils.IsIntegerOrBool(args[0].LimitType)) {
                            return new MetaObject(
                                Ast.Not(args[0].Expression),
                                restrictions
                            );
                        }
                        break;
                    case Operators.Documentation:
                        object[] attrs = args[0].LimitType.GetCustomAttributes(typeof(DocumentationAttribute), true);
                        string documentation = String.Empty;

                        if (attrs.Length > 0) {
                            documentation = ((DocumentationAttribute)attrs[0]).Documentation;
                        }

                        return new MetaObject(
                            Ast.Constant(documentation),
                            restrictions
                        );
                    case Operators.MemberNames:
                        if (typeof(IMembersList).IsAssignableFrom(args[0].LimitType)) {
                            return MakeIMembersListRule(codeContext, args[0]);
                        }

                        MemberInfo[] members = args[0].LimitType.GetMembers();
                        Dictionary<string, string> mems = new Dictionary<string, string>();
                        foreach (MemberInfo mi in members) {
                            mems[mi.Name] = mi.Name;
                        }

                        string[] res = new string[mems.Count];
                        mems.Keys.CopyTo(res, 0);

                        return new MetaObject(
                            Ast.Constant(res),
                            restrictions
                        );
                    case Operators.CallSignatures:
                        return MakeCallSignatureResult(CompilerHelpers.GetMethodTargets(args[0].LimitType), args[0]);
                    case Operators.IsCallable:
                        // IsCallable() is tightly tied to Call actions. So in general, we need the call-action providers to also
                        // provide IsCallable() status. 
                        // This is just a rough fallback. We could also attempt to simulate the default CallBinder logic to see
                        // if there are any applicable calls targets, but that would be complex (the callbinder wants the argument list, 
                        // which we don't have here), and still not correct. 
                        bool callable = false;
                        if (typeof(Delegate).IsAssignableFrom(args[0].LimitType) ||
                            typeof(MethodGroup).IsAssignableFrom(args[0].LimitType)) {
                            callable = true;
                        }

                        return new MetaObject(
                            Ast.Constant(callable),
                            restrictions
                        );
                }
            }
            return null;
        }
        private MetaObject TryInplaceOperator(OperatorInfo info, Expression codeContext, MetaObject[] args) {
            Operators op = CompilerHelpers.InPlaceOperatorToOperator(info.Operator);

            if (op != Operators.None) {
                // recurse to try and get the non-inplace action...
                return MakeOperatorRule(OperatorInfo.GetOperatorInfo(op), codeContext, args);
            }

            return null;
        }
        private MetaObject TryReverseOperator(OperatorInfo info, Expression codeContext, MetaObject[] args) {
            // we need a special conversion for the return type on MemberNames
            if (info.Operator != Operators.MemberNames) {
                if (args.Length > 0) {
                    MethodInfo[] targets = GetApplicableMembers(args[0].LimitType, info);
                    if (targets.Length > 0) {
                        return TryMakeBindingTarget(targets, args, codeContext, Restrictions.Empty);
                    }
                }
            }

            return null;
        }
        private MetaObject TryForwardOperator(OperatorInfo info, Expression codeContext, MetaObject[] args) {
            // we need a special conversion for the return type on MemberNames
            if (info.Operator != Operators.MemberNames) {
                MethodInfo[] targets = GetApplicableMembers(args[0].LimitType, info);
                Restrictions restrictions = Restrictions.Empty;
                if (targets.Length == 0) {
                    targets = GetFallbackMembers(args[0].LimitType, info, args, out restrictions);
                }

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

            return null;
        }
        private MetaObject TryInvertedComparison(OperatorInfo info, MetaObject target, MetaObject[] args) {
            Operators 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.LimitType, revInfo);
            if (targets.Length > 0) {
                return TryMakeInvertedBindingTarget(targets, args);
            }

            return null;
        }
        private DynamicMetaObject MakeGeneratorOperatorRule(OverloadResolverFactory resolverFactory, DynamicMetaObject[] args, OperatorInfo info) {
            DynamicMetaObject res;

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

            return res;
        }
        private MethodInfo[] GetApplicableMembers(Type t, OperatorInfo info) {
            Assert.NotNull(t, info);

            OldDoOperationAction act = OldDoOperationAction.Make(this, OperatorInfo.ExpressionTypeToOperator(info.Operator));

            MemberGroup members = GetMember(act, t, info.Name);
            if (members.Count == 0 && info.AlternateName != null) {
                members = GetMember(act, t, info.AlternateName);
            }

            // filter down to just methods
            return FilterNonMethods(t, members);
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] // TODO: fix
        private void MakeOperatorRule(OperatorInfo info)
        {
            MethodInfo[] targets = GetApplicableMembers(info);
            if (targets.Length == 0)
            {
                targets = GetFallbackMembers(_types[0], info);
            }

            if (targets.Length > 0 && TryMakeBindingTarget(targets))
            {
                return;
            }

            if (_types.Length > 1)
            {
                targets = GetApplicableMembers(_types[1], info);
                if (targets.Length > 0 && TryMakeBindingTarget(targets))
                {
                    return;
                }
            }

            Operators op = CompilerHelpers.InPlaceOperatorToOperator(info.Operator);

            if (op != Operators.None)
            {
                // recurse to try and get the non-inplace action...
                MakeOperatorRule(OperatorInfo.GetOperatorInfo(op));
                return;
            }

            if (_types.Length == 2 &&
                TypeUtils.GetNonNullableType(_types[0]) == TypeUtils.GetNonNullableType(_types[1]) &&
                TypeUtils.IsArithmetic(_types[0]))
            {
                // TODO: Nullable<PrimitveType> Support
                Expression expr;
                switch (info.Operator)
                {
                case Operators.Add: expr = Ast.Add(Param0, Param1); break;

                case Operators.Subtract: expr = Ast.Subtract(Param0, Param1); break;

                case Operators.Divide: expr = Ast.Divide(Param0, Param1); break;

                case Operators.Mod: expr = Ast.Modulo(Param0, Param1); break;

                case Operators.Multiply: expr = Ast.Multiply(Param0, Param1); break;

                case Operators.LeftShift: expr = Ast.LeftShift(Param0, Param1); break;

                case Operators.RightShift: expr = Ast.RightShift(Param0, Param1); break;

                case Operators.BitwiseAnd: expr = Ast.And(Param0, Param1); break;

                case Operators.BitwiseOr: expr = Ast.Or(Param0, Param1); break;

                case Operators.ExclusiveOr: expr = Ast.ExclusiveOr(Param0, Param1); break;

                default: throw new InvalidOperationException();
                }
                _rule.Target = _rule.MakeReturn(Binder, expr);
                return;
            }
            else if (_types.Length == 1 && TryMakeDefaultUnaryRule(info))
            {
                return;
            }

            SetErrorTarget(info);
        }
示例#19
0
        private DynamicMetaObject MakeGeneratorOperatorRule(OverloadResolverFactory resolverFactory, DynamicMetaObject[] args, OperatorInfo info)
        {
            DynamicMetaObject res;

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

            return(res);
        }
        private bool TryMakeDefaultUnaryRule(OperatorInfo info)
        {
            switch (info.Operator)
            {
            case Operators.IsTrue:
                if (_types[0] == typeof(bool))
                {
                    _rule.Target = _rule.MakeReturn(Binder, Param0);
                    return(true);
                }
                break;

            case Operators.Negate:
                if (TypeUtils.IsArithmetic(_types[0]))
                {
                    _rule.Target = _rule.MakeReturn(Binder, Ast.Negate(Param0));
                    return(true);
                }
                break;

            case Operators.Not:
                if (TypeUtils.IsIntegerOrBool(_types[0]))
                {
                    _rule.Target = _rule.MakeReturn(Binder, Ast.Not(Param0));
                    return(true);
                }
                break;

            case Operators.Documentation:
                object[] attrs         = _types[0].GetCustomAttributes(typeof(DocumentationAttribute), true);
                string   documentation = String.Empty;

                if (attrs.Length > 0)
                {
                    documentation = ((DocumentationAttribute)attrs[0]).Documentation;
                }

                _rule.Target = _rule.MakeReturn(Binder, Ast.Constant(documentation));
                return(true);

            case Operators.MemberNames:
                if (typeof(IMembersList).IsAssignableFrom(_types[0]))
                {
                    MakeIMembersListRule();
                    return(true);
                }

                MemberInfo[] members             = _types[0].GetMembers();
                Dictionary <string, string> mems = new Dictionary <string, string>();
                foreach (MemberInfo mi in members)
                {
                    mems[mi.Name] = mi.Name;
                }

                string[] res = new string[mems.Count];
                mems.Keys.CopyTo(res, 0);
                _rule.Target = _rule.MakeReturn(Binder, Ast.Constant(res));
                return(true);

            case Operators.CallSignatures:
                MakeCallSignatureResult(CompilerHelpers.GetMethodTargets(_args[0]));
                break;

            case Operators.IsCallable:
                // IsCallable() is tightly tied to Call actions. So in general, we need the call-action providers to also
                // provide IsCallable() status.
                // This is just a rough fallback. We could also attempt to simulate the default CallBinder logic to see
                // if there are any applicable calls targets, but that would be complex (the callbinder wants the argument list,
                // which we don't have here), and still not correct.
                bool callable = false;
                if (typeof(Delegate).IsAssignableFrom(_types[0]) ||
                    typeof(MethodGroup).IsAssignableFrom(_types[0]))
                {
                    callable = true;
                }

                _rule.Target = _rule.MakeReturn(Context.LanguageContext.Binder, Ast.Constant(callable));
                return(true);
            }
            return(false);
        }
        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;
        }
 private MethodInfo[] GetApplicableMembers(OperatorInfo info)
 {
     return(GetApplicableMembers(CompilerHelpers.GetType(_args[0]), info));
 }
        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, Expression codeContext, DynamicMetaObject target, DynamicMetaObject[] args) {
            MethodInfo[] targets = GetApplicableMembers(target.GetLimitType(), info);
            if (targets.Length > 0) {
                return TryMakeBindingTarget(targets, args, codeContext, BindingRestrictions.Empty);
            }

            return null;
        }
        private static DynamicMetaObject TryPrimitiveCompare(OperatorInfo info, DynamicMetaObject[] args) {
            if (TypeUtils.GetNonNullableType(args[0].GetLimitType()) == TypeUtils.GetNonNullableType(args[1].GetLimitType()) &&
                TypeUtils.IsNumeric(args[0].GetLimitType())) {
                Expression arg0 = args[0].Expression;
                Expression arg1 = args[1].Expression;

                // TODO: Nullable<PrimitveType> Support
                Expression expr;
                switch (info.Operator) {
                    case ExpressionType.Equal: expr = Ast.Equal(arg0, arg1); break;
                    case ExpressionType.NotEqual: expr = Ast.NotEqual(arg0, arg1); break;
                    case ExpressionType.GreaterThan: expr = Ast.GreaterThan(arg0, arg1); break;
                    case ExpressionType.LessThan: expr = Ast.LessThan(arg0, arg1); break;
                    case ExpressionType.GreaterThanOrEqual: expr = Ast.GreaterThanOrEqual(arg0, arg1); break;
                    case ExpressionType.LessThanOrEqual: expr = Ast.LessThanOrEqual(arg0, arg1); break;
                    default: throw new InvalidOperationException();
                }

                return new DynamicMetaObject(
                    expr,
                    BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg0, args[0].GetLimitType()).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg1, args[0].GetLimitType())).Merge(BindingRestrictions.Combine(args))
                );
            }

            return null;
        }
        private DynamicMetaObject TryNumericComparison(OperatorInfo info, DynamicMetaObject[] args) {
            MethodInfo[] targets = FilterNonMethods(
                args[0].GetLimitType(),
                GetMember(OldDoOperationAction.Make(this, OperatorInfo.ExpressionTypeToOperator(info.Operator)),
                args[0].GetLimitType(),
                "Compare")
            );

            if (targets.Length > 0) {
                MethodBinder mb = MethodBinder.MakeBinder(this, targets[0].Name, targets);
                BindingTarget target = mb.MakeBindingTarget(CallTypes.None, args);
                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,
                        BindingRestrictions.Combine(target.RestrictedArguments)
                    );
                }
            }

            return null;
        }
        private static DynamicMetaObject TryPrimitiveOperator(OperatorInfo info, DynamicMetaObject[] args) {
            if (args.Length == 2 &&
                TypeUtils.GetNonNullableType(args[0].GetLimitType()) == TypeUtils.GetNonNullableType(args[1].GetLimitType()) &&
                TypeUtils.IsArithmetic(args[0].GetLimitType())) {
                // TODO: Nullable<PrimitveType> Support
                Expression expr;
                DynamicMetaObject self = args[0].Restrict(args[0].GetLimitType());
                DynamicMetaObject arg0 = args[1].Restrict(args[0].GetLimitType());

                switch (info.Operator) {
                    case ExpressionType.Add: expr = Ast.Add(self.Expression, arg0.Expression); break;
                    case ExpressionType.Subtract: expr = Ast.Subtract(self.Expression, arg0.Expression); break;
                    case ExpressionType.Divide: expr = Ast.Divide(self.Expression, arg0.Expression); break;
                    case ExpressionType.Modulo: expr = Ast.Modulo(self.Expression, arg0.Expression); break;
                    case ExpressionType.Multiply: expr = Ast.Multiply(self.Expression, arg0.Expression); break;
                    case ExpressionType.LeftShift: expr = Ast.LeftShift(self.Expression, arg0.Expression); break;
                    case ExpressionType.RightShift: expr = Ast.RightShift(self.Expression, arg0.Expression); break;
                    case ExpressionType.And: expr = Ast.And(self.Expression, arg0.Expression); break;
                    case ExpressionType.Or: expr = Ast.Or(self.Expression, arg0.Expression); break;
                    case ExpressionType.ExclusiveOr: expr = Ast.ExclusiveOr(self.Expression, arg0.Expression); break;
                    default: throw new InvalidOperationException();
                }

                return new DynamicMetaObject(
                    expr,
                    self.Restrictions.Merge(arg0.Restrictions)
                );
            }

            return null;
        }
 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] // TODO: fix
 private DynamicMetaObject MakeOperatorRule(OperatorInfo info, Expression codeContext, DynamicMetaObject[] args) {
     return
         TryForwardOperator(info, codeContext, args) ??
         TryReverseOperator(info, codeContext, args) ??
         TryPrimitiveOperator(info, args) ??
         TryMakeDefaultUnaryRule(info, codeContext, args) ??
         MakeOperatorError(info, args);
 }
        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, Expression codeContext, DynamicMetaObject[] args) {
            MethodInfo[] targets = GetApplicableMembers(args[0].GetLimitType(), info);
            BindingRestrictions restrictions = BindingRestrictions.Empty;

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

            return null;
        }
        private MethodInfo[] GetApplicableMembers(Type t, OperatorInfo info) {
            Assert.NotNull(t, info);

            MemberGroup members = GetMember(MemberRequestKind.Operation, t, info.Name);
            if (members.Count == 0 && info.AlternateName != null) {
                members = GetMember(MemberRequestKind.Operation, t, info.AlternateName);
            }

            // filter down to just methods
            return FilterNonMethods(t, members);
        }
示例#32
0
        private static MetaObject TryMakeDefaultUnaryRule(OperatorInfo info, Expression codeContext, MetaObject[] args)
        {
            if (args.Length == 1)
            {
                Restrictions restrictions = Restrictions.GetTypeRestriction(args[0].Expression, args[0].LimitType).Merge(Restrictions.Combine(args));
                switch (info.Operator)
                {
                case Operators.IsTrue:
                    if (args[0].LimitType == typeof(bool))
                    {
                        return(args[0]);
                    }
                    break;

                case Operators.Negate:
                    if (TypeUtils.IsArithmetic(args[0].LimitType))
                    {
                        return(new MetaObject(
                                   Ast.Negate(args[0].Expression),
                                   restrictions
                                   ));
                    }
                    break;

                case Operators.Not:
                    if (TypeUtils.IsIntegerOrBool(args[0].LimitType))
                    {
                        return(new MetaObject(
                                   Ast.Not(args[0].Expression),
                                   restrictions
                                   ));
                    }
                    break;

                case Operators.Documentation:
                    object[] attrs         = args[0].LimitType.GetCustomAttributes(typeof(DocumentationAttribute), true);
                    string   documentation = String.Empty;

                    if (attrs.Length > 0)
                    {
                        documentation = ((DocumentationAttribute)attrs[0]).Documentation;
                    }

                    return(new MetaObject(
                               Ast.Constant(documentation),
                               restrictions
                               ));

                case Operators.MemberNames:
                    if (typeof(IMembersList).IsAssignableFrom(args[0].LimitType))
                    {
                        return(MakeIMembersListRule(codeContext, args[0]));
                    }

                    MemberInfo[] members             = args[0].LimitType.GetMembers();
                    Dictionary <string, string> mems = new Dictionary <string, string>();
                    foreach (MemberInfo mi in members)
                    {
                        mems[mi.Name] = mi.Name;
                    }

                    string[] res = new string[mems.Count];
                    mems.Keys.CopyTo(res, 0);

                    return(new MetaObject(
                               Ast.Constant(res),
                               restrictions
                               ));

                case Operators.CallSignatures:
                    return(MakeCallSignatureResult(CompilerHelpers.GetMethodTargets(args[0].LimitType), args[0]));

                case Operators.IsCallable:
                    // IsCallable() is tightly tied to Call actions. So in general, we need the call-action providers to also
                    // provide IsCallable() status.
                    // This is just a rough fallback. We could also attempt to simulate the default CallBinder logic to see
                    // if there are any applicable calls targets, but that would be complex (the callbinder wants the argument list,
                    // which we don't have here), and still not correct.
                    bool callable = false;
                    if (typeof(Delegate).IsAssignableFrom(args[0].LimitType) ||
                        typeof(MethodGroup).IsAssignableFrom(args[0].LimitType))
                    {
                        callable = true;
                    }

                    return(new MetaObject(
                               Ast.Constant(callable),
                               restrictions
                               ));
                }
            }
            return(null);
        }