private DynamicMetaObject /*!*/ MakeConvertToIEnumerable(DynamicMetaObjectBinder /*!*/ conversion) { ParameterExpression tmp = Ast.Variable(typeof(IEnumerable), "res"); DynamicMetaObject self = Restrict(typeof(OldInstance)); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod("OldInstanceConvertToIEnumerableNonThrowing"), AstUtils.Constant(PythonContext.GetPythonContext(conversion).SharedContext), self.Expression ) ), AstUtils.Constant(null) ), tmp, AstUtils.Convert( AstUtils.Convert( // first to object (incase it's a throw), then to IEnumerable FallbackConvert(conversion).Expression, typeof(object) ), typeof(IEnumerable) ) ) ), self.Restrictions )); }
private static Expression /*!*/ AddExtensibleSelfCheck(DynamicMetaObjectBinder /*!*/ convertToAction, Type toType, DynamicMetaObject /*!*/ self, Expression /*!*/ callExpr) { ParameterExpression tmp = Ast.Variable(callExpr.Type, "tmp"); ConversionResultKind resKind = GetResultKind(convertToAction); Type retType = (resKind == ConversionResultKind.ExplicitTry || resKind == ConversionResultKind.ImplicitTry) ? typeof(object) : toType; callExpr = Ast.Block( new ParameterExpression[] { tmp }, Ast.Block( Ast.Assign(tmp, callExpr), Ast.Condition( Ast.Equal(tmp, self.Expression), AstUtils.Convert( Ast.Property( AstUtils.Convert(self.Expression, self.GetLimitType()), self.GetLimitType().GetProperty("Value") ), retType ), Ast.Dynamic( new PythonConversionBinder( PythonContext.GetPythonContext(convertToAction), toType, GetResultKind(convertToAction) ), retType, tmp ) ) ) ); return(callExpr); }
/// <code> /// End-exclusive range: /// if state /// state = IsFalse({end}) /// true /// else /// state = IsTrue({begin}) /// end /// /// End-inclusive range: /// if state || IsTrue({begin}) /// state = IsFalse({end}) /// true /// else /// false /// end /// </code> private MSA.Expression /*!*/ TransformReadCondition(AstGenerator /*!*/ gen) { // Define state variable in the inner most method scope. var stateVariable = gen.CurrentMethod.Builder.DefineHiddenVariable("#in_range", typeof(bool)); var begin = AstFactory.Box(_begin.TransformRead(gen)); var end = AstFactory.Box(_end.TransformRead(gen)); if (_isExclusive) { return(Ast.Condition( stateVariable, Ast.Block(Ast.Assign(stateVariable, Methods.IsFalse.OpCall(end)), Ast.Constant(true)), Ast.Assign(stateVariable, Methods.IsTrue.OpCall(begin)) )); } else { return(Ast.Condition( Ast.OrElse(stateVariable, Methods.IsTrue.OpCall(begin)), Ast.Block(Ast.Assign(stateVariable, Methods.IsFalse.OpCall(end)), Ast.Constant(true)), Ast.Constant(false) )); } }
private DynamicMetaObject /*!*/ MakeConvertToIEnumerable(DynamicMetaObjectBinder /*!*/ conversion, Type toType, Type genericType) { ParameterExpression tmp = Ast.Variable(toType, "res"); DynamicMetaObject self = Restrict(typeof(OldInstance)); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceConvertToIEnumerableOfTNonThrowing)).MakeGenericMethod(genericType), AstUtils.Constant(PythonContext.GetPythonContext(conversion).SharedContext), self.Expression ) ), AstUtils.Constant(null) ), tmp, AstUtils.Convert( AstUtils.Convert( FallbackConvert(conversion).Expression, typeof(object) ), toType ) ) ), self.Restrictions )); }
public static Expression Not(params Expression[] obj) { if (obj.Length == 1) { Expression e = Unwrap(obj[0]); if (e is UnaryExpression) { UnaryExpression ue = (UnaryExpression)e; if (ue.NodeType == AstNodeType.Not) { return(ue.Operand); } } if (e is ConditionalExpression) { ConditionalExpression ce = (ConditionalExpression)e; return(Ast.Condition(ce.Test, Not(ce.IfTrue), Not(ce.IfFalse))); } if (e.Type == typeof(bool)) { return(Ast.Not(e)); } //return Ast.Equal(Ast.Constant(false), obj[0]); return(Ast.Not(Ast.Call(IsTrue, obj[0]))); } return(null); }
/// <summary> /// Gets the resulting meta object for the full body. FinishCondition /// must have been called. /// </summary> public DynamicMetaObject /*!*/ GetMetaObject(params DynamicMetaObject /*!*/[] /*!*/ types) { if (_body == null) { throw new InvalidOperationException("FinishCondition not called before GetMetaObject"); } Expression body = _body; for (int i = _bodies.Count - 1; i >= 0; i--) { body = Ast.Condition( _conditions[i], AstUtils.Convert(_bodies[i], _retType), AstUtils.Convert(body, _retType) ); } body = Ast.Block(_variables, body); return(new DynamicMetaObject( body, BindingRestrictions.Combine(types) )); }
public override MSAst.Expression Reduce() { MSAst.Expression left = _left; MSAst.Expression right = _right; Type t = Type; MSAst.ParameterExpression tmp = Ast.Variable(t, "__all__"); return(Ast.Block( new[] { tmp }, Ast.Condition( GlobalParent.Convert( typeof(bool), ConversionResultKind.ExplicitCast, Ast.Assign( tmp, AstUtils.Convert( left, t ) ) ), tmp, AstUtils.Convert( right, t ) ) )); }
private DynamicMetaObject /*!*/ MakeConvertToBool(DynamicMetaObjectBinder /*!*/ conversion) { DynamicMetaObject self = Restrict(typeof(OldInstance)); ParameterExpression tmp = Ast.Variable(typeof(bool?), "tmp"); DynamicMetaObject fallback = FallbackConvert(conversion); Type resType = BindingHelpers.GetCompatibleType(typeof(bool), fallback.Expression.Type); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceConvertToBoolNonThrowing)), AstUtils.Constant(PythonContext.GetPythonContext(conversion).SharedContext), self.Expression ) ), AstUtils.Constant(null) ), AstUtils.Convert(tmp, resType), AstUtils.Convert(fallback.Expression, resType) ) ), self.Restrictions )); }
internal static DynamicMetaObject /*!*/ AddDynamicTestAndDefer(DynamicMetaObjectBinder /*!*/ operation, DynamicMetaObject /*!*/ res, DynamicMetaObject /*!*/[] args, ValidationInfo typeTest, Type deferType, params ParameterExpression[] temps) { if (typeTest != null) { if (typeTest.Test != null) { // add the test and a validator if persent Expression defer = operation.GetUpdateExpression(deferType ?? typeof(object)); Type bestType = BindingHelpers.GetCompatibleType(defer.Type, res.Expression.Type); res = new DynamicMetaObject( Ast.Condition( typeTest.Test, AstUtils.Convert(res.Expression, bestType), AstUtils.Convert(defer, bestType) ), res.Restrictions ); } } if (temps.Length > 0) { // finally add the scoped variables res = new DynamicMetaObject( Ast.Block(temps, res.Expression), res.Restrictions, null ); } return(res); }
internal override Expression ToExpression(MethodBinderContext context, Expression[] parameters) { // Ideally we'd pass in Ast.ReadField(parameters[Index], "Value") but due to // a bug in partial trust we can't access the generic field. // arg is boxType ? &_tmp : throw new ArgumentTypeException() // IncorrectBoxType throws the exception to avoid stack imbalance issues. return(Ast.Condition( Ast.TypeIs(parameters[Index], BoxType), Ast.Comma( Ast.Assign( _tmp, Ast.Call( typeof(BinderOps).GetMethod("GetBox").MakeGenericMethod(_elementType), Ast.ConvertHelper(parameters[Index], typeof(StrongBox <>).MakeGenericType(_elementType)) ) ), Ast.Read(_tmp) ), // Condition requires types of both expressions to be identical. // Putting the cast here is a temporary workaround until the // emit address and reference argument passing is finished. Ast.Convert( Ast.Call( typeof(BinderOps).GetMethod("IncorrectBoxType"), Ast.Constant(BoxType), Ast.ConvertHelper(parameters[Index], typeof(object)) ), _elementType ) )); }
internal DynamicMetaObject /*!*/ CreateMetaObject(DynamicMetaObjectBinder /*!*/ binder, Type /*!*/ returnType) { Debug.Assert(ControlFlowBuilder == null, "Control flow required but not built"); var restrictions = _restrictions; var expr = _error ? Ast.Throw(_result, returnType) : AstUtils.Convert(_result, returnType); if (_condition != null) { var deferral = binder.GetUpdateExpression(returnType); expr = Ast.Condition(_condition, expr, deferral); } if (_temps != null || _initializations != null) { AddInitialization(expr); if (_temps != null) { expr = Ast.Block(_temps, _initializations); } else { expr = Ast.Block(_initializations); } } Clear(); RubyBinder.DumpRule(binder, restrictions, expr); return(new DynamicMetaObject(expr, restrictions)); }
private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert) { MSAst.Expression result; if (_else != null) { result = _else; } else { result = AstUtils.Empty(); } // Now build from the inside out int i = _tests.Length; while (i-- > 0) { IfStatementTest ist = _tests[i]; result = GlobalParent.AddDebugInfoAndVoid( Ast.Condition( optimizeDynamicConvert ? TransformAndDynamicConvert(ist.Test, typeof(bool)) : GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test), TransformMaybeSingleLineSuite(ist.Body, ist.Test.Start), result ), new SourceSpan(ist.Start, ist.Header) ); } return(result); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(Ast.Condition( _condition.TransformReadBoolean(gen, !_negateCondition), AstUtils.Box(_body.TransformRead(gen)), (_elseStatement != null) ? AstUtils.Box(_elseStatement.TransformRead(gen)) : (MSA.Expression)AstUtils.Constant(null) )); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(Ast.Condition( TransformCondition(gen), AstFactory.Box(_body.TransformRead(gen)), (_elseStatement != null) ? AstFactory.Box(_elseStatement.TransformRead(gen)) : (MSA.Expression)Ast.Constant(null) )); }
private DynamicMetaObject /*!*/ MakeCallRule(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject[] args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass Invoke w/ " + args.Length + " args"); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass Invoke"); CallSignature signature = BindingHelpers.GetCallSignature(call); // TODO: If we know __init__ wasn't present we could construct the OldInstance directly. Expression[] exprArgs = new Expression[args.Length]; for (int i = 0; i < args.Length; i++) { exprArgs[i] = args[i].Expression; } ParameterExpression init = Ast.Variable(typeof(object), "init"); ParameterExpression instTmp = Ast.Variable(typeof(object), "inst"); DynamicMetaObject self = Restrict(typeof(OldClass)); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { init, instTmp }, Ast.Assign( instTmp, Ast.New( typeof(OldInstance).GetConstructor(new Type[] { typeof(CodeContext), typeof(OldClass) }), codeContext, self.Expression ) ), Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( init, Ast.Call( typeof(PythonOps).GetMethod("OldClassTryLookupInit"), self.Expression, instTmp ) ), typeof(OperationFailed) ) ), Ast.Dynamic( PythonContext.GetPythonContext(call).Invoke( signature ), typeof(object), ArrayUtils.Insert <Expression>(codeContext, init, exprArgs) ), NoInitCheckNoArgs(signature, self, args) ), instTmp ), self.Restrictions.Merge(BindingRestrictions.Combine(args)) )); }
private DynamicMetaObject /*!*/ InvokeWorker(DynamicMetaObjectBinder /*!*/ invoke, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass Invoke"); DynamicMetaObject self = Restrict(typeof(OldInstance)); Expression[] exprArgs = new Expression[args.Length + 1]; for (int i = 0; i < args.Length; i++) { exprArgs[i + 1] = args[i].Expression; } ParameterExpression tmp = Ast.Variable(typeof(object), "callFunc"); exprArgs[0] = tmp; return(new DynamicMetaObject( // we could get better throughput w/ a more specific rule against our current custom old class but // this favors less code generation. Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("OldInstanceTryGetBoundCustomMember"), codeContext, self.Expression, AstUtils.Constant("__call__"), tmp ), Ast.Block( Utils.Try( Ast.Call(typeof(PythonOps).GetMethod("FunctionPushFrameCodeContext"), codeContext), Ast.Assign( tmp, Ast.Dynamic( PythonContext.GetPythonContext(invoke).Invoke( BindingHelpers.GetCallSignature(invoke) ), typeof(object), ArrayUtils.Insert(codeContext, exprArgs) ) ) ).Finally( Ast.Call(typeof(PythonOps).GetMethod("FunctionPopFrame")) ), tmp ), Utils.Convert( BindingHelpers.InvokeFallback(invoke, codeContext, this, args).Expression, typeof(object) ) ) ), self.Restrictions.Merge(BindingRestrictions.Combine(args)) )); }
public override MSAst.Expression Reduce() { MSAst.Expression ifTrue = AstUtils.Convert(_trueExpr, typeof(object)); MSAst.Expression ifFalse = AstUtils.Convert(_falseExpr, typeof(object)); return(Ast.Condition( GlobalParent.Convert(typeof(bool), ConversionResultKind.ExplicitCast, _testExpr), ifTrue, ifFalse )); }
// Function Body Code Generation // // object Func(object self, object[] args) { // object p1 = ...; // object p2 = ...; // ... // object pn = ...; // (..Body..) // } // // <if has_default(p[i]) then> // <p[i]> = <i> < args.Length ? (args[<i>] == void ? <default(p[i])> : args[<i>]) : <default(p[i])>; // <else if any_length_args(p[i]) then> // <if has_name(p[i]) then> // <p[i]> = new Array(args.Skip(<i>)); // <else> // <p[i]> = new UnnamedSpreadArguments(args, <i>); // <end if> // <else> // <p[i]> = <i> < args.Length ? args[<i>] : void; // <end if> public System.Linq.Expressions.Expression <Func <object, object, object[], object> > TransformLambda() { List <Ast> body = new List <Ast>(); for (int i = 0; i < Parameters.Count; i++) { var capCheck = Ast.LessThan(Ast.Constant(i), Ast.Property(_arguments, "Length")); Ast exp; if (Parameters[i].HasDefaultValue) { exp = Ast.Condition(capCheck, Ast.Condition(Ast.TypeEqual(Ast.ArrayAccess(_arguments, Ast.Constant(i)), typeof(Builtins.Void)), Ast.Constant(Parameters[i].DefaultValue, typeof(object)), Ast.ArrayAccess(_arguments, Ast.Constant(i)) ), Ast.Constant(Parameters[i].DefaultValue, typeof(object)) ); } else if (Parameters[i].ExpandToArray) { if (Parameters[i].ParameterVariable.Name != null) { exp = Ast.New((System.Reflection.ConstructorInfo)Utils.GetMember(() => new Builtins.Array(null)), Ast.Call(new Func <IEnumerable <object>, int, IEnumerable <object> >(Enumerable.Skip).Method, _arguments, Ast.Constant(i)) ); } else { exp = Ast.New((System.Reflection.ConstructorInfo)Utils.GetMember(() => new Runtime.UnnamedSpreadArguments(null, 0)), _arguments, Ast.Constant(i) ); } } else { exp = Ast.Condition(capCheck, Ast.ArrayAccess(_arguments, Ast.Constant(i)), Ast.Constant(Builtins.Void.Value, typeof(object)) ); } body.Add(Ast.Assign(Parameters[i].ParameterVariable, exp)); } foreach (var statement in Body) { body.Add(statement.Transform()); } body.Add(Ast.Label(ReturnLabel, Ast.Constant(Builtins.Void.Value))); return(Ast.Lambda <Func <object, object, object[], object> >(Ast.Block(_variables.Values.Concat(Parameters.Select(x => x.ParameterVariable)), body), Name, new[] { _global, _context, _arguments })); }
static Expression RewriteExpression(CodeBlock cb, Expression e) { if (e is MethodCallExpression) { MethodCallExpression mce = (MethodCallExpression)e; List <Expression> args = new List <Expression>(); foreach (var arg in mce.Arguments) { args.Add(RewriteExpression(cb, arg)); } return(Ast.Call(RewriteExpression(cb, mce.Instance), mce.Method, args.ToArray())); } if (e is BoundExpression) { BoundExpression be = (BoundExpression)e; return(Ast.Read(cb.Lookup(be.Variable.Name))); } if (e is BinaryExpression) { BinaryExpression be = (BinaryExpression)e; return(new BinaryExpression(be.NodeType, RewriteExpression(cb, be.Left), RewriteExpression(cb, be.Right))); } if (e is UnaryExpression) { UnaryExpression ue = (UnaryExpression)e; if (ue.NodeType == AstNodeType.Convert) { return(Ast.ConvertHelper(RewriteExpression(cb, ue.Operand), ue.Type)); } return(null); } if (e is TypeBinaryExpression) { TypeBinaryExpression tbe = (TypeBinaryExpression)e; return(Ast.TypeIs(RewriteExpression(cb, tbe.Expression), tbe.TypeOperand)); } if (e is ConditionalExpression) { ConditionalExpression ce = (ConditionalExpression)e; return(Ast.Condition(RewriteExpression(cb, ce.Test), RewriteExpression(cb, ce.IfTrue), RewriteExpression(cb, ce.IfFalse))); } return(e); }
/// <summary> /// Helper to produce the rule for converting T to Nullable of T /// </summary> private DynamicMetaObject MakeConvertingToTToNullableOfTTarget(OverloadResolverFactory resolverFactory, Type toType, ConversionResultKind kind, BindingRestrictions restrictions, DynamicMetaObject arg) { Type valueType = toType.GetGenericArguments()[0]; // ConvertSelfToT -> Nullable<T> if (kind == ConversionResultKind.ExplicitCast) { // if the conversion to T fails we just throw Expression conversion = ConvertExpression(arg.Expression, valueType, kind, resolverFactory); return(new DynamicMetaObject( Ast.New( toType.GetConstructor(new Type[] { valueType }), conversion ), restrictions )); } else { Expression conversion = ConvertExpression(arg.Expression, valueType, kind, resolverFactory); // if the conversion to T succeeds then produce the nullable<T>, otherwise return default(retType) ParameterExpression tmp = Ast.Variable(typeof(object), "tmp"); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign(tmp, conversion), AstUtils.Constant(null) ), Ast.New( toType.GetConstructor(new Type[] { valueType }), Ast.Convert( tmp, valueType ) ), GetTryConvertReturnValue(toType) ) ), restrictions )); } }
private Expression /*!*/ MakeCheckSelf(DynamicMetaObjectBinder /*!*/ binder, CallSignature signature, DynamicMetaObject /*!*/[] /*!*/ args) { ArgumentType firstArgKind = signature.GetArgumentKind(0); Expression res; if (firstArgKind == ArgumentType.Simple || firstArgKind == ArgumentType.Instance) { res = CheckSelf(binder, AstUtils.Convert(Expression, typeof(Method)), args[0].Expression); } else if (firstArgKind != ArgumentType.List) { res = CheckSelf(binder, AstUtils.Convert(Expression, typeof(Method)), AstUtils.Constant(null)); } else { // list, check arg[0] and then return original list. If not a list, // or we have no items, then check against null & throw. res = CheckSelf( binder, AstUtils.Convert(Expression, typeof(Method)), Ast.Condition( Ast.AndAlso( Ast.TypeIs(args[0].Expression, typeof(IList <object>)), Ast.NotEqual( Ast.Property( Ast.Convert(args[0].Expression, typeof(ICollection)), typeof(ICollection).GetProperty("Count") ), AstUtils.Constant(0) ) ), Ast.Call( Ast.Convert(args[0].Expression, typeof(IList <object>)), typeof(IList <object>).GetMethod("get_Item"), AstUtils.Constant(0) ), AstUtils.Constant(null) ) ); } return(res); }
/// <code> /// End-exclusive range: /// if state /// state = IsFalse({end}) /// true /// else /// state = IsTrue({begin}) /// end /// /// End-inclusive range: /// if state || IsTrue({begin}) /// state = IsFalse({end}) /// true /// else /// false /// end /// </code> internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { var begin = AstUtils.Box(_range.Begin.TransformRead(gen)); var end = AstUtils.Box(_range.End.TransformRead(gen)); // state: // false <=> null // true <=> non-null if (_range.IsExclusive) { return(Ast.Condition( Ast.ReferenceNotEqual( _stateVariable.TransformReadVariable(gen, false), AstUtils.Constant(null) ), Ast.Block( _stateVariable.TransformWriteVariable(gen, Methods.NullIfTrue.OpCall(end)), AstUtils.Constant(true) ), Ast.ReferenceNotEqual( _stateVariable.TransformWriteVariable(gen, Methods.NullIfFalse.OpCall(begin)), AstUtils.Constant(null) ) )); } else { return(Ast.Condition( Ast.OrElse( Ast.ReferenceNotEqual( _stateVariable.TransformReadVariable(gen, false), AstUtils.Constant(null) ), Methods.IsTrue.OpCall(begin) ), Ast.Block( _stateVariable.TransformWriteVariable(gen, Methods.NullIfTrue.OpCall(end)), AstUtils.Constant(true) ), AstUtils.Constant(false) )); } }
internal static DynamicMetaObject /*!*/ FilterShowCls(DynamicMetaObject /*!*/ codeContext, DynamicMetaObjectBinder /*!*/ action, DynamicMetaObject /*!*/ res, Expression /*!*/ failure) { if (action is IPythonSite) { return(new DynamicMetaObject( Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("IsClsVisible"), codeContext.Expression ), AstUtils.Convert(res.Expression, typeof(object)), AstUtils.Convert(failure, typeof(object)) ), res.Restrictions )); } return(res); }
protected override MSAst.Expression VisitConditional(MSAst.ConditionalExpression node) { MSAst.Expression t = Visit(node.Test); MSAst.Expression l; MSAst.Expression r; _insideConditionalBlock = true; try { l = Visit(node.IfTrue); r = Visit(node.IfFalse); } finally { _insideConditionalBlock = false; } if (t == node.Test && l == node.IfTrue && r == node.IfFalse) { return(node); } return(Ast.Condition(t, l, r, node.Type)); }
private DynamicMetaObject /*!*/ MakeConvertToCommon(DynamicMetaObjectBinder /*!*/ conversion, Type toType, Type retType, string name) { // TODO: support trys ParameterExpression tmp = Ast.Variable(typeof(object), "convertResult"); DynamicMetaObject self = Restrict(typeof(OldInstance)); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( MakeOneConvert(conversion, self, name, tmp), Expression.Convert( tmp, retType ), FallbackConvert(conversion).Expression ) ), self.Restrictions )); }
/// <summary> /// Adds the non-conditional terminating node. /// </summary> public void FinishCondition(Expression body) { if (_body != null) { throw new InvalidOperationException(); } for (int i = _bodies.Count - 1; i >= 0; i--) { Type t = _bodies[i].Type; if (t != body.Type) { if (t.IsSubclassOf(body.Type)) { // subclass t = body.Type; } else if (body.Type.IsSubclassOf(t)) { // keep t } else { // incompatible, both go to object t = typeof(object); } } body = Ast.Condition( _conditions[i], AstUtils.Convert(_bodies[i], t), AstUtils.Convert(body, t) ); } _body = Ast.Block( _variables, body ); }
public static MSA.Expression /*!*/ Condition(MSA.Expression /*!*/ test, MSA.Expression /*!*/ ifTrue, MSA.Expression /*!*/ ifFalse) { Assert.NotNull(test, ifTrue, ifFalse); Debug.Assert(test.Type == typeof(bool)); if (ifTrue.Type != ifFalse.Type) { if (ifTrue.Type.IsAssignableFrom(ifFalse.Type)) { ifFalse = Ast.Convert(ifFalse, ifTrue.Type); } else if (ifFalse.Type.IsAssignableFrom(ifTrue.Type)) { ifTrue = Ast.Convert(ifTrue, ifFalse.Type); } else { ifTrue = AstUtils.Box(ifTrue); ifFalse = AstUtils.Box(ifFalse); } } return(Ast.Condition(test, ifTrue, ifFalse)); }
private DynamicMetaObject /*!*/ MakeConvertRuleForCall(DynamicMetaObjectBinder /*!*/ convertToAction, Type toType, DynamicMetaObject /*!*/ self, string name, string returner, Func <DynamicMetaObject> fallback, Func <Expression, Expression> resultConverter) { PythonType pt = ((IPythonObject)self.Value).PythonType; PythonTypeSlot pts; CodeContext context = PythonContext.GetPythonContext(convertToAction).SharedContext; ValidationInfo valInfo = BindingHelpers.GetValidationInfo(this, pt); if (pt.TryResolveSlot(context, name, out pts) && !IsBuiltinConversion(context, pts, name, pt)) { ParameterExpression tmp = Ast.Variable(typeof(object), "func"); Expression callExpr = resultConverter( Ast.Call( PythonOps.GetConversionHelper(returner, GetResultKind(convertToAction)), Ast.Dynamic( PythonContext.GetPythonContext(convertToAction).InvokeNone, typeof(object), PythonContext.GetCodeContext(convertToAction), tmp ) ) ); if (typeof(Extensible <>).MakeGenericType(toType).IsAssignableFrom(self.GetLimitType())) { // if we're doing a conversion to the underlying type and we're an // Extensible<T> of that type: // if an extensible type returns it's self in a conversion, then we need // to actually return the underlying value. If an extensible just keeps // returning more instances of it's self a stack overflow occurs - both // behaviors match CPython. callExpr = AstUtils.Convert(AddExtensibleSelfCheck(convertToAction, toType, self, callExpr), typeof(object)); } return(BindingHelpers.AddDynamicTestAndDefer( convertToAction, new DynamicMetaObject( Ast.Condition( MakeTryGetTypeMember( PythonContext.GetPythonContext(convertToAction), pts, self.Expression, tmp ), callExpr, AstUtils.Convert( ConversionFallback(convertToAction), typeof(object) ) ), self.Restrict(self.GetRuntimeType()).Restrictions ), new DynamicMetaObject[] { this }, valInfo, tmp )); } return(fallback()); }
internal DynamicMetaObject FallbackConvert(Type returnType, DynamicMetaObject self, DynamicMetaObject errorSuggestion) { Type type = Type; DynamicMetaObject res = null; switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: res = MakeToBoolConversion(self); break; case TypeCode.Char: res = TryToCharConversion(self); break; case TypeCode.String: if (self.GetLimitType() == typeof(Bytes) && !_context.PythonOptions.Python30) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeString"), AstUtils.Convert(self.Expression, typeof(IList <byte>)) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(Bytes)) ); } break; case TypeCode.Object: // !!! Deferral? if (type.IsArray && self.Value is PythonTuple && type.GetArrayRank() == 1) { res = MakeToArrayConversion(self, type); } else if (type.IsGenericType && !type.IsAssignableFrom(CompilerHelpers.GetType(self.Value))) { Type genTo = type.GetGenericTypeDefinition(); // Interface conversion helpers... if (genTo == typeof(IList <>)) { if (self.LimitType == typeof(string)) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeByteArray"), AstUtils.Convert(self.Expression, typeof(string)) ), BindingRestrictions.GetTypeRestriction( self.Expression, typeof(string) ) ); } else { res = TryToGenericInterfaceConversion(self, type, typeof(IList <object>), typeof(ListGenericWrapper <>)); } } else if (genTo == typeof(IDictionary <,>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IDictionary <object, object>), typeof(DictionaryGenericWrapper <,>)); } else if (genTo == typeof(IEnumerable <>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IEnumerable), typeof(IEnumerableOfTWrapper <>)); } } else if (type == typeof(IEnumerable)) { if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = ConvertToIEnumerable(this, self.Restrict(self.GetLimitType())); } } else if (type == typeof(IEnumerator)) { if (!typeof(IEnumerator).IsAssignableFrom(self.GetLimitType()) && !typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = ConvertToIEnumerator(this, self.Restrict(self.GetLimitType())); } } break; } if (type.IsEnum && Enum.GetUnderlyingType(type) == self.GetLimitType()) { // numeric type to enum, this is ok if the value is zero object value = Activator.CreateInstance(type); return(new DynamicMetaObject( Ast.Condition( Ast.Equal( AstUtils.Convert(self.Expression, Enum.GetUnderlyingType(type)), AstUtils.Constant(Activator.CreateInstance(self.GetLimitType())) ), AstUtils.Constant(value), Ast.Call( typeof(PythonOps).GetMethod("TypeErrorForBadEnumConversion").MakeGenericMethod(type), AstUtils.Convert(self.Expression, typeof(object)) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())), value )); } return(res ?? EnsureReturnType(returnType, Context.Binder.ConvertTo(Type, ResultKind, self, _context.SharedOverloadResolverFactory, errorSuggestion))); }
private DynamicMetaObject /*!*/ MakeDynamicMemberAccess(DynamicMetaObjectBinder /*!*/ member, string /*!*/ name, MemberAccess access, DynamicMetaObject /*!*/[] /*!*/ args) { DynamicMetaObject self = Restrict(typeof(OldInstance)); Expression target; ParameterExpression tmp = Ast.Variable(typeof(object), "result"); switch (access) { case MemberAccess.Invoke: target = Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceTryGetBoundCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name) ) ), typeof(OperationFailed) ) ), ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(tmp, BindingRestrictions.Empty), args, null).Expression, AstUtils.Convert( ((InvokeMemberBinder)member).FallbackInvokeMember(this, args).Expression, typeof(object) ) ) ); break; case MemberAccess.Get: target = Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceTryGetBoundCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name) ) ), typeof(OperationFailed) ) ), tmp, AstUtils.Convert( FallbackGet(member, args), typeof(object) ) ) ); break; case MemberAccess.Set: target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceSetCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name), AstUtils.Convert(args[1].Expression, typeof(object)) ); break; case MemberAccess.Delete: target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDeleteCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name) ); break; default: throw new InvalidOperationException(); } return(new DynamicMetaObject( target, self.Restrictions.Merge(BindingRestrictions.Combine(args)) )); }