Пример #1
0
        /// <summary>
        /// Gets an expression which is used for accessing this slot.  If the slot lookup fails the error expression
        /// is used again.
        ///
        /// The default implementation just calls the TryGetValue method.  Subtypes of PythonTypeSlot can override
        /// this and provide a more optimal implementation.
        /// </summary>
        internal virtual void MakeGetExpression(PythonBinder /*!*/ binder, Expression /*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject /*!*/ owner, ConditionalBuilder /*!*/ builder)
        {
            ParameterExpression tmp  = Ast.Variable(typeof(object), "slotTmp");
            Expression          call = Ast.Call(
                typeof(PythonOps).GetMethod("SlotTryGetValue"),
                codeContext,
                AstUtils.Convert(AstUtils.WeakConstant(this), typeof(PythonTypeSlot)),
                instance != null ? instance.Expression : AstUtils.Constant(null),
                owner.Expression,
                tmp
                );

            builder.AddVariable(tmp);
            if (!GetAlwaysSucceeds)
            {
                builder.AddCondition(
                    call,
                    tmp
                    );
            }
            else
            {
                builder.FinishCondition(Ast.Block(call, tmp));
            }
        }
        /// <summary>
        /// Helper to handle a comparison operator call.  Checks to see if the call can
        /// return NotImplemented and allows the caller to modify the expression that
        /// is ultimately returned (e.g. to turn __cmp__ into a bool after a comparison)
        /// </summary>
        private static bool MakeOneCompareGeneric(SlotOrFunction/*!*/ target, bool reverse, DynamicMetaObject/*!*/[]/*!*/ types, ComparisonHelper returner, ConditionalBuilder/*!*/ bodyBuilder, Type retType) {
            if (target == SlotOrFunction.Empty || !target.Success) return true;

            ParameterExpression tmp;

            if (target.ReturnType == typeof(bool)) {
                tmp = bodyBuilder.CompareRetBool;
            } else {
                tmp = Ast.Variable(target.ReturnType, "compareRetValue");
                bodyBuilder.AddVariable(tmp);
            }

            if (target.MaybeNotImplemented) {
                Expression call = target.Target.Expression;
                Expression assign = Ast.Assign(tmp, call);

                returner(
                    bodyBuilder,
                    Ast.NotEqual(
                        assign,
                        AstUtils.Constant(PythonOps.NotImplemented)
                    ),
                    tmp,
                    reverse,
                    retType);
                return true;
            } else {
                returner(
                    bodyBuilder,
                    null,
                    target.Target.Expression,
                    reverse,
                    retType
                );
                return false;
            }
        }
        private static void MakeSlotCall(PythonContext/*!*/ state, DynamicMetaObject/*!*/[]/*!*/ types, ConditionalBuilder/*!*/ bodyBuilder, PythonTypeSlot/*!*/ slotTarget, bool reverse) {
            Debug.Assert(slotTarget != null);

            Expression self, other;
            if (reverse) {
                self = types[1].Expression;
                other = types[0].Expression;
            } else {
                self = types[0].Expression;
                other = types[1].Expression;
            }

            MakeSlotCallWorker(state, slotTarget, self, bodyBuilder, other);
        }
 private static void MakeCompareTest(PythonOperationKind op, ConditionalBuilder/*!*/ bodyBuilder, Expression retCond, Expression/*!*/ expr, bool reverse, Type retType) {
     MakeCompareReturn(bodyBuilder, retCond, GetCompareTest(op, expr, reverse), reverse, retType);
 }
        private static DynamicMetaObject/*!*/ MakeBinaryOperatorResult(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ operation, PythonOperationKind op, SlotOrFunction/*!*/ fCand, SlotOrFunction/*!*/ rCand, PythonTypeSlot fSlot, PythonTypeSlot rSlot, DynamicMetaObject errorSuggestion) {
            Assert.NotNull(operation, fCand, rCand);

            SlotOrFunction fTarget, rTarget;
            PythonContext state = PythonContext.GetPythonContext(operation);

            ConditionalBuilder bodyBuilder = new ConditionalBuilder(operation);

            if ((op & PythonOperationKind.InPlace) != 0) {
                // in place operator, see if there's a specific method that handles it.
                SlotOrFunction function = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(operation), Symbols.OperatorToSymbol(op), types);

                // we don't do a coerce for in place operators if the lhs implements __iop__
                if (!MakeOneCompareGeneric(function, false, types, MakeCompareReturn, bodyBuilder, typeof(object))) {
                    // the method handles it and always returns a useful value.
                    return bodyBuilder.GetMetaObject(types);
                }
            }

            if (!SlotOrFunction.GetCombinedTargets(fCand, rCand, out fTarget, out rTarget) &&
                fSlot == null &&
                rSlot == null &&
                !ShouldCoerce(state, op, types[0], types[1], false) &&
                !ShouldCoerce(state, op, types[1], types[0], false) &&
                bodyBuilder.NoConditions) {
                return MakeRuleForNoMatch(operation, op, errorSuggestion, types);
            }

            if (ShouldCoerce(state, op, types[0], types[1], false) &&
                (op != PythonOperationKind.Mod || !MetaPythonObject.GetPythonType(types[0]).IsSubclassOf(TypeCache.String))) {
                // need to try __coerce__ first.
                DoCoerce(state, bodyBuilder, op, types, false);
            }

            if (MakeOneTarget(PythonContext.GetPythonContext(operation), fTarget, fSlot, bodyBuilder, false, types)) {
                if (ShouldCoerce(state, op, types[1], types[0], false)) {
                    // need to try __coerce__ on the reverse first                    
                    DoCoerce(state, bodyBuilder, op, new DynamicMetaObject[] { types[1], types[0] }, true);
                }

                if (rSlot != null) {
                    MakeSlotCall(PythonContext.GetPythonContext(operation), types, bodyBuilder, rSlot, true);
                    bodyBuilder.FinishCondition(MakeBinaryThrow(operation, op, types).Expression, typeof(object));
                } else if (MakeOneTarget(PythonContext.GetPythonContext(operation), rTarget, rSlot, bodyBuilder, false, types)) {
                    // need to fallback to throwing or coercion
                    bodyBuilder.FinishCondition(MakeBinaryThrow(operation, op, types).Expression, typeof(object));
                }
            }

            return bodyBuilder.GetMetaObject(types);
        }
        /// <summary>
        /// Makes the comparison rule which returns an int (-1, 0, 1).  TODO: Better name?
        /// </summary>
        private static DynamicMetaObject/*!*/ MakeSortComparisonRule(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ operation, PythonOperationKind op) {
            RestrictTypes(types);

            DynamicMetaObject fastPath = FastPathCompare(types);
            if (fastPath != null) {
                return fastPath;
            }

            // Python compare semantics: 
            //      if the types are the same invoke __cmp__ first.
            //      If __cmp__ is not defined or the types are different:
            //          try rich comparisons (eq, lt, gt, etc...) 
            //      If the types are not the same and rich cmp didn't work finally try __cmp__
            //      If __cmp__ isn't defined return a comparison based upon the types.
            //
            // Along the way we try both forward and reverse versions (try types[0] and then
            // try types[1] reverse version).  For these comparisons __cmp__ and __eq__ are their
            // own reversals and __gt__ is the opposite of __lt__.

            // collect all the comparison methods, most likely we won't need them all.
            DynamicMetaObject[] rTypes = new DynamicMetaObject[] { types[1], types[0] };
            SlotOrFunction cfunc, rcfunc, eqfunc, reqfunc, ltfunc, gtfunc, rltfunc, rgtfunc;

            PythonContext state = PythonContext.GetPythonContext(operation);
            cfunc = SlotOrFunction.GetSlotOrFunction(state, "__cmp__", types);
            rcfunc = SlotOrFunction.GetSlotOrFunction(state, "__cmp__", rTypes);
            eqfunc = SlotOrFunction.GetSlotOrFunction(state, "__eq__", types);
            reqfunc = SlotOrFunction.GetSlotOrFunction(state, "__eq__", rTypes);
            ltfunc = SlotOrFunction.GetSlotOrFunction(state, "__lt__", types);
            gtfunc = SlotOrFunction.GetSlotOrFunction(state, "__gt__", types);
            rltfunc = SlotOrFunction.GetSlotOrFunction(state, "__lt__", rTypes);
            rgtfunc = SlotOrFunction.GetSlotOrFunction(state, "__gt__", rTypes);

            // inspect forward and reverse versions so we can pick one or both.
            SlotOrFunction cTarget, rcTarget, eqTarget, reqTarget, ltTarget, rgtTarget, gtTarget, rltTarget;
            SlotOrFunction.GetCombinedTargets(cfunc, rcfunc, out cTarget, out rcTarget);
            SlotOrFunction.GetCombinedTargets(eqfunc, reqfunc, out eqTarget, out reqTarget);
            SlotOrFunction.GetCombinedTargets(ltfunc, rgtfunc, out ltTarget, out rgtTarget);
            SlotOrFunction.GetCombinedTargets(gtfunc, rltfunc, out gtTarget, out rltTarget);

            PythonType xType = MetaPythonObject.GetPythonType(types[0]);
            PythonType yType = MetaPythonObject.GetPythonType(types[1]);

            // now build the rule from the targets.
            // bail if we're comparing to null and the rhs can't do anything special...
            if (xType.IsNull) {
                if (yType.IsNull) {
                    return new DynamicMetaObject(
                        AstUtils.Constant(0),
                        BindingRestrictions.Combine(types)
                    );
                } else if (yType.UnderlyingSystemType.IsPrimitive() || yType.UnderlyingSystemType == typeof(BigInteger)) {
                    return new DynamicMetaObject(
                        AstUtils.Constant(-1),
                        BindingRestrictions.Combine(types)
                    );
                }
            }

            ConditionalBuilder bodyBuilder = new ConditionalBuilder(operation);

            bool tryRich = true, more = true;
            if (xType == yType && cTarget != SlotOrFunction.Empty) {
                // if the types are equal try __cmp__ first
                if (ShouldCoerce(state, op, types[0], types[1], true)) {
                    // need to try __coerce__ first.
                    DoCoerce(state, bodyBuilder, PythonOperationKind.Compare, types, false);
                }

                more = more && MakeOneCompareGeneric(cTarget, false, types, MakeCompareReverse, bodyBuilder, typeof(int));

                if (xType != TypeCache.OldInstance) {
                    // try __cmp__ backwards for new-style classes and don't fallback to
                    // rich comparisons if available
                    more = more && MakeOneCompareGeneric(rcTarget, true, types, MakeCompareReverse, bodyBuilder, typeof(int));
                    tryRich = false;
                }
            }

            if (tryRich && more) {
                // try the >, <, ==, !=, >=, <=.  These don't get short circuited using the more logic
                // because they don't give a definitive answer even if they return bool.  Only if they
                // return true do we know to return 0, -1, or 1.
                // try eq
                MakeOneCompareGeneric(eqTarget, false, types, MakeCompareToZero, bodyBuilder, typeof(int));
                MakeOneCompareGeneric(reqTarget, true, types, MakeCompareToZero, bodyBuilder, typeof(int));

                // try less than & reverse
                MakeOneCompareGeneric(ltTarget, false, types, MakeCompareToNegativeOne, bodyBuilder, typeof(int));
                MakeOneCompareGeneric(rgtTarget, true, types, MakeCompareToNegativeOne, bodyBuilder, typeof(int));

                // try greater than & reverse
                MakeOneCompareGeneric(gtTarget, false, types, MakeCompareToOne, bodyBuilder, typeof(int));
                MakeOneCompareGeneric(rltTarget, true, types, MakeCompareToOne, bodyBuilder, typeof(int));
            }

            if (xType != yType) {
                if (more && ShouldCoerce(state, op, types[0], types[1], true)) {
                    // need to try __coerce__ first.
                    DoCoerce(state, bodyBuilder, PythonOperationKind.Compare, types, false);
                }

                more = more && MakeOneCompareGeneric(cTarget, false, types, MakeCompareReverse, bodyBuilder, typeof(int));

                if (more && ShouldCoerce(state, op, types[1], types[0], true)) {
                    // try __coerce__ first
                    DoCoerce(state, bodyBuilder, PythonOperationKind.Compare, rTypes, true, delegate(Expression e) {
                        return ReverseCompareValue(e);
                    });
                }

                more = more && MakeOneCompareGeneric(rcTarget, true, types, MakeCompareReverse, bodyBuilder, typeof(int));
            }

            if (more) {
                // fall back to compare types
                bodyBuilder.FinishCondition(MakeFallbackCompare(operation, op, types), typeof(int));
            }

            return bodyBuilder.GetMetaObject(types);
        }
        private static void MakeValueCheck(int val, Expression retValue, ConditionalBuilder/*!*/ bodyBuilder, Expression retCondition) {
            if (retValue.Type != typeof(bool)) {
                retValue = DynamicExpression.Dynamic(
                    PythonContext.GetPythonContext(bodyBuilder.Action).Convert(
                        typeof(bool),
                        ConversionResultKind.ExplicitCast
                    ),
                    typeof(bool),
                    retValue
                );
            }
            if (retCondition != null) {
                retValue = Ast.AndAlso(retCondition, retValue);
            }

            bodyBuilder.AddCondition(
                retValue,
                AstUtils.Constant(val)
            );
        }
