protected override Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result) { return(AstUtils.LightDynamic(ConvertToStrAction.Make(args.RubyContext), AstUtils.Box(result))); }
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); }
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); }
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); }
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); }
// 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)); }
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) ); } }
// 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))); }
internal static Expression ExplicitConvert(Type /*!*/ toType, CallArguments /*!*/ args) { return(Converter.ExplicitConvert(args.TargetExpression, CompilerHelpers.GetType(args.Target), toType)); }
protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback) { Debug.Assert(defaultFallback, "custom fallback not supported"); BuildConversion(metaBuilder, args, ReturnType, this); return(true); }
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); } }
internal override void BuildInvoke(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { args.InsertMethodName(_methodNameArg); base.BuildInvoke(metaBuilder, args); }
// return the target object on error: protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType) { return(ToA(args, targetClassNameConstant)); }
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); }
internal protected abstract bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args);
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); }
protected virtual void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType) { metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(targetClassNameConstant, AstUtils.Constant(TargetTypeName))); }
// 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)); }
protected virtual Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result) { var validator = ConversionResultValidator; return((validator != null) ? validator.OpCall(targetClassNameConstant, AstUtils.Box(result)) : result); }
internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { object target = args.Target; return(target != null && (metaBuilder.Result = Convert(ReturnType, args)) != null); }
internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { return(TryImplicitConversionInternal(metaBuilder, args)); }
// 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); }
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); }
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); }