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