Пример #8
0
 internal override void MakeGetExpression(PythonBinder /*!*/ binder, Expression /*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject /*!*/ owner, ConditionalBuilder /*!*/ builder)
 {
     if (!_info.IsPublic || _info.DeclaringType.ContainsGenericParameters)
     {
         // fallback to reflection
         base.MakeGetExpression(binder, codeContext, instance, owner, builder);
     }
     else if (instance == null)
     {
         if (_info.IsStatic)
         {
             builder.FinishCondition(AstUtils.Convert(Ast.Field(null, _info), typeof(object)));
         }
         else
         {
             builder.FinishCondition(Ast.Constant(this));
         }
     }
     else
     {
         builder.FinishCondition(
             AstUtils.Convert(
                 Ast.Field(
                     binder.ConvertExpression(
                         instance.Expression,
                         _info.DeclaringType,
                         ConversionResultKind.ExplicitCast,
                         new PythonOverloadResolverFactory(binder, codeContext)
                         ),
                     _info
                     ),
                 typeof(object)
                 )
             );
     }
 }
Пример #9
0
        internal static DynamicMetaObject Call(DynamicMetaObjectBinder/*!*/ call, DynamicMetaObject target, DynamicMetaObject/*!*/[]/*!*/ args) {
            Assert.NotNull(call, args);
            Assert.NotNullItems(args);

            if (target.NeedsDeferral()) {
                return call.Defer(ArrayUtils.Insert(target, args));
            }

            foreach (DynamicMetaObject mo in args) {
                if (mo.NeedsDeferral()) {
                    RestrictTypes(args);

                    return call.Defer(
                        ArrayUtils.Insert(target, args)
                    );
                }
            }

            DynamicMetaObject self = target.Restrict(target.GetLimitType());

            ValidationInfo valInfo = BindingHelpers.GetValidationInfo(target);
            PythonType pt = DynamicHelpers.GetPythonType(target.Value);
            BinderState state = BinderState.GetBinderState(call);

            // look for __call__, if it's present dispatch to it.  Otherwise fall back to the
            // default binder
            PythonTypeSlot callSlot;
            if (!typeof(Delegate).IsAssignableFrom(target.GetLimitType()) &&
                pt.TryResolveSlot(state.Context, Symbols.Call, out callSlot)) {
                ConditionalBuilder cb = new ConditionalBuilder(call);
                Expression body;

                callSlot.MakeGetExpression(
                    state.Binder,
                    BinderState.GetCodeContext(call),
                    self.Expression,
                    GetPythonType(self),
                    cb
                );
                
                if (!cb.IsFinal) {
                    cb.FinishCondition(GetCallError(self));
                }

                Expression[] callArgs = ArrayUtils.Insert(
                    BinderState.GetCodeContext(call),
                    cb.GetMetaObject().Expression, 
                    DynamicUtils.GetExpressions(args)
                );

                body = Ast.Dynamic(
                    BinderState.GetBinderState(call).Invoke(
                        BindingHelpers.GetCallSignature(call)
                    ),
                    typeof(object),
                    callArgs
                );

                return BindingHelpers.AddDynamicTestAndDefer(
                    call,
                    new DynamicMetaObject(body, self.Restrictions.Merge(BindingRestrictions.Combine(args))),
                    args,
                    valInfo
                );
            }

            return null;
        }
