/// <summary> /// Adds a dynamic test which checks if the version has changed. The test is only necessary for /// performance as the methods will do the correct thing if called with an incorrect version. /// </summary> private Expression AddDynamicTestAndDefer(MetaObjectBinder binder, MetaObject[] args, ExpandoClass klass, ExpandoClass originalClass, Expression ifTestSucceeds) { if (originalClass != null) { // we are accessing a member which has not yet been defined on this class. // We force a class promotion after the type check. If the class changes the // promotion will fail and the set/delete will do a full lookup using the new // class to discover the name. Debug.Assert(originalClass != klass); ifTestSucceeds = Expression.Block( Expression.Call( null, typeof(RuntimeOps).GetMethod("ExpandoPromoteClass"), GetLimitedSelf(), Expression.Constant(originalClass), Expression.Constant(klass) ), ifTestSucceeds ); } return(Expression.Condition( Expression.Call( null, typeof(RuntimeOps).GetMethod("ExpandoCheckVersion"), GetLimitedSelf(), Expression.Constant(originalClass ?? klass) ), ifTestSucceeds, binder.Defer(args).Expression )); }
/// <summary> /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic, but uses one of the arguments for /// the result. /// </summary> private MetaObject CallMethodNoResult(string methodName, MetaObjectBinder binder, Expression[] args, Fallback fallback) { // // First, call fallback to do default binding // This produces either an error or a call to a .NET member // MetaObject fallbackResult = fallback(null); // // Build a new expression like: // TryDeleteMember(payload) ? null : fallbackResult // var callDynamic = new MetaObject( Expression.Condition( Expression.Call( GetLimitedSelf(), typeof(DynamicObject).GetMethod(methodName), args.AddFirst(Constant(binder)) ), Expression.Constant(null), Expression.Convert(fallbackResult.Expression, typeof(object)) ), GetRestrictions().Merge(fallbackResult.Restrictions) ); // // Now, call fallback again using our new MO as the error // When we do this, one of two things can happen: // 1. Binding will succeed, and it will ignore our call to // the dynamic method, OR // 2. Binding will fail, and it will use the MO we created // above. // return(fallback(callDynamic)); }
private static ConstantExpression Constant(MetaObjectBinder binder) { Type t = binder.GetType(); while (!t.IsVisible) { t = t.BaseType; } return(Expression.Constant(binder, t)); }
/// <summary> /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic that returns a result /// </summary> private MetaObject CallMethodWithResult(string methodName, MetaObjectBinder binder, Expression[] args, Fallback fallback) { // // First, call fallback to do default binding // This produces either an error or a call to a .NET member // MetaObject fallbackResult = fallback(null); // // Build a new expression like: // { // object result; // TryGetMember(payload, out result) ? result : fallbackResult // } // var result = Expression.Parameter(typeof(object), null); var callArgs = new Expression[args.Length + 2]; Array.Copy(args, 0, callArgs, 1, args.Length); callArgs[0] = Constant(binder); callArgs[callArgs.Length - 1] = result; var callDynamic = new MetaObject( Expression.Block( new[] { result }, Expression.Condition( Expression.Call( GetLimitedSelf(), typeof(DynamicObject).GetMethod(methodName), callArgs ), result, Expression.Convert(fallbackResult.Expression, typeof(object)) ) ), GetRestrictions().Merge(fallbackResult.Restrictions) ); // // Now, call fallback again using our new MO as the error // When we do this, one of two things can happen: // 1. Binding will succeed, and it will ignore our call to // the dynamic method, OR // 2. Binding will fail, and it will use the MO we created // above. // return(fallback(callDynamic)); }
internal MetaObject/*!*/ CreateMetaObject(MetaObjectBinder/*!*/ action, MetaObject/*!*/[]/*!*/ siteArgs) { var expr = _error ? Ast.Throw(_result) : _result; Restrictions restrictions; if (_condition != null) { var deferral = action.Defer(siteArgs); expr = Ast.Condition(_condition, AstUtils.Convert(expr, typeof(object)), deferral.Expression); restrictions = deferral.Restrictions; } else { restrictions = Restrictions.Empty; } if (_temps != null) { expr = Ast.Block(_temps, expr); } if (_restriction != null) { restrictions = restrictions.Merge(Restrictions.GetExpressionRestriction(_restriction)); } return new MetaObject(expr, restrictions); }
/// <summary> /// Adds a dynamic test which checks if the version has changed. The test is only necessary for /// performance as the methods will do the correct thing if called with an incorrect version. /// </summary> private Expression AddDynamicTestAndDefer(MetaObjectBinder binder, MetaObject[] args, ExpandoClass klass, ExpandoClass originalClass, Expression ifTestSucceeds) { if (originalClass != null) { // we are accessing a member which has not yet been defined on this class. // We force a class promotion after the type check. If the class changes the // promotion will fail and the set/delete will do a full lookup using the new // class to discover the name. Debug.Assert(originalClass != klass); ifTestSucceeds = Expression.Block( Expression.Call( null, typeof(RuntimeOps).GetMethod("ExpandoPromoteClass"), GetLimitedSelf(), Expression.Constant(originalClass), Expression.Constant(klass) ), ifTestSucceeds ); } return Expression.Condition( Expression.Call( null, typeof(RuntimeOps).GetMethod("ExpandoCheckVersion"), GetLimitedSelf(), Expression.Constant(originalClass ?? klass) ), ifTestSucceeds, binder.Defer(args).Expression ); }
public BinderMappingInfo(MetaObjectBinder binder, params ParameterMappingInfo[] mappingInfos) : this(binder, (IList<ParameterMappingInfo>)mappingInfos) { }
public BinderMappingInfo(MetaObjectBinder binder, IList<ParameterMappingInfo> mappingInfo) { Binder = binder; MappingInfo = mappingInfo; }
/// <summary> /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic, but uses one of the arguments for /// the result. /// </summary> private MetaObject CallMethodNoResult(string methodName, MetaObjectBinder binder, Expression[] args, Fallback fallback) { // // First, call fallback to do default binding // This produces either an error or a call to a .NET member // MetaObject fallbackResult = fallback(null); // // Build a new expression like: // TryDeleteMember(payload) ? null : fallbackResult // var callDynamic = new MetaObject( Expression.Condition( Expression.Call( GetLimitedSelf(), typeof(DynamicObject).GetMethod(methodName), args.AddFirst(Constant(binder)) ), Expression.Constant(null), Expression.Convert(fallbackResult.Expression, typeof(object)) ), GetRestrictions().Merge(fallbackResult.Restrictions) ); // // Now, call fallback again using our new MO as the error // When we do this, one of two things can happen: // 1. Binding will succeed, and it will ignore our call to // the dynamic method, OR // 2. Binding will fail, and it will use the MO we created // above. // return fallback(callDynamic); }
/// <summary> /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic that returns a result /// </summary> private MetaObject CallMethodWithResult(string methodName, MetaObjectBinder binder, Expression[] args, Fallback fallback) { // // First, call fallback to do default binding // This produces either an error or a call to a .NET member // MetaObject fallbackResult = fallback(null); // // Build a new expression like: // { // object result; // TryGetMember(payload, out result) ? result : fallbackResult // } // var result = Expression.Parameter(typeof(object), null); var callArgs = new Expression[args.Length + 2]; Array.Copy(args, 0, callArgs, 1, args.Length); callArgs[0] = Constant(binder); callArgs[callArgs.Length - 1] = result; var callDynamic = new MetaObject( Expression.Block( new[] { result }, Expression.Condition( Expression.Call( GetLimitedSelf(), typeof(DynamicObject).GetMethod(methodName), callArgs ), result, Expression.Convert(fallbackResult.Expression, typeof(object)) ) ), GetRestrictions().Merge(fallbackResult.Restrictions) ); // // Now, call fallback again using our new MO as the error // When we do this, one of two things can happen: // 1. Binding will succeed, and it will ignore our call to // the dynamic method, OR // 2. Binding will fail, and it will use the MO we created // above. // return fallback(callDynamic); }
private static ConstantExpression Constant(MetaObjectBinder binder) { Type t = binder.GetType(); while (!t.IsVisible) { t = t.BaseType; } return Expression.Constant(binder, t); }
internal MetaObject/*!*/ CreateMetaObject(MetaObjectBinder/*!*/ action, MetaObject/*!*/ context, MetaObject/*!*/[]/*!*/ args) { return CreateMetaObject(action, ArrayUtils.Insert(context, args)); }