Provides a mapping for inputs of combo action expressions. The input can map to either an input of the new dynamic site, an input of a previous DynamicExpression, or a ConstantExpression which has been pulled out of the dynamic site arguments.
Пример #1
0
        private DynamicMetaObject[] GetArguments(DynamicMetaObject[] args, IList<DynamicMetaObject> results, int metaBinderIndex) {
            BinderMappingInfo indices = _metaBinders[metaBinderIndex];

            DynamicMetaObject[] res = new DynamicMetaObject[indices.MappingInfo.Count];
            for (int i = 0; i < res.Length; i++) {
                ParameterMappingInfo mappingInfo = indices.MappingInfo[i];

                if (mappingInfo.IsAction) {
                    // input is the result of a previous bind
                    res[i] = results[mappingInfo.ActionIndex];
                } else if (mappingInfo.IsParameter) {
                    // input is one of the original arguments
                    res[i] = args[mappingInfo.ParameterIndex];
                } else {
                    // input is a constant
                    res[i] = new DynamicMetaObject(
                        mappingInfo.Constant,
                        BindingRestrictions.Empty,
                        mappingInfo.Constant.Value
                    );
                }
            }

            return res;
        }
Пример #2
0
        public override bool Equals(object obj)
        {
            ParameterMappingInfo pmi = obj as ParameterMappingInfo;

            if (pmi == null)
            {
                return(false);
            }

            if (pmi.ParameterIndex == ParameterIndex && pmi.ActionIndex == ActionIndex)
            {
                if (Constant != null)
                {
                    if (pmi.Constant == null)
                    {
                        return(false);
                    }

                    return(Constant.Value == pmi.Constant.Value);
                }

                return(pmi.Constant == null);
            }

            return(false);
        }
Пример #3
0
        internal MSAst.Expression TransformAndDynamicConvert(Expression expression, Type/*!*/ type) {
            Debug.Assert(expression != null);
            
            MSAst.Expression res = expression;

            // Do we need conversion?
            if (!CanAssign(type, expression.Type)) {
                // ensure we're reduced before we check for dynamic expressions.

                var reduced = expression.Reduce();
                if (reduced is LightDynamicExpression) {
                    reduced = reduced.Reduce();
                }
                
                // Add conversion step to the AST
                MSAst.DynamicExpression ae = reduced as MSAst.DynamicExpression;
                ReducableDynamicExpression rde = reduced as ReducableDynamicExpression;

                if ((ae != null && ae.Binder is PythonBinaryOperationBinder) ||
                    (rde != null && rde.Binder is PythonBinaryOperationBinder)) {
                    // create a combo site which does the conversion
                    PythonBinaryOperationBinder binder;
                    IList<MSAst.Expression> args;
                    if (ae != null) {
                        binder = (PythonBinaryOperationBinder)ae.Binder;
                        args = ArrayUtils.ToArray(ae.Arguments);
                    } else {
                        binder = (PythonBinaryOperationBinder)rde.Binder;
                        args = rde.Args;
                    }

                    ParameterMappingInfo[] infos = new ParameterMappingInfo[args.Count];
                    for (int i = 0; i < infos.Length; i++) {
                        infos[i] = ParameterMappingInfo.Parameter(i);
                    }
                    
                    res = Expression.Dynamic(
                        GlobalParent.PyContext.BinaryOperationRetType(
                            binder,
                            GlobalParent.PyContext.Convert(
                                type,
                                ConversionResultKind.ExplicitCast
                            )
                        ),
                        type,
                        args
                    );
                } else {
                    res = GlobalParent.Convert(
                        type,
                        ConversionResultKind.ExplicitCast,
                        reduced
                    );
                }
            }
            return res;
        }
Пример #4
0
        internal MSAst.Expression/*!*/ DynamicConvertIfNeeded(MSAst.Expression/*!*/ expression, Type/*!*/ type) {
            Debug.Assert(expression != null);
            // Do we need conversion?
            if (!CanAssign(type, expression.Type)) {
                // Add conversion step to the AST
                DynamicExpression ae = expression as DynamicExpression;
                ReducableDynamicExpression rde = expression as ReducableDynamicExpression;

                if ((ae != null && ae.Binder is PythonBinaryOperationBinder) ||
                    (rde != null && rde.Binder is PythonBinaryOperationBinder)) {
                    // create a combo site which does the conversion
                    PythonBinaryOperationBinder binder;
                    MSAst.Expression[] args;
                    if (ae != null) {
                        binder = (PythonBinaryOperationBinder)ae.Binder;
                        args = ArrayUtils.ToArray(ae.Arguments);
                    } else {
                        binder = (PythonBinaryOperationBinder)rde.Binder;
                        args = rde.Args;
                    }

                    ParameterMappingInfo[] infos = new ParameterMappingInfo[args.Length];
                    for (int i = 0; i<infos.Length; i++) {
                        infos[i] = ParameterMappingInfo.Parameter(i);
                    }

                    expression = Globals.Dynamic(
                        BinderState.BinaryOperationRetType(
                            binder,
                            BinderState.Convert(
                                type,
                                ConversionResultKind.ExplicitCast
                            )
                        ),
                        type,
                        args
                    );
                } else {
                    expression = Convert(
                        type,
                        ConversionResultKind.ExplicitCast,
                        expression
                    );
                }
            }
            return expression;
        }