Пример #10
0
 internal override void MakeGetExpression(PythonBinder/*!*/ binder, Expression/*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject/*!*/ owner, ConditionalBuilder/*!*/ builder) {
     if (!_info.IsPublic || _info.DeclaringType.ContainsGenericParameters) {
         // fallback to reflection
         base.MakeGetExpression(binder, codeContext, instance, owner, builder);
     } else if (instance == null) {
         if (_info.IsStatic) {
             builder.FinishCondition(AstUtils.Convert(Ast.Field(null, _info), typeof(object)));
         } else {
             builder.FinishCondition(Ast.Constant(this));
         }
     } else {
         builder.FinishCondition(
             AstUtils.Convert(
                 Ast.Field(
                     binder.ConvertExpression(
                         instance.Expression,
                         _info.DeclaringType,
                         ConversionResultKind.ExplicitCast,
                         new PythonOverloadResolverFactory(binder, codeContext)
                     ),
                     _info
                 ),
                 typeof(object)
             )
         );
     }
 }
Пример #11
0
        /// <summary>
        /// calls __coerce__ for old-style classes and performs the operation if the coercion is successful.
        /// </summary>
        private static void DoCoerce(PythonContext/*!*/ state, ConditionalBuilder/*!*/ bodyBuilder, PythonOperationKind op, DynamicMetaObject/*!*/[]/*!*/ types, bool reverse, Func<Expression, Expression> returnTransform) {
            ParameterExpression coerceResult = Ast.Variable(typeof(object), "coerceResult");
            ParameterExpression coerceTuple = Ast.Variable(typeof(PythonTuple), "coerceTuple");

            if (!bodyBuilder.TestCoercionRecursionCheck) {
                // during coercion we need to enforce recursion limits if
                // they're enabled and the rule's test needs to reflect this.                
                bodyBuilder.Restrictions = bodyBuilder.Restrictions.Merge(
                    BindingRestrictions.GetExpressionRestriction(
                        Ast.Equal(
                            Ast.Call(typeof(PythonOps).GetMethod("ShouldEnforceRecursion")),
                            AstUtils.Constant(PythonFunction.EnforceRecursion)
                        )
                    )
                );

                bodyBuilder.TestCoercionRecursionCheck = true;
            }

            // tmp = self.__coerce__(other)
            // if tmp != null && tmp != NotImplemented && (tuple = PythonOps.ValidateCoerceResult(tmp)) != null:
            //      return operation(tuple[0], tuple[1])                        
            SlotOrFunction slot = SlotOrFunction.GetSlotOrFunction(state, Symbols.Coerce, types);

            if (slot.Success) {
                bodyBuilder.AddCondition(
                    Ast.AndAlso(
                        Ast.Not(
                            Ast.TypeIs(
                                Ast.Assign(
                                    coerceResult,
                                    slot.Target.Expression
                                ),
                                typeof(OldInstance)
                            )
                        ),
                        Ast.NotEqual(
                            Ast.Assign(
                                coerceTuple,
                                Ast.Call(
                                    typeof(PythonOps).GetMethod("ValidateCoerceResult"),
                                    coerceResult
                                )
                            ),
                            AstUtils.Constant(null)
                        )
                    ),
                    BindingHelpers.AddRecursionCheck(
                        returnTransform(
                            Ast.Dynamic(
                                state.Operation(op | PythonOperationKind.DisableCoerce),
                                op == PythonOperationKind.Compare ? typeof(int) : typeof(object),
                                reverse ? CoerceTwo(coerceTuple) : CoerceOne(coerceTuple),
                                reverse ? CoerceOne(coerceTuple) : CoerceTwo(coerceTuple)
                            )
                        )
                    )
                );
                bodyBuilder.AddVariable(coerceResult);
                bodyBuilder.AddVariable(coerceTuple);
            }
        }
 private static void MakeCompareToZero(ConditionalBuilder/*!*/ bodyBuilder, Expression retCondition, Expression/*!*/ expr, bool reverse) {
     MakeValueCheck(0, expr, bodyBuilder, retCondition);
 }
        private static DynamicMetaObject/*!*/ MakeComparisonOperation(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ operation, PythonOperationKind opString) {
            RestrictTypes(types);

            PythonOperationKind op = NormalizeOperator(opString);

            BinderState state = BinderState.GetBinderState(operation);
            Debug.Assert(types.Length == 2);
            DynamicMetaObject xType = types[0], yType = types[1];
            SymbolId opSym = Symbols.OperatorToSymbol(op);
            SymbolId ropSym = Symbols.OperatorToReversedSymbol(op);
            // reverse
            DynamicMetaObject[] rTypes = new DynamicMetaObject[] { types[1], types[0] };

            SlotOrFunction fop, rop, cmp, rcmp;
            fop = SlotOrFunction.GetSlotOrFunction(state, opSym, types);
            rop = SlotOrFunction.GetSlotOrFunction(state, ropSym, rTypes);
            cmp = SlotOrFunction.GetSlotOrFunction(state, Symbols.Cmp, types);
            rcmp = SlotOrFunction.GetSlotOrFunction(state, Symbols.Cmp, rTypes);

            ConditionalBuilder bodyBuilder = new ConditionalBuilder(operation);

            SlotOrFunction.GetCombinedTargets(fop, rop, out fop, out rop);
            SlotOrFunction.GetCombinedTargets(cmp, rcmp, out cmp, out rcmp);

            // first try __op__ or __rop__ and return the value
            if (MakeOneCompareGeneric(fop, false, types, MakeCompareReturn, bodyBuilder)) {
                if (MakeOneCompareGeneric(rop, true, types, MakeCompareReturn, bodyBuilder)) {

                    // then try __cmp__ or __rcmp__ and compare the resulting int appropriaetly
                    if (ShouldCoerce(state, opString, xType, yType, true)) {
                        DoCoerce(state, bodyBuilder, PythonOperationKind.Compare, types, false, delegate(Expression e) {
                            return GetCompareTest(op, e, false);
                        });
                    }

                    if (MakeOneCompareGeneric(
                        cmp,
                        false,
                        types,
                        delegate(ConditionalBuilder builder, Expression retCond, Expression expr, bool reverse) {
                            MakeCompareTest(op, builder, retCond, expr, reverse);
                        },
                        bodyBuilder)) {

                        if (ShouldCoerce(state, opString, yType, xType, true)) {
                            DoCoerce(state, bodyBuilder, PythonOperationKind.Compare, rTypes, true, delegate(Expression e) {
                                return GetCompareTest(op, e, true);
                            });
                        }

                        if (MakeOneCompareGeneric(
                            rcmp,
                            true,
                            types,
                            delegate(ConditionalBuilder builder, Expression retCond, Expression expr, bool reverse) {
                                MakeCompareTest(op, builder, retCond, expr, reverse);
                            },
                            bodyBuilder)) {
                            bodyBuilder.FinishCondition(MakeFallbackCompare(op, types));
                        }
                    }
                }
            }

            return bodyBuilder.GetMetaObject(types);
        }
