예제 #1
0
        /// <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;
        }
예제 #3
0
        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
                           ));
            }
        }
예제 #4
0
 public void FinishCondition(DynamicMetaObject body)
 {
     _restrictions = _restrictions.Merge(body.Restrictions);
     FinishCondition(body.Expression);
 }
예제 #5
0
        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
                           ));
            }
        }
예제 #6
0
        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)
                           ));
            }
        }
예제 #7
0
                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));
                }
예제 #8
0
        /// <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);
        }
예제 #9
0
        /// <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;
                }
            }
        }
예제 #10
0
        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));
        }
예제 #11
0
 private void Add(BindingRestrictions /*!*/ restriction)
 {
     Debug.Assert(!_treatRestrictionsAsConditions);
     _restrictions = _restrictions.Merge(restriction);
 }
예제 #12
0
        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));
        }
예제 #13
0
        /// <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;
        }