示例#1
0
 internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op) {
     if (op == PythonOperationKind.None) {
         return GlobalParent.AddDebugInfoAndVoid(
             GlobalParent.Set(
                 typeof(object),
                 _name,
                 _target,
                 right
             ),
             span
         );
     } else {
         MSAst.ParameterExpression temp = Ast.Variable(typeof(object), "inplace");
         return GlobalParent.AddDebugInfo(
             Ast.Block(
                 new[] { temp },
                 Ast.Assign(temp, _target),
                 SetMemberOperator(right, op, temp),
                 AstUtils.Empty()
             ),
             Span.Start,
             span.End
         );
     }
 }
示例#2
0
        internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, PythonOperationKind op) {
            MSAst.Expression assignment;

            if (op != PythonOperationKind.None) {
                right = ag.Operation(
                    typeof(object),
                    op,
                    Transform(ag, typeof(object)),
                    right
                );
            }

            if (_reference.PythonVariable != null) {
                assignment = ag.Globals.Assign(
                    ag.Globals.GetVariable(_reference.PythonVariable), 
                    AstGenerator.ConvertIfNeeded(right, typeof(object))
                );
            } else {
                assignment = Ast.Call(
                    null,
                    typeof(ScriptingRuntimeHelpers).GetMethod("SetName"),
                    new [] {
                        ag.LocalContext, 
                        ag.Globals.GetSymbol(_name),
                        AstUtils.Convert(right, typeof(object))
                        }
                );
            }

            SourceSpan aspan = span.IsValid ? new SourceSpan(Span.Start, span.End) : SourceSpan.None;
            return ag.AddDebugInfoAndVoid(assignment, aspan);
        }
示例#3
0
        internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, PythonOperationKind op) {
            if (Items.Length == 0) {
                ag.AddError("can't assign to ()", Span);
                return null;
            }

            return base.TransformSet(ag, span, right, op);
        }
        public static PythonOperationKind DirectOperation(PythonOperationKind op)
        {
            if ((op & PythonOperationKind.InPlace) == 0) {
                throw new InvalidOperationException();
            }

            return op & ~PythonOperationKind.InPlace;
        }
示例#5
0
 private static ExpressionType? GetExpressionTypeFromUnaryOperator(PythonOperationKind operatorName) {
     switch (operatorName) {
         case PythonOperationKind.Positive: return ExpressionType.UnaryPlus;
         case PythonOperationKind.Negate: return ExpressionType.Negate;
         case PythonOperationKind.OnesComplement: return ExpressionType.OnesComplement;
         case PythonOperationKind.Not: return ExpressionType.IsFalse;
     }
     return null;
 }
示例#6
0
        public static DynamicMetaObjectBinder BinaryOperationBinder(PythonContext state, PythonOperationKind operatorName) {
            ExpressionType? et = GetExpressionTypeFromBinaryOperator(operatorName);

            if (et == null) {
                return state.Operation(
                    operatorName
                );
            }

            return state.BinaryOperation(et.Value);
        }
示例#7
0
 public static DynamicMetaObjectBinder/*!*/ BinaryOperationRetType(BinderState/*!*/ state, PythonOperationKind operatorName, Type retType) {
     return new ComboBinder(
         new BinderMappingInfo(
             BinaryOperationBinder(state, operatorName),
             ParameterMappingInfo.Parameter(0),
             ParameterMappingInfo.Parameter(1)
         ),
         new BinderMappingInfo(
             state.Convert(retType, ConversionResultKind.ExplicitCast),
             ParameterMappingInfo.Action(0)
         )
     );
 }
示例#8
0
 private MSAst.Expression SetMemberOperator(AstGenerator ag, MSAst.Expression right, PythonOperationKind op, MSAst.ParameterExpression temp) {
     return ag.Set(
         typeof(object),
         SymbolTable.IdToString(_name),
         temp,
         ag.Operation(
             typeof(object),
             op,
             ag.Get(
                 typeof(object),
                 SymbolTable.IdToString(_name),
                 temp
             ),
             right
         )
     );
 }
示例#9
0
 internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, PythonOperationKind op) {
     if (op == PythonOperationKind.None) {
         return ag.AddDebugInfoAndVoid(
             ag.Set(
                 typeof(object),
                 _name,
                 ag.Transform(_target),
                 right
             ),
             span
         );
     } else {
         MSAst.ParameterExpression temp = ag.GetTemporary("inplace");
         return ag.AddDebugInfo(
             Ast.Block(
                 Ast.Assign(temp, ag.Transform(_target)),
                 SetMemberOperator(ag, right, op, temp),
                 AstUtils.Empty()
             ),
             Span.Start,
             span.End
         );
     }
 }
        private static Expression/*!*/ GetCompareNode(PythonOperationKind op, bool reverse, Expression expr) {
            op = NormalizeOperator(op);

            switch (reverse ? OperatorToReverseOperator(op) : op) {
                case PythonOperationKind.Equal: return Ast.Equal(expr, AstUtils.Constant(0));
                case PythonOperationKind.NotEqual: return Ast.NotEqual(expr, AstUtils.Constant(0));
                case PythonOperationKind.GreaterThan: return Ast.GreaterThan(expr, AstUtils.Constant(0));
                case PythonOperationKind.GreaterThanOrEqual: return Ast.GreaterThanOrEqual(expr, AstUtils.Constant(0));
                case PythonOperationKind.LessThan: return Ast.LessThan(expr, AstUtils.Constant(0));
                case PythonOperationKind.LessThanOrEqual: return Ast.LessThanOrEqual(expr, AstUtils.Constant(0));
                default: throw new InvalidOperationException();
            }
        }