Пример #14
0
 private static void DoCoerce(OperationBinder/*!*/ operation, ConditionalBuilder/*!*/ bodyBuilder, string op, DynamicMetaObject/*!*/[]/*!*/ types, bool reverse) {
     DoCoerce(operation, bodyBuilder, op, types, reverse, delegate(Expression e) {
         return e;
     });
 }
Пример #15
0
 private static void MakeCompareTest(string op, ConditionalBuilder/*!*/ bodyBuilder, Expression retCond, Expression/*!*/ expr, bool reverse) {
     MakeCompareReturn(bodyBuilder, retCond, GetCompareTest(op, expr, reverse), reverse);
 }
Пример #16
0
 public MemberBindingInfo(DynamicMetaObject/*!*/[]/*!*/ args, ConditionalBuilder/*!*/ body, ValidationInfo/*!*/ validation) {
     Body = body;
     Validation = validation;
     Args = args;
 }
        private static DynamicMetaObject/*!*/ MakeComparisonOperation(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ operation, PythonOperationKind opString, DynamicMetaObject errorSuggestion) {
            RestrictTypes(types);

            PythonOperationKind op = NormalizeOperator(opString);

            PythonContext state = PythonContext.GetPythonContext(operation);
            Debug.Assert(types.Length == 2);
            DynamicMetaObject xType = types[0], yType = types[1];
            string opSym = Symbols.OperatorToSymbol(op);
            string ropSym = Symbols.OperatorToReversedSymbol(op);
            // reverse
            DynamicMetaObject[] rTypes = new DynamicMetaObject[] { types[1], types[0] };

            SlotOrFunction fop, rop, cmp, rcmp;
            fop = SlotOrFunction.GetSlotOrFunction(state, opSym, types);
            rop = SlotOrFunction.GetSlotOrFunction(state, ropSym, rTypes);
            cmp = SlotOrFunction.GetSlotOrFunction(state, "__cmp__", types);
            rcmp = SlotOrFunction.GetSlotOrFunction(state, "__cmp__", rTypes);

            ConditionalBuilder bodyBuilder = new ConditionalBuilder(operation);

            SlotOrFunction.GetCombinedTargets(fop, rop, out fop, out rop);
            SlotOrFunction.GetCombinedTargets(cmp, rcmp, out cmp, out rcmp);

            bool shouldWarn = false;
            WarningInfo info = null;

            // first try __op__ or __rop__ and return the value
            shouldWarn = fop.ShouldWarn(state, out info);
            if (MakeOneCompareGeneric(fop, false, types, MakeCompareReturn, bodyBuilder, typeof(object))) {
                shouldWarn = shouldWarn || rop.ShouldWarn(state, out info);
                if (MakeOneCompareGeneric(rop, true, types, MakeCompareReturn, bodyBuilder, typeof(object))) {

                    // then try __cmp__ or __rcmp__ and compare the resulting int appropriaetly
                    shouldWarn = shouldWarn || cmp.ShouldWarn(state, out info);

                    if (ShouldCoerce(state, opString, xType, yType, true)) {
                        DoCoerce(state, bodyBuilder, PythonOperationKind.Compare, types, false, delegate(Expression e) {
                            return GetCompareTest(op, e, false);
                        });
                    }

                    if (MakeOneCompareGeneric(
                        cmp,
                        false,
                        types,
                        delegate(ConditionalBuilder builder, Expression retCond, Expression expr, bool reverse, Type retType) {
                            MakeCompareTest(op, builder, retCond, expr, reverse, retType);
                        },
                        bodyBuilder,
                        typeof(object))) {

                        shouldWarn = shouldWarn || rcmp.ShouldWarn(state, out info);

                        if (ShouldCoerce(state, opString, yType, xType, true)) {
                            DoCoerce(state, bodyBuilder, PythonOperationKind.Compare, rTypes, true, delegate(Expression e) {
                                return GetCompareTest(op, e, true);
                            });
                        }

                        if (MakeOneCompareGeneric(
                            rcmp,
                            true,
                            types,
                            delegate(ConditionalBuilder builder, Expression retCond, Expression expr, bool reverse, Type retType) {
                                MakeCompareTest(op, builder, retCond, expr, reverse, retType);
                            },
                            bodyBuilder,
                            typeof(object))) {
                            if (errorSuggestion != null) {
                                bodyBuilder.FinishCondition(errorSuggestion.Expression, typeof(object));
                            } else {
                                bodyBuilder.FinishCondition(BindingHelpers.AddPythonBoxing(MakeFallbackCompare(operation, op, types)), typeof(object));
                            }
                        }
                    }
                }
            }

            DynamicMetaObject res = bodyBuilder.GetMetaObject(types);
            if (!shouldWarn || res == null) {
                return res;
            } else {
                return info.AddWarning(Ast.Constant(state.SharedContext), res);
            }
        }
