[Emitted] // AliasStatement: public static void AliasMethod(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) { scope.GetMethodDefinitionOwner().AddMethodAlias(newName, oldName); }
[Emitted] // MethodDeclaration: public static RubyMethodInfo/*!*/ DefineMethod(object targetOrSelf, object/*!*/ ast, RubyScope/*!*/ scope, bool hasTarget, string/*!*/ name, Delegate/*!*/ clrMethod, int mandatory, int optional, bool hasUnsplatParameter) { Assert.NotNull(ast, scope, clrMethod, name); RubyModule instanceOwner, singletonOwner; RubyMemberFlags instanceFlags, singletonFlags; if (hasTarget) { if (!RubyUtils.CanCreateSingleton(targetOrSelf)) { throw RubyExceptions.CreateTypeError("can't define singleton method for literals"); } instanceOwner = null; instanceFlags = RubyMemberFlags.Invalid; singletonOwner = scope.RubyContext.CreateSingletonClass(targetOrSelf); singletonFlags = RubyMemberFlags.Public; } else { // TODO: ??? var attributesScope = scope.GetMethodAttributesDefinitionScope(); //var attributesScope = scope; if ((attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) { // Singleton module-function's scope points to the instance method's RubyMemberInfo. // This affects: // 1) super call // Super call is looking for Method.DeclaringModule while searching MRO, which would fail if the singleton module-function // was in MRO. Since module-function can only be used on module the singleton method could only be on module's singleton. // Module's singleton is never part of MRO so we are safe. // 2) trace // Method call trace reports non-singleton module. // MRI 1.8: instance method owner is self -> it is possible (via define_method) to define m.f. on a class (bug) // MRI 1.9: instance method owner GetMethodDefinitionOwner // MRI allows to define m.f. on classes but then doesn't work correctly with it. instanceOwner = scope.GetMethodDefinitionOwner(); if (instanceOwner.IsClass) { throw RubyExceptions.CreateTypeError("A module function cannot be defined on a class."); } instanceFlags = RubyMemberFlags.ModuleFunction | RubyMemberFlags.Private; singletonOwner = instanceOwner.SingletonClass; singletonFlags = RubyMemberFlags.ModuleFunction | RubyMemberFlags.Public; } else { instanceOwner = scope.GetMethodDefinitionOwner(); instanceFlags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, name); singletonOwner = null; singletonFlags = RubyMemberFlags.Invalid; } } RubyMethodInfo instanceMethod = null, singletonMethod = null; if (instanceOwner != null) { SetMethod(scope.RubyContext, instanceMethod = new RubyMethodInfo(ast, clrMethod, instanceOwner, name, mandatory, optional, hasUnsplatParameter, instanceFlags) ); } if (singletonOwner != null) { SetMethod(scope.RubyContext, singletonMethod = new RubyMethodInfo(ast, clrMethod, singletonOwner, name, mandatory, optional, hasUnsplatParameter, singletonFlags) ); } // the method's scope saves the result => singleton module-function uses instance-method return instanceMethod ?? singletonMethod; }
[Emitted] // MethodDeclaration: public static object DefineMethod(object targetOrSelf, RubyScope/*!*/ scope, RubyMethodBody/*!*/ body) { Assert.NotNull(body, scope); RubyModule instanceOwner, singletonOwner; RubyMemberFlags instanceFlags, singletonFlags; bool moduleFunction = false; if (body.HasTarget) { if (!RubyUtils.CanCreateSingleton(targetOrSelf)) { throw RubyExceptions.CreateTypeError("can't define singleton method for literals"); } instanceOwner = null; instanceFlags = RubyMemberFlags.Invalid; singletonOwner = scope.RubyContext.CreateSingletonClass(targetOrSelf); singletonFlags = RubyMemberFlags.Public; } else { var attributesScope = scope.GetMethodAttributesDefinitionScope(); if ((attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) { // Singleton module-function's scope points to the instance method's RubyMemberInfo. // This affects: // 1) super call // Super call is looking for Method.DeclaringModule while searching MRO, which would fail if the singleton module-function // was in MRO. Since module-function can only be used on module the singleton method could only be on module's singleton. // Module's singleton is never part of MRO so we are safe. // 2) trace // Method call trace reports non-singleton module. // MRI 1.8: instance method owner is self -> it is possible (via define_method) to define m.f. on a class (bug) // MRI 1.9: instance method owner GetMethodDefinitionOwner // MRI allows to define m.f. on classes but then doesn't work correctly with it. instanceOwner = scope.GetMethodDefinitionOwner(); if (instanceOwner.IsClass) { throw RubyExceptions.CreateTypeError("A module function cannot be defined on a class."); } instanceFlags = RubyMemberFlags.Private; singletonOwner = instanceOwner.SingletonClass; singletonFlags = RubyMemberFlags.Public; moduleFunction = true; } else { instanceOwner = scope.GetMethodDefinitionOwner(); instanceFlags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, body.Name); singletonOwner = null; singletonFlags = RubyMemberFlags.Invalid; } } RubyMethodInfo instanceMethod = null, singletonMethod = null; if (instanceOwner != null) { SetMethod(scope.RubyContext, instanceMethod = new RubyMethodInfo(body, scope, instanceOwner, instanceFlags) ); } if (singletonOwner != null) { SetMethod(scope.RubyContext, singletonMethod = new RubyMethodInfo(body, scope, singletonOwner, singletonFlags) ); } // the method's scope saves the result => singleton module-function uses instance-method var method = instanceMethod ?? singletonMethod; method.DeclaringModule.MethodAdded(body.Name); if (moduleFunction) { Debug.Assert(!method.DeclaringModule.IsClass); method.DeclaringModule.SingletonClass.MethodAdded(body.Name); } return null; }
[Emitted] // AliasStatement: public static void AliasMethod(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) { // MRI 1.8: if (newName == oldName) return; // MRI 1.9: no check // lexical lookup: RubyModule owner = scope.GetMethodDefinitionOwner(); RubyMemberInfo method = owner.ResolveMethodFallbackToObject(oldName, true); if (method != null) { owner.AddMethodAlias(scope.RubyContext, newName, method); return; } throw RubyExceptions.CreateUndefinedMethodError(owner, oldName); }