Beispiel #1
0
        internal static void SetMethodAttributes(RubyScope/*!*/ scope, RubyModule/*!*/ module, object[]/*!*/ methodNames, RubyMethodAttributes attributes) {
            ContractUtils.RequiresNotNull(scope, "scope");
            ContractUtils.RequiresNotNull(methodNames, "methodNames");

            if (methodNames.Length == 0) {
                scope.GetMethodAttributesDefinitionScope().MethodAttributes = attributes;
            } else {
                foreach (string methodName in Protocols.CastToSymbols(scope.RubyContext, methodNames)) {
                    RubyMemberInfo method = module.ResolveMethodFallbackToObject(methodName, true);
                    if (method == null) {
                        throw RubyExceptions.CreateNameError(RubyExceptions.FormatMethodMissingMessage(scope.RubyContext, module, methodName));
                    }

                    if ((attributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) {
                        module.AddModuleFunction(scope.RubyContext, methodName, method);
                    } else {
                        module.SetMethodVisibility(scope.RubyContext, methodName, method, (RubyMethodVisibility)(attributes & RubyMethodAttributes.VisibilityMask));
                    }
                }
            }
        }
Beispiel #2
0
        private static RubyMethodVisibility GetDefinedMethodVisibility(RubyScope/*!*/ scope, RubyModule/*!*/ module, string/*!*/ methodName) {
            // MRI: Special names are private.
            // MRI: Doesn't create a singleton method if module_function is used in the scope, however the private visibility is applied (bug?)
            // MRI 1.8: uses the current scope's visibility only if the target module is the same as the scope's module (bug?)
            // MFI 1.9: always uses public visibility (bug?)
            RubyMethodVisibility visibility;
            if (scope.RubyContext.RubyOptions.Compatibility == RubyCompatibility.Ruby18) {
                var attributesScope = scope.GetMethodAttributesDefinitionScope();
                if (attributesScope.GetInnerMostModuleForMethodLookup() == module) {
                    bool isModuleFunction = (attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction;
                    visibility = (isModuleFunction) ? RubyMethodVisibility.Private : attributesScope.Visibility;
                } else {
                    visibility = RubyMethodVisibility.Public;
                }
            } else {
                visibility = RubyMethodVisibility.Public;
            }

            return RubyUtils.GetSpecialMethodVisibility(visibility, methodName);
        }
Beispiel #3
0
        private static void DefineAccessor(RubyScope/*!*/ scope, RubyModule/*!*/ self, string/*!*/ name, bool readable, bool writable) {
            // MRI: ignores ModuleFunction scope flag (doesn't create singleton methods):

            if (!Tokenizer.IsVariableName(name, true)) {
                throw RubyExceptions.CreateNameError("invalid attribute name `{0}'", name);
            }

            var varName = "@" + name;
            var attributesScope = scope.GetMethodAttributesDefinitionScope();

            if (readable) {
                var flags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, name);
                self.AddMethod(scope.RubyContext, name, new RubyAttributeReaderInfo(flags, self, varName));
            }
            
            if (writable) {
                self.AddMethod(scope.RubyContext, name + "=", new RubyAttributeWriterInfo((RubyMemberFlags)attributesScope.Visibility, self, varName));
            }
        }
Beispiel #4
0
 internal static void SetMethodAttributes(RubyScope/*!*/ scope, RubyModule/*!*/ module, string/*!*/[]/*!*/ methodNames, RubyMethodAttributes attributes) {
     if (methodNames.Length == 0) {
         scope.GetMethodAttributesDefinitionScope().MethodAttributes = attributes;
     } else {
         SetMethodAttributes(module, methodNames, attributes);
     }
 }
Beispiel #5
0
        [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;
        }
Beispiel #6
0
        private static void DefineAccessor(RubyScope/*!*/ scope, RubyModule/*!*/ self, string/*!*/ name, bool readable, bool writable) {
            // MRI: ignores ModuleFunction scope flag (doesn't create singleton methods):

            var varName = "@" + name;
            var attributesScope = scope.GetMethodAttributesDefinitionScope();

            if (readable) {
                var flags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, name);
                self.SetLibraryMethod(name, new RubyAttributeReaderInfo(flags, self, varName), false);
            }
            
            if (writable) {
                self.SetLibraryMethod(name + "=", new RubyAttributeWriterInfo((RubyMemberFlags)attributesScope.Visibility, self, varName), false);
            }
        }
Beispiel #7
0
        private static void DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self, string/*!*/ methodName, RubyMemberInfo/*!*/ info,
            RubyModule/*!*/ targetConstraint) {

            // MRI: doesn't create a singleton method if module_function is used in the scope, however the the private visibility is applied
            var attributesScope = scope.GetMethodAttributesDefinitionScope();
            bool isModuleFunction = (attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction;
            var visibility = isModuleFunction ? RubyMethodVisibility.Private : attributesScope.Visibility;

            using (self.Context.ClassHierarchyLocker()) {
                // MRI 1.8 does the check when the method is called, 1.9 checks it upfront as we do:
                if (!self.HasAncestorNoLock(targetConstraint)) {
                    throw RubyExceptions.CreateTypeError(
                        String.Format("bind argument must be a subclass of {0}", targetConstraint.GetName(scope.RubyContext))
                    );
                }

                self.SetDefinedMethodNoEventNoLock(self.Context, methodName, info, visibility);
            }

            self.Context.MethodAdded(self, methodName);
        }
Beispiel #8
0
        [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;
        }