Пример #18
0
 public SetBindingInfo(SetMemberBinder/*!*/ action, DynamicMetaObject/*!*/[]/*!*/ args, ConditionalBuilder/*!*/ body, ValidationInfo/*!*/ validation)
     : base(args, body, validation) {
     Action = action;
 }
 private static void MakeCompareToNegativeOne(ConditionalBuilder/*!*/ bodyBuilder, Expression retCondition, Expression/*!*/ expr, bool reverse, Type retType) {
     MakeValueCheck(-1, expr, bodyBuilder, retCondition);
 }
Пример #20
0
 public GetBindingInfo(DynamicMetaObjectBinder/*!*/ action, DynamicMetaObject/*!*/[]/*!*/ args, ParameterExpression/*!*/ self, ParameterExpression/*!*/ result, ConditionalBuilder/*!*/ body, ValidationInfo/*!*/ validationInfo)
     : base(args, body, validationInfo) {
     Action = action;
     Self = self;
     Result = result;
 }
        private static void MakeCompareReverse(ConditionalBuilder/*!*/ bodyBuilder, Expression retCondition, Expression/*!*/ expr, bool reverse, Type retType) {
            Expression res = expr;
            if (reverse) {
                res = ReverseCompareValue(expr);
            }

            MakeCompareReturn(bodyBuilder, retCondition, res, reverse, retType);
        }
