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 = ((IInteropBinder)interopBinder).ResultType; } return metaBuilder.CreateMetaObject(interopBinder, resultType); } else { metaBuilder.SetError(Ast.New( typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }), Ast.Constant(String.Format("{0} not supported on foreign meta-objects", this)) )); } } 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); } } } }
protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { if (TryImplicitConversion(metaBuilder, args)) { metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression); return true; } // TODO: this is our meta object, should we add IRubyMetaConvertible interface instead of using interop-binder? if (args.Target is IDynamicMetaObjectProvider) { metaBuilder.SetMetaResult(args.MetaTarget.BindConvert(new InteropBinder.Convert(args.RubyContext, _type, true)), false); return true; } if (defaultFallback) { metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression); metaBuilder.SetError(Methods.MakeTypeConversionError.OpCall( args.MetaContext.Expression, AstUtils.Convert(args.TargetExpression, typeof(object)), Ast.Constant(_type) )); return true; } return false; }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { metaBuilder.Result = Methods.GetInstanceVariable.OpCall( args.ScopeExpression, AstFactory.Box(args.TargetExpression), AstUtils.Constant(InstanceVariableName) ); }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { Proc.BuildCall( metaBuilder, AstUtils.Constant(_lambda), // proc object args.TargetExpression, // self args ); }
internal RubyOverloadResolver(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, SelfCallConvention callConvention, bool implicitProtocolConversions) : base(args.RubyContext.Binder) { _args = args; _metaBuilder = metaBuilder; _callConvention = callConvention; _implicitProtocolConversions = implicitProtocolConversions; }
protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { // TODO: this is our meta object, should we add IRubyMetaConvertible interface instead of using interop-binder? if (args.Target is IDynamicMetaObjectProvider) { metaBuilder.SetMetaResult(args.MetaTarget.BindConvert(new InteropBinder.Convert(args.RubyContext, _type, true)), false); return true; } return BuildConversion(metaBuilder, args.MetaTarget, args.MetaContext.Expression, _type, defaultFallback); }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { var visibleOverloads = GetVisibleOverloads(args, MethodBases, false); if (visibleOverloads.Count == 0) { metaBuilder.SetError(Methods.MakeClrProtectedMethodCalledError.OpCall( args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name) )); } else { BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions); } }
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) ); } }
protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; object target; scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target); var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); metaBuilder.AddCondition( Methods.IsSuperCallTarget.OpCall( AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)), AstUtils.Constant(currentDeclaringModule), AstUtils.Constant(currentMethodName), targetExpression ) ); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); RubyMemberInfo method; RubyMemberInfo methodMissing = null; // we need to lock the hierarchy of the target class: var targetClass = scope.RubyContext.GetImmediateClassOf(target); using (targetClass.Context.ClassHierarchyLocker()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback); } return true; }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { var actualArgs = RubyMethodGroupInfo.MakeActualArgs(metaBuilder, args, true, false, false, false); metaBuilder.Result = Methods.SetInstanceVariable.OpCall( AstFactory.Box(actualArgs[0]), AstFactory.Box(actualArgs[1]), args.ScopeExpression, AstUtils.Constant(InstanceVariableName) ); }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { Debug.Assert(!args.Signature.HasBlock); Proc.SetProcCallRule( metaBuilder, Ast.Constant(_lambda), // proc object args.TargetExpression, // self Ast.Constant(this), // this method for super and class_eval args ); }
public override DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ scopeOrContextOrTarget, DynamicMetaObject/*!*/[]/*!*/ args) { var callArgs = new CallArguments(_context, scopeOrContextOrTarget, args, Signature); var metaBuilder = new MetaObjectBuilder(this, args); if (IsForeignMetaObject(callArgs.MetaTarget)) { return InteropBind(metaBuilder, callArgs); } Build(metaBuilder, callArgs, true); return metaBuilder.CreateMetaObject(this); }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { var actualArgs = RubyMethodGroupInfo.NormalizeArguments(metaBuilder, args, SelfCallConvention.NoSelf, false, false); if (actualArgs.Length == 0) { metaBuilder.Result = Methods.GetInstanceVariable.OpCall( args.ScopeExpression, AstFactory.Box(args.TargetExpression), AstUtils.Constant(InstanceVariableName) ); } else { metaBuilder.SetWrongNumberOfArgumentsError(actualArgs.Length, 0); } }
public override DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ context, DynamicMetaObject/*!*/[]/*!*/ args) { var callArgs = new CallArguments(context, args, Signature); // TODO: COM interop if (IsForeignMetaObject(callArgs.MetaTarget)) { return InteropBind(callArgs); } var metaBuilder = new MetaObjectBuilder(); Build(metaBuilder, callArgs); return metaBuilder.CreateMetaObject(this); }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { if (args.Signature.HasBlock) { metaBuilder.Result = Methods.HookupEvent.OpCall( Ast.Convert(Ast.Constant(_eventInfo), typeof(EventInfo)), args.TargetExpression, Ast.Convert(args.GetBlockExpression(), typeof(Proc)) ); } else { // TODO: make error throw new NotImplementedError("no block given"); } }
internal void BuildInvoke(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { Assert.NotNull(metaBuilder, args); Debug.Assert(args.Target == this); // TODO: we could compare infos here: // first argument must be this method: metaBuilder.AddRestriction(Ast.Equal(args.TargetExpression, AstUtils.Constant(this))); // set the target (becomes self in the called method): args.SetTarget(AstUtils.Constant(_target), _target); _info.BuildCall(metaBuilder, args, _name); }
public static DynamicMetaObject/*!*/ Bind(InvokeBinder/*!*/ binder, RubyMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, Action<MetaObjectBuilder, CallArguments>/*!*/ buildInvoke) { RubyCallSignature callSignature; if (RubyCallSignature.TryCreate(binder.CallInfo, out callSignature)) { return binder.FallbackInvoke(target, args); } var callArgs = new CallArguments(target.CreateMetaContext(), target, args, callSignature); var metaBuilder = new MetaObjectBuilder(target, args); buildInvoke(metaBuilder, callArgs); return metaBuilder.CreateMetaObject(binder); }
// Only used if method_missing() is called directly on the main singleton. internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { var globalScope = args.TargetClass.GlobalScope; // TODO: this just calls super for now, so it doesn't look up the scope: metaBuilder.Result = AstUtils.LightDynamic( new RubyCallAction(globalScope.Context, Symbols.MethodMissing, new RubyCallSignature( args.Signature.ArgumentCount, args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall ) ), typeof(object), args.GetCallSiteArguments(args.TargetExpression) ); }
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) ); }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { // TODO: splat, rhs, ... if (args.Signature.ArgumentCount == 0) { if (args.Signature.HasBlock) { metaBuilder.Result = Methods.HookupEvent.OpCall( AstUtils.Constant(this), args.TargetExpression, Ast.Convert(args.GetBlockExpression(), typeof(Proc)) ); } else { metaBuilder.Result = Methods.CreateEvent.OpCall( AstUtils.Constant(this), args.TargetExpression, AstUtils.Constant(name) ); } } else { metaBuilder.SetError(Methods.MakeWrongNumberOfArgumentsError.OpCall(Ast.Constant(args.Signature.ArgumentCount), Ast.Constant(0))); } }
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) ); }
internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { Expression expr = null; Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType); if (_isSetter) { // parameters should be: instance/type, value if (args.SimpleArgumentCount == 0 && args.Signature.HasRhsArgument) { expr = Ast.Assign( Ast.Field(instance, _fieldInfo), Converter.ConvertExpression( args.GetRhsArgumentExpression(), _fieldInfo.FieldType, args.RubyContext, args.MetaContext.Expression, true ) ); } } else { // parameter should be: instance/type if (args.SimpleArgumentCount == 0) { 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) expr = AstUtils.Constant(_fieldInfo.GetValue(null)); } else { expr = Ast.Field(instance, _fieldInfo); } } } if (expr != null) { metaBuilder.Result = expr; } else { metaBuilder.SetError( Methods.MakeInvalidArgumentTypesError.OpCall(AstUtils.Constant(_isSetter ? name + "=" : name)) ); } }
// Returns true if the call was bound (with success or failure), false if fallback should be performed. internal static bool BuildAccess(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args, bool defaultFallback, bool callClrMethods) { RubyMemberInfo methodMissing; var method = Resolve(metaBuilder, methodName, args, out methodMissing); if (method.Found) { if (!callClrMethods && !method.Info.IsRubyMember) { return(false); } if (method.Info.IsDataMember) { method.Info.BuildCall(metaBuilder, args, methodName); } else { metaBuilder.Result = Methods.CreateBoundMember.OpCall( AstUtils.Convert(args.TargetExpression, typeof(object)), Ast.Constant(method.Info, typeof(RubyMemberInfo)), Ast.Constant(methodName) ); } return(true); } else { // Ruby doesn't have "attribute_missing" so we will always use method_missing and return a bound method object: return(BuildMethodMissingAccess(metaBuilder, args, methodName, methodMissing, method.IncompatibleVisibility, false, defaultFallback)); } }
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(RubyMetaBinderFactory.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(RubyMetaBinderFactory.InteropTryGetMemberExact(unmanagled), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ) ); } metaBuilder.Result = Ast.Condition( scopeLookup, scopeLookupResultExpr, fallbackExp ); } }
/// <exception cref="MissingMethodException">The resolved method is Kernel#method_missing.</exception> internal static void Bind(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args) { metaBuilder.AddTargetTypeTest(args); RubyMemberInfo method = args.RubyContext.ResolveMethod(args.Target, methodName, true).InvalidateSitesOnOverride(); if (method != null && RubyModule.IsMethodVisible(method, args.Signature.HasImplicitSelf)) { method.BuildCall(metaBuilder, args, methodName); } else { // insert the method name argument into the args object symbol = SymbolTable.StringToId(methodName); args.InsertSimple(0, new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol)); BindToMethodMissing(metaBuilder, methodName, args, method != null); } }
internal virtual void BuildMethodMissingCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { args.InsertMethodName(name); BuildCallNoFlow(metaBuilder, args, Symbols.MethodMissing); }
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); }
protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)); RubyScope targetScope; int scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope); if (scopeNesting == -1) { metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr)); metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall()); return(true); } object target = targetScope.SelfObject; var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); var assignTarget = Ast.Assign( targetExpression, Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting)) ); if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod) { metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate))); metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall()); return(true); } // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail: metaBuilder.AddInitialization(assignTarget); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); RubyMemberInfo method; RubyMemberInfo methodMissing = null; // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419. // we need to lock the hierarchy of the target class: var targetClass = scope.RubyContext.GetImmediateClassOf(target); using (targetClass.Context.ClassHierarchyLocker()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (_signature.ResolveOnly) { metaBuilder.Result = AstUtils.Constant(method != null); return(true); } if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return(RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback)); } return(true); }
internal static void BindToMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args, bool privateMethod) { // args already contain method name: var method = args.RubyContext.ResolveMethod(args.Target, Symbols.MethodMissing, true).InvalidateSitesOnOverride(); // TODO: better check for builtin method if (method == null || method.DeclaringModule == args.RubyContext.KernelModule && method is RubyMethodGroupInfo) { // throw an exception immediately, do not cache the rule: if (privateMethod) { throw RubyExceptions.CreatePrivateMethodCalled(args.RubyContext, args.Target, methodName); } else { throw RubyExceptions.CreateMethodMissing(args.RubyContext, args.Target, methodName); } } method.BuildCall(metaBuilder, args, methodName); }
/// <summary> /// Takes current result and wraps it into try-filter(MethodUnwinder)-finally block that ensures correct "break" behavior for /// library method calls with block given in bfcVariable (BlockParam). /// </summary> public static void RuleControlFlowBuilder(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { if (metaBuilder.Error) { return; } var metaBlock = args.GetMetaBlock(); Debug.Assert(metaBlock != null, "RuleControlFlowBuilder should only be used if the signature has a block"); // We construct CF only for non-nil blocks thus we need a test for it: if (metaBlock.Value == null) { metaBuilder.AddRestriction(Ast.Equal(metaBlock.Expression, AstUtils.Constant(null))); return; } // 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))); Expression bfcVariable = metaBuilder.BfcVariable; Debug.Assert(bfcVariable != null); // Method call with proc can invoke control flow that returns an arbitrary value from the call, so we need to type result to Object. // Otherwise, the result could only be result of targetExpression unless its return type is void. Expression resultVariable = metaBuilder.GetTemporary(typeof(object), "#result"); ParameterExpression unwinder; metaBuilder.Result = Ast.Block( Ast.Assign(bfcVariable, Methods.CreateBfcForLibraryMethod.OpCall(AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)))), AstUtils.Try( Ast.Assign(resultVariable, AstUtils.Convert(metaBuilder.Result, typeof(object))) ).Filter(unwinder = Ast.Parameter(typeof(MethodUnwinder), "#unwinder"), Methods.IsProcConverterTarget.OpCall(bfcVariable, unwinder), Ast.Assign(resultVariable, Ast.Field(unwinder, MethodUnwinder.ReturnValueField)), AstUtils.Default(typeof(object)) ).Finally( Methods.LeaveProcConverter.OpCall(bfcVariable) ), resultVariable ); }
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); }
/// <summary> /// Takes current result and wraps it into try-filter(MethodUnwinder)-finally block that ensures correct "break" behavior for /// Ruby method calls with a block given in arguments. /// /// Sets up a RFC frame similarly to MethodDeclaration. /// </summary> public static void RuleControlFlowBuilder(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { Debug.Assert(args.Signature.HasBlock); if (metaBuilder.Error) { return; } // TODO (improvement): // We don't special case null block here, although we could (we would need a test for that then). // We could also statically know (via call-site flag) that the current method is not a proc-converter (passed by ref), // which would make such calls faster. var rfcVariable = metaBuilder.GetTemporary(typeof(RuntimeFlowControl), "#rfc"); var resultVariable = metaBuilder.GetTemporary(typeof(object), "#result"); MSA.ParameterExpression unwinder; metaBuilder.Result = Ast.Block( // initialize frame (RFC): Ast.Assign(rfcVariable, Methods.CreateRfcForMethod.OpCall(AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)))), AstUtils.Try( Ast.Assign(resultVariable, metaBuilder.Result) ).Filter(unwinder = Ast.Parameter(typeof(MethodUnwinder), "#unwinder"), Ast.Equal(Ast.Field(unwinder, MethodUnwinder.TargetFrameField), rfcVariable), // return unwinder.ReturnValue; Ast.Assign(resultVariable, Ast.Field(unwinder, MethodUnwinder.ReturnValueField)) ).Finally( // we need to mark the RFC dead snce the block might escape and break later: Methods.LeaveMethodFrame.OpCall(rfcVariable) ), resultVariable ); }
internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { BuildCallNoFlow(metaBuilder, args, name, MethodBases, CallConvention, ImplicitProtocolConversions); }
public static void InstanceAllocator(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { ((RubyClass)args.Target).BuildObjectAllocation(metaBuilder, args, name); }
internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { _ruleGenerator(metaBuilder, args, name); }
internal void BuildMethodMissingCall(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { BuildMethodMissingCallNoFlow(metaBuilder, args, name); metaBuilder.BuildControlFlow(args); }
// Returns true if the call was bound (with success or failure), false if fallback should be performed. internal static bool BuildCall(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args, bool defaultFallback, bool callClrMethods) { RubyMemberInfo methodMissing; var method = Resolve(metaBuilder, methodName, args, out methodMissing); if (method.Found) { if (!callClrMethods && !method.Info.IsRubyMember) { return(false); } if (args.Signature.ResolveOnly) { metaBuilder.Result = AstFactory.True; return(true); } if (args.Signature.IsVirtualCall && !method.Info.IsRubyMember) { metaBuilder.Result = Ast.Field(null, Fields.ForwardToBase); return(true); } method.Info.BuildCall(metaBuilder, args, methodName); return(true); } else if (args.Signature.ResolveOnly) { metaBuilder.Result = AstFactory.False; return(true); } else { return(BuildMethodMissingCall(metaBuilder, args, methodName, methodMissing, method.IncompatibleVisibility, false, defaultFallback)); } }
private void AddBlockArguments(MetaObjectBuilder/*!*/ rule, List<Expression>/*!*/ actualArgs, CallArguments/*!*/ args, int parameterIndex) { while (parameterIndex < args.Length) { switch (args.GetArgumentKind(parameterIndex)) { case ArgumentKind.Simple: actualArgs.Add(args.Expressions[parameterIndex]); break; case ArgumentKind.List: ArgsBuilder.SplatListToArguments(rule, actualArgs, args.Values[parameterIndex], args.Expressions[parameterIndex], false); break; case ArgumentKind.Instance: case ArgumentKind.Block: default: throw new NotImplementedException(); } parameterIndex++; } }
protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback) { return(BuildCall(metaBuilder, _methodName, args, defaultFallback, true)); }
internal static DynamicMetaObject FallbackInvokeMember(IInteropBinder/*!*/ binder, string/*!*/ methodName, CallInfo/*!*/ callInfo, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, DynamicMetaObject errorSuggestion) { var metaBuilder = new MetaObjectBuilder(binder, target, args); var callArgs = new CallArguments(binder.Context, target, args, callInfo); if (!RubyCallAction.BuildCall(metaBuilder, methodName, callArgs, errorSuggestion == null, true)) { Debug.Assert(errorSuggestion != null); // method wasn't found so we didn't do any operation with arguments that would require restrictions converted to conditions: metaBuilder.SetMetaResult(errorSuggestion, false); } return metaBuilder.CreateMetaObject((DynamicMetaObjectBinder)binder); }
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 ); } }
public static DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ context, GetMemberBinder/*!*/ binder, DynamicMetaObject/*!*/ target, Func<DynamicMetaObject, DynamicMetaObject>/*!*/ fallback) { Debug.Assert(fallback != null); var callArgs = new CallArguments(context, target, DynamicMetaObject.EmptyMetaObjects, RubyCallSignature.Interop(0)); var metaBuilder = new MetaObjectBuilder(target); if (!RubyCallAction.BuildAccess(metaBuilder, binder.Name, callArgs, false, false)) { metaBuilder.SetMetaResult(fallback(target), false); } return metaBuilder.CreateMetaObject(binder); }
internal static IList <OverloadInfo> /*!*/ GetVisibleOverloads(CallArguments /*!*/ args, IList <OverloadInfo> /*!*/ overloads, bool isSuperCall) { IList <OverloadInfo> newOverloads = null; Debug.Assert(overloads.Count > 0); // handle CLR-protected and virtual methods: // TODO (opt): // We might be able to cache the callable overloads in a MethodGroup. // However, the _overloadOwners of that group would need to point to the original overload owners, not the current class, in order // to preserve semantics of overload deletion/redefinition (deletion of the protected overload would need to imply deletion // of the correpsondig public overload in the cached MethodGroup). if (isSuperCall || !args.RubyContext.DomainManager.Configuration.PrivateBinding) { Type underlyingType = null; BindingFlags bindingFlags = 0; for (int i = 0; i < overloads.Count; i++) { var overload = overloads[i]; if ((isSuperCall && overload.IsVirtual && !overload.IsFinal) || overload.IsProtected) { if (newOverloads == null) { newOverloads = CollectionUtils.GetRange(overloads, 0, i); RubyClass cls; IRubyType rt = args.Target as IRubyType; if (rt != null) { bindingFlags = BindingFlags.Instance; underlyingType = args.Target.GetType(); } else if ((cls = args.Target as RubyClass) != null && cls.IsRubyClass && !cls.IsSingletonClass) { bindingFlags = BindingFlags.Static; underlyingType = cls.GetUnderlyingSystemType(); } } if (underlyingType != null) { // TODO (opt): we can define a method on the emitted type that does this more efficently: IList <Type> genericArguments = overload.IsGenericMethod ? overload.GenericArguments : null; OverloadInfo visibleMethod = GetMethodOverload( ArrayUtils.ToArray(overload.Parameters, (pi) => pi.ParameterType), genericArguments, underlyingType, #if FEATURE_REFEMIT // TODO: should we always prefix with #base# ??? ClsTypeEmitter.BaseMethodPrefix + overload.Name, #else overload.Name, #endif BindingFlags.Public | bindingFlags ); Debug.Assert(visibleMethod != null); newOverloads.Add(visibleMethod); } } else if (newOverloads != null) { newOverloads.Add(overload); } } } return(newOverloads ?? overloads); }
internal virtual void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { throw Assert.Unreachable; }
private void SetCallRuleArguments( Expression/*!*/ blockParameterExpression, // special arg #0 Expression/*!*/ selfParameterExpression, // special arg #1 CallArguments/*!*/ args, // user args Expression/*!*/ codeContextExpression, MetaObjectBuilder/*!*/ rule, ArgsBuilder/*!*/ actualArgs) { // mandatory args: actualArgs.Add(blockParameterExpression); actualArgs.Add(selfParameterExpression); int parameterIndex = 0; // mimics CompoundLeftValue.TransformWrite // // L(1,-)? bool leftOneNone = OptionalParamCount == 1 && !HasParamsArray; // L(0,*)? bool leftNoneSplat = OptionalParamCount == 0 && HasParamsArray; // R(0,*)? bool rightNoneSplat = !args.Signature.IsSimple && args.Length == 1 && args.GetArgumentKind(0) == ArgumentKind.List; // R(1,-)? bool rightOneNone = !args.Signature.IsSimple && args.Length == 1 && args.GetArgumentKind(0) == ArgumentKind.Simple || args.Signature.IsSimple && args.Length == 1; // R(1,*)? bool rightOneSplat = !args.Signature.IsSimple && args.Length == 2 && args.GetArgumentKind(0) == ArgumentKind.Simple && args.GetArgumentKind(1) == ArgumentKind.List; // R(0,-)? bool rightNoneNone = args.Length == 0; if (leftOneNone) { Expression rvalue; if (rightOneNone) { // simple assignment rvalue = args.Expressions[parameterIndex]; } else if (rightOneSplat && TestEmptyList(rule, args.Values[parameterIndex + 1], args.Expressions[parameterIndex + 1])) { // simple assignment if the splatted value is an empty array: rvalue = args.Expressions[parameterIndex]; } else if (rightNoneNone) { // nil assignment rvalue = AddWarning(codeContextExpression, Ast.Constant(null)); } else if (rightNoneSplat) { // Splat(RHS[*]): rvalue = MakeArgumentSplatWithWarning(rule, args.Values[parameterIndex], args.Expressions[parameterIndex], codeContextExpression); } else { // more than one argument -> pack to an array + warning // MakeArray(RHS) + SplatAppend(RHS*): List<Expression> arguments = new List<Expression>(); AddBlockArguments(rule, arguments, args, parameterIndex); rvalue = AddWarning(codeContextExpression, ArgsBuilder.MakeArgsArray(arguments)); } actualArgs.Add(rvalue); } else { // R(0,*) || R(1,-) && !L(0,*) ==> CompoundLeftValue.TransformWrite does Unsplat, MakeArray otherwise. // // However, we are not constructing a materalized resulting array (contrary to CompoundLeftValue.TransformWrite). // The resulting array is comprised of slots on the stack (loaded to the formal parameters of the block #1, ..., #n). // Therefore, we effectively need to take items of imaginary Unsplat's result and put them into the actualArgs as arguments. // // Unsplat of x makes an array containing x if x is not an array, otherwise it returns x. // So, we just need to take elements of x and push them onto the stack. // List<Expression> arguments = new List<Expression>(); if (rightNoneSplat) { ArgsBuilder.SplatListToArguments(rule, arguments, args.Values[parameterIndex], args.Expressions[parameterIndex], false); } else if (rightOneNone && !leftNoneSplat) { ArgsBuilder.SplatListToArguments(rule, arguments, args.Values[parameterIndex], args.Expressions[parameterIndex], true); } else { AddBlockArguments(rule, arguments, args, parameterIndex); } actualArgs.AddRange(arguments); } actualArgs.AddForEachMissingArgument(delegate() { return Ast.Constant(null); }); if (HasParamsArray) { actualArgs.AddParamsArray(); } }
internal override void BuildSuperCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name, RubyModule /*!*/ declaringModule) { Assert.NotNull(declaringModule, metaBuilder, args); var visibleOverloads = GetVisibleOverloads(args, MethodBases, true); if (visibleOverloads.Count == 0) { metaBuilder.SetError(Methods.MakeClrVirtualMethodCalledError.OpCall( args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name) )); } else { BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions); } }
public static DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ context, string/*!*/ methodName, CallInfo/*!*/ callInfo, DynamicMetaObjectBinder/*!*/ binder, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, Func<DynamicMetaObject, DynamicMetaObject[], DynamicMetaObject>/*!*/ fallback) { Debug.Assert(fallback != null); var callArgs = new CallArguments(context, target, args, RubyCallSignature.Interop(callInfo.ArgumentCount)); var metaBuilder = new MetaObjectBuilder(target, args); if (!RubyCallAction.BuildCall(metaBuilder, methodName, callArgs, false, false)) { metaBuilder.SetMetaResult(fallback(target, args), false); } return metaBuilder.CreateMetaObject(binder); }
private static MethodMissingBinding BindToKernelMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName, RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall) { // TODO: better specialization of method_missing methods if (methodMissing == null || methodMissing.DeclaringModule == methodMissing.Context.KernelModule && methodMissing is RubyLibraryMethodInfo) { if (isSuperCall) { metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName))); } else if (incompatibleVisibility == RubyMethodVisibility.Private) { metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall( AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName)) ); } else if (incompatibleVisibility == RubyMethodVisibility.Protected) { metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall( AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName)) ); } else { return(MethodMissingBinding.Fallback); } return(MethodMissingBinding.Error); } return(MethodMissingBinding.Custom); }
public static DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ context, SetMemberBinder/*!*/ binder, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/ value, Func<DynamicMetaObject, DynamicMetaObject, DynamicMetaObject>/*!*/ fallback) { Debug.Assert(fallback != null); var args = new[] { value }; var callArgs = new CallArguments(context, target, args, RubyCallSignature.Interop(1)); var metaBuilder = new MetaObjectBuilder(target, args); if (!RubyCallAction.BuildCall(metaBuilder, binder.Name + "=", callArgs, false, false)) { metaBuilder.SetMetaResult(fallback(target, value), false); } return metaBuilder.CreateMetaObject(binder); }
// Returns true if the call was bound (with success or failure), false if fallback should be performed. internal static bool BuildMethodMissingAccess(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName, RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall, bool defaultFallback) { switch (BindToKernelMethodMissing(metaBuilder, args, methodName, methodMissing, incompatibleVisibility, isSuperCall)) { case MethodMissingBinding.Custom: // we pretend we found the member and return a method that calls method_missing: Debug.Assert(!metaBuilder.Error); metaBuilder.Result = Methods.CreateBoundMissingMember.OpCall( AstUtils.Convert(args.TargetExpression, typeof(object)), Ast.Constant(methodMissing, typeof(RubyMemberInfo)), Ast.Constant(methodName) ); return(true); case MethodMissingBinding.Error: // method_missing is defined in Kernel, error has been reported: return(true); case MethodMissingBinding.Fallback: // method_missing is defined in Kernel: if (defaultFallback) { metaBuilder.SetError(Methods.MakeMissingMemberError.OpCall(Ast.Constant(methodName))); return(true); } return(false); } throw Assert.Unreachable; }
public static void MethodCall(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { ((RubyMethod)args.Target).BuildInvoke(metaBuilder, args); }
internal static MethodResolutionResult Resolve(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args, out RubyMemberInfo methodMissing) { MethodResolutionResult method; var targetClass = args.TargetClass; var visibilityContext = GetVisibilityContext(args.Signature, args.Scope); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext, new[] { methodName, Symbols.MethodMissing } ); if (args.Signature.IsSuperCall) { Debug.Assert(!args.Signature.IsVirtualCall && args.Signature.HasImplicitSelf); method = targetClass.ResolveSuperMethodNoLock(methodName, targetClass).InvalidateSitesOnOverride(); } else { var options = args.Signature.IsVirtualCall ? MethodLookup.Virtual : MethodLookup.Default; method = targetClass.ResolveMethodForSiteNoLock(methodName, visibilityContext, options); } if (!method.Found) { methodMissing = targetClass.ResolveMethodMissingForSite(methodName, method.IncompatibleVisibility); } else { methodMissing = null; } } // Whenever the current self's class changes we need to invalidate the rule, if a protected method is being called. if (method.Info != null && method.Info.IsProtected && visibilityContext.Class != null) { // We don't need to compare versions, just the class objects (super-class relationship cannot be changed). // Since we don't want to hold on a class object (to make it collectible) we compare references to the version handlers. metaBuilder.AddCondition(Ast.Equal( Methods.GetSelfClassVersionHandle.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))), Ast.Constant(visibilityContext.Class.Version) )); } return(method); }
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; }
internal override void ApplyBlockFlowHandling(MetaObjectBuilder metaBuilder, CallArguments args) { // nop }