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 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 ); }
private void BuildCall(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { var actualArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue); if (metaBuilder.Error) { return; } metaBuilder.AddRestriction( Ast.Equal( Ast.Property(Ast.Convert(args.TargetExpression, typeof(Win32API)), VersionProperty), Ast.Constant(_version) ) ); if (_function == IntPtr.Zero) { metaBuilder.SetError(Ast.Throw(new Func <Exception>(UninitializedFunctionError).Method.OpCall(), typeof(object))); return; } if (_signature.Length != actualArgs.Count) { metaBuilder.SetError(Ast.Throw(new Func <int, int, Exception>(InvalidParameterCountError).Method.OpCall( Ast.Constant(_signature.Length), Ast.Constant(actualArgs.Count)), typeof(object) )); return; } var calliArgs = new AstExpressions(); calliArgs.Add(Ast.Property(Ast.Convert(args.TargetExpression, typeof(Win32API)), FunctionProperty)); for (int i = 0; i < actualArgs.Count; i++) { calliArgs.Add(MarshalArgument(metaBuilder, actualArgs[i], _signature[i])); } metaBuilder.Result = Ast.Call(EmitCalliStub(), calliArgs); // MRI returns 0 if void return type is given: if (_returnType == ArgType.None) { metaBuilder.Result = Ast.Block(metaBuilder.Result, AstUtils.Constant(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); }
/// <summary> /// OldCallAction on Proc target. /// From control flow perspective it "yields" to the proc. /// </summary> internal void SetCallActionRule(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 ); }
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); }
public override MetaObject /*!*/ BindInvoke(InvokeBinder /*!*/ action, MetaObject /*!*/[] /*!*/ args) { RubyCallSignature callSignature; if (RubyCallSignature.TryCreate(action.Arguments, out callSignature)) { return(action.FallbackInvoke(this, args)); } var metaBuilder = new MetaObjectBuilder(); var context = new MetaObject( Methods.GetContextFromBlockParam.OpCall(AstUtils.Convert(Expression, typeof(BlockParam))), Restrictions.Empty, RubyOps.GetContextFromBlockParam((BlockParam)Value) ); BlockParam.SetCallActionRule(metaBuilder, new CallArguments(context, this, args, callSignature)); return(metaBuilder.CreateMetaObject(action, args)); }
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 ); }
public void OverloadResolution_Block1() { var scope = Context.EmptyScope; var proc = new Proc(ProcKind.Proc, null, scope, new BlockDispatcher0(BlockSignatureAttributes.None, null, 0). SetMethod(new BlockCallTarget0((x, y) => null))); var arguments = new[] { // 1.times new CallArguments(Context, MO(scope), new[] { MO(1) }, RubyCallSignature.WithScope(0)), // 1.times &nil new CallArguments(Context, MO(scope), new[] { MO(1), MO(null) }, RubyCallSignature.WithScopeAndBlock(0)), // 1.times &p new CallArguments(Context, MO(1), new[] { MO(proc) }, RubyCallSignature.WithBlock(0)), // obj.times &p new CallArguments(Context, MO("foo"), new[] { MO(proc) }, RubyCallSignature.WithBlock(0)), }; var results = new[] { "Times2", "Times1", "Times3", "Times4", }; var metaBuilder = new MetaObjectBuilder(null); for (int i = 0; i < arguments.Length; i++) { RubyOverloadResolver resolver; var methods = GetStaticMethodsStartingWith(typeof(OverloadsWithBlock), "Times"); var bindingTarget = RubyMethodGroupInfo.ResolveOverload( metaBuilder, arguments[i], "times", methods, SelfCallConvention.SelfIsParameter, false, out resolver ); Assert(bindingTarget.Success); Assert(bindingTarget.Overload.Name == results[i]); } }
private static void BuildOverriddenInitializerCall(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, RubyMemberInfo /*!*/ initializer) { var instanceExpr = metaBuilder.Result; metaBuilder.Result = null; var instanceVariable = metaBuilder.GetTemporary(instanceExpr.Type, "#instance"); // We know an exact type of the new instance and that there is no singleton for that instance. // We also have the exact method we need to call ("initialize" is a RubyMethodInfo). // => no tests are necessary: args.SetTarget(instanceVariable, null); if (initializer is RubyMethodInfo) { initializer.BuildCall(metaBuilder, args, Symbols.Initialize); } else { // TODO: we need more refactoring of RubyMethodGroupInfo.BuildCall to be able to inline this: metaBuilder.Result = Ast.Dynamic( RubyCallAction.Make("initialize", new RubyCallSignature(args.Signature.ArgumentCount, args.Signature.Flags | RubyCallFlags.HasImplicitSelf) ), typeof(object), args.GetCallSiteArguments(instanceVariable) ); } if (!metaBuilder.Error) { // PropagateRetrySingleton(instance = new <type>(), instance.initialize(<args>)) metaBuilder.Result = Methods.PropagateRetrySingleton.OpCall( Ast.Assign(instanceVariable, instanceExpr), metaBuilder.Result ); RubyMethodInfo.ApplyBlockFlowHandlingInternal(metaBuilder, args); } }
/// <summary> /// From control flow perspective it "calls" the proc. /// </summary> internal static void BuildCall( MetaObjectBuilder /*!*/ metaBuilder, Expression /*!*/ procExpression, // proc object Expression /*!*/ selfExpression, // self passed to the proc CallArguments /*!*/ args // user arguments passed to the proc ) { var bfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc"); metaBuilder.Result = Ast.Block( Ast.Assign(bfcVariable, Methods.CreateBfcForProcCall.OpCall(AstUtils.Convert(procExpression, typeof(Proc)))), Methods.MethodProcCall.OpCall(bfcVariable, AstFactory.YieldExpression( args.RubyContext, args.GetSimpleArgumentExpressions(), args.GetSplattedArgumentExpression(), args.GetRhsArgumentExpression(), bfcVariable, selfExpression ) ) ); }
internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { return(TryImplicitConversionInternal(metaBuilder, args)); }
protected virtual void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType) { metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(targetClassNameConstant, AstUtils.Constant(TargetTypeName))); }
internal protected abstract bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args);
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) ); } }
protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback) { Debug.Assert(defaultFallback, "custom fallback not supported"); BuildConversion(metaBuilder, args, ReturnType, this); return(true); }
internal override void BuildInvoke(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { args.InsertMethodName(_methodNameArg); base.BuildInvoke(metaBuilder, args); }
internal protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { object target = args.Target; return(target != null && (metaBuilder.Result = Convert(ReturnType, args)) != null); }
public DeferredTypeProxy(MetaObjectBuilder builder) { _name = builder.Name; }
public static MetaTypeProxy Create(MetaObjectBuilder builder) { Check.ArgumentNotNull(builder, "builder"); return new DeferredTypeProxy(builder); }
// 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)); }
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); } }
// 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); }
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); }