Пример #5
0
        protected override Expression VisitDynamic(DynamicExpression node)
        {
            DynamicMetaObjectBinder metaBinder = node.Binder as DynamicMetaObjectBinder;

            if (metaBinder == null)
            {
                // don't rewrite non meta-binder nodes, we can't compose them
                return(node);
            }

            // gather the real arguments for the new dynamic site node
            var  args = node.Arguments;
            bool foundSideEffectingArgs = false;
            List <Expression> inputs    = new List <Expression>();

            // parameter mapping is 1 List<ComboParameterMappingInfo> for each meta binder, the inner list
            // contains the mapping info for each particular binder

            List <BinderMappingInfo>    binders = new List <BinderMappingInfo>();
            List <ParameterMappingInfo> myInfo  = new List <ParameterMappingInfo>();

            int actionCount = 0;

            for (int i = 0; i < args.Count; i++)
            {
                Expression e = args[i];

                if (!foundSideEffectingArgs)
                {
                    // attempt to combine the arguments...
                    Expression rewritten = Visit(e);

                    ComboDynamicSiteExpression combo = rewritten as ComboDynamicSiteExpression;
                    ConstantExpression         ce;
                    if (combo != null)
                    {
                        // an action expression we can combine with our own expression

                        // remember how many actions we have so far - if any of our children consume
                        // actions their offset is bumped up
                        int baseActionCount = actionCount;

                        foreach (BinderMappingInfo comboInfo in combo.Binders)
                        {
                            List <ParameterMappingInfo> newInfo = new List <ParameterMappingInfo>();

                            foreach (ParameterMappingInfo info in comboInfo.MappingInfo)
                            {
                                if (info.IsParameter)
                                {
                                    // all of the inputs from the child now become ours
                                    newInfo.Add(ParameterMappingInfo.Parameter(inputs.Count));
                                    inputs.Add(combo.Inputs[info.ParameterIndex]);
                                }
                                else if (info.IsAction)
                                {
                                    newInfo.Add(ParameterMappingInfo.Action(info.ActionIndex + baseActionCount));
                                    actionCount++;
                                }
                                else
                                {
                                    Debug.Assert(info.Constant != null);

                                    // constants can just flow through
                                    newInfo.Add(info);
                                }
                            }

                            binders.Add(new BinderMappingInfo(comboInfo.Binder, newInfo));
                        }

                        myInfo.Add(ParameterMappingInfo.Action(actionCount++));
                    }
                    else if ((ce = rewritten as ConstantExpression) != null)
                    {
                        // we can hoist the constant into the combo
                        myInfo.Add(ParameterMappingInfo.Fixed(ce));
                    }
                    else if (IsSideEffectFree(rewritten))
                    {
                        // we can treat this as an input parameter
                        myInfo.Add(ParameterMappingInfo.Parameter(inputs.Count));
                        inputs.Add(rewritten);
                    }
                    else
                    {
                        // this argument is doing something we don't understand - we have to leave
                        // it as is (an input we consume) and all the remaining arguments need to be
                        // evaluated normally as this could have side effects on them.
                        foundSideEffectingArgs = true;
                        myInfo.Add(ParameterMappingInfo.Parameter(inputs.Count));
                        inputs.Add(e);
                    }
                }
                else
                {
                    // we've already seen an argument which may have side effects, don't do
                    // any more combinations.
                    myInfo.Add(ParameterMappingInfo.Parameter(inputs.Count));
                    inputs.Add(e);
                }
            }
            binders.Add(new BinderMappingInfo(metaBinder, myInfo));
            // TODO: Remove any duplicate inputs (e.g. locals being fed in multiple times)
            return(new ComboDynamicSiteExpression(node.Type, binders, inputs.ToArray()));
        }
Пример #6
0
        public static DynamicMetaObjectBinder/*!*/ InvokeAndConvert(BinderState/*!*/ state, int argCount, Type retType) {
            // +2 for the target object and CodeContext which InvokeBinder recevies
            ParameterMappingInfo[] args = new ParameterMappingInfo[argCount + 2];   
            for (int i = 0; i < argCount + 2; i++) {
                args[i] = ParameterMappingInfo.Parameter(i);
            }

            return new ComboBinder(
                new BinderMappingInfo(
                    state.Invoke(
                        new CallSignature(argCount)
                    ),
                    args
                ),
                new BinderMappingInfo(
                    state.Convert(retType, ConversionResultKind.ExplicitCast),
                    ParameterMappingInfo.Action(0)
                )
            );
        }