/// <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 List<ArgumentInfo/*!*/>/*!*/ newArgs, out List<Expression/*!*/>/*!*/ metaArgs, out Expression test, out BindingRestrictions restrictions) { Argument[] argInfo = _signature.GetArgumentInfos(); newArgs = new List<ArgumentInfo>(); 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: IAttributesCollection iac = (IAttributesCollection)args[i].Value; List<string> argNames = new List<string>(); foreach (KeyValuePair<object, object> kvp in iac) { string key = (string)kvp.Key; newArgs.Add(Expression.NamedArg(key)); argNames.Add(key); metaArgs.Add( Expression.Call( AstUtils.Convert(args[i].Expression, typeof(IAttributesCollection)), typeof(IAttributesCollection).GetMethod("get_Item"), AstUtils.Constant(SymbolTable.StringToId(key)) ) ); } restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType())); splatKwArgTest = Expression.Call( typeof(PythonOps).GetMethod("CheckDictionaryMembers"), AstUtils.Convert(args[i].Expression, typeof(IAttributesCollection)), Expression.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")), Expression.Constant(splattedArgs.Count) ); for (int splattedArg = 0; splattedArg < splattedArgs.Count; splattedArg++) { newArgs.Add(Expression.PositionalArg(splattedArg + i)); metaArgs.Add( Expression.Call( AstUtils.Convert(args[i].Expression, typeof(IList<object>)), typeof(IList<object>).GetMethod("get_Item"), Expression.Constant(splattedArg) ) ); } restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType())); break; case ArgumentType.Named: newArgs.Add(Expression.NamedArg(SymbolTable.IdToString(ai.Name))); metaArgs.Add(args[i].Expression); break; case ArgumentType.Simple: newArgs.Add(Expression.PositionalArg(i)); metaArgs.Add(args[i].Expression); break; default: throw new InvalidOperationException(); } } test = splatArgTest; if (splatKwArgTest != null) { if (test != null) { test = Expression.AndAlso(test, splatKwArgTest); } else { test = splatKwArgTest; } } }
private static BindingRestrictions AddRemoteObjectRestrictions(BindingRestrictions restrictions, object[] args, ReadOnlyCollection<ParameterExpression> parameters) { #if !SILVERLIGHT for (int i = 0; i < parameters.Count; i++) { var expr = parameters[i]; var value = args[i] as MarshalByRefObject; // special case for MBR objects. // when MBR objects are remoted they can have different conversion behavior // so bindings created for local and remote objects should not be mixed. if (value != null && !IsComObject(value)) { BindingRestrictions remotedRestriction; if (RemotingServices.IsObjectOutOfAppDomain(value)) { remotedRestriction = BindingRestrictions.GetExpressionRestriction( Expression.AndAlso( Expression.NotEqual(expr, Expression.Constant(null)), Expression.Call( typeof(RemotingServices).GetMethod("IsObjectOutOfAppDomain"), expr ) ) ); } else { remotedRestriction = BindingRestrictions.GetExpressionRestriction( Expression.AndAlso( Expression.NotEqual(expr, Expression.Constant(null)), Expression.Not( Expression.Call( typeof(RemotingServices).GetMethod("IsObjectOutOfAppDomain"), expr ) ) ) ); } restrictions = restrictions.Merge(remotedRestriction); } } #endif return restrictions; }
internal static DynamicMetaObject Bind( ICSharpBinder action, RuntimeBinder binder, DynamicMetaObject[] args, IEnumerable <CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError) { Expression[] parameters = new Expression[args.Length]; BindingRestrictions restrictions = BindingRestrictions.Empty; ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder; ParameterExpression tempForIncrement = null; IEnumerator <CSharpArgumentInfo> arginfosEnum = (arginfos ?? Array.Empty <CSharpArgumentInfo>()).GetEnumerator(); for (int index = 0; index < args.Length; ++index) { DynamicMetaObject o = args[index]; // Our contract with the DLR is such that we will not enter a bind unless we have // values for the meta-objects involved. Debug.Assert(o.HasValue); CSharpArgumentInfo info = arginfosEnum.MoveNext() ? arginfosEnum.Current : null; if (index == 0 && IsIncrementOrDecrementActionOnLocal(action)) { // We have an inc or a dec operation. Insert the temp local instead. // // We need to do this because for value types, the object will come // in boxed, and we'd need to unbox it to get the original type in order // to increment. The only way to do that is to create a new temporary. object value = o.Value; tempForIncrement = Expression.Variable(value != null ? value.GetType() : typeof(object), "t0"); parameters[0] = tempForIncrement; } else { parameters[index] = o.Expression; } BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info); restrictions = restrictions.Merge(r); // Here we check the argument info. If the argument info shows that the current argument // is a literal constant, then we also add an instance restriction on the value of // the constant. if (info != null && info.LiteralConstant) { if (o.Value is double && double.IsNaN((double)o.Value)) { MethodInfo isNaN = s_DoubleIsNaN ?? (s_DoubleIsNaN = typeof(double).GetMethod("IsNaN")); Expression e = Expression.Call(null, isNaN, o.Expression); restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e)); } else if (o.Value is float && float.IsNaN((float)o.Value)) { MethodInfo isNaN = s_SingleIsNaN ?? (s_SingleIsNaN = typeof(float).GetMethod("IsNaN")); Expression e = Expression.Call(null, isNaN, o.Expression); restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e)); } else { Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type)); r = BindingRestrictions.GetExpressionRestriction(e); restrictions = restrictions.Merge(r); } } } // Get the bound expression. try { Expression expression = binder.Bind(action, parameters, args, out DynamicMetaObject deferredBinding); if (deferredBinding != null) { expression = ConvertResult(deferredBinding.Expression, action); restrictions = deferredBinding.Restrictions.Merge(restrictions); return(new DynamicMetaObject(expression, restrictions)); } if (tempForIncrement != null) { // If we have a ++ or -- payload, we need to do some temp rewriting. // We rewrite to the following: // // temp = (type)o; // temp++; // o = temp; // return o; DynamicMetaObject arg0 = args[0]; expression = Expression.Block( new[] { tempForIncrement }, Expression.Assign(tempForIncrement, Expression.Convert(arg0.Expression, arg0.Value.GetType())), expression, Expression.Assign(arg0.Expression, Expression.Convert(tempForIncrement, arg0.Expression.Type))); } expression = ConvertResult(expression, action); return(new DynamicMetaObject(expression, restrictions)); } catch (RuntimeBinderException e) { if (onBindingError != null) { return(onBindingError); } return(new DynamicMetaObject( Expression.Throw( Expression.New( typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }), Expression.Constant(e.Message) ), GetTypeForErrorMetaObject(action, args) ), restrictions )); } }
public void FinishCondition(DynamicMetaObject body) { _restrictions = _restrictions.Merge(body.Restrictions); FinishCondition(body.Expression); }
internal static DynamicMetaObject Bind( DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable <DynamicMetaObject> args, IEnumerable <CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError) { List <Expression> parameters = new List <Expression>(); BindingRestrictions restrictions = BindingRestrictions.Empty; ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder; ParameterExpression tempForIncrement = null; IEnumerator <CSharpArgumentInfo> arginfosEnum = arginfos == null ? null : arginfos.GetEnumerator(); int index = 0; foreach (DynamicMetaObject o in args) { // Our contract with the DLR is such that we will not enter a bind unless we have // values for the meta-objects involved. if (!o.HasValue) { Debug.Assert(false, "The runtime binder is being asked to bind a metaobject without a value"); throw Error.InternalCompilerError(); } CSharpArgumentInfo info = null; if (arginfosEnum != null && arginfosEnum.MoveNext()) { info = arginfosEnum.Current; } if (index == 0 && IsIncrementOrDecrementActionOnLocal(action)) { // We have an inc or a dec operation. Insert the temp local instead. // // We need to do this because for value types, the object will come // in boxed, and we'd need to unbox it to get the original type in order // to increment. The only way to do that is to create a new temporary. tempForIncrement = Expression.Variable(o.Value != null ? o.Value.GetType() : typeof(object), "t0"); parameters.Add(tempForIncrement); } else { parameters.Add(o.Expression); } BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info); restrictions = restrictions.Merge(r); // Here we check the argument info. If the argument info shows that the current argument // is a literal constant, then we also add an instance restriction on the value of // the constant. if (info != null && info.LiteralConstant) { if ((o.Value is float && float.IsNaN((float)o.Value)) || o.Value is double && double.IsNaN((double)o.Value)) { // We cannot create an equality restriction for NaN, because equality is implemented // in such a way that NaN != NaN and the rule we make would be unsatisfiable. } else { Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type)); r = BindingRestrictions.GetExpressionRestriction(e); restrictions = restrictions.Merge(r); } } ++index; } // Get the bound expression. try { DynamicMetaObject deferredBinding; Expression expression = binder.Bind(action, parameters, args.ToArray(), out deferredBinding); if (deferredBinding != null) { expression = ConvertResult(deferredBinding.Expression, action); restrictions = deferredBinding.Restrictions.Merge(restrictions); return(new DynamicMetaObject(expression, restrictions)); } if (tempForIncrement != null) { // If we have a ++ or -- payload, we need to do some temp rewriting. // We rewrite to the following: // // temp = (type)o; // temp++; // o = temp; // return o; DynamicMetaObject arg0 = Enumerable.First(args); Expression assignTemp = Expression.Assign( tempForIncrement, Expression.Convert(arg0.Expression, arg0.Value.GetType())); Expression assignResult = Expression.Assign( arg0.Expression, Expression.Convert(tempForIncrement, arg0.Expression.Type)); List <Expression> expressions = new List <Expression>(); expressions.Add(assignTemp); expressions.Add(expression); expressions.Add(assignResult); expression = Expression.Block(new ParameterExpression[] { tempForIncrement }, expressions); } expression = ConvertResult(expression, action); return(new DynamicMetaObject(expression, restrictions)); } catch (RuntimeBinderException e) { if (onBindingError != null) { return(onBindingError); } return(new DynamicMetaObject( Expression.Throw( Expression.New( typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }), Expression.Constant(e.Message) ), GetTypeForErrorMetaObject(action, args.FirstOrDefault()) ), restrictions )); } }
private DynamicMetaObject InvokeWorker(DynamicMetaObjectBinder /*!*/ callAction, DynamicMetaObject /*!*/[] args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "Method Invoke " + args.Length); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "Method"); CallSignature signature = BindingHelpers.GetCallSignature(callAction); DynamicMetaObject self = Restrict(typeof(Method)); BindingRestrictions restrictions = self.Restrictions; DynamicMetaObject func = GetMetaFunction(self); DynamicMetaObject call; if (Value.im_self == null) { // restrict to null self (Method is immutable so this is an invariant test) restrictions = restrictions.Merge( BindingRestrictions.GetExpressionRestriction( Ast.Equal( GetSelfExpression(self), AstUtils.Constant(null) ) ) ); if (args.Length == 0) { // this is an error, we pass null which will throw the normal error call = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.MethodCheckSelf)), PythonContext.GetCodeContext(callAction), self.Expression, AstUtils.Constant(null) ), restrictions ); } else { // this may or may not be an error call = new DynamicMetaObject( Ast.Block( MakeCheckSelf(callAction, signature, args), DynamicExpression.Dynamic( PythonContext.GetPythonContext(callAction).Invoke( BindingHelpers.GetCallSignature(callAction) ).GetLightExceptionBinder(callAction.SupportsLightThrow()), typeof(object), ArrayUtils.Insert(PythonContext.GetCodeContext(callAction), DynamicUtils.GetExpressions(ArrayUtils.Insert(func, args))) ) ), BindingRestrictions.Empty ); /*call = func.Invoke(callAction, ArrayUtils.Insert(func, args)); * call = new MetaObject( * Ast.Comma( * Ast.Call( * typeof(PythonOps).GetMethod("MethodCheckSelf"), * self.Expression, * args[0].Expression * ), * call.Expression * ), * call.Restrictions * );*/ } } else { // restrict to non-null self (Method is immutable so this is an invariant test) restrictions = restrictions.Merge( BindingRestrictions.GetExpressionRestriction( Ast.NotEqual( GetSelfExpression(self), AstUtils.Constant(null) ) ) ); DynamicMetaObject im_self = GetMetaSelf(self); DynamicMetaObject[] newArgs = ArrayUtils.Insert(func, im_self, args); CallSignature newSig = new CallSignature(ArrayUtils.Insert(new Argument(ArgumentType.Simple), signature.GetArgumentInfos())); call = new DynamicMetaObject( DynamicExpression.Dynamic( PythonContext.GetPythonContext(callAction).Invoke( newSig ).GetLightExceptionBinder(callAction.SupportsLightThrow()), typeof(object), ArrayUtils.Insert(PythonContext.GetCodeContext(callAction), DynamicUtils.GetExpressions(newArgs)) ), BindingRestrictions.Empty ); /* * call = func.Invoke( * new CallBinder( * PythonContext.GetBinderState(callAction), * newSig * ), * newArgs * );*/ } if (call.HasValue) { return(new DynamicMetaObject( call.Expression, restrictions.Merge(call.Restrictions), call.Value )); } else { return(new DynamicMetaObject( call.Expression, restrictions.Merge(call.Restrictions) )); } }
public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) { CodeContext context = PythonContext.GetPythonContext(binder).SharedContext; ArgumentMarshaller[] signature = GetArgumentMarshallers(args); BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction( Expression, Value.GetType() ).Merge( BindingRestrictions.GetExpressionRestriction( Expression.Call( typeof(ModuleOps).GetMethod(nameof(ModuleOps.CheckFunctionId)), Expression.Convert(Expression, typeof(_CFuncPtr)), Expression.Constant(Value.Id) ) ) ); foreach (var arg in signature) { restrictions = restrictions.Merge(arg.GetRestrictions()); } int argCount = args.Length; if (Value._comInterfaceIndex != -1) { argCount--; } // need to verify we have the correct # of args if (Value._argtypes != null) { if (argCount < Value._argtypes.Count || (Value.CallingConvention != CallingConvention.Cdecl && argCount > Value._argtypes.Count)) { return(IncorrectArgCount(binder, restrictions, Value._argtypes.Count, argCount)); } } else { CFuncPtrType funcType = ((CFuncPtrType)Value.NativeType); if (funcType._argtypes != null && (argCount < funcType._argtypes.Length || (Value.CallingConvention != CallingConvention.Cdecl && argCount > funcType._argtypes.Length))) { return(IncorrectArgCount(binder, restrictions, funcType._argtypes.Length, argCount)); } } if (Value._comInterfaceIndex != -1 && args.Length == 0) { return(NoThisParam(binder, restrictions)); } Expression call = MakeCall(signature, GetNativeReturnType(), Value.Getrestype() == null, GetFunctionAddress(args)); List <Expression> block = new List <Expression>(); Expression res; if (call.Type != typeof(void)) { ParameterExpression tmp = Expression.Parameter(call.Type, "ret"); block.Add(Expression.Assign(tmp, call)); AddKeepAlives(signature, block); block.Add(tmp); res = Expression.Block(new[] { tmp }, block); } else { block.Add(call); AddKeepAlives(signature, block); res = Expression.Block(block); } res = AddReturnChecks(context, args, res); return(new DynamicMetaObject(Utils.Convert(res, typeof(object)), restrictions)); }
/// <summary> /// Helper for generating the call to a builtin function. This is used for calls from built-in method /// descriptors and built-in functions w/ and w/o a bound instance. /// /// This provides all sorts of common checks on top of the call while the caller provides a delegate /// to do the actual call. The common checks include: /// check for generic-only methods /// reversed operator support /// transforming arguments so the default binder can understand them (currently user defined mapping types to PythonDictionary) /// returning NotImplemented from binary operators /// Warning when calling certain built-in functions /// /// </summary> /// <param name="call">The call binder we're doing the call for</param> /// <param name="codeContext">An expression which points to the code context</param> /// <param name="function">the meta object for the built in function</param> /// <param name="hasSelf">true if we're calling with an instance</param> /// <param name="args">The arguments being passed to the function</param> /// <param name="functionRestriction">A restriction for the built-in function, method desc, etc...</param> /// <param name="bind">A delegate to perform the actual call to the method.</param> internal DynamicMetaObject /*!*/ MakeBuiltinFunctionCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/ function, DynamicMetaObject /*!*/[] args, bool hasSelf, BindingRestrictions /*!*/ functionRestriction, Func <DynamicMetaObject /*!*/[] /*!*/, BindingResult /*!*/> bind) { DynamicMetaObject res = null; // if we have a user defined operator for **args then transform it into a PythonDictionary DynamicMetaObject translated = TranslateArguments(call, codeContext, new DynamicMetaObject(function.Expression, functionRestriction, function.Value), args, hasSelf, Name); if (translated != null) { return(translated); } // swap the arguments if we have a reversed operator if (IsReversedOperator) { ArrayUtils.SwapLastTwo(args); } // do the appropriate calling logic BindingResult result = bind(args); // validate the result BindingTarget target = result.Target; res = result.MetaObject; if (target.Overload != null && target.Overload.IsProtected) { // report an error when calling a protected member res = new DynamicMetaObject( BindingHelpers.TypeErrorForProtectedMember( target.Overload.DeclaringType, target.Overload.Name ), res.Restrictions ); } else if (IsBinaryOperator && args.Length == 2 && IsThrowException(res.Expression)) { // Binary Operators return NotImplemented on failure. res = new DynamicMetaObject( Ast.Property(null, typeof(PythonOps), nameof(PythonOps.NotImplemented)), res.Restrictions ); } else if (target.Overload != null) { // Add profiling information for this builtin function, if applicable if (call is IPythonSite pythonSite) { var pc = pythonSite.Context; if (pc.Options is PythonOptions po && po.EnableProfiler) { Profiler profiler = Profiler.GetProfiler(pc); res = new DynamicMetaObject( profiler.AddProfiling(res.Expression, target.Overload.ReflectionInfo), res.Restrictions ); } } } // add any warnings that are applicable for calling this function WarningInfo info; if (target.Overload != null && BindingWarnings.ShouldWarn(PythonContext.GetPythonContext(call), target.Overload, out info)) { res = info.AddWarning(codeContext, res); } // finally add the restrictions for the built-in function and return the result. res = new DynamicMetaObject( res.Expression, functionRestriction.Merge(res.Restrictions) ); // The function 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 = BindingHelpers.AddPythonBoxing(res); } else if (res.Expression.Type == typeof(void)) { res = new DynamicMetaObject( Expression.Block( res.Expression, Expression.Constant(null) ), res.Restrictions ); } return(res); }
/// <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("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) { if (test != null) { test = Expression.AndAlso(test, splatKwArgTest); } else { test = splatKwArgTest; } } }
private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) { Type targetType = target.GetLimitType(); BindingRestrictions restrictions = target.Restrictions; DynamicMetaObject self = target; target = target.Restrict(target.GetLimitType()); // Specially recognized types: TypeTracker, NamespaceTracker, and StrongBox. // TODO: TypeTracker and NamespaceTracker should technically be IDO's. MemberGroup members = MemberGroup.EmptyGroup; if (typeof(TypeTracker).IsAssignableFrom(targetType)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); TypeGroup tg = target.Value as TypeGroup; Type nonGen; if (tg == null || tg.TryGetNonGenericType(out nonGen)) { members = GetMember(MemberRequestKind.Get, ((TypeTracker)target.Value).Type, getMemInfo.Name); if (members.Count > 0) { // we have a member that's on the type associated w/ the tracker, return that... targetType = ((TypeTracker)target.Value).Type; self = null; } } } if (members.Count == 0) { // Get the members members = GetMember(MemberRequestKind.Get, targetType, getMemInfo.Name); } if (members.Count == 0) { if (typeof(TypeTracker).IsAssignableFrom(targetType)) { // Throws an exception if we don't have a non-generic type, and if we do report an error now. This matches // the rule version of the default binder but should probably be removed long term. EnsureTrackerRepresentsNonGenericType((TypeTracker)target.Value); } else if (targetType.IsInterface()) { // all interfaces have object members targetType = typeof(object); members = GetMember(MemberRequestKind.Get, targetType, getMemInfo.Name); } } DynamicMetaObject propSelf = self; // if lookup failed try the strong-box type if available. if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(targetType) && propSelf != null) { // properties/fields need the direct value, methods hold onto the strong box. propSelf = new DynamicMetaObject( Ast.Field(AstUtils.Convert(propSelf.Expression, targetType), targetType.GetInheritedFields("Value").First()), propSelf.Restrictions, ((IStrongBox)propSelf.Value).Value ); targetType = targetType.GetGenericArguments()[0]; members = GetMember( MemberRequestKind.Get, targetType, getMemInfo.Name ); } MakeBodyHelper(getMemInfo, self, propSelf, targetType, members); getMemInfo.Body.Restrictions = restrictions; return(getMemInfo.Body.GetMetaObject(target)); }
private void Add(BindingRestrictions /*!*/ restriction) { Debug.Assert(!_treatRestrictionsAsConditions); _restrictions = _restrictions.Merge(restriction); }
public static Expression FillDataFrame(LambdaSignature signature, DynamicMetaObject[] input, ref BindingRestrictions restrictions) { var elementType = typeof(object); var offset = 0; var output = new List <Expression>(); if (signature.ArgModifier == Symbols.RawParams) { var tail = new List <Expression>(); for (var i = offset; i < input.Length; ++i) { tail.Add(Expression.Convert(input[i].Expression, elementType)); } var tailExpr = Expression.NewArrayInit(elementType, tail); return(tailExpr); } for (offset = 0; offset < signature.RequiredArgsCount; ++offset) { if (offset >= input.Length) { throw new LispException("Missing required arguments"); } output.Add(Expression.Convert(input[offset].Expression, elementType)); } if (offset != signature.Parameters.Count) { var mod = signature.ArgModifier; if (mod == Symbols.Rest || mod == Symbols.Body || mod == Symbols.Params || mod == Symbols.Vector) { var tail = new List <Expression>(); for (var i = offset; i < input.Length; ++i) { tail.Add(Expression.Convert(input[i].Expression, elementType)); } var tailExpr = Expression.NewArrayInit(elementType, tail); if (mod == Symbols.Rest || mod == Symbols.Body) { var conversion = Expression.Call(Runtime.AsListMethod, tailExpr); output.Add(conversion); } else if (mod == Symbols.Params) { output.Add(tailExpr); } else if (mod == Symbols.Vector) { var conversion = Expression.Call(Runtime.AsVectorMethod, tailExpr); output.Add(conversion); } } else if (mod == Symbols.Optional) { for (var i = offset; i < input.Length && i < signature.Parameters.Count; ++i) { output.Add(Expression.Convert(input[i].Expression, elementType)); } for (var i = input.Length; i < signature.Parameters.Count; ++i) { var expr = signature.Parameters[i].InitForm ?? Expression.Constant(null); output.Add(expr); } if (input.Length > signature.Parameters.Count) { throw new LispException("Too many arguments supplied"); } } else if (mod == Symbols.Key) { var firstKey = offset; var usedKeys = 0; for (var i = firstKey; i < input.Length; i += 2) { if (!Runtime.Keywordp(input[i].Value) || i + 1 == input.Length) { throw new LispException("Invalid keyword/value list"); } var keywordRestriction = BindingRestrictions.GetExpressionRestriction(Expression.Equal(input[i].Expression, Expression.Constant(input[i].Value))); restrictions = restrictions.Merge(keywordRestriction); } for (var i = offset; i < signature.Parameters.Count; ++i) { Expression val = null; for (var j = firstKey; j + 1 < input.Length; j += 2) { if (signature.Parameters[i].Sym.Name == ((Symbol)input[j].Value).Name) { val = input[j + 1].Expression; ++usedKeys; break; } } if (val == null) { output.Add(signature.Parameters[i].InitForm ?? Expression.Constant(null)); } else { output.Add(Expression.Convert(val, elementType)); } } } } if (signature.WholeArg != null) { var tail = new List <Expression>(); for (var i = 0; i < input.Length; ++i) { tail.Add(Expression.Convert(input[i].Expression, elementType)); } var tailExpr = Expression.NewArrayInit(elementType, tail); var conversion = Expression.Call(Runtime.AsListMethod, tailExpr); output.Add(conversion); } return(Expression.NewArrayInit(elementType, output)); }
/// <summary> /// Helper for generating the call to a builtin function. This is used for calls from built-in method /// descriptors and built-in functions w/ and w/o a bound instance. /// /// This provides all sorts of common checks on top of the call while the caller provides a delegate /// to do the actual call. The common checks include: /// check for generic-only methods /// reversed operator support /// transforming arguments so the default binder can understand them (currently user defined mapping types to PythonDictionary) /// returning NotImplemented from binary operators /// Warning when calling certain built-in functions /// /// </summary> /// <param name="call">The call binder we're doing the call for</param> /// <param name="codeContext">An expression which points to the code context</param> /// <param name="args">The arguments being passed to the function</param> /// <param name="functionRestriction">A restriction for the built-in function, method desc, etc...</param> /// <param name="bind">A delegate to perform the actual call to the method.</param> internal DynamicMetaObject/*!*/ MakeBuiltinFunctionCall(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/ function, DynamicMetaObject/*!*/[] args, bool hasSelf, bool enforceProtected, BindingRestrictions/*!*/ functionRestriction, Func<DynamicMetaObject/*!*/[]/*!*/, BindingResult/*!*/> bind) { DynamicMetaObject res = null; // produce an error if all overloads are generic if (IsOnlyGeneric) { return BindingHelpers.TypeErrorGenericMethod(DeclaringType, Name, functionRestriction); } // swap the arguments if we have a reversed operator if (IsReversedOperator) { ArrayUtils.SwapLastTwo(args); } // if we have a user defined operator for **args then transform it into a PythonDictionary CallSignature sig = BindingHelpers.GetCallSignature(call); if (sig.HasDictionaryArgument()) { int index = sig.IndexOf(ArgumentType.Dictionary); if (hasSelf) { index++; } DynamicMetaObject dict = args[index]; if (!(dict.Value is IDictionary)) { // 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("UserMappingToPythonDictionary"), codeContext, args[index].Expression, Ast.Constant(Name) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()), PythonOps.UserMappingToPythonDictionary(BinderState.GetBinderState(call).Context, dict.Value, Name) ); if (call is IPythonSite) { dynamicArgs = ArrayUtils.Insert( new DynamicMetaObject(codeContext, BindingRestrictions.Empty), dynamicArgs ); } return new DynamicMetaObject( Ast.Dynamic( call, typeof(object), DynamicUtils.GetExpressions(dynamicArgs) ), BindingRestrictions.Combine(dynamicArgs).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType())) ); } } // do the appropriate calling logic BindingResult result = bind(args); // validate the result BindingTarget target = result.Target; res = result.MetaObject; // BUG: enforceProtected should alwyas be enforced, but we have some tests that depend upon it not being enforced. if (enforceProtected && target.Method != null && (target.Method.IsFamily || target.Method.IsFamilyOrAssembly)) { // report an error when calling a protected member res = new DynamicMetaObject( BindingHelpers.TypeErrorForProtectedMember( target.Method.DeclaringType, target.Method.Name ), res.Restrictions ); } else if (IsBinaryOperator && args.Length == 2 && res.Expression.NodeType == ExpressionType.Throw) { // Binary Operators return NotImplemented on failure. res = new DynamicMetaObject( Ast.Property(null, typeof(PythonOps), "NotImplemented"), res.Restrictions ); } // add any warnings that are applicable for calling this function WarningInfo info; if (target.Method != null && BindingWarnings.ShouldWarn(BinderState.GetBinderState(call).Binder, target.Method, out info)) { res = info.AddWarning(codeContext, res); } // finally add the restrictions for the built-in function and return the result. res = new DynamicMetaObject( res.Expression, functionRestriction.Merge(res.Restrictions) ); // The function can return something typed to boolean or int. // If that happens, we need to apply Python's boxing rules. if (res.Expression.Type == typeof(bool) || res.Expression.Type == typeof(int)) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return res; }