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 ); } }
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); }
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; }
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; }
public static DynamicMetaObjectBinder BinaryOperationBinder(PythonContext state, PythonOperationKind operatorName) { ExpressionType? et = GetExpressionTypeFromBinaryOperator(operatorName); if (et == null) { return state.Operation( operatorName ); } return state.BinaryOperation(et.Value); }
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) ) ); }
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 ) ); }
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(); } }
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)); }
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 )); } }
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; }
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); }
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); }
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(); } }
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); }
internal static bool IsReverseOperator(PythonOperationKind op) { return (op & PythonOperationKind.Reversed) != 0; }
private static bool IsReverseOperator(PythonOperationKind oper) { return (oper & PythonOperationKind.Reversed) != 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()); } }
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); }
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); }
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); }
/// <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)); }
/// <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())); }
internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op) => Value.TransformSet(span, right, op);