/// <summary> /// When overridden in the derived class, performs the binding of the dynamic create operation if the target dynamic object cannot bind. /// </summary> /// <param name="target">The target of the dynamic create operation.</param> /// <param name="args">The arguments of the dynamic create operation.</param> /// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param> /// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> public abstract DynamicMetaObject FallbackCreateInstance(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion);
public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion) { // First try COM binding. if (ComBinder.TryBindInvoke(this, target, args, out var result)) { return(result); } // Defer if any object has no value so that we evaulate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue || Array.Exists(args, a => !a.HasValue)) { var deferArgs = new DynamicMetaObject[args.Length + 1]; deferArgs[0] = target; args.CopyTo(deferArgs.AsSpan(1)); return(Defer(deferArgs)); } // Find our own binding. if (!target.LimitType.IsSubclassOf(typeof(Delegate))) { return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), typeof(InvalidOperationException), $"Wrong number of arguments for function -- {target.LimitType} got {args}")); } var parameters = target.LimitType.GetMethod("Invoke") !.GetParameters(); if (parameters.Length != args.Length) { return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), typeof(InvalidOperationException), $"Wrong number of arguments for function -- {target.LimitType} got {args}")); } // Don't need to check if argument types match parameters. If they don't, users // get an argument conversion error. var callArgs = RuntimeHelpers.ConvertArguments(args, parameters); var expression = Expression.Invoke(Expression.Convert(target.Expression, target.LimitType), callArgs); return(new DynamicMetaObject(RuntimeHelpers.EnsureObjectResult(expression), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); }
/// <summary> /// When overridden in the derived class, performs the binding of the dynamic delete index operation if the target dynamic object cannot bind. /// </summary> /// <param name="target">The target of the dynamic delete index operation.</param> /// <param name="indexes">The arguments of the dynamic delete index operation.</param> /// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param> /// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> public abstract DynamicMetaObject FallbackDeleteIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject?errorSuggestion);
/// <summary> /// Performs the binding of the dynamic invoke operation if the target dynamic object cannot bind. /// </summary> /// <param name="target">The target of the dynamic invoke operation.</param> /// <param name="args">The arguments of the dynamic invoke operation.</param> /// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param> /// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> public abstract DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion);
/// <summary> /// When overridden in the derived class, performs the binding of the dynamic convert operation if the target dynamic /// object cannot bind. /// </summary> /// <param name="target">The target of the dynamic convert operation.</param> /// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param> /// <returns>The <see cref="DynamicMetaObject" /> representing the result of the binding.</returns> public abstract DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject?errorSuggestion);
public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject?errorSuggestion) { // First try COM binding. if (ComBinder.TryBindSetMember(this, target, value, out var result)) { return(result); } // Defer if any object has no value so that we evaluate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue) { return(Defer(target)); } // Find our own binding. var members = target.LimitType.GetMember(Name, BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); if (members.Length == 1) { var mem = members[0]; Expression val; switch (mem.MemberType) { // Should check for member domain type being Type and value being TypeModel, similar // to ConvertArguments, and building an expression like GetRuntimeTypeMoFromModel. case MemberTypes.Property: val = Expression.Convert(value.Expression, ((PropertyInfo)mem).PropertyType); break; case MemberTypes.Field: val = Expression.Convert(value.Expression, ((FieldInfo)mem).FieldType); break; default: return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, null, BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), typeof(InvalidOperationException), "Sympl only supports setting Properties and fields at this time.")); } return(new DynamicMetaObject( // Assign returns the stored value, so we're good for Sympl. RuntimeHelpers.EnsureObjectResult(Expression.Assign( Expression.MakeMemberAccess(Expression.Convert(target.Expression, members[0].DeclaringType !), members[0]), val)), // Don't need restriction test for name since this rule is only used where binder // is used, which is only used in sites with this binder.Name. BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } else { return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, null, BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), typeof(MissingMemberException), "IDynObj member name conflict.")); } }
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject?errorSuggestion) { // First try COM binding. if (ComBinder.TryBindGetMember(this, target, out var result, true)) { return(result); } // Defer if any object has no value so that we evaluate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue) { return(Defer(target)); } // Find our own binding. var members = target.LimitType.GetMember(Name, BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); return(members.Length == 1 ? new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult(Expression.MakeMemberAccess( Expression.Convert(target.Expression, members[0].DeclaringType !), members[0])), // Don't need restriction test for name since this rule is only used where binder // is used, which is only used in sites with this binder.Name. BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)) : errorSuggestion ?? RuntimeHelpers.CreateThrow(target, null, BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), typeof(MissingMemberException), $"cannot bind member, {Name}, on object {target.Value}")); }
/// <summary> /// When overridden in the derived class, performs the binding of the dynamic get member operation if the target dynamic object cannot bind. /// </summary> /// <param name="target">The target of the dynamic get member operation.</param> /// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param> /// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> public abstract DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject?errorSuggestion);
public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion) { // First try COM binding. if (ComBinder.TryBindInvokeMember(this, target, args, out var result)) { return(result); } // Defer if any object has no value so that we evaluate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue || Array.Exists(args, a => !a.HasValue)) { var deferArgs = new DynamicMetaObject[args.Length + 1]; deferArgs[0] = target; args.CopyTo(deferArgs.AsSpan(1)); return(Defer(deferArgs)); } // Find our own binding. Could consider allowing invoking static members from an instance. var members = target.LimitType.GetMember(Name, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public); if (members.Length == 1 && (members[0] is PropertyInfo || members[0] is FieldInfo)) { // NEED TO TEST, should check for delegate value too // var mem = members[0]; throw new NotImplementedException(); //return new DynamicMetaObject( // Expression.Dynamic( // new SymplInvokeBinder(new CallInfo(args.Length)), // typeof(object), // args.Select(a => a.Expression).AddFirst( // Expression.MakeMemberAccess(this.Expression, mem))); // Don't test for eventinfos since we do nothing with them now. } else { // Get MethodInfos with param types that work for args. This works except for value // args that need to pass to reftype params. We could detect that to be smarter and // then explicitly StrongBox the args. var res = Array.FindAll(members, meth => meth is MethodInfo m && m.GetParameters().Length == args.Length && RuntimeHelpers.ParametersMatchArguments(m.GetParameters(), args)); // False below means generate a type restriction on the MO. We are looking at the // members targetMO's Type. var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(target, args, false); if (res.Length == 0) { return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, restrictions, typeof(MissingMemberException), $"Can't bind member invoke -- {args}")); } // restrictions and conversion must be done consistently. var callArgs = RuntimeHelpers.ConvertArguments(args, ((MethodInfo)res[0]).GetParameters()); return(new DynamicMetaObject(RuntimeHelpers.EnsureObjectResult(Expression.Call(Expression.Convert(target.Expression, target.LimitType), (MethodInfo)res[0], callArgs)), restrictions)); // Could hve tried just letting expression.Call factory do the work, but if there is more // than one applicable method using just assignablefrom, expression.Call throws. It does // not pick a "most applicable" method or any method. } }
public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion) { var argExpressions = new Expression[args.Length + 1]; for (var i = 0; i < args.Length; i++) { argExpressions[i + 1] = args[i].Expression; } argExpressions[0] = target.Expression; // Just "defer" since we have code in SymplInvokeBinder that knows what to do, and // typically this fallback is from a language like Python that passes a DynamicMetaObject // with HasValue == false. return(new DynamicMetaObject(Expression.Dynamic( // This call site doesn't share any L2 caching since we don't call // GetInvokeBinder from Sympl. We aren't plumbed to get the runtime instance here. new SymplInvokeBinder(new CallInfo(args.Length)), typeof(Object), // ret type argExpressions), // No new restrictions since SymplInvokeBinder will handle it. target.Restrictions.Merge(BindingRestrictions.Combine(args)))); }
public override DynamicMetaObject FallbackCreateInstance(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion) { // Defer if any object has no value so that we evaluate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue || Array.Exists(args, a => !a.HasValue)) { var deferArgs = new DynamicMetaObject[args.Length + 1]; deferArgs[0] = target; args.CopyTo(deferArgs.AsSpan(1)); return(Defer(deferArgs)); } // Make sure target actually contains a Type. if (!typeof(Type).IsAssignableFrom(target.LimitType)) { return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, BindingRestrictions.Empty, typeof(InvalidOperationException), $"Type object must be used when creating instance -- {args}")); } var type = target.Value as Type; Debug.Assert(type is not null); var constructors = type.GetConstructors(); // Get constructors with right arg counts. var res = Array.FindAll(constructors, c => c.GetParameters().Length == args.Length && RuntimeHelpers.ParametersMatchArguments(c.GetParameters(), args)); // We generate an instance restriction on the target since it is a Type and the // constructor is associate with the actual Type instance. var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(target, args, true); if (res.Length == 0) { return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, restrictions, typeof(MissingMemberException), $"Can't bind create instance -- {args}")); } var ctorArgs = RuntimeHelpers.ConvertArguments(args, res[0].GetParameters()); return(new DynamicMetaObject( // Creating an object, so don't need EnsureObjectResult. Expression.New(res[0], ctorArgs), restrictions)); }
FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject?errorSuggestion) => errorSuggestion ?? RuntimeHelpers.CreateThrow(target, null, BindingRestrictions.Empty, typeof(MissingMemberException), "If IDynObj doesn't support setting members, DOHelpers can't do it for the IDO.");
FallbackGetMember(DynamicMetaObject target, DynamicMetaObject?errorSuggestion) => errorSuggestion ?? new DynamicMetaObject(Expression.Constant(Sentinel), target.Restrictions.Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)));
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject?errorSuggestion) { var instance = Expression.Call( DynamicGetMemberMethod, target.Expression, Expression.Constant(Name), Expression.Constant(IgnoreCase)); return(DynamicMetaObject.Create(target.Value !, instance)); }
public override DynamicMetaObject FallbackSetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject value, DynamicMetaObject?errorSuggestion) { // First try COM binding. if (ComBinder.TryBindSetIndex(this, target, indexes, value, out var result)) { return(result); } // Defer if any object has no value so that we evaulate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue || !value.HasValue || Array.Exists(indexes, a => !a.HasValue)) { var deferArgs = new DynamicMetaObject[indexes.Length + 2]; indexes.CopyTo(deferArgs.AsSpan(1)); deferArgs[0] = target; deferArgs[^ 1] = value;
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject?errorSuggestion) { throw new NotSupportedException(); }
public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject?errorSuggestion) { // Defer if any object has no value so that we evaluate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue || !arg.HasValue) { return(Defer(target, arg)); } var restrictions = target.Restrictions.Merge(arg.Restrictions) .Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)) .Merge(BindingRestrictions.GetTypeRestriction(arg.Expression, arg.LimitType)); return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult(Expression.MakeBinary(Operation, Expression.Convert(target.Expression, target.LimitType), Expression.Convert(arg.Expression, arg.LimitType))), restrictions)); }
/// <summary> /// When overridden in the derived class, performs the binding of the dynamic set index operation if the target dynamic object cannot bind. /// </summary> /// <param name="target">The target of the dynamic set index operation.</param> /// <param name="indexes">The arguments of the dynamic set index operation.</param> /// <param name="value">The value to set to the collection.</param> /// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param> /// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> public abstract DynamicMetaObject FallbackSetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject value, DynamicMetaObject?errorSuggestion);
public override DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion) { // First try COM binding. if (ComBinder.TryBindGetIndex(this, target, args, out var result)) { return(result); } // Defer if any object has no value so that we evaulate their Expressions and nest a // CallSite for the InvokeMember. if (!target.HasValue || Array.Exists(args, a => !a.HasValue)) { var deferArgs = new DynamicMetaObject[args.Length + 1]; deferArgs[0] = target; args.CopyTo(deferArgs.AsSpan(1)); return(Defer(deferArgs)); } // Give good error for Cons. if (target.LimitType == typeof(Cons)) { if (args.Length != 1) { return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, BindingRestrictions.Empty, typeof(InvalidOperationException), $"Indexing list takes single index. Got {args.Length}")); } } // Find our own binding. // Conversions created in GetIndexExpression must be consistent with restrictions made in GetTargetArgsRestrictions. var indexingExpr = RuntimeHelpers.EnsureObjectResult(RuntimeHelpers.GetIndexingExpression(target, args)); var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(target, args, false); return(new DynamicMetaObject(indexingExpr, restrictions)); }
/// <summary> /// When overridden in the derived class, performs the binding of the binary dynamic operation if the target dynamic object cannot bind. /// </summary> /// <param name="target">The target of the dynamic binary operation.</param> /// <param name="arg">The right hand side operand of the dynamic binary operation.</param> /// <param name="errorSuggestion">The binding result in case the binding fails, or null.</param> /// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> public abstract DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject?errorSuggestion);
public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject?errorSuggestion) => // Defer if any object has no value so that we evaluate their Expressions and nest a // CallSite for the InvokeMember. target.HasValue ? new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult(Expression.MakeUnary(Operation, Expression.Convert(target.Expression, target.LimitType), target.LimitType)), target.Restrictions.Merge( BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))) : Defer(target);