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)); }
public override int GetArity() { int minParameters = Int32.MaxValue; int maxParameters = 0; bool hasOptional = false; foreach (OverloadInfo method in MethodBases) { int mandatory, optional; RubyOverloadResolver.GetParameterCount(method, CallConvention, out mandatory, out optional); if (mandatory < minParameters) { minParameters = mandatory; } if (mandatory > maxParameters) { maxParameters = mandatory; } if (!hasOptional && optional > 0) { hasOptional = true; } } if (hasOptional || maxParameters > minParameters) { return(-minParameters - 1); } else { return(minParameters); } }
internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0); if (!metaBuilder.Error) { metaBuilder.Result = Methods.GetInstanceVariable.OpCall( AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)), AstUtils.Box(args.TargetExpression), AstUtils.Constant(InstanceVariableName) ); } }
private bool IsOverloadSignature(OverloadInfo /*!*/ method, Type /*!*/[] /*!*/ parameterTypes) { int firstInfo = RubyOverloadResolver.GetHiddenParameterCount(method, CallConvention); var infos = method.Parameters; if (infos.Count - firstInfo != parameterTypes.Length) { return(false); } for (int i = 0; i < parameterTypes.Length; i++) { if (infos[firstInfo + i].ParameterType != parameterTypes[i]) { return(false); } } return(true); }
internal static BindingTarget /*!*/ ResolveOverload(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name, IList <OverloadInfo> /*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions, out RubyOverloadResolver /*!*/ resolver) { resolver = new RubyOverloadResolver(metaBuilder, args, callConvention, implicitProtocolConversions); var bindingTarget = resolver.ResolveOverload(name, overloads, NarrowingLevel.None, NarrowingLevel.All); bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Overload); // At runtime the BlockParam is created with a new RFC instance that identifies the library method frame as // a proc-converter target of a method unwinder triggered by break from a block. if (args.Signature.HasBlock && calleeHasBlockParam) { metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder; } // add restrictions used for overload resolution: resolver.AddArgumentRestrictions(metaBuilder, bindingTarget); return(bindingTarget); }
private DynamicMetaObject InteropBind(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { // TODO: argument count limit depends on the binder! // TODO: pass block as the last (before RHS arg?) parameter/ignore block if args not accepting block: var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue); if (!metaBuilder.Error) { MethodInfo postConverter; var interopBinder = GetInteropBinder(args.RubyContext, normalizedArgs, out postConverter); if (interopBinder != null) { Type resultType; var result = interopBinder.Bind(args.MetaTarget, ArrayUtils.MakeArray(normalizedArgs)); metaBuilder.SetMetaResult(result, args); if (postConverter != null) { // TODO: do better? var paramType = postConverter.GetParameters()[0].ParameterType; metaBuilder.Result = Ast.Call(null, postConverter, AstUtils.Convert(metaBuilder.Result, paramType)); resultType = postConverter.ReturnType; } else { resultType = interopBinder.ReturnType; } return(metaBuilder.CreateMetaObject(interopBinder, resultType)); } else { // interop protocol not supported for this binder -> ignore IDO and treat it as a CLR object: return(null); } } return(metaBuilder.CreateMetaObject(this)); }
internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType); if (_isSetter) { var actualArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1); if (!metaBuilder.Error) { metaBuilder.Result = Ast.Assign( Ast.Field(instance, _fieldInfo), Converter.ConvertExpression( actualArgs[0].Expression, _fieldInfo.FieldType, args.RubyContext, args.MetaContext.Expression, true ) ); } } else { RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0); if (!metaBuilder.Error) { if (_fieldInfo.IsLiteral) { // TODO: seems like Compiler should correctly handle the literal field case // (if you emit a read to a literal field, you get a NotSupportedExpception from // FieldHandle when we try to emit) metaBuilder.Result = AstUtils.Constant(_fieldInfo.GetValue(null)); } else { metaBuilder.Result = Ast.Field(instance, _fieldInfo); } } } }
internal override void BuildMethodMissingCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { var globalScope = args.TargetClass.GlobalScope; var context = globalScope.Context; if (name.LastCharacter() == '=') { var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1); if (!metaBuilder.Error) { var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); var interopSetter = context.MetaBinderFactory.InteropSetMember(name.Substring(0, name.Length - 1)); metaBuilder.SetMetaResult( interopSetter.Bind( new DynamicMetaObject( scopeVar, BindingRestrictions.Empty, globalScope.Scope ), new[] { normalizedArgs[0] } ), true ); } } else { RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0); Expression errorExpr = metaBuilder.Error ? Ast.Throw(metaBuilder.Result, typeof(object)) : null; var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); var scopeLookupResultVar = metaBuilder.GetTemporary(typeof(object), "#result"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); Expression scopeLookupResultExpr = errorExpr ?? scopeLookupResultVar; Expression fallbackExp; if (name == "scope") { fallbackExp = errorExpr ?? args.TargetExpression; } else { // super(methodName, ...args...) - ignore argument error: args.InsertMethodName(name); fallbackExp = AstUtils.LightDynamic( context.MetaBinderFactory.Call(Symbols.MethodMissing, new RubyCallSignature( args.Signature.ArgumentCount + 1, args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall ) ), typeof(object), args.GetCallSiteArguments(args.TargetExpression) ); } var scopeLookup = Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(context.MetaBinderFactory.InteropTryGetMemberExact(name), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ); string unmanagled = RubyUtils.TryUnmangleMethodName(name); if (unmanagled != null) { scopeLookup = Ast.OrElse( scopeLookup, Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(context.MetaBinderFactory.InteropTryGetMemberExact(unmanagled), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ) ); } metaBuilder.Result = Ast.Condition( scopeLookup, scopeLookupResultExpr, fallbackExp ); } }
internal static BindingTarget/*!*/ ResolveOverload(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, IList<OverloadInfo>/*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions, out RubyOverloadResolver/*!*/ resolver) { resolver = new RubyOverloadResolver(metaBuilder, args, callConvention, implicitProtocolConversions); var bindingTarget = resolver.ResolveOverload(name, overloads, NarrowingLevel.None, NarrowingLevel.All); bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Overload); // At runtime the BlockParam is created with a new RFC instance that identifies the library method frame as // a proc-converter target of a method unwinder triggered by break from a block. if (args.Signature.HasBlock && calleeHasBlockParam) { metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder; } // add restrictions used for overload resolution: resolver.AddArgumentRestrictions(metaBuilder, bindingTarget); return bindingTarget; }
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 = SymbolTable.StringToId("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" }, }; 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.Method.Name == cases[i].Result); } }
internal static BindingTarget/*!*/ ResolveOverload(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, IList<MethodBase>/*!*/ overloads, SelfCallConvention callConvention, out RubyOverloadResolver/*!*/ resolver) { resolver = new RubyOverloadResolver(metaBuilder, args, callConvention); var bindingTarget = resolver.ResolveOverload(name, overloads, NarrowingLevel.None, NarrowingLevel.All); bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Method); // At runtime the BlockParam is created with a new RFC instance that identifies the library method frame as // a proc-converter target of a method unwinder triggered by break from a block. if (args.Signature.HasBlock) { var metaBlock = args.GetMetaBlock(); if (metaBlock.Value != null && calleeHasBlockParam) { Debug.Assert(metaBuilder.BfcVariable != null); metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder; } // Overload resolution might not need to distinguish between nil and non-nil block. // However, we still do since we construct CF only for non-nil blocks. if (metaBlock.Value == null) { metaBuilder.AddRestriction(Ast.Equal(metaBlock.Expression, AstUtils.Constant(null))); } else { // don't need to test the exact type of the Proc since the code is subclass agnostic: metaBuilder.AddRestriction(Ast.NotEqual(metaBlock.Expression, AstUtils.Constant(null))); } } // add restrictions used for overload resolution: resolver.AddArgumentRestrictions(metaBuilder, bindingTarget); return bindingTarget; }