/// <summary> /// Creates a new BindingTarget when the method binding has succeeded /// </summary> internal BindingTarget(string name, int actualArgumentCount, MethodTarget target, NarrowingLevel level, MetaObject[] restrictedArgs) { _name = name; _target = target; _restrictedArgs = restrictedArgs; _level = level; _actualArgs = actualArgumentCount; }
public static bool TryBindInvokeMember(InvokeMemberBinder binder, ref MetaObject instance, MetaObject[] args) { if (TryGetMetaObject(ref instance)) { instance = instance.BindInvokeMember(binder, args); return true; } return false; }
private MetaObject[] GetArguments(MetaObject[] args, IList<MetaObject> results, int metaBinderIndex) { BinderMappingInfo indices = _metaBinders[metaBinderIndex]; MetaObject[] res = new MetaObject[indices.MappingInfo.Count]; for (int i = 0; i < res.Length; i++) { ParameterMappingInfo mappingInfo = indices.MappingInfo[i]; if (mappingInfo.IsAction) { // input is the result of a previous bind res[i] = results[mappingInfo.ActionIndex]; } else if (mappingInfo.IsParameter) { // input is one of the original arguments res[i] = args[mappingInfo.ParameterIndex]; } else { // input is a constant res[i] = new MetaObject( mappingInfo.Constant, Restrictions.Empty, mappingInfo.Constant.Value ); } } return res; }
public static bool TryBindSetIndex(SetIndexBinder binder, ref MetaObject instance, MetaObject[] args, MetaObject value) { if (TryGetMetaObject(ref instance)) { instance = instance.BindSetIndex(binder, args, value); return true; } return false; }
public override MetaObject BindInvokeMember(InvokeMemberBinder binder, MetaObject[] args) { ContractUtils.RequiresNotNull(binder, "binder"); if (args.Any(arg => ComBinderHelpers.IsStrongBoxArg(arg))) { return ComBinderHelpers.RewriteStrongBoxAsRef(binder, this, args); } ComMethodDesc methodDesc; if (_wrapperType.Funcs.TryGetValue(binder.Name, out methodDesc) || _self.TryGetMemberMethodExplicit(binder.Name, out methodDesc)) { return new ComInvokeBinder( binder.Arguments, args, IDispatchRestriction(), Expression.Constant(methodDesc), Expression.Property( Expression.Convert(Expression, typeof(IDispatchComObject)), typeof(IDispatchComObject).GetProperty("DispatchObject") ), methodDesc ).Invoke(); } return base.BindInvokeMember(binder, args); }
public static bool TryBindSetMember(SetMemberBinder binder, ref MetaObject instance, MetaObject value) { if (TryGetMetaObject(ref instance)) { instance = instance.BindSetMember(binder, value); return true; } return false; }
public sealed override MetaObject Bind(MetaObject target, MetaObject[] args) { ContractUtils.RequiresNotNull(target, "target"); ContractUtils.RequiresNotNullItems(args, "args"); ContractUtils.Requires(args.Length == 1); return target.BindSetMember(this, args[0]); }
public sealed override Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel) { if (args.Length == 0) { throw new InvalidOperationException(); } MetaObject[] mos; if (args.Length != 1) { mos = new MetaObject[args.Length - 1]; for (int i = 1; i < args.Length; i++) { mos[i - 1] = MetaObject.ObjectToMetaObject(args[i], parameters[i]); } } else { mos = MetaObject.EmptyMetaObjects; } MetaObject binding = Bind( MetaObject.ObjectToMetaObject(args[0], parameters[0]), mos ); if (binding == null) { throw Error.BindingCannotBeNull(); } return GetMetaObjectRule(binding, returnLabel); }
/// <summary> /// Builds a MetaObject for performing a member get. Supports all built-in .NET members, the OperatorMethod /// GetBoundMember, and StrongBox instances. /// </summary> /// <param name="name"> /// The name of the member to retrieve. This name is not processed by the DefaultBinder and /// is instead handed off to the GetMember API which can do name mangling, case insensitive lookups, etc... /// </param> /// <param name="target"> /// The MetaObject from which the member is retrieved. /// </param> /// <param name="codeContext"> /// An expression which provides access to the CodeContext if its required for /// accessing the member (e.g. for an extension property which takes CodeContext). By default this /// a null CodeContext object is passed. /// </param> public MetaObject GetMember(string name, MetaObject target, Expression codeContext) { return GetMember( name, target, codeContext, false ); }
public override MetaObject/*!*/ FallbackGetMember(MetaObject/*!*/ self, MetaObject/*!*/ onBindingError) { var result = TryBind(_context, this, self); if (result != null) { return result; } // TODO: remove CodeContext return ((DefaultBinder)_context.Binder).GetMember(Name, self, Ast.Constant(null, typeof(CodeContext)), true); }
/// <summary> /// Checks if the conversion can be handled by a simple cast. /// </summary> private static MetaObject TryAssignableConversion(Type toType, Type type, Restrictions restrictions, MetaObject arg) { if (toType.IsAssignableFrom(type) || (type == typeof(Null) && (toType.IsClass || toType.IsInterface))) { // MakeSimpleConversionTarget handles the ConversionResultKind check return MakeSimpleConversionTarget(toType, restrictions, arg); } return null; }
/// <summary> /// Checks if any conversions are available and if so builds the target for that conversion. /// </summary> private MetaObject TryAllConversions(Type toType, ConversionResultKind kind, Type knownType, Restrictions restrictions, MetaObject arg) { return TryAssignableConversion(toType, knownType, restrictions, arg) ?? // known type -> known type TryExtensibleConversion(toType, knownType, restrictions, arg) ?? // Extensible<T> -> Extensible<T>.Value TryUserDefinedConversion(kind, toType, knownType, restrictions, arg) ?? // op_Implicit TryImplicitNumericConversion(toType, knownType, restrictions, arg) ?? // op_Implicit TryNullableConversion(toType, kind, knownType, restrictions, arg) ?? // null -> Nullable<T> or T -> Nullable<T> TryNullConversion(toType, knownType, restrictions); // null -> reference type }
public override MetaObject/*!*/ FallbackInvokeMember(MetaObject/*!*/ self, MetaObject/*!*/[]/*!*/ args, MetaObject/*!*/ onBindingError) { var result = TryBind(_context, this, self, args); if (result != null) { return result; } // TODO: return ((DefaultBinder)_context.Binder).GetMember(Name, self, Ast.Null(typeof(CodeContext)), true); throw new NotImplementedException(); }
public override MetaObject BindSetIndex(SetIndexBinder binder, MetaObject[] indexes, MetaObject value) { if (_callable.ComMethodDesc.IsPropertyPut) { if (indexes.Any(arg => ComBinderHelpers.IsStrongBoxArg(arg))) { return ComBinderHelpers.RewriteStrongBoxAsRef(binder, this, indexes.AddLast(value)); } return BindComInvoke(binder.Arguments, indexes.AddLast(value)); } return base.BindSetIndex(binder, indexes, value); }
/// <summary> /// Checks if the conversion is to object and produces a target if it is. /// </summary> private static MetaObject TryConvertToObject(Type toType, Type knownType, MetaObject arg) { if (toType == typeof(object)) { if (knownType.IsValueType) { return MakeBoxingTarget(arg); } else { return arg; } } return null; }
public override MetaObject/*!*/ FallbackCreateInstance(MetaObject/*!*/ target, MetaObject/*!*/[]/*!*/ args, MetaObject errorSuggestion) { var result = TryBind(_context, this, target, args); if (result != null) { return result; } throw new NotImplementedException(); // TODO: //return ((DefaultBinder)_context.Binder).Create(.GetMember(Name, self, Ast.Null(typeof(CodeContext)), true); }
/// <summary> /// Builds a MetaObject for performing a member delete. Supports all built-in .NET members, the OperatorMethod /// DeleteMember, and StrongBox instances. /// </summary> public MetaObject DeleteMember(string name, MetaObject target) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); return DeleteMember( name, target, Ast.Constant(null, typeof(CodeContext)) ); }
private MetaObject MakeComparisonRule(OperatorInfo info, Expression codeContext, MetaObject[] args) { return TryComparisonMethod(info, codeContext, args[0], args) ?? // check the first type if it has an applicable method TryComparisonMethod(info, codeContext, args[0], args) ?? // then check the second type TryNumericComparison(info, args) ?? // try Compare: cmp(x,y) (>, <, >=, <=, ==, !=) 0 TryInvertedComparison(info, args[0], args) ?? // try inverting the operator & result (e.g. if looking for Equals try NotEquals, LessThan for GreaterThan)... TryInvertedComparison(info, args[0], args) ?? // inverted binding on the 2nd type TryNullComparisonRule(args) ?? // see if we're comparing to null w/ an object ref or a Nullable<T> TryPrimitiveCompare(info, args) ?? // see if this is a primitive type where we're comparing the two values. MakeOperatorError(info, args); // no comparisons are possible }
/// <summary> /// Creates the MetaObject for indexing directly into arrays or indexing into objects which have /// default members. Returns null if we're not an indexing operation. /// </summary> private MetaObject MakeDefaultMemberRule(string oper, MetaObject[] args) { if (oper == StandardOperators.GetItem || oper == StandardOperators.SetItem) { if (args[0].LimitType.IsArray) { return MakeArrayIndexRule(oper, args); } return MakeMethodIndexRule(oper, args); } return null; }
public override MetaObject BindCreateInstance(CreateInstanceBinder binder, MetaObject[] args) { return new MetaObject( Expression.Call( AstUtils.Convert(Expression, typeof(ComTypeClassDesc)), typeof(ComTypeClassDesc).GetMethod("CreateInstance") ), Restrictions.Combine(args).Merge( Restrictions.GetTypeRestriction(Expression, typeof(ComTypeClassDesc)) ) ); }
/// <summary> /// Creates the meta object for the rest of the operations: comparisons and all other /// operators. If the operation cannot be completed a MetaObject which indicates an /// error will be returned. /// </summary> private MetaObject MakeGeneralOperatorRule(string operation, Expression codeContext, MetaObject[] args) { OperatorInfo info = OperatorInfo.GetOperatorInfo(operation); MetaObject res; if (CompilerHelpers.IsComparisonOperator(operation)) { res = MakeComparisonRule(info, codeContext, args); } else { res = MakeOperatorRule(info, codeContext, args); } return res; }
/// <summary> /// Builds a MetaObject for performing a member get. Supports all built-in .NET members, the OperatorMethod /// GetBoundMember, and StrongBox instances. /// </summary> /// <param name="name"> /// The name of the member to retrieve. This name is not processed by the DefaultBinder and /// is instead handed off to the GetMember API which can do name mangling, case insensitive lookups, etc... /// </param> /// <param name="target"> /// The MetaObject from which the member is retrieved. /// </param> /// <param name="value"> /// The value being assigned to the target member. /// </param> /// <param name="codeContext"> /// An expression which provides access to the CodeContext if its required for /// accessing the member (e.g. for an extension property which takes CodeContext). By default this /// a null CodeContext object is passed. /// </param> public MetaObject SetMember(string name, MetaObject target, MetaObject value, Expression codeContext) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); ContractUtils.RequiresNotNull(value, "value"); ContractUtils.RequiresNotNull(codeContext, "codeContext"); return MakeSetMemberTarget( new SetOrDeleteMemberInfo(name, codeContext), target, value ); }
public MetaObject DeleteMember(string name, MetaObject target, Expression codeContext) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); return MakeDeleteMemberTarget( new SetOrDeleteMemberInfo( name, codeContext ), target.Restrict(target.LimitType) ); }
public sealed override MetaObject Bind(MetaObject target, MetaObject[] args) { ContractUtils.RequiresNotNull(target, "target"); ContractUtils.RequiresNotNullItems(args, "args"); // Try to call BindOperation var emo = target as OperationMetaObject; if (emo != null) { return emo.BindOperation(this, args); } // Otherwise just fall back (it's as if they didn't override BindOperation) return FallbackOperation(target, args); }
/// <summary> /// Provides default binding for performing a call on the specified meta objects. /// </summary> /// <param name="signature">The signature describing the call</param> /// <param name="target">The meta object to be called.</param> /// <param name="args"> /// Additional meta objects are the parameters for the call as specified by the CallSignature in the CallAction. /// </param> /// <param name="parameterBinder">ParameterBinder used to map arguments to parameters.</param> /// <returns>A MetaObject representing the call or the error.</returns> public MetaObject Call(CallSignature signature, ParameterBinder parameterBinder, MetaObject target, params MetaObject[] args) { ContractUtils.RequiresNotNullItems(args, "args"); ContractUtils.RequiresNotNull(parameterBinder, "parameterBinder"); TargetInfo targetInfo = GetTargetInfo(signature, target, args); if (targetInfo != null) { // we're calling a well-known MethodBase return MakeMetaMethodCall(signature, parameterBinder, targetInfo); } else { // we can't call this object return MakeCannotCallRule(target, target.LimitType); } }
internal static MetaObject RewriteStrongBoxAsRef(CallSiteBinder action, MetaObject target, MetaObject[] args) { Debug.Assert(action != null && target != null && args != null); var restrictions = target.Restrictions.Merge(Restrictions.Combine(args)); Expression[] argExpressions = new Expression[args.Length + 1]; Type[] signatureTypes = new Type[args.Length + 3]; // args + CallSite, target, returnType signatureTypes[0] = typeof(CallSite); //TODO: we are not restricting on target type here, but in theory we could. //It is a tradeoff between rule reuse and higher polymorphism of the site. argExpressions[0] = target.Expression; signatureTypes[1] = target.Expression.Type; for (int i = 0; i < args.Length; i++) { MetaObject currArgument = args[i]; if (IsStrongBoxArg(currArgument)) { restrictions = restrictions.Merge(Restrictions.GetTypeRestriction(currArgument.Expression, currArgument.LimitType)); // we have restricted this argument to LimitType so we can convert and conversion will be trivial cast. Expression boxedValueAccessor = Expression.Field( Helpers.Convert( currArgument.Expression, currArgument.LimitType ), currArgument.LimitType.GetField("Value") ); argExpressions[i + 1] = boxedValueAccessor; signatureTypes[i + 2] = boxedValueAccessor.Type.MakeByRefType(); } else { argExpressions[i + 1] = currArgument.Expression; signatureTypes[i + 2] = currArgument.Expression.Type; } } // Last signatureType is the return value signatureTypes[signatureTypes.Length - 1] = typeof(object); return new MetaObject( Expression.MakeDynamic( Expression.GetDelegateType(signatureTypes), action, argExpressions ), restrictions ); }
public MetaObject Defer(MetaObject target, params MetaObject[] args) { ContractUtils.RequiresNotNull(target, "target"); if (args == null) { return MakeDeferred( target.Restrictions, target ); } else { return MakeDeferred( target.Restrictions.Merge(Restrictions.Combine(args)), args.AddFirst(target) ); } }
public override MetaObject/*!*/ BindInvoke(InvokeBinder/*!*/ action, MetaObject/*!*/[]/*!*/ args) { RubyCallSignature callSignature; if (RubyCallSignature.TryCreate(action.Arguments, out callSignature)) { return action.FallbackInvoke(this, args); } var context = new MetaObject( Methods.GetContextFromProc.OpCall(AstUtils.Convert(Expression, typeof(Proc))), Restrictions.Empty, RubyOps.GetContextFromProc((Proc)Value) ); var metaBuilder = new MetaObjectBuilder(); Proc.SetCallActionRule(metaBuilder, new CallArguments(context, this, args, callSignature), true); return metaBuilder.CreateMetaObject(action, args); }
public static MetaObject TryBind(RubyContext/*!*/ context, CreateInstanceBinder/*!*/ binder, MetaObject/*!*/ target, MetaObject/*!*/[]/*!*/ args) { Assert.NotNull(context, binder, target, args); var metaBuilder = new MetaObjectBuilder(); RubyCallAction.Bind(metaBuilder, "new", new CallArguments( new MetaObject(Ast.Constant(context), Restrictions.Empty, context), target, args, RubyCallSignature.Simple(args.Length) ) ); // TODO: we should return null if we fail, we need to throw exception due to version update optimization: return metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects); }
public static MetaObject TryBind(RubyContext/*!*/ context, GetMemberBinder/*!*/ binder, MetaObject/*!*/ target) { Assert.NotNull(context, target); var metaBuilder = new MetaObjectBuilder(); var contextExpression = Ast.Constant(context); metaBuilder.AddTargetTypeTest(target.Value, target.Expression, context, contextExpression); RubyMemberInfo method = context.ResolveMethod(target.Value, binder.Name, true).InvalidateSitesOnOverride(); if (method != null && RubyModule.IsMethodVisible(method, false)) { // we need to create a bound member: metaBuilder.Result = Ast.Constant(new RubyMethod(target.Value, method, binder.Name)); } else { // TODO: // We need to throw an exception if we don't find method_missing so that our version update optimization works: // This limits interop with other languages. // // class B CLR type with method 'foo' // class C < B Ruby class // x = C.new // // 1. x.GET("foo") from Ruby // No method found or CLR method found -> fallback to Python // Python might see its method foo or might just fallback to .NET, // in any case it will add rule [1] with restriction on type of C w/o Ruby version check. // 2. B.define_method("foo") // This doesn't update C due to the optimization (there is no overridden method foo in C). // 3. x.GET("foo") from Ruby // This will not invoke the binder since the rule [1] is still valid. // object symbol = SymbolTable.StringToId(binder.Name); RubyCallAction.BindToMethodMissing(metaBuilder, binder.Name, new CallArguments( new MetaObject(contextExpression, Restrictions.Empty, context), new[] { target, new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol) }, RubyCallSignature.Simple(1) ), method != null ); } // TODO: we should return null if we fail, we need to throw exception for now: return metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects); }
public MetaObject FallbackDeleteIndex(MetaObject target, MetaObject[] indexes) { return(FallbackDeleteIndex(target, indexes, null)); }
public MetaObject FallbackConvert(MetaObject target) { return(FallbackConvert(target, null)); }
public MetaObject FallbackBinaryOperation(MetaObject target, MetaObject arg) { return(FallbackBinaryOperation(target, arg, null)); }
public abstract MetaObject FallbackDeleteIndex(MetaObject target, MetaObject[] indexes, MetaObject errorSuggestion);