示例#11
0
        public static DynamicMetaObjectBinder BinaryOperationBinder(PythonContext state, PythonOperationKind operatorName)
        {
            ExpressionType?et = GetExpressionTypeFromBinaryOperator(operatorName);

            if (et == null)
            {
                return(state.Operation(
                           operatorName
                           ));
            }

            return(state.BinaryOperation(et.Value));
        }
        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);
        }
        private static void GetOperatorMethods(DynamicMetaObject/*!*/[]/*!*/ types, PythonOperationKind oper, PythonContext state, out SlotOrFunction fbinder, out SlotOrFunction rbinder, out PythonTypeSlot fSlot, out PythonTypeSlot rSlot) {
            oper = NormalizeOperator(oper);
            oper &= ~PythonOperationKind.InPlace;

            string op, rop;
            if (!IsReverseOperator(oper)) {
                op = Symbols.OperatorToSymbol(oper);
                rop = Symbols.OperatorToReversedSymbol(oper);
            } else {
                // coming back after coercion, just try reverse operator.
                rop = Symbols.OperatorToSymbol(oper);
                op = Symbols.OperatorToReversedSymbol(oper);
            }

            fSlot = null;
            rSlot = null;
            PythonType fParent, rParent;

            if (oper == PythonOperationKind.Multiply &&
                IsSequence(types[0]) &&
                !PythonOps.IsNonExtensibleNumericType(types[1].GetLimitType())) {
                // class M:
                //      def __rmul__(self, other):
                //          print "CALLED"
                //          return 1
                //
                // print [1,2] * M()
                //
                // in CPython this results in a successful call to __rmul__ on the type ignoring the forward
                // multiplication.  But calling the __mul__ method directly does NOT return NotImplemented like
                // one might expect.  Therefore we explicitly convert the MetaObject argument into an Index
                // for binding purposes.  That allows this to work at multiplication time but not with
                // a direct call to __mul__.

                DynamicMetaObject[] newTypes = new DynamicMetaObject[2];
                newTypes[0] = types[0];
                newTypes[1] = new DynamicMetaObject(
                    Ast.New(
                        typeof(Index).GetConstructor(new Type[] { typeof(object) }),
                        AstUtils.Convert(types[1].Expression, typeof(object))
                    ),
                    BindingRestrictions.Empty
                );
                types = newTypes;
            }

            if (!SlotOrFunction.TryGetBinder(state, types, op, null, out fbinder, out fParent)) {
                foreach (PythonType pt in MetaPythonObject.GetPythonType(types[0]).ResolutionOrder) {
                    if (pt.TryLookupSlot(state.SharedContext, op, out fSlot)) {
                        fParent = pt;
                        break;
                    }
                }
            }

            if (!SlotOrFunction.TryGetBinder(state, types, null, rop, out rbinder, out rParent)) {
                foreach (PythonType pt in MetaPythonObject.GetPythonType(types[1]).ResolutionOrder) {
                    if (pt.TryLookupSlot(state.SharedContext, rop, out rSlot)) {
                        rParent = pt;
                        break;
                    }
                }
            }

            if (fParent != null && (rbinder.Success || rSlot != null) && rParent != fParent && rParent.IsSubclassOf(fParent)) {
                // Python says if x + subx and subx defines __r*__ we should call r*.
                fbinder = SlotOrFunction.Empty;
                fSlot = null;
            }

            if (!fbinder.Success && !rbinder.Success && fSlot == null && rSlot == null) {
                if (op == "__truediv__" || op == "__rtruediv__") {
                    // true div on a type which doesn't support it, go ahead and try normal divide
                    PythonOperationKind newOp = op == "__truediv__" ? PythonOperationKind.Divide : PythonOperationKind.ReverseDivide;

                    GetOperatorMethods(types, newOp, state, out fbinder, out rbinder, out fSlot, out rSlot);
                }
            }
        }
        private static DynamicMetaObject/*!*/ MakeBinaryThrow(DynamicMetaObjectBinder/*!*/ action, PythonOperationKind op, DynamicMetaObject/*!*/[]/*!*/ args) {
            if (action is IPythonSite) {
                // produce the custom Python error message
                return new DynamicMetaObject(
                    action.Throw(
                        Ast.Call(
                            typeof(PythonOps).GetMethod("TypeErrorForBinaryOp"),
                            AstUtils.Constant(Symbols.OperatorToSymbol(NormalizeOperator(op))),
                            AstUtils.Convert(args[0].Expression, typeof(object)),
                            AstUtils.Convert(args[1].Expression, typeof(object))
                        ),
                        typeof(object)
                    ),
                    BindingRestrictions.Combine(args)
                );
            }

            // let the site produce its own error
            return GenericFallback(action, args);
        }
 internal static string/*!*/ MakeBinaryOpErrorMessage(PythonOperationKind op, string/*!*/ xType, string/*!*/ yType) {
     return string.Format("unsupported operand type(s) for {2}: '{0}' and '{1}'",
                         xType, yType, GetOperatorDisplay(op));
 }
        private static MethodInfo/*!*/ GetComparisonFallbackMethod(PythonOperationKind op) {
            op = NormalizeOperator(op);

            string name;
            switch (op) {
                case PythonOperationKind.Equal: name = "CompareTypesEqual"; break;
                case PythonOperationKind.NotEqual: name = "CompareTypesNotEqual"; break;
                case PythonOperationKind.GreaterThan: name = "CompareTypesGreaterThan"; break;
                case PythonOperationKind.LessThan: name = "CompareTypesLessThan"; break;
                case PythonOperationKind.GreaterThanOrEqual: name = "CompareTypesGreaterThanOrEqual"; break;
                case PythonOperationKind.LessThanOrEqual: name = "CompareTypesLessThanOrEqual"; break;
                case PythonOperationKind.Compare: name = "CompareTypes"; break;
                default: throw new InvalidOperationException();
            }
            return typeof(PythonOps).GetMethod(name);
        }
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
        {
            // if we just have a simple named multi-assignment  (e.g. a, b = 1,2)
            // then go ahead and step over the entire statement at once.  If we have a
            // more complex statement (e.g. a.b, c.d = 1, 2) then we'll step over the
            // sets individually as they could be property sets the user wants to step
            // into.  TODO: Enable stepping of the right hand side?
            bool emitIndividualSets = false;

            foreach (Expression e in _items)
            {
                if (IsComplexAssignment(e))
                {
                    emitIndividualSets = true;
                    break;
                }
            }

            SourceSpan rightSpan = SourceSpan.None;
            SourceSpan leftSpan  =
                (Span.Start.IsValid && span.IsValid) ?
                new SourceSpan(Span.Start, span.End) :
                SourceSpan.None;

            SourceSpan totalSpan = SourceSpan.None;

            if (emitIndividualSets)
            {
                rightSpan = span;
                leftSpan  = SourceSpan.None;
                totalSpan = (Span.Start.IsValid && span.IsValid) ?
                            new SourceSpan(Span.Start, span.End) :
                            SourceSpan.None;
            }

            // 1. Evaluate the expression and assign the value to the temp.
            MSAst.ParameterExpression right_temp = Ast.Variable(typeof(object), "unpacking");

            // 2. Add the assignment "right_temp = right" into the suite/block
            MSAst.Expression assignStmt1 = MakeAssignment(right_temp, right);

            // 3. Call GetEnumeratorValues on the right side (stored in temp)
            MSAst.Expression enumeratorValues = Expression.Convert(LightExceptions.CheckAndThrow(
                                                                       Expression.Call(
                                                                           emitIndividualSets ?
                                                                           AstMethods.GetEnumeratorValues :
                                                                           AstMethods.GetEnumeratorValuesNoComplexSets, // method
                                                                           // arguments
                                                                           Parent.LocalContext,
                                                                           right_temp,
                                                                           AstUtils.Constant(_items.Length)
                                                                           )
                                                                       ), typeof(object[]));

            // 4. Create temporary variable for the array
            MSAst.ParameterExpression array_temp = Ast.Variable(typeof(object[]), "array");

            // 5. Assign the value of the method call (mce) into the array temp
            // And add the assignment "array_temp = Ops.GetEnumeratorValues(...)" into the block
            MSAst.Expression assignStmt2 = MakeAssignment(
                array_temp,
                enumeratorValues,
                rightSpan
                );

            ReadOnlyCollectionBuilder <MSAst.Expression> sets = new ReadOnlyCollectionBuilder <MSAst.Expression>(_items.Length + 1);

            for (int i = 0; i < _items.Length; i++)
            {
                // target = array_temp[i]

                Expression target = _items[i];
                if (target == null)
                {
                    continue;
                }

                // 6. array_temp[i]
                MSAst.Expression element = Ast.ArrayAccess(
                    array_temp,                             // array expression
                    AstUtils.Constant(i)                    // index
                    );

                // 7. target = array_temp[i], and add the transformed assignment into the list of sets
                MSAst.Expression set = target.TransformSet(
                    emitIndividualSets ?                    // span
                    target.Span :
                    SourceSpan.None,
                    element,
                    PythonOperationKind.None
                    );
                sets.Add(set);
            }
            // 9. add the sets as their own block so they can be marked as a single span, if necessary.
            sets.Add(AstUtils.Empty());
            MSAst.Expression itemSet = GlobalParent.AddDebugInfo(Ast.Block(sets.ToReadOnlyCollection()), leftSpan);

            // 10. Return the suite statement (block)
            return(GlobalParent.AddDebugInfo(Ast.Block(new[] { array_temp, right_temp }, assignStmt1, assignStmt2, itemSet, AstUtils.Empty()), totalSpan));
        }
