public override DynamicMetaObject /*!*/ FallbackInvoke(DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args, DynamicMetaObject errorSuggestion) { // Used in combination with GetMember to compose InvokeMember operation. // Gets here only if the target is not a callable meta-object. var metaBuilder = new MetaObjectBuilder(this, target, args); var callArgs = new CallArguments(_context, target, args, CallInfo); metaBuilder.AddTypeRestriction(target.GetLimitType(), target.Expression); RubyOverloadResolver.NormalizeArguments(metaBuilder, callArgs, 0, 0); if (!metaBuilder.Error) { // no arguments => just return the target: metaBuilder.Result = target.Expression; } else { // any arguments found (expected none): metaBuilder.SetMetaResult(errorSuggestion, false); } return(metaBuilder.CreateMetaObject(this)); }
internal static bool TryBuildConversionToDelegate(MetaObjectBuilder /*!*/ metaBuilder, RubyMetaObject /*!*/ target, Type /*!*/ delegateType, MethodInfo /*!*/ delegateFactory) { if (!typeof(Delegate).IsAssignableFrom(delegateType) || delegateType.GetMethod("Invoke") == null) { return(false); } var type = target.Value.GetType(); metaBuilder.AddTypeRestriction(type, target.Expression); metaBuilder.Result = delegateFactory.OpCall(AstUtils.Constant(delegateType), Ast.Convert(target.Expression, type)); return(true); }
internal static void BuildConversion(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { const string ToS = "to_s"; if (TryImplicitConversion(metaBuilder, args)) { metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); return; } RubyMemberInfo conversionMethod, methodMissing = null; RubyClass targetClass = args.RubyContext.GetImmediateClassOf(args.Target); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext, new[] { ToS, Symbols.MethodMissing } ); conversionMethod = targetClass.ResolveMethodForSiteNoLock(ToS, VisibilityContext.AllVisible).Info; // find method_missing - we need to add "to_s" method to the missing methods table: if (conversionMethod == null) { methodMissing = targetClass.ResolveMethodMissingForSite(ToS, RubyMethodVisibility.None); } } // invoke target.to_s and if successful convert the result to string unless it is already: if (conversionMethod != null) { conversionMethod.BuildCall(metaBuilder, args, ToS); } else { RubyCallAction.BuildMethodMissingCall(metaBuilder, args, ToS, methodMissing, RubyMethodVisibility.None, false, true); } if (metaBuilder.Error) { return; } metaBuilder.Result = Methods.ToSDefaultConversion.OpCall( AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), AstUtils.Box(args.TargetExpression), AstUtils.Box(metaBuilder.Result) ); }
protected override void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { const string ToS = "to_s"; // no conversion for a subclass of string: var stringTarget = args.Target as MutableString; if (stringTarget != null) { metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(MutableString)); return; } RubyMemberInfo conversionMethod, methodMissing = null; RubyClass targetClass = args.RubyContext.GetImmediateClassOf(args.Target); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext); conversionMethod = targetClass.ResolveMethodForSiteNoLock(ToS, RubyClass.IgnoreVisibility).Info; // find method_missing - we need to add "to_xxx" methods to the missing methods table: if (conversionMethod == null) { methodMissing = targetClass.ResolveMethodMissingForSite(ToS, RubyMethodVisibility.None); } } // invoke target.to_s and if successful convert the result to string unless it is already: if (conversionMethod != null) { conversionMethod.BuildCall(metaBuilder, args, ToS); if (metaBuilder.Error) { return; } } else { RubyCallAction.BindToMethodMissing(metaBuilder, args, ToS, methodMissing, RubyMethodVisibility.None, false, true); } metaBuilder.Result = Methods.ToSDefaultConversion.OpCall( AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), AstFactory.Box(args.TargetExpression), AstFactory.Box(metaBuilder.Result) ); }
public override DynamicMetaObject/*!*/ FallbackInvoke(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, DynamicMetaObject errorSuggestion) { // Used in combination with GetMember to compose InvokeMember operation. // Gets here only if the target is not a callable meta-object. var metaBuilder = new MetaObjectBuilder(this, target, args); var callArgs = new CallArguments(_context, target, args, CallInfo); metaBuilder.AddTypeRestriction(target.GetLimitType(), target.Expression); var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, callArgs, 0, 0); if (!metaBuilder.Error) { // no arguments => just return the target: metaBuilder.Result = target.Expression; } else { // any arguments found (expected none): metaBuilder.SetMetaResult(errorSuggestion, false); } return metaBuilder.CreateMetaObject(this); }
internal void BuildInvoke(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { Assert.NotNull(metaBuilder, args); var convertedTarget = AstUtils.Convert(args.TargetExpression, typeof(Proc)); // test for target type: metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); BuildCall( metaBuilder, convertedTarget, // proc object Methods.GetProcSelf.OpCall(convertedTarget), // self captured by the block closure args ); }
internal void SetRule(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { Assert.NotNull(metaBuilder, args); Debug.Assert(args.SimpleArgumentCount == 0 && !args.Signature.HasBlock && !args.Signature.HasSplattedArgument && !args.Signature.HasRhsArgument); Debug.Assert(args.Signature.HasScope); var ec = args.RubyContext; // implicit conversions should only depend on a static type: if (TryImplicitConversion(metaBuilder, args)) { if (args.Target == null) { metaBuilder.AddRestriction(Ast.Equal(args.TargetExpression, Ast.Constant(null, args.TargetExpression.Type))); } else { metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); } return; } // check for type version: metaBuilder.AddTargetTypeTest(args); string toMethodName = ToMethodName; Expression targetClassNameConstant = Ast.Constant(ec.GetClassOf(args.Target).Name); // Kernel#respond_to? method is not overridden => we can optimize RubyMemberInfo respondToMethod = ec.ResolveMethod(args.Target, Symbols.RespondTo, true).InvalidateSitesOnOverride(); if (respondToMethod == null || // the method is defined in library, hasn't been replaced by user defined method (TODO: maybe we should make this check better) (respondToMethod.DeclaringModule == ec.KernelModule && respondToMethod is RubyMethodGroupInfo)) { RubyMemberInfo conversionMethod = ec.ResolveMethod(args.Target, toMethodName, false).InvalidateSitesOnOverride(); if (conversionMethod == null) { // error: SetError(metaBuilder, targetClassNameConstant, args); return; } else { // invoke target.to_xxx() and validate it; returns an instance of TTargetType: conversionMethod.BuildCall(metaBuilder, args, toMethodName); if (!metaBuilder.Error && ConversionResultValidator != null) { metaBuilder.Result = ConversionResultValidator.OpCall(targetClassNameConstant, AstFactory.Box(metaBuilder.Result)); } return; } } else if (!RubyModule.IsMethodVisible(respondToMethod, false)) { // respond_to? is private: SetError(metaBuilder, targetClassNameConstant, args); return; } // slow path: invoke respond_to?, to_xxx and result validation: var conversionCallSite = Ast.Dynamic( RubyCallAction.Make(toMethodName, RubyCallSignature.WithScope(0)), typeof(object), args.ScopeExpression, args.TargetExpression ); Expression opCall; metaBuilder.Result = Ast.Condition( // If // respond_to?() Methods.IsTrue.OpCall( Ast.Dynamic( RubyCallAction.Make(Symbols.RespondTo, RubyCallSignature.WithScope(1)), typeof(object), args.ScopeExpression, args.TargetExpression, Ast.Constant(SymbolTable.StringToId(toMethodName)) ) ), // Then // to_xxx(): opCall = (ConversionResultValidator == null) ? conversionCallSite : ConversionResultValidator.OpCall(targetClassNameConstant, conversionCallSite), // Else AstUtils.Convert( (ConversionResultValidator == null) ? args.TargetExpression : Ast.Convert( Ast.Throw(Methods.CreateTypeConversionError.OpCall(targetClassNameConstant, Ast.Constant(TargetTypeName))), typeof(object) ), opCall.Type ) ); }
private Expression/*!*/ MarshalArgument(MetaObjectBuilder/*!*/ metaBuilder, DynamicMetaObject/*!*/ arg, ArgType parameterType) { object value = arg.Value; if (value == null) { metaBuilder.AddRestriction(Ast.Equal(arg.Expression, AstUtils.Constant(null))); } else { metaBuilder.AddTypeRestriction(value.GetType(), arg.Expression); } switch (parameterType) { case ArgType.Buffer: if (value == null) { return AstUtils.Constant(null, typeof(byte[])); } if (value is int && (int)value == 0) { metaBuilder.AddRestriction(Ast.Equal(AstUtils.Convert(arg.Expression, typeof(int)), AstUtils.Constant(0))); return AstUtils.Constant(null, typeof(byte[])); } if (value.GetType() == typeof(MutableString)) { return Methods.GetMutableStringBytes.OpCall( AstUtils.Convert(arg.Expression, typeof(MutableString)) ); } return Methods.GetMutableStringBytes.OpCall( AstUtils.LightDynamic(ConvertToStrAction.Make(_context), typeof(MutableString), arg.Expression) ); case ArgType.Int32: if (value is int) { return AstUtils.Convert(arg.Expression, typeof(int)); } return Ast.Convert( Ast.Call( AstUtils.LightDynamic(ConvertToIntAction.Make(_context), typeof(IntegerValue), arg.Expression), Methods.IntegerValue_ToUInt32Unchecked ), typeof(int) ); } throw Assert.Unreachable; }
/// <summary> /// "yields" to the proc. /// </summary> internal void BuildInvoke(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { Assert.NotNull(metaBuilder, args); Debug.Assert(!args.Signature.HasBlock); var convertedTarget = AstUtils.Convert(args.TargetExpression, typeof(BlockParam)); // test for target type: metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); metaBuilder.Result = AstFactory.YieldExpression( args.GetSimpleArgumentExpressions(), args.GetSplattedArgumentExpression(), args.GetRhsArgumentExpression(), convertedTarget, // block param Ast.Property(convertedTarget, SelfProperty) // self ); }
internal static bool TryBuildConversionToDelegate(MetaObjectBuilder/*!*/ metaBuilder, RubyMetaObject/*!*/ metaTarget, Type/*!*/ delegateType, MethodInfo/*!*/ delegateFactory) { MethodInfo invoke; if (!typeof(Delegate).IsAssignableFrom(delegateType) || (invoke = delegateType.GetMethod("Invoke")) == null) { return false; } var type = metaTarget.Value.GetType(); metaBuilder.AddTypeRestriction(type, metaTarget.Expression); metaBuilder.Result = delegateFactory.OpCall(AstUtils.Constant(delegateType), Ast.Convert(metaTarget.Expression, type)); return true; }
internal static void SetCallActionRule(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool testTarget) { Assert.NotNull(metaBuilder, args); var convertedTarget = AstUtils.Convert(args.TargetExpression, typeof(Proc)); // test for target type: if (testTarget) { metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); } SetProcCallRule( metaBuilder, convertedTarget, // proc object Ast.Property(convertedTarget, SelfProperty), // self captured by the block closure null, args ); }