Пример #22
0
 internal override void MakeGetExpression(PythonBinder/*!*/ binder, Expression/*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject/*!*/ owner, ConditionalBuilder/*!*/ builder) {
     if (Getter.Length != 0 && !Getter[0].IsPublic) {
         // fallback to runtime call
         base.MakeGetExpression(binder, codeContext, instance, owner, builder);
     } else if (NeedToReturnProperty(instance, Getter)) {
         builder.FinishCondition(AstUtils.Constant(this));
     } else if (Getter[0].ContainsGenericParameters) {
         builder.FinishCondition(
             DefaultBinder.MakeError(
                 binder.MakeContainsGenericParametersError(
                     MemberTracker.FromMemberInfo(_info)
                 ),
                 typeof(object)
             ).Expression
         );
     } else if (instance != null) {
         builder.FinishCondition(
             AstUtils.Convert(
                 binder.MakeCallExpression(
                     new PythonOverloadResolverFactory(binder, codeContext),
                     Getter[0],
                     instance
                 ).Expression,
                 typeof(object)
             )
         );
     } else {
         builder.FinishCondition(
             AstUtils.Convert(
                 binder.MakeCallExpression(
                     new PythonOverloadResolverFactory(binder, codeContext),
                     Getter[0]
                 ).Expression,
                 typeof(object)
             )
         );                
     }
 }
            public override DynamicMetaObject/*!*/ CompleteRuleTarget(DynamicMetaObjectBinder/*!*/ metaBinder, DynamicMetaObject/*!*/[]/*!*/ args, Func<DynamicMetaObject> customFailure) {
                ConditionalBuilder cb = new ConditionalBuilder();
                _slot.MakeGetExpression(
                    Binder,
                    AstUtils.Constant(PythonContext.SharedContext),
                    args[0],
                    new DynamicMetaObject(
                        Ast.Call(
                            typeof(DynamicHelpers).GetMethod("GetPythonType"),
                            AstUtils.Convert(args[0].Expression, typeof(object))
                        ),
                        BindingRestrictions.Empty,
                        DynamicHelpers.GetPythonType(args[0].Value)
                    ),
                    cb
                );
                if (!cb.IsFinal) {
                    cb.FinishCondition(metaBinder.Throw(Ast.New(typeof(InvalidOperationException))));
                }

                Expression callable = cb.GetMetaObject().Expression;
                Expression[] exprArgs = new Expression[args.Length - 1];
                for (int i = 1; i < args.Length; i++) {
                    exprArgs[i - 1] = args[i].Expression;
                }

                Expression retVal = DynamicExpression.Dynamic(
                    PythonContext.Invoke(
                        new CallSignature(exprArgs.Length)
                    ),
                    typeof(object),
                    ArrayUtils.Insert(AstUtils.Constant(PythonContext.SharedContext), (Expression)callable, exprArgs)
                );

                if (IsSetter) {
                    retVal = Ast.Block(retVal, args[args.Length - 1].Expression);
                }

                return new DynamicMetaObject(
                    retVal,
                    BindingRestrictions.Combine(args)
                );
            }