示例#18
0
 internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
 {
     if (op == PythonOperationKind.None)
     {
         return(GlobalParent.AddDebugInfoAndVoid(
                    GlobalParent.Set(
                        _name,
                        _target,
                        right
                        ),
                    span
                    ));
     }
     else
     {
         MSAst.ParameterExpression temp = Ast.Variable(typeof(object), "inplace");
         return(GlobalParent.AddDebugInfo(
                    Ast.Block(
                        new[] { temp },
                        Ast.Assign(temp, _target),
                        SetMemberOperator(right, op, temp),
                        AstUtils.Empty()
                        ),
                    Span.Start,
                    span.End
                    ));
     }
 }
示例#19
0
 internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
 {
     return(_expression.TransformSet(span, right, op));
 }
 public PythonOperationBinder(PythonContext /*!*/ context, PythonOperationKind /*!*/ operation)
 {
     _context   = context;
     _operation = operation;
 }
示例#21
0
        private MSAst.Expression MakeBinaryOperation(PythonOperator op, MSAst.Expression left, MSAst.Expression right, SourceSpan span)
        {
            if (op == PythonOperator.NotIn)
            {
                return(AstUtils.Convert(
                           Ast.Not(
                               GlobalParent.Operation(
                                   typeof(bool),
                                   PythonOperationKind.Contains,
                                   left,
                                   right
                                   )
                               ),
                           typeof(object)
                           ));
            }
            else if (op == PythonOperator.In)
            {
                return(AstUtils.Convert(
                           GlobalParent.Operation(
                               typeof(bool),
                               PythonOperationKind.Contains,
                               left,
                               right
                               ),
                           typeof(object)
                           ));
            }

            PythonOperationKind action = PythonOperatorToAction(op);

            if (action != PythonOperationKind.None)
            {
                // Create action expression
                if (CanEmitWarning(op))
                {
                    MSAst.ParameterExpression tempLeft  = Ast.Parameter(left.Type, "left");
                    MSAst.ParameterExpression tempRight = Ast.Parameter(right.Type, "right");
                    return(Ast.Block(
                               new[] { tempLeft, tempRight },
                               Ast.Call(
                                   AstMethods.WarnDivision,
                                   Parent.LocalContext,
                                   AstUtils.Constant(GlobalParent.DivisionOptions),
                                   AstUtils.Convert(
                                       Ast.Assign(tempLeft, left),
                                       typeof(object)
                                       ),
                                   AstUtils.Convert(
                                       Ast.Assign(tempRight, right),
                                       typeof(object)
                                       )
                                   ),
                               GlobalParent.Operation(
                                   typeof(object),
                                   action,
                                   tempLeft,
                                   tempRight
                                   )
                               ));
                }

                return(GlobalParent.Operation(
                           typeof(object),
                           action,
                           left,
                           right
                           ));
            }
            else
            {
                // Call helper method
                return(Ast.Call(
                           GetHelperMethod(op),
                           ConvertIfNeeded(left, typeof(object)),
                           ConvertIfNeeded(right, typeof(object))
                           ));
            }
        }
 public static PythonOperationKind OperatorToReverseOperator(PythonOperationKind op) {
     switch (op) {
         case PythonOperationKind.LessThan: return PythonOperationKind.GreaterThan;
         case PythonOperationKind.LessThanOrEqual: return PythonOperationKind.GreaterThanOrEqual;
         case PythonOperationKind.GreaterThan: return PythonOperationKind.LessThan;
         case PythonOperationKind.GreaterThanOrEqual: return PythonOperationKind.LessThanOrEqual;
         case PythonOperationKind.Equal: return PythonOperationKind.Equal;
         case PythonOperationKind.NotEqual: return PythonOperationKind.NotEqual;
         case PythonOperationKind.DivMod: return PythonOperationKind.ReverseDivMod;
         case PythonOperationKind.ReverseDivMod: return PythonOperationKind.DivMod;
         default:
             return op & ~PythonOperationKind.Reversed;
     }
 }
        private static Expression/*!*/ GetCompareExpression(PythonOperationKind op, bool reverse, Expression/*!*/ value) {
            op = NormalizeOperator(op);

            Debug.Assert(value.Type == typeof(int));

            Expression zero = AstUtils.Constant(0);
            Expression res;
            switch (reverse ? OperatorToReverseOperator(op) : op) {
                case PythonOperationKind.Equal: res = Ast.Equal(value, zero); break;
                case PythonOperationKind.NotEqual: res = Ast.NotEqual(value, zero); break;
                case PythonOperationKind.GreaterThan: res = Ast.GreaterThan(value, zero); break;
                case PythonOperationKind.GreaterThanOrEqual: res = Ast.GreaterThanOrEqual(value, zero); break;
                case PythonOperationKind.LessThan: res = Ast.LessThan(value, zero); break;
                case PythonOperationKind.LessThanOrEqual: res = Ast.LessThanOrEqual(value, zero); break;
                default: throw new InvalidOperationException();
            }

            return BindingHelpers.AddPythonBoxing(res);
        }
