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