Пример #24
0
 internal override void MakeGetExpression(PythonBinder /*!*/ binder, Expression /*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject /*!*/ owner, ConditionalBuilder /*!*/ builder)
 {
     if (Getter.Length != 0 && !Getter[0].IsPublic)
     {
         // fallback to runtime call
         base.MakeGetExpression(binder, codeContext, instance, owner, builder);
     }
     else if (NeedToReturnProperty(instance, Getter))
     {
         builder.FinishCondition(AstUtils.Constant(this));
     }
     else if (Getter[0].ContainsGenericParameters)
     {
         builder.FinishCondition(
             DefaultBinder.MakeError(
                 binder.MakeContainsGenericParametersError(
                     MemberTracker.FromMemberInfo(_info)
                     ),
                 typeof(object)
                 ).Expression
             );
     }
     else if (instance != null)
     {
         builder.FinishCondition(
             AstUtils.Convert(
                 binder.MakeCallExpression(
                     new PythonOverloadResolverFactory(binder, codeContext),
                     Getter[0],
                     instance
                     ).Expression,
                 typeof(object)
                 )
             );
     }
     else
     {
         builder.FinishCondition(
             AstUtils.Convert(
                 binder.MakeCallExpression(
                     new PythonOverloadResolverFactory(binder, codeContext),
                     Getter[0]
                     ).Expression,
                 typeof(object)
                 )
             );
     }
 }
 private static void MakeCompareReturn(ConditionalBuilder/*!*/ bodyBuilder, Expression retCondition, Expression/*!*/ retValue, bool isReverse, Type retType) {
     if (retCondition != null) {
         bodyBuilder.AddCondition(retCondition, retValue);
     } else {
         bodyBuilder.FinishCondition(retValue, retType);
     }
 }
        private static void MakeSlotCallWorker(PythonContext/*!*/ state, PythonTypeSlot/*!*/ slotTarget, Expression/*!*/ self, ConditionalBuilder/*!*/ bodyBuilder, params Expression/*!*/[]/*!*/ args) {
            // Generate:
            // 
            // SlotTryGetValue(context, slot, selfType, out callable) && (tmp=callable(args)) != NotImplemented) ?
            //      tmp :
            //      RestOfOperation
            //
            ParameterExpression callable = Ast.Variable(typeof(object), "slot");
            ParameterExpression tmp = Ast.Variable(typeof(object), "slot");

            bodyBuilder.AddCondition(
                Ast.AndAlso(
                    Ast.Call(
                        typeof(PythonOps).GetMethod("SlotTryGetValue"),
                        AstUtils.Constant(state.SharedContext),
                        AstUtils.Convert(Utils.WeakConstant(slotTarget), typeof(PythonTypeSlot)),
                        AstUtils.Convert(self, typeof(object)),
                        Ast.Call(
                            typeof(DynamicHelpers).GetMethod("GetPythonType"),
                            AstUtils.Convert(self, typeof(object))
                        ),
                        callable
                    ),
                    Ast.NotEqual(
                        Ast.Assign(
                            tmp,
                            DynamicExpression.Dynamic(
                                state.Invoke(
                                    new CallSignature(args.Length)
                                ),
                                typeof(object),
                                ArrayUtils.Insert(AstUtils.Constant(state.SharedContext), (Expression)callable, args)
                            )
                        ),
                        Ast.Property(null, typeof(PythonOps).GetProperty("NotImplemented"))
                    )
                ),
                tmp
            );
            bodyBuilder.AddVariable(callable);
            bodyBuilder.AddVariable(tmp);
        }
        private static bool MakeOneTarget(PythonContext/*!*/ state, SlotOrFunction/*!*/ target, PythonTypeSlot slotTarget, ConditionalBuilder/*!*/ bodyBuilder, bool reverse, DynamicMetaObject/*!*/[]/*!*/ types) {
            if (target == SlotOrFunction.Empty && slotTarget == null) return true;

            if (slotTarget != null) {
                MakeSlotCall(state, types, bodyBuilder, slotTarget, reverse);
                return true;
            } else if (target.MaybeNotImplemented) {
                Debug.Assert(target.ReturnType == typeof(object));

                ParameterExpression tmp = Ast.Variable(typeof(object), "slot");
                bodyBuilder.AddVariable(tmp);

                bodyBuilder.AddCondition(
                    Ast.NotEqual(
                        Ast.Assign(
                            tmp,
                            target.Target.Expression
                        ),
                        Ast.Property(null, typeof(PythonOps).GetProperty("NotImplemented"))
                    ),
                    tmp
                );

                return true;
            } else {
                bodyBuilder.FinishCondition(target.Target.Expression, typeof(object));
                return false;
            }
        }
 private static void DoCoerce(PythonContext/*!*/ state, ConditionalBuilder/*!*/ bodyBuilder, PythonOperationKind op, DynamicMetaObject/*!*/[]/*!*/ types, bool reverse) {
     DoCoerce(state, bodyBuilder, op, types, reverse, delegate(Expression e) {
         return e;
     });
 }
