/// <summary> /// Builds the restrictions for calling with a splatted argument array. Ensures that the /// argument is still an ICollection of object and that it has the same number of arguments. /// </summary> private static BindingRestrictions MakeParamsTest(DynamicMetaObject splattee, bool testTypes) { IList <object> list = splattee.Value as IList <object>; if (list == null) { if (splattee.Value == null) { return(BindingRestrictions.GetExpressionRestriction(Ast.Equal(splattee.Expression, AstUtils.Constant(null)))); } else { return(BindingRestrictions.GetTypeRestriction(splattee.Expression, splattee.Value.GetType())); } } BindingRestrictions res = BindingRestrictions.GetExpressionRestriction( Ast.AndAlso( Ast.TypeIs(splattee.Expression, typeof(IList <object>)), Ast.Equal( Ast.Property( Ast.Convert(splattee.Expression, typeof(IList <object>)), typeof(ICollection <object>).GetDeclaredProperty("Count") ), AstUtils.Constant(list.Count) ) ) ); if (testTypes) { for (int i = 0; i < list.Count; i++) { res = res.Merge( BindingRestrictionsHelpers.GetRuntimeTypeRestriction( Ast.Call( AstUtils.Convert( splattee.Expression, typeof(IList <object>) ), typeof(IList <object>).GetMethod("get_Item"), AstUtils.Constant(i) ), CompilerHelpers.GetType(list[i]) ) ); } } return(res); }
/// <summary> /// Produces a rule for comparing a value to null - supports comparing object references and nullable types. /// </summary> private static DynamicMetaObject TryNullComparisonRule(DynamicMetaObject[] args) { Type otherType = args[1].GetLimitType(); BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[0].Expression, args[0].GetLimitType()).Merge(BindingRestrictions.Combine(args)); if (args[0].GetLimitType() == typeof(DynamicNull)) { if (!otherType.IsValueType) { return(new DynamicMetaObject( Expression.Equal(args[0].Expression, AstUtils.Constant(null)), restrictions )); } if (otherType.GetGenericTypeDefinition() == typeof(Nullable <>)) { return(new DynamicMetaObject( Expression.Property(args[0].Expression, otherType.GetDeclaredProperty("HasValue")), restrictions )); } } else if (otherType == typeof(DynamicNull)) { if (!args[0].GetLimitType().IsValueType) { return(new DynamicMetaObject( Expression.Equal(args[0].Expression, AstUtils.Constant(null)), restrictions )); } if (args[0].GetLimitType().GetGenericTypeDefinition() == typeof(Nullable <>)) { return(new DynamicMetaObject( Expression.Property(args[0].Expression, otherType.GetDeclaredProperty("HasValue")), restrictions )); } } return(null); }
public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) { Expression[] exprs = new Expression[args.Length + 1]; exprs[0] = Expression.Constant("FallbackInvoke"); for (int i = 0; i < args.Length; i++) { exprs[i + 1] = args[i].Expression; } return(new DynamicMetaObject( Expression.Call( typeof(String).GetMethod("Concat", new Type[] { typeof(object[]) }), Expression.NewArrayInit( typeof(object), exprs ) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target) )); }
public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { var newTarget = new DynamicMetaObject(Expression.Convert(target.Expression, target.LimitType), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), target.Value); var exp = TryConvertExpression(newTarget.Expression, Type, null); if (exp == null) { exp = Expression.Throw(Expression.Constant(new InvalidCastException()), Type); } if (ReturnType != Type) { exp = Expression.Convert(exp, ReturnType); } var ret = _context.Binder.ConvertTo( Type, Explicit ? Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast : Microsoft.Scripting.Actions.ConversionResultKind.ImplicitCast, newTarget, new TjsOverloadResolverFactory(_context.Binder), new DynamicMetaObject(exp, BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target)) ); return(ret); }
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); }
public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) { var restrictions = target.Restrictions.Merge( BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target)); //target = target.Restrict(target.RuntimeType); //args = args.Select(o => o.Restrict(o.RuntimeType)).ToArray(); MethodBase targetMethod; switch (Name) { case "SelectMany": targetMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where( o => o.Name == Name).Skip(3).First().MakeGenericMethod( typeof(object), typeof(object), typeof(object)); break; default: targetMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where( o => o.Name == Name).First().MakeGenericMethod( typeof(object), typeof(object)); break; } foreach (var o in args) { restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(o)); } return(_binder.CallMethod( new DefaultOverloadResolver(_binder, target, args.ToList(), new CallSignature(args.Length)), new[] { targetMethod }, restrictions, Name)); }
internal static DynamicMetaObject TranslateArguments(DynamicMetaObjectBinder call, Expression codeContext, DynamicMetaObject function, DynamicMetaObject /*!*/[] args, bool hasSelf, string name) { if (hasSelf) { args = ArrayUtils.RemoveFirst(args); } CallSignature sig = BindingHelpers.GetCallSignature(call); if (sig.HasDictionaryArgument()) { int index = sig.IndexOf(ArgumentType.Dictionary); DynamicMetaObject dict = args[index]; if (!(dict.Value is IDictionary) && dict.Value != null) { // The DefaultBinder only handles types that implement IDictionary. Here we have an // arbitrary user-defined mapping type. We'll convert it into a PythonDictionary // and then have an embedded dynamic site pass that dictionary through to the default // binder. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args); dynamicArgs[index + 1] = new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.UserMappingToPythonDictionary)), codeContext, args[index].Expression, AstUtils.Constant(name) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()), PythonOps.UserMappingToPythonDictionary(PythonContext.GetPythonContext(call).SharedContext, dict.Value, name) ); if (call is IPythonSite) { dynamicArgs = ArrayUtils.Insert( new DynamicMetaObject(codeContext, BindingRestrictions.Empty), dynamicArgs ); } return(new DynamicMetaObject( DynamicExpression.Dynamic( call, typeof(object), DynamicUtils.GetExpressions(dynamicArgs) ), BindingRestrictions.Combine(dynamicArgs).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType())) )); } } if (sig.HasListArgument()) { int index = sig.IndexOf(ArgumentType.List); DynamicMetaObject str = args[index]; // TODO: ANything w/ __iter__ that's not an IList<object> if (!(str.Value is IList <object>) && str.Value is IEnumerable) { // The DefaultBinder only handles types that implement IList<object>. Here we have a // string. We'll convert it into a tuple // and then have an embedded dynamic site pass that tuple through to the default // binder. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args); dynamicArgs[index + 1] = new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.MakeTupleFromSequence)), Expression.Convert(args[index].Expression, typeof(object)) ), BindingRestrictions.Empty ); if (call is IPythonSite) { dynamicArgs = ArrayUtils.Insert( new DynamicMetaObject(codeContext, BindingRestrictions.Empty), dynamicArgs ); } return(new DynamicMetaObject( DynamicExpression.Dynamic( call, typeof(object), DynamicUtils.GetExpressions(dynamicArgs) ), function.Restrictions.Merge( BindingRestrictions.Combine(args).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(str.Expression, str.GetLimitType())) ) )); } } return(null); }
/// <summary> /// Creating a Python type involves calling __new__ and __init__. We resolve them /// and generate calls to either the builtin funcions directly or embed sites which /// call the slots at runtime. /// </summary> private DynamicMetaObject /*!*/ MakePythonTypeCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] /*!*/ args) { ValidationInfo valInfo = MakeVersionCheck(); DynamicMetaObject self = new RestrictedMetaObject( AstUtils.Convert(Expression, LimitType), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(Expression, LimitType), Value ); CallSignature sig = BindingHelpers.GetCallSignature(call); ArgumentValues ai = new ArgumentValues(sig, self, args); NewAdapter newAdapter; InitAdapter initAdapter; if (TooManyArgsForDefaultNew(call, args)) { return(MakeIncorrectArgumentsForCallError(call, ai, valInfo)); } else if (Value.UnderlyingSystemType.IsGenericTypeDefinition) { return(MakeGenericTypeDefinitionError(call, ai, valInfo)); } else if (Value.HasAbstractMethods(PythonContext.GetPythonContext(call).SharedContext)) { return(MakeAbstractInstantiationError(call, ai, valInfo)); } DynamicMetaObject translated = BuiltinFunction.TranslateArguments(call, codeContext, self, args, false, Value.Name); if (translated != null) { return(translated); } GetAdapters(ai, call, codeContext, out newAdapter, out initAdapter); PythonContext state = PythonContext.GetPythonContext(call); // get the expression for calling __new__ DynamicMetaObject createExpr = newAdapter.GetExpression(state.Binder); if (createExpr.Expression.Type == typeof(void)) { return(BindingHelpers.AddDynamicTestAndDefer( call, createExpr, args, valInfo )); } Expression res; BindingRestrictions additionalRestrictions = BindingRestrictions.Empty; if (!Value.IsSystemType && (!(newAdapter is DefaultNewAdapter) || HasFinalizer(call))) { // we need to dynamically check the return value to see if it's a subtype of // the type that we are calling. If it is then we need to call __init__/__del__ // for the actual returned type. res = Expression.Dynamic( Value.GetLateBoundInitBinder(sig), typeof(object), ArrayUtils.Insert( codeContext, Expression.Convert(createExpr.Expression, typeof(object)), DynamicUtils.GetExpressions(args) ) ); additionalRestrictions = createExpr.Restrictions; } else { // just call the __init__ method, built-in types currently have // no wacky return values which don't return the derived type. // then get the statement for calling __init__ ParameterExpression allocatedInst = Ast.Variable(createExpr.GetLimitType(), "newInst"); Expression tmpRead = allocatedInst; DynamicMetaObject initCall = initAdapter.MakeInitCall( state.Binder, new RestrictedMetaObject( AstUtils.Convert(allocatedInst, Value.UnderlyingSystemType), createExpr.Restrictions ) ); List <Expression> body = new List <Expression>(); Debug.Assert(!HasFinalizer(call)); // add the call to init if we need to if (initCall.Expression != tmpRead) { // init can fail but if __new__ returns a different type // no exception is raised. DynamicMetaObject initStmt = initCall; if (body.Count == 0) { body.Add( Ast.Assign(allocatedInst, createExpr.Expression) ); } if (!Value.UnderlyingSystemType.IsAssignableFrom(createExpr.Expression.Type)) { // return type of object, we need to check the return type before calling __init__. body.Add( AstUtils.IfThen( Ast.TypeIs(allocatedInst, Value.UnderlyingSystemType), initStmt.Expression ) ); } else { // just call the __init__ method, no type check necessary (TODO: need null check?) body.Add(initStmt.Expression); } } // and build the target from everything we have if (body.Count == 0) { res = createExpr.Expression; } else { body.Add(allocatedInst); res = Ast.Block(body); } res = Ast.Block(new ParameterExpression[] { allocatedInst }, res); additionalRestrictions = initCall.Restrictions; } return(BindingHelpers.AddDynamicTestAndDefer( call, new DynamicMetaObject( res, self.Restrictions.Merge(additionalRestrictions) ), ArrayUtils.Insert(this, args), valInfo )); }
private static DynamicMetaObject TryPrimitiveCompare(OperatorInfo info, DynamicMetaObject[] args) { if (args[0].GetLimitType().GetNonNullableType() == args[1].GetLimitType().GetNonNullableType() && args[0].GetLimitType().IsNumeric()) { Expression arg0 = args[0].Expression; Expression arg1 = args[1].Expression; // TODO: Nullable<PrimitveType> Support Expression expr; switch (info.Operator) { case ExpressionType.Equal: expr = Expression.Equal(arg0, arg1); break; case ExpressionType.NotEqual: expr = Expression.NotEqual(arg0, arg1); break; case ExpressionType.GreaterThan: expr = Expression.GreaterThan(arg0, arg1); break; case ExpressionType.LessThan: expr = Expression.LessThan(arg0, arg1); break; case ExpressionType.GreaterThanOrEqual: expr = Expression.GreaterThanOrEqual(arg0, arg1); break; case ExpressionType.LessThanOrEqual: expr = Expression.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 /*!*/ MakeSelfCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] /*!*/ args) { BindingRestrictions selfRestrict = Restrictions.Merge( BindingRestrictionsHelpers.GetRuntimeTypeRestriction( Expression, LimitType ) ).Merge( BindingRestrictions.GetExpressionRestriction( Value.MakeBoundFunctionTest( AstUtils.Convert(Expression, typeof(BuiltinFunction)) ) ) ); Expression instance = Ast.Call( typeof(PythonOps).GetMethod("GetBuiltinFunctionSelf"), AstUtils.Convert( Expression, typeof(BuiltinFunction) ) ); DynamicMetaObject self = GetInstance(instance, CompilerHelpers.GetType(Value.BindingSelf)); return(Value.MakeBuiltinFunctionCall( call, codeContext, this, ArrayUtils.Insert(self, args), true, // has self selfRestrict, (newArgs) => { CallSignature signature = BindingHelpers.GetCallSignature(call); DynamicMetaObject res; PythonContext state = PythonContext.GetPythonContext(call); BindingTarget target; PythonOverloadResolver resolver; if (Value.IsReversedOperator) { resolver = new PythonOverloadResolver( state.Binder, newArgs, GetReversedSignature(signature), codeContext ); } else { resolver = new PythonOverloadResolver( state.Binder, self, args, signature, codeContext ); } res = state.Binder.CallMethod( resolver, Value.Targets, self.Restrictions, Value.Name, NarrowingLevel.None, Value.IsBinaryOperator ? PythonNarrowing.BinaryOperator : NarrowingLevel.All, out target ); return BindingHelpers.CheckLightThrow(call, res, target); } )); }
private DynamicMetaObject /*!*/ GetInstance(Expression /*!*/ instance, Type /*!*/ testType) { Assert.NotNull(instance, testType); object instanceValue = Value.BindingSelf; BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(instance, testType); // cast the instance to the correct type if (CompilerHelpers.IsStrongBox(instanceValue)) { instance = ReadStrongBoxValue(instance); instanceValue = ((IStrongBox)instanceValue).Value; } else if (!testType.IsEnum) { // We need to deal w/ wierd types like MarshalByRefObject. // We could have an MBRO whos DeclaringType is completely different. // Therefore we special case it here and cast to the declaring type Type selfType = CompilerHelpers.GetType(Value.BindingSelf); selfType = CompilerHelpers.GetVisibleType(selfType); if (selfType == typeof(object) && Value.DeclaringType.IsInterface) { selfType = Value.DeclaringType; } if (Value.DeclaringType.IsInterface && selfType.IsValueType) { // explicit interface implementation dispatch on a value type, don't // unbox the value type before the dispatch. instance = AstUtils.Convert(instance, Value.DeclaringType); } else if (selfType.IsValueType) { // We might be calling a a mutating method (like // Rectangle.Intersect). If so, we want it to mutate // the boxed value directly instance = Ast.Unbox(instance, selfType); } else { #if SILVERLIGHT instance = AstUtils.Convert(instance, selfType); #else Type convType = selfType == typeof(MarshalByRefObject) ? CompilerHelpers.GetVisibleType(Value.DeclaringType) : selfType; instance = AstUtils.Convert(instance, convType); #endif } } else { // we don't want to cast the enum to its real type, it will unbox it // and turn it into its underlying type. We presumably want to call // a method on the Enum class though - so we cast to Enum instead. instance = AstUtils.Convert(instance, typeof(Enum)); } return(new DynamicMetaObject( instance, restrictions, instanceValue )); }
public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { var arg = Expression.Convert(target.Expression, target.LimitType); var restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target); Expression res = null; switch (Operation) { case ExpressionType.Decrement: if (Binders.IsFloatingPoint(target.LimitType)) { res = Expression.Decrement(_context.Convert(arg, typeof(double))); } else { res = Expression.Decrement(_context.Convert(arg, typeof(long))); } break; case ExpressionType.Increment: if (Binders.IsFloatingPoint(target.LimitType)) { res = Expression.Increment(_context.Convert(arg, typeof(double))); } else { res = Expression.Increment(_context.Convert(arg, typeof(long))); } break; case ExpressionType.Negate: if (Binders.IsFloatingPoint(target.LimitType)) { res = Expression.Negate(_context.Convert(arg, typeof(double))); } else { res = Expression.Negate(_context.Convert(arg, typeof(long))); } break; case ExpressionType.Not: res = Expression.Condition(_context.Convert(arg, typeof(bool)), Expression.Constant(0L), Expression.Constant(1L)); break; case ExpressionType.OnesComplement: res = Expression.OnesComplement(_context.Convert(arg, typeof(long))); break; case ExpressionType.UnaryPlus: if (Binders.IsFloatingPoint(target.LimitType)) { res = _context.Convert(arg, typeof(double)); } else if (Binders.IsInteger(target.LimitType)) { res = _context.Convert(arg, typeof(long)); } else if (target.LimitType == typeof(string)) { res = Expression.Call(new Func <string, object>(Binders.ConvertNumber).Method, arg); } break; } if (res != null) { if (res.Type != typeof(object)) { return(new DynamicMetaObject(Expression.Convert(res, typeof(object)), restrictions)); } else { return(new DynamicMetaObject(res, restrictions)); } } else { return(errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("不正な単項演算です。")), typeof(object)), restrictions)); } }
public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) { var left = Expression.Convert(target.Expression, target.LimitType); var right = Expression.Convert(arg.Expression, arg.LimitType); Expression res = null; switch (Operation) { case ExpressionType.Add: if (target.LimitType == typeof(string) || arg.LimitType == typeof(string)) { res = Expression.Call(new Func <string, string, string>(string.Concat).Method, _context.Convert(left, typeof(string)), _context.Convert(right, typeof(string))); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { res = Expression.Add(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { res = Expression.Add(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } break; case ExpressionType.And: res = Expression.And(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.Divide: res = Expression.Divide(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); break; case ExpressionType.Equal: res = Expression.Condition(Equal(left, right), Expression.Constant(1L), Expression.Constant(0L)); break; case ExpressionType.ExclusiveOr: res = Expression.ExclusiveOr(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.GreaterThan: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.GreaterThan(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.GreaterThan(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.GreaterThan(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.GreaterThanOrEqual: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.GreaterThanOrEqual(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.GreaterThanOrEqual(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.GreaterThanOrEqual(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.LeftShift: res = Expression.LeftShift(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(int))); break; case ExpressionType.LessThan: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.LessThan(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.LessThan(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.LessThan(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.LessThanOrEqual: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.LessThanOrEqual(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.LessThanOrEqual(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.LessThanOrEqual(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.Modulo: res = Expression.Modulo(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.Multiply: if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { res = Expression.Multiply(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { res = Expression.Multiply(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } break; case ExpressionType.NotEqual: res = Expression.Condition(Equal(left, right), Expression.Constant(0L), Expression.Constant(1L)); break; case ExpressionType.Or: res = Expression.Or(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.RightShift: res = Expression.RightShift(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(int))); break; case ExpressionType.Subtract: if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { res = Expression.Subtract(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { res = Expression.Subtract(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } break; } var restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg)); if (res != null) { return(new DynamicMetaObject(Expression.Convert(res, typeof(object)), restrictions)); } else { return(errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("不正な二項演算です。")), typeof(object)), restrictions)); } }
internal DynamicMetaObject FallbackConvert(Type returnType, DynamicMetaObject self, DynamicMetaObject errorSuggestion) { Type type = Type; DynamicMetaObject res = null; switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: res = MakeToBoolConversion(self); break; case TypeCode.Char: res = TryToCharConversion(self); break; case TypeCode.String: if (self.GetLimitType() == typeof(Bytes) && !_context.PythonOptions.Python30) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeString"), AstUtils.Convert(self.Expression, typeof(IList <byte>)) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(Bytes)) ); } break; case TypeCode.Object: // !!! Deferral? if (type.IsArray && self.Value is PythonTuple && type.GetArrayRank() == 1) { res = MakeToArrayConversion(self, type); } else if (type.IsGenericType && !type.IsAssignableFrom(CompilerHelpers.GetType(self.Value))) { Type genTo = type.GetGenericTypeDefinition(); // Interface conversion helpers... if (genTo == typeof(IList <>)) { if (self.LimitType == typeof(string)) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeByteArray"), AstUtils.Convert(self.Expression, typeof(string)) ), BindingRestrictions.GetTypeRestriction( self.Expression, typeof(string) ) ); } else { res = TryToGenericInterfaceConversion(self, type, typeof(IList <object>), typeof(ListGenericWrapper <>)); } } else if (genTo == typeof(IDictionary <,>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IDictionary <object, object>), typeof(DictionaryGenericWrapper <,>)); } else if (genTo == typeof(IEnumerable <>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IEnumerable), typeof(IEnumerableOfTWrapper <>)); } } else if (type == typeof(IEnumerable)) { if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = ConvertToIEnumerable(this, self.Restrict(self.GetLimitType())); } } else if (type == typeof(IEnumerator)) { if (!typeof(IEnumerator).IsAssignableFrom(self.GetLimitType()) && !typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = ConvertToIEnumerator(this, self.Restrict(self.GetLimitType())); } } break; } if (type.IsEnum && Enum.GetUnderlyingType(type) == self.GetLimitType()) { // numeric type to enum, this is ok if the value is zero object value = Activator.CreateInstance(type); return(new DynamicMetaObject( Ast.Condition( Ast.Equal( AstUtils.Convert(self.Expression, Enum.GetUnderlyingType(type)), AstUtils.Constant(Activator.CreateInstance(self.GetLimitType())) ), AstUtils.Constant(value), Ast.Call( typeof(PythonOps).GetMethod("TypeErrorForBadEnumConversion").MakeGenericMethod(type), AstUtils.Convert(self.Expression, typeof(object)) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())), value )); } return(res ?? EnsureReturnType(returnType, Context.Binder.ConvertTo(Type, ResultKind, self, _context.SharedOverloadResolverFactory, errorSuggestion))); }
private DynamicMetaObject /*!*/ GetInstance(Expression /*!*/ instance, Type /*!*/ testType) { Assert.NotNull(instance, testType); object instanceValue = Value.BindingSelf; BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(instance, testType); // cast the instance to the correct type if (CompilerHelpers.IsStrongBox(instanceValue)) { instance = ReadStrongBoxValue(instance); instanceValue = ((IStrongBox)instanceValue).Value; } else if (!testType.IsEnum) { // We need to deal w/ wierd types like MarshalByRefObject. // We could have an MBRO whos DeclaringType is completely different. // Therefore we special case it here and cast to the declaring type Type selfType = CompilerHelpers.GetType(Value.BindingSelf); selfType = CompilerHelpers.GetVisibleType(selfType); if (selfType == typeof(object) && Value.DeclaringType.IsInterface) { selfType = Value.DeclaringType; Type genericTypeDefinition = null; if (Value.DeclaringType.IsGenericType && Value.DeclaringType.FullName == null && Value.DeclaringType.ContainsGenericParameters && !Value.DeclaringType.IsGenericTypeDefinition) { // from MSDN: If the current type contains generic type parameters that have not been replaced by // specific types (that is, the ContainsGenericParameters property returns true), but the type // is not a generic type definition (that is, the IsGenericTypeDefinition property returns false), // this property returns Nothing. For example, consider the classes Base and Derived in the following code. // if this type is completely generic (no type arguments specified) then we'll go ahead and get the // generic type definition for the this parameter - that'll let us successfully type infer on it later. var genericArgs = Value.DeclaringType.GetGenericArguments(); bool hasOnlyGenerics = genericArgs.Length > 0; foreach (var genericParam in genericArgs) { if (!genericParam.IsGenericParameter) { hasOnlyGenerics = false; break; } } if (hasOnlyGenerics) { genericTypeDefinition = Value.DeclaringType.GetGenericTypeDefinition(); } } else if (Value.DeclaringType.IsGenericTypeDefinition) { genericTypeDefinition = Value.DeclaringType; } if (genericTypeDefinition != null) { // we're a generic interface method on a non-public type. // We need to see if we can match any types implemented on // the concrete selfType. var interfaces = CompilerHelpers.GetType(Value.BindingSelf).GetInterfaces(); foreach (var iface in interfaces) { if (iface.IsGenericType && iface.GetGenericTypeDefinition() == genericTypeDefinition) { selfType = iface; break; } } } } if (Value.DeclaringType.IsInterface && selfType.IsValueType) { // explicit interface implementation dispatch on a value type, don't // unbox the value type before the dispatch. instance = AstUtils.Convert(instance, Value.DeclaringType); } else if (selfType.IsValueType) { // We might be calling a a mutating method (like // Rectangle.Intersect). If so, we want it to mutate // the boxed value directly instance = Ast.Unbox(instance, selfType); } else { #if SILVERLIGHT instance = AstUtils.Convert(instance, selfType); #else Type convType = selfType == typeof(MarshalByRefObject) ? CompilerHelpers.GetVisibleType(Value.DeclaringType) : selfType; instance = AstUtils.Convert(instance, convType); #endif } } else { // we don't want to cast the enum to its real type, it will unbox it // and turn it into its underlying type. We presumably want to call // a method on the Enum class though - so we cast to Enum instead. instance = AstUtils.Convert(instance, typeof(Enum)); } return(new DynamicMetaObject( instance, restrictions, instanceValue )); }
/// <summary> /// Translates our CallSignature into a DLR Argument list and gives the simple MetaObject's which are extracted /// from the tuple or dictionary parameters being splatted. /// </summary> private void TranslateArguments(DynamicMetaObject target, DynamicMetaObject /*!*/[] /*!*/ args, out CallInfo /*!*/ callInfo, out List <Expression /*!*/> /*!*/ metaArgs, out Expression test, out BindingRestrictions restrictions) { Argument[] argInfo = _signature.GetArgumentInfos(); List <string> namedArgNames = new List <string>(); metaArgs = new List <Expression>(); metaArgs.Add(target.Expression); Expression splatArgTest = null; Expression splatKwArgTest = null; restrictions = BindingRestrictions.Empty; for (int i = 0; i < argInfo.Length; i++) { Argument ai = argInfo[i]; switch (ai.Kind) { case ArgumentType.Dictionary: PythonDictionary iac = (PythonDictionary)args[i].Value; List <string> argNames = new List <string>(); foreach (KeyValuePair <object, object> kvp in iac) { string key = (string)kvp.Key; namedArgNames.Add(key); argNames.Add(key); metaArgs.Add( Expression.Call( AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)), typeof(PythonDictionary).GetMethod("get_Item", new[] { typeof(object) }), AstUtils.Constant(key) ) ); } restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType())); splatKwArgTest = Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.CheckDictionaryMembers)), AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)), AstUtils.Constant(argNames.ToArray()) ); break; case ArgumentType.List: IList <object> splattedArgs = (IList <object>)args[i].Value; splatArgTest = Expression.Equal( Expression.Property(AstUtils.Convert(args[i].Expression, args[i].GetLimitType()), typeof(ICollection <object>).GetProperty("Count")), AstUtils.Constant(splattedArgs.Count) ); for (int splattedArg = 0; splattedArg < splattedArgs.Count; splattedArg++) { metaArgs.Add( Expression.Call( AstUtils.Convert(args[i].Expression, typeof(IList <object>)), typeof(IList <object>).GetMethod("get_Item"), AstUtils.Constant(splattedArg) ) ); } restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType())); break; case ArgumentType.Named: namedArgNames.Add(ai.Name); metaArgs.Add(args[i].Expression); break; case ArgumentType.Simple: metaArgs.Add(args[i].Expression); break; default: throw new InvalidOperationException(); } } callInfo = new CallInfo(metaArgs.Count - 1, namedArgNames.ToArray()); test = splatArgTest; if (splatKwArgTest != null) { test = test != null?Expression.AndAlso(test, splatKwArgTest) : splatKwArgTest; } }
internal static DynamicMetaObject FallbackWorker(PythonContext context, DynamicMetaObject /*!*/ self, DynamicMetaObject /*!*/ codeContext, string name, GetMemberOptions options, DynamicMetaObjectBinder action, DynamicMetaObject errorSuggestion) { if (self.NeedsDeferral()) { return(action.Defer(self)); } PythonOverloadResolverFactory resolverFactory = new PythonOverloadResolverFactory(context.Binder, codeContext.Expression); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "FallbackGet"); bool isNoThrow = ((options & GetMemberOptions.IsNoThrow) != 0) ? true : false; Type limitType = self.GetLimitType(); if (limitType == typeof(DynamicNull) || PythonBinder.IsPythonType(limitType)) { // look up in the PythonType so that we can // get our custom method names (e.g. string.startswith) PythonType argType = DynamicHelpers.GetPythonTypeFromType(limitType); // if the name is defined in the CLS context but not the normal context then // we will hide it. if (argType.IsHiddenMember(name)) { DynamicMetaObject baseRes = PythonContext.GetPythonContext(action).Binder.GetMember( name, self, resolverFactory, isNoThrow, errorSuggestion ); Expression failure = GetFailureExpression(limitType, self, name, isNoThrow, action); return(BindingHelpers.FilterShowCls(codeContext, action, baseRes, failure)); } } if (self.GetLimitType() == typeof(OldInstance)) { if ((options & GetMemberOptions.IsNoThrow) != 0) { return(new DynamicMetaObject( Ast.Field( null, typeof(OperationFailed).GetField("Value") ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) )); } else { return(new DynamicMetaObject( Ast.Throw( Ast.Call( typeof(PythonOps).GetMethod("AttributeError"), AstUtils.Constant("{0} instance has no attribute '{1}'"), Ast.NewArrayInit( typeof(object), AstUtils.Constant(((OldInstance)self.Value)._class._name), AstUtils.Constant(name) ) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) )); } } var res = PythonContext.GetPythonContext(action).Binder.GetMember(name, self, resolverFactory, isNoThrow, errorSuggestion); // Default binder can return something typed to boolean or int. // If that happens, we need to apply Python's boxing rules. if (res.Expression.Type.IsValueType) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return(res); }