示例#24
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
        {
            if (op != PythonOperationKind.None)
            {
                right = GlobalParent.Operation(
                    typeof(object),
                    op,
                    this,
                    right
                    );
            }

            MSAst.Expression index = IsSlice
                ? GlobalParent.SetSlice(GetActionArgumentsForSet(right))
                : GlobalParent.SetIndex(GetActionArgumentsForSet(right));

            return(GlobalParent.AddDebugInfoAndVoid(index, Span));
        }
 private static DynamicMetaObject/*!*/ MakeRuleForNoMatch(DynamicMetaObjectBinder/*!*/ operation, PythonOperationKind op, DynamicMetaObject errorSuggestion, params DynamicMetaObject/*!*/[]/*!*/ types) {
     // we get the error message w/ {0}, {1} so that TypeError formats it correctly
     return errorSuggestion ?? TypeError(
            operation,
            MakeBinaryOpErrorMessage(op, "{0}", "{1}"),
            types);
 }
示例#26
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op) {
            MSAst.Expression assignment;

            if (op != PythonOperationKind.None) {
                right = GlobalParent.Operation(
                    typeof(object),
                    op,
                    this,
                    right
                );
            }

            SourceSpan aspan = span.IsValid ? new SourceSpan(Span.Start, span.End) : SourceSpan.None;

            if (_reference.PythonVariable != null) {
                assignment = AssignValue(
                    Parent.GetVariableExpression(_reference.PythonVariable),
                    ConvertIfNeeded(right, typeof(object))
                );
            } else {
                assignment = Ast.Call(
                    null,
                    typeof(PythonOps).GetMethod("SetName"),
                    new[] {
                        Parent.LocalContext, 
                        Ast.Constant(_name),
                        AstUtils.Convert(right, typeof(object))
                    }
                );
            }

            return GlobalParent.AddDebugInfoAndVoid(assignment, aspan);
        }
        private static string/*!*/ GetOperatorDisplay(PythonOperationKind op) {
            op = NormalizeOperator(op);

            switch (op) {
                case PythonOperationKind.Add: return "+";
                case PythonOperationKind.Subtract: return "-";
                case PythonOperationKind.Power: return "**";
                case PythonOperationKind.Multiply: return "*";
                case PythonOperationKind.FloorDivide: return "//";
                case PythonOperationKind.Divide: return "/";
                case PythonOperationKind.TrueDivide: return "//";
                case PythonOperationKind.Mod: return "%";
                case PythonOperationKind.LeftShift: return "<<";
                case PythonOperationKind.RightShift: return ">>";
                case PythonOperationKind.BitwiseAnd: return "&";
                case PythonOperationKind.BitwiseOr: return "|";
                case PythonOperationKind.ExclusiveOr: return "^";
                case PythonOperationKind.LessThan: return "<";
                case PythonOperationKind.GreaterThan: return ">";
                case PythonOperationKind.LessThanOrEqual: return "<=";
                case PythonOperationKind.GreaterThanOrEqual: return ">=";
                case PythonOperationKind.Equal: return "==";
                case PythonOperationKind.NotEqual: return "!=";
                case PythonOperationKind.LessThanGreaterThan: return "<>";
                case PythonOperationKind.InPlaceAdd: return "+=";
                case PythonOperationKind.InPlaceSubtract: return "-=";
                case PythonOperationKind.InPlacePower: return "**=";
                case PythonOperationKind.InPlaceMultiply: return "*=";
                case PythonOperationKind.InPlaceFloorDivide: return "/=";
                case PythonOperationKind.InPlaceDivide: return "/=";
                case PythonOperationKind.InPlaceTrueDivide: return "//=";
                case PythonOperationKind.InPlaceMod: return "%=";
                case PythonOperationKind.InPlaceLeftShift: return "<<=";
                case PythonOperationKind.InPlaceRightShift: return ">>=";
                case PythonOperationKind.InPlaceBitwiseAnd: return "&=";
                case PythonOperationKind.InPlaceBitwiseOr: return "|=";
                case PythonOperationKind.InPlaceExclusiveOr: return "^=";
                case PythonOperationKind.ReverseAdd: return "+";
                case PythonOperationKind.ReverseSubtract: return "-";
                case PythonOperationKind.ReversePower: return "**";
                case PythonOperationKind.ReverseMultiply: return "*";
                case PythonOperationKind.ReverseFloorDivide: return "/";
                case PythonOperationKind.ReverseDivide: return "/";
                case PythonOperationKind.ReverseTrueDivide: return "//";
                case PythonOperationKind.ReverseMod: return "%";
                case PythonOperationKind.ReverseLeftShift: return "<<";
                case PythonOperationKind.ReverseRightShift: return ">>";
                case PythonOperationKind.ReverseBitwiseAnd: return "&";
                case PythonOperationKind.ReverseBitwiseOr: return "|";
                case PythonOperationKind.ReverseExclusiveOr: return "^";
                default: return op.ToString();
            }
        }
示例#28
0
            public OneOffPowerBinder(string/*!*/ pythonName, PythonOperationKind op) {
                Assert.NotNull(pythonName, op);

                _pythonName = pythonName;
                _op = op;
            }
        private static DynamicMetaObject/*!*/ MakeSimpleOperation(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ binder, PythonOperationKind operation, DynamicMetaObject errorSuggestion) {
            RestrictTypes(types);

            SlotOrFunction fbinder;
            SlotOrFunction rbinder;
            PythonTypeSlot fSlot;
            PythonTypeSlot rSlot;
            GetOperatorMethods(types, operation, PythonContext.GetPythonContext(binder), out fbinder, out rbinder, out fSlot, out rSlot);

            return MakeBinaryOperatorResult(types, binder, operation, fbinder, rbinder, fSlot, rSlot, errorSuggestion);
        }
示例#30
0
 internal static bool IsReverseOperator(PythonOperationKind op) {
     return (op & PythonOperationKind.Reversed) != 0;
 }
 private static bool IsReverseOperator(PythonOperationKind oper) {
     return (oper & PythonOperationKind.Reversed) != 0;
 }
示例#32
0
        internal static string OperatorToSymbol(PythonOperationKind op)
        {
            switch (op)
            {
                #region Generated StringOperatorToSymbol

            // *** BEGIN GENERATED CODE ***
            // generated by function: gen_StringOperatorToSymbol from: generate_ops.py

            case PythonOperationKind.Add: return("__add__");

            case PythonOperationKind.ReverseAdd: return("__radd__");

            case PythonOperationKind.InPlaceAdd: return("__iadd__");

            case PythonOperationKind.Subtract: return("__sub__");

            case PythonOperationKind.ReverseSubtract: return("__rsub__");

            case PythonOperationKind.InPlaceSubtract: return("__isub__");

            case PythonOperationKind.Power: return("__pow__");

            case PythonOperationKind.ReversePower: return("__rpow__");

            case PythonOperationKind.InPlacePower: return("__ipow__");

            case PythonOperationKind.Multiply: return("__mul__");

            case PythonOperationKind.ReverseMultiply: return("__rmul__");

            case PythonOperationKind.InPlaceMultiply: return("__imul__");

            case PythonOperationKind.FloorDivide: return("__floordiv__");

            case PythonOperationKind.ReverseFloorDivide: return("__rfloordiv__");

            case PythonOperationKind.InPlaceFloorDivide: return("__ifloordiv__");

            case PythonOperationKind.Divide: return("__div__");

            case PythonOperationKind.ReverseDivide: return("__rdiv__");

            case PythonOperationKind.InPlaceDivide: return("__idiv__");

            case PythonOperationKind.TrueDivide: return("__truediv__");

            case PythonOperationKind.ReverseTrueDivide: return("__rtruediv__");

            case PythonOperationKind.InPlaceTrueDivide: return("__itruediv__");

            case PythonOperationKind.Mod: return("__mod__");

            case PythonOperationKind.ReverseMod: return("__rmod__");

            case PythonOperationKind.InPlaceMod: return("__imod__");

            case PythonOperationKind.LeftShift: return("__lshift__");

            case PythonOperationKind.ReverseLeftShift: return("__rlshift__");

            case PythonOperationKind.InPlaceLeftShift: return("__ilshift__");

            case PythonOperationKind.RightShift: return("__rshift__");

            case PythonOperationKind.ReverseRightShift: return("__rrshift__");

            case PythonOperationKind.InPlaceRightShift: return("__irshift__");

            case PythonOperationKind.BitwiseAnd: return("__and__");

            case PythonOperationKind.ReverseBitwiseAnd: return("__rand__");

            case PythonOperationKind.InPlaceBitwiseAnd: return("__iand__");

            case PythonOperationKind.BitwiseOr: return("__or__");

            case PythonOperationKind.ReverseBitwiseOr: return("__ror__");

            case PythonOperationKind.InPlaceBitwiseOr: return("__ior__");

            case PythonOperationKind.ExclusiveOr: return("__xor__");

            case PythonOperationKind.ReverseExclusiveOr: return("__rxor__");

            case PythonOperationKind.InPlaceExclusiveOr: return("__ixor__");

            case PythonOperationKind.LessThan: return("__lt__");

            case PythonOperationKind.GreaterThan: return("__gt__");

            case PythonOperationKind.LessThanOrEqual: return("__le__");

            case PythonOperationKind.GreaterThanOrEqual: return("__ge__");

            case PythonOperationKind.Equal: return("__eq__");

            case PythonOperationKind.NotEqual: return("__ne__");

            case PythonOperationKind.LessThanGreaterThan: return("__lg__");

                // *** END GENERATED CODE ***

                #endregion

            // unary operators
            case PythonOperationKind.OnesComplement: return("__invert__");

            case PythonOperationKind.Negate: return("__neg__");

            case PythonOperationKind.Positive: return("__pos__");

            case PythonOperationKind.AbsoluteValue: return("__abs__");

            case PythonOperationKind.DivMod: return("__divmod__");

            case PythonOperationKind.ReverseDivMod: return("__rdivmod__");

            case PythonOperationKind.Compare: return("__cmp__");

            default:
                throw new InvalidOperationException(op.ToString());
            }
        }
示例#33
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op) {
            // if we just have a simple named multi-assignment  (e.g. a, b = 1,2)
            // then go ahead and step over the entire statement at once.  If we have a 
            // more complex statement (e.g. a.b, c.d = 1, 2) then we'll step over the
            // sets individually as they could be property sets the user wants to step
            // into.  TODO: Enable stepping of the right hand side?
            bool emitIndividualSets = false;
            foreach (Expression e in _items) {
                if (IsComplexAssignment(e)) {
                    emitIndividualSets = true;
                    break;
                }
            }

            SourceSpan rightSpan = SourceSpan.None;
            SourceSpan leftSpan =
                (Span.Start.IsValid && span.IsValid) ?
                    new SourceSpan(Span.Start, span.End) :
                    SourceSpan.None;

            SourceSpan totalSpan = SourceSpan.None;
            if (emitIndividualSets) {
                rightSpan = span;
                leftSpan = SourceSpan.None;
                totalSpan = (Span.Start.IsValid && span.IsValid) ?
                    new SourceSpan(Span.Start, span.End) :
                    SourceSpan.None;
            }

            // 1. Evaluate the expression and assign the value to the temp.
            MSAst.ParameterExpression right_temp = Ast.Variable(typeof(object), "unpacking");

            // 2. Add the assignment "right_temp = right" into the suite/block
            MSAst.Expression assignStmt1 = MakeAssignment(right_temp, right);

            // 3. Call GetEnumeratorValues on the right side (stored in temp)
            MSAst.Expression enumeratorValues = Expression.Convert(LightExceptions.CheckAndThrow(
                Expression.Call(
                    emitIndividualSets ? 
                        AstMethods.GetEnumeratorValues : 
                        AstMethods.GetEnumeratorValuesNoComplexSets,    // method
                    // arguments
                    Parent.LocalContext,
                    right_temp,
                    AstUtils.Constant(_items.Length)
                )
            ), typeof(object[]));

            // 4. Create temporary variable for the array
            MSAst.ParameterExpression array_temp = Ast.Variable(typeof(object[]), "array");

            // 5. Assign the value of the method call (mce) into the array temp
            // And add the assignment "array_temp = Ops.GetEnumeratorValues(...)" into the block
            MSAst.Expression assignStmt2 = MakeAssignment(
                array_temp,
                enumeratorValues,
                rightSpan
            );

            ReadOnlyCollectionBuilder<MSAst.Expression> sets = new ReadOnlyCollectionBuilder<MSAst.Expression>(_items.Length + 1);
            for (int i = 0; i < _items.Length; i++) {
                // target = array_temp[i]

                Expression target = _items[i];
                if (target == null) {
                    continue;
                }

                // 6. array_temp[i]
                MSAst.Expression element = Ast.ArrayAccess(
                    array_temp,                             // array expression
                    AstUtils.Constant(i)                         // index
                );

                // 7. target = array_temp[i], and add the transformed assignment into the list of sets
                MSAst.Expression set = target.TransformSet(
                    emitIndividualSets ?                    // span
                        target.Span :
                        SourceSpan.None,
                    element,
                    PythonOperationKind.None
                );
                sets.Add(set);
            }
            // 9. add the sets as their own block so they can be marked as a single span, if necessary.
            sets.Add(AstUtils.Empty());
            MSAst.Expression itemSet = GlobalParent.AddDebugInfo(Ast.Block(sets.ToReadOnlyCollection()), leftSpan);

            // 10. Return the suite statement (block)
            return GlobalParent.AddDebugInfo(Ast.Block(new[] { array_temp, right_temp }, assignStmt1, assignStmt2, itemSet, AstUtils.Empty()), totalSpan);
        }
示例#34
0
        private static ExpressionType?GetExpressionTypeFromBinaryOperator(PythonOperationKind operatorName)
        {
            switch (operatorName)
            {
            case PythonOperationKind.Add: return(ExpressionType.Add);

            case PythonOperationKind.BitwiseAnd: return(ExpressionType.And);

            case PythonOperationKind.ExclusiveOr: return(ExpressionType.ExclusiveOr);

            case PythonOperationKind.Mod: return(ExpressionType.Modulo);

            case PythonOperationKind.Multiply: return(ExpressionType.Multiply);

            case PythonOperationKind.BitwiseOr: return(ExpressionType.Or);

            case PythonOperationKind.Power: return(ExpressionType.Power);

            case PythonOperationKind.RightShift: return(ExpressionType.RightShift);

            case PythonOperationKind.LeftShift: return(ExpressionType.LeftShift);

            case PythonOperationKind.Subtract: return(ExpressionType.Subtract);

            case PythonOperationKind.TrueDivide: return(ExpressionType.Divide);

            case PythonOperationKind.InPlaceAdd: return(ExpressionType.AddAssign);

            case PythonOperationKind.InPlaceBitwiseAnd: return(ExpressionType.AndAssign);

            case PythonOperationKind.InPlaceExclusiveOr: return(ExpressionType.ExclusiveOrAssign);

            case PythonOperationKind.InPlaceMod: return(ExpressionType.ModuloAssign);

            case PythonOperationKind.InPlaceMultiply: return(ExpressionType.MultiplyAssign);

            case PythonOperationKind.InPlaceBitwiseOr: return(ExpressionType.OrAssign);

            case PythonOperationKind.InPlacePower: return(ExpressionType.PowerAssign);

            case PythonOperationKind.InPlaceRightShift: return(ExpressionType.RightShiftAssign);

            case PythonOperationKind.InPlaceLeftShift: return(ExpressionType.LeftShiftAssign);

            case PythonOperationKind.InPlaceSubtract: return(ExpressionType.SubtractAssign);

            case PythonOperationKind.InPlaceTrueDivide: return(ExpressionType.DivideAssign);

            case PythonOperationKind.Equal: return(ExpressionType.Equal);

            case PythonOperationKind.GreaterThan: return(ExpressionType.GreaterThan);

            case PythonOperationKind.GreaterThanOrEqual: return(ExpressionType.GreaterThanOrEqual);

            case PythonOperationKind.LessThan: return(ExpressionType.LessThan);

            case PythonOperationKind.LessThanOrEqual: return(ExpressionType.LessThanOrEqual);

            case PythonOperationKind.NotEqual: return(ExpressionType.NotEqual);
            }
            return(null);
        }
示例#35
0
            public OneOffOperatorBinder(string/*!*/ methodName, string/*!*/ pythonName, PythonOperationKind opMap) {
                Assert.NotNull(methodName, pythonName, opMap);

                _methodName = methodName;
                _pythonName = pythonName;
                _op = opMap;
            }
        private static DynamicMetaObject MakeBinaryOperation(DynamicMetaObjectBinder operation, DynamicMetaObject/*!*/[] args, PythonOperationKind opStr, DynamicMetaObject errorSuggestion) {
            if (IsComparison(opStr)) {
                return MakeComparisonOperation(args, operation, opStr, errorSuggestion);
            }

            return MakeSimpleOperation(args, operation, opStr, errorSuggestion);
        }
示例#37
0
 /// <summary>
 /// Filters out methods which are present on standard .NET types but shouldn't be there in Python
 /// </summary>
 internal static bool IncludeOperatorMethod(Type/*!*/ t, PythonOperationKind op) {
     // numeric types in python don't define equality, just __cmp__
     if (t == typeof(bool) ||
         (Converter.IsNumeric(t) && t != typeof(Complex64) && t != typeof(double) && t != typeof(float))) {
         switch (op) {
             case PythonOperationKind.Equal:
             case PythonOperationKind.NotEqual:
             case PythonOperationKind.GreaterThan:
             case PythonOperationKind.LessThan:
             case PythonOperationKind.GreaterThanOrEqual:
             case PythonOperationKind.LessThanOrEqual:
                 return false;
         }
     }
     return true;
 }
 private static bool IsComparison(PythonOperationKind op) {
     return IsComparisonOperator(NormalizeOperator(op));
 }
示例#39
0
        /// <summary>
        /// If an operator is a reverisble operator (e.g. addition) then we need to filter down to just the forward/reverse
        /// versions of the .NET method.  For example consider:
        /// 
        ///     String.op_Multiplication(int, string)
        ///     String.op_Multiplication(string, int)
        ///     
        /// If this method were defined on string it defines that you can do:
        ///     2 * 'abc'
        ///   or:
        ///     'abc' * 2
        ///     
        /// either of which will produce 'abcabc'.  The 1st form is considered the reverse form because it is declared on string
        /// but takes a non-string for the 1st argument.  The 2nd is considered the forward form because it takes a string as the
        /// 1st argument.
        /// 
        /// When dynamically dispatching for 2 * 'abc' we'll first try __mul__ on int, which will fail with a string argument.  Then we'll try
        /// __rmul__ on a string which will succeed and dispatch to the (int, string) overload.
        /// 
        /// For multiplication in this case it's not too interesting because it's commutative.  For addition this might be more interesting
        /// if, for example, we had unicode and ASCII strings.  In that case Unicode strings would define addition taking both unicode and
        /// ASCII strings in both forms.
        /// </summary>
        private static MemberGroup/*!*/ FilterForwardReverseMethods(string name, MemberGroup/*!*/ group, Type/*!*/ type, PythonOperationKind oper) {
            List<MethodTracker> res = new List<MethodTracker>(group.Count);
            PythonOperationKind reversed = Symbols.OperatorToReverseOperator(oper);
            foreach (MemberTracker mt in group) {
                if (mt.MemberType != TrackerTypes.Method) {
                    continue;
                }

                MethodTracker mTracker = (MethodTracker)mt;
                if (reversed == PythonOperationKind.None) {
                    res.Add(mTracker);
                    continue;
                }

                MethodInfo method = mTracker.Method;

                if (!method.IsStatic) {
                    if (!IsReverseOperator(oper)) {
                        res.Add(mTracker);
                    }
                    continue;
                }

                ParameterInfo[] parms = method.GetParameters();

                int ctxOffset = (parms.Length > 0 && parms[0].ParameterType == typeof(CodeContext)) ? 1 : 0;
                bool regular;

                bool reverse;

                if ((parms.Length - ctxOffset) == 2) {
                    Type param1Type = parms[0 + ctxOffset].ParameterType;
                    Type param2Type = parms[1 + ctxOffset].ParameterType;

                    // both parameters could be typed to object in which case we want to add
                    // the method as whatever we're being requested for here.  One example of this
                    // is EnumOps which can't be typed to Enum.
                    if (param1Type == typeof(object) && param2Type == typeof(object)) {
                        regular = !IsReverseOperator(oper);
                        reverse = IsReverseOperator(oper);
                    } else {
                        regular = parms.Length > 0 && AreTypesCompatible(param1Type, type);
                        reverse = ((oper & PythonOperationKind.Comparison) == 0) && parms.Length > 1 && AreTypesCompatible(param2Type, type);
                    }

                    if (IsReverseOperator(oper)) {
                        if (reverse) {
                            res.Add(mTracker);
                        }
                    } else {
                        if (regular) {
                            res.Add(mTracker);
                        }
                    }
                } else {
                    res.Add(mTracker);
                }
            }

            if (res.Count == 0) {
                return MemberGroup.EmptyGroup;
            }

            return new MemberGroup(new OperatorTracker(type, name, IsReverseOperator(oper), res.ToArray()));
        }
示例#40
0
 internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
 => Value.TransformSet(span, right, op);