Пример #29
0
 internal override void MakeGetExpression(PythonBinder /*!*/ binder, Expression /*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject /*!*/ owner, ConditionalBuilder /*!*/ builder)
 {
     builder.FinishCondition(Ast.Constant(this));
 }
        /// <summary>
        /// calls __coerce__ for old-style classes and performs the operation if the coercion is successful.
        /// </summary>
        private static void DoCoerce(PythonContext/*!*/ pyContext, ConditionalBuilder/*!*/ bodyBuilder, PythonOperationKind op, DynamicMetaObject/*!*/[]/*!*/ types, bool reverse, Func<Expression, Expression> returnTransform) {
            ParameterExpression coerceResult = Ast.Variable(typeof(object), "coerceResult");
            ParameterExpression coerceTuple = Ast.Variable(typeof(PythonTuple), "coerceTuple");

            // tmp = self.__coerce__(other)
            // if tmp != null && tmp != NotImplemented && (tuple = PythonOps.ValidateCoerceResult(tmp)) != null:
            //      return operation(tuple[0], tuple[1])                        
            SlotOrFunction slot = SlotOrFunction.GetSlotOrFunction(pyContext, "__coerce__", types);

            if (slot.Success) {
                bodyBuilder.AddCondition(
                    Ast.AndAlso(
                        Ast.Not(
                            Ast.TypeIs(
                                Ast.Assign(
                                    coerceResult,
                                    slot.Target.Expression
                                ),
                                typeof(OldInstance)
                            )
                        ),
                        Ast.NotEqual(
                            Ast.Assign(
                                coerceTuple,
                                Ast.Call(
                                    typeof(PythonOps).GetMethod("ValidateCoerceResult"),
                                    coerceResult
                                )
                            ),
                            AstUtils.Constant(null)
                        )
                    ),
                    BindingHelpers.AddRecursionCheck(
                        pyContext,
                        returnTransform(
                            DynamicExpression.Dynamic(
                                pyContext.Operation(op | PythonOperationKind.DisableCoerce),
                                op == PythonOperationKind.Compare ? typeof(int) : typeof(object),
                                reverse ? CoerceTwo(coerceTuple) : CoerceOne(coerceTuple),
                                reverse ? CoerceOne(coerceTuple) : CoerceTwo(coerceTuple)
                            )
                        )
                    )
                );
                bodyBuilder.AddVariable(coerceResult);
                bodyBuilder.AddVariable(coerceTuple);
            }
        }
Пример #31
0
 internal override void MakeGetExpression(PythonBinder /*!*/ binder, Expression /*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject /*!*/ owner, ConditionalBuilder /*!*/ builder)
 {
     if (instance != null)
     {
         builder.FinishCondition(
             Ast.Call(
                 typeof(PythonOps).GetMethod(nameof(PythonOps.MakeBoundBuiltinFunction)),
                 AstUtils.Constant(_template),
                 instance.Expression
                 )
             );
     }
     else
     {
         builder.FinishCondition(AstUtils.Constant(this));
     }
 }
Пример #32
0
        private static void MakeValueCheck(int val, Expression retValue, ConditionalBuilder/*!*/ bodyBuilder, Expression retCondition) {
            if (retValue.Type != typeof(bool)) {
                retValue = Ast.Dynamic(
                    new ConversionBinder(
                        BinderState.GetBinderState(bodyBuilder.Action),
                        typeof(bool),
                        ConversionResultKind.ExplicitCast
                    ),
                    typeof(bool),
                    retValue
                );
            }
            if (retCondition != null) {
                retValue = Ast.AndAlso(retCondition, retValue);
            }

            bodyBuilder.AddCondition(
                retValue,
                Ast.Constant(val)
            );
        }