Example #1
0
 protected override Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result)
 {
     return(AstUtils.LightDynamic(ConvertToStrAction.Make(args.RubyContext), AstUtils.Box(result)));
 }
Example #2
0
        protected internal override bool TryImplicitConversion(MetaObjectBuilder metaBuilder, CallArguments args)
        {
            if (base.TryImplicitConversion(metaBuilder, args))
            {
                return(true);
            }

            var convertedTarget = args.Target as RubySymbol;

            if (convertedTarget != null)
            {
                metaBuilder.Result = Methods.ConvertSymbolToMutableString.OpCall(AstUtils.Convert(args.TargetExpression, typeof(RubySymbol)));
                return(true);
            }
            return(false);
        }
Example #3
0
        internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            if (args.Target == null)
            {
                metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(AstUtils.Constant("nil"), AstUtils.Constant(TargetTypeName)));
                return(true);
            }

            metaBuilder.Result =
                ImplicitConvert(typeof(int), args) ??
                ImplicitConvert(typeof(BigInteger), args);

            return(metaBuilder.Result != null);
        }
Example #4
0
        protected internal override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            // *nil -> [nil]
            if (args.Target == null)
            {
                metaBuilder.Result = Methods.MakeArray1.OpCall(AstUtils.Constant(null));
                return(true);
            }

            var convertedTarget = args.Target as IList;

            if (convertedTarget != null)
            {
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(IList));
                return(true);
            }
            return(false);
        }
Example #5
0
        internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            object target = args.Target;

            if (target == null)
            {
                metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(AstUtils.Constant("nil"), AstUtils.Constant(TargetTypeName)));
                return(true);
            }

            return((metaBuilder.Result = Convert(ReturnType, args)) != null);
        }
Example #6
0
 // return null if the object doesn't handle the conversion:
 protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     return(AstUtils.Constant(null, resultType));
 }
Example #7
0
        internal static void BuildConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Type /*!*/ resultType,
                                             params ProtocolConversionAction /*!*/[] /*!*/ conversions)
        {
            Assert.NotNull(metaBuilder, args, conversions);
            Debug.Assert(args.SimpleArgumentCount == 0 && !args.Signature.HasBlock && !args.Signature.HasSplattedArgument && !args.Signature.HasRhsArgument);
            Debug.Assert(!args.Signature.HasScope);

            // implicit conversions should only depend on the static type:
            foreach (var conversion in conversions)
            {
                if (conversion.TryImplicitConversion(metaBuilder, args))
                {
                    metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression);

                    if (!metaBuilder.Error)
                    {
                        metaBuilder.Result = ConvertResult(metaBuilder.Result, resultType);
                    }
                    return;
                }
            }

            RubyClass                targetClass = args.RubyContext.GetImmediateClassOf(args.Target);
            Expression               targetClassNameConstant = AstUtils.Constant(targetClass.GetNonSingletonClass().Name, typeof(string));
            MethodResolutionResult   respondToMethod, methodMissing = MethodResolutionResult.NotFound;
            ProtocolConversionAction selectedConversion = null;
            RubyMemberInfo           conversionMethod   = null;

            using (targetClass.Context.ClassHierarchyLocker()) {
                // check for type version:
                metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext,
                                              ArrayUtils.Insert(Symbols.RespondTo, Symbols.MethodMissing, ArrayUtils.ConvertAll(conversions, (c) => c.ToMethodName))
                                              );

                // we can optimize if Kernel#respond_to? method is not overridden:
                respondToMethod = targetClass.ResolveMethodForSiteNoLock(Symbols.RespondTo, VisibilityContext.AllVisible);
                if (respondToMethod.Found && respondToMethod.Info.DeclaringModule == targetClass.Context.KernelModule && respondToMethod.Info is RubyLibraryMethodInfo)   // TODO: better override detection
                {
                    respondToMethod = MethodResolutionResult.NotFound;

                    // get the first applicable conversion:
                    foreach (var conversion in conversions)
                    {
                        selectedConversion = conversion;
                        conversionMethod   = targetClass.ResolveMethodForSiteNoLock(conversion.ToMethodName, VisibilityContext.AllVisible).Info;
                        if (conversionMethod != null)
                        {
                            break;
                        }
                        else
                        {
                            // find method_missing - we need to add "to_xxx" methods to the missing methods table:
                            if (!methodMissing.Found)
                            {
                                methodMissing = targetClass.ResolveMethodNoLock(Symbols.MethodMissing, VisibilityContext.AllVisible);
                            }
                            methodMissing.InvalidateSitesOnMissingMethodAddition(conversion.ToMethodName, targetClass.Context);
                        }
                    }
                }
            }

            if (!respondToMethod.Found)
            {
                if (conversionMethod == null)
                {
                    // error:
                    selectedConversion.SetError(metaBuilder, args, targetClassNameConstant, resultType);
                    return;
                }
                else
                {
                    // invoke target.to_xxx() and validate it; returns an instance of TTargetType:
                    conversionMethod.BuildCall(metaBuilder, args, selectedConversion.ToMethodName);

                    if (!metaBuilder.Error)
                    {
                        metaBuilder.Result = ConvertResult(
                            selectedConversion.MakeValidatorCall(args, targetClassNameConstant, metaBuilder.Result),
                            resultType
                            );
                    }
                    return;
                }
            }

            // slow path: invoke respond_to?, to_xxx and result validation:
            for (int i = conversions.Length - 1; i >= 0; i--)
            {
                string toMethodName = conversions[i].ToMethodName;

                var conversionCallSite = AstUtils.LightDynamic(
                    RubyCallAction.Make(args.RubyContext, toMethodName, RubyCallSignature.WithImplicitSelf(0)),
                    args.TargetExpression
                    );

                metaBuilder.Result = Ast.Condition(
                    // If

                    // respond_to?()
                    Methods.IsTrue.OpCall(
                        AstUtils.LightDynamic(
                            RubyCallAction.Make(args.RubyContext, Symbols.RespondTo, RubyCallSignature.WithImplicitSelf(1)),
                            args.TargetExpression,
                            Ast.Constant(args.RubyContext.CreateSymbol(toMethodName, RubyEncoding.Binary))
                            )
                        ),

                    // Then

                    // to_xxx():
                    ConvertResult(
                        conversions[i].MakeValidatorCall(args, targetClassNameConstant, conversionCallSite),
                        resultType
                        ),

                    // Else

                    (i < conversions.Length - 1) ? metaBuilder.Result :
                    conversions[i].MakeErrorExpression(args, targetClassNameConstant, resultType)
                    );
            }
        }
Example #8
0
 // return the target object on error:
 protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     return(Ast.Convert(Methods.MakeArray1.OpCall(AstUtils.Box(args.TargetExpression)), typeof(IList)));
 }
Example #9
0
 internal static Expression ExplicitConvert(Type /*!*/ toType, CallArguments /*!*/ args)
 {
     return(Converter.ExplicitConvert(args.TargetExpression, CompilerHelpers.GetType(args.Target), toType));
 }
Example #10
0
 protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback)
 {
     Debug.Assert(defaultFallback, "custom fallback not supported");
     BuildConversion(metaBuilder, args, ReturnType, this);
     return(true);
 }
Example #11
0
        public void OverloadResolution_Numeric1()
        {
            var metaBuilder = new MetaObjectBuilder(null);

            Context.ObjectClass.SetConstant("X", Context.GetClass(typeof(Overloads1.X)));

            object c   = Engine.Execute(@"class C < X; new; end");
            var    sym = Context.CreateAsciiSymbol("x");
            var    ms  = MutableString.CreateAscii("x");

            var cases = new[] {
                // F
                new { Args = new[] { MO(1) }, Overloads = "F*", Result = "F1" },
                new { Args = new[] { MO((byte)1) }, Overloads = "F*", Result = "F1" },
                new { Args = new[] { MO(1L) }, Overloads = "F*", Result = "F2" },
                new { Args = new[] { MO(1.2F) }, Overloads = "F*", Result = "F3" },

                // G
                new { Args = new[] { MO(1) }, Overloads = "G*", Result = "G1" },
                new { Args = new[] { MO((byte)1) }, Overloads = "G*", Result = "G1" },
                new { Args = new[] { MO(1L) }, Overloads = "G*", Result = "G2" },
                new { Args = new[] { MO(1.2F) }, Overloads = "G*", Result = "G3" },
                new { Args = new[] { MO(c) }, Overloads = "G*", Result = "G1" },

                // I
                new { Args = new[] { MO(c) }, Overloads = "I*", Result = "I3" },

                // J
                new { Args = new[] { MO(1) }, Overloads = "J*", Result = "J1" },
                new { Args = new[] { MO((BigInteger)1000) }, Overloads = "J*", Result = "J2" },
                new { Args = new[] { MO((byte)12) }, Overloads = "J*", Result = "J1" },
                new { Args = new[] { MO(c) }, Overloads = "J*", Result = "J3" },
                new { Args = new[] { MO(1.0) }, Overloads = "J*", Result = "J3" },

                // K
                new { Args = new[] { MO(1) }, Overloads = "K*", Result = "K2" },
                new { Args = new[] { MO(c) }, Overloads = "K*", Result = "K1" },
                new { Args = new[] { MO("x") }, Overloads = "K*", Result = "K1" },

                // L
                new { Args = new[] { MO(sym), MO(sym) }, Overloads = "L*", Result = "L1" },
                new { Args = new[] { MO("x"), MO(sym) }, Overloads = "L*", Result = "L2" },
                new { Args = new[] { MO(ms), MO(sym) }, Overloads = "L*", Result = "L3" },
                new { Args = new[] { MO(null), MO(sym) }, Overloads = "L*", Result = "L3" },
                new { Args = new[] { MO(c), MO(sym) }, Overloads = "L*", Result = "L3" },

                // M
                new { Args = new[] { MO(1) }, Overloads = "M*", Result = "M1" },
                new { Args = new[] { MO(Overloads1.E.A) }, Overloads = "M*", Result = "M2" },

                // N
                new { Args = new[] { MO(MutableString.CreateAscii("x")) }, Overloads = "N*", Result = "N1" },
            };

            for (int i = 0; i < cases.Length; i++)
            {
                var args      = new CallArguments(Context, MO(new Overloads1()), cases[i].Args, RubyCallSignature.Simple(cases[i].Args.Length));
                var resolver  = new RubyOverloadResolver(metaBuilder, args, SelfCallConvention.SelfIsInstance, false);
                var overloads = GetInstanceMethods(typeof(Overloads1), cases[i].Overloads);
                var result    = resolver.ResolveOverload(i.ToString(), overloads, NarrowingLevel.None, NarrowingLevel.All);

                Assert(result.Success && result.Overload.Name == cases[i].Result);
            }
        }
Example #12
0
 internal override void BuildInvoke(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
 {
     args.InsertMethodName(_methodNameArg);
     base.BuildInvoke(metaBuilder, args);
 }
Example #13
0
 // return the target object on error:
 protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     return(ToA(args, targetClassNameConstant));
 }
Example #14
0
        internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            if (base.TryImplicitConversion(metaBuilder, args))
            {
                return(true);
            }

            object target           = args.Target;
            var    targetExpression = args.TargetExpression;

            var str = target as MutableString;

            if (str != null)
            {
                metaBuilder.Result = Methods.ConvertMutableStringToClrString.OpCall(AstUtils.Convert(targetExpression, typeof(MutableString)));
                return(true);
            }

            if (target is RubySymbol)
            {
                metaBuilder.Result = Methods.ConvertSymbolToClrString.OpCall(AstUtils.Convert(targetExpression, typeof(RubySymbol)));
                return(true);
            }

            if (target is int)
            {
                metaBuilder.Result = Methods.ConvertRubySymbolToClrString.OpCall(
                    AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)),
                    AstUtils.Convert(targetExpression, typeof(int))
                    );
                return(true);
            }

            return(false);
        }
Example #15
0
 internal protected abstract bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args);
Example #16
0
        protected internal override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            var convertedTarget = args.Target as IList;

            if (convertedTarget != null)
            {
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(IList));
                return(true);
            }
            return(false);
        }
Example #17
0
 protected virtual void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(targetClassNameConstant, AstUtils.Constant(TargetTypeName)));
 }
Example #18
0
 // return the target object on error:
 protected override void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     metaBuilder.Result = Ast.Convert(Methods.MakeArray1.OpCall(AstUtils.Box(args.TargetExpression)), typeof(IList));
 }
Example #19
0
        protected virtual Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result)
        {
            var validator = ConversionResultValidator;

            return((validator != null) ? validator.OpCall(targetClassNameConstant, AstUtils.Box(result)) : result);
        }
Example #20
0
        internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            object target = args.Target;

            return(target != null && (metaBuilder.Result = Convert(ReturnType, args)) != null);
        }
Example #21
0
 internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
 {
     return(TryImplicitConversionInternal(metaBuilder, args));
 }
Example #22
0
 // return null if the object doesn't handle the conversion:
 protected override void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     metaBuilder.Result = AstUtils.Constant(null, resultType);
 }
Example #23
0
        internal static bool TryImplicitConversionInternal(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            if (args.Target == null)
            {
                metaBuilder.Result = AstUtils.Constant(null, typeof(TTargetType));
                return(true);
            }

            var convertedTarget = args.Target as TTargetType;

            if (convertedTarget != null)
            {
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(TTargetType));
                return(true);
            }
            return(false);
        }
 protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback)
 {
     Debug.Assert(defaultFallback, "custom fallback not supported");
     ProtocolConversionAction.BuildConversion(metaBuilder, args, _resultType, _conversions);
     return(true);
 }
Example #25
0
        private static bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            var stringTarget = args.Target as MutableString;

            if (stringTarget != null)
            {
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(MutableString));
                return(true);
            }

            return(false);
        }