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(methodName, method); } else { module.SetMethodVisibility(methodName, method, (RubyMethodVisibility)(attributes & RubyMethodAttributes.VisibilityMask)); } } } }
/// <summary> /// Implements Class#new feature. /// </summary> public void BuildObjectConstruction(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName) { Debug.Assert(!IsSingletonClass, "Cannot instantiate singletons"); Type type = GetUnderlyingSystemType(); RubyMemberInfo initializer = ResolveMethod(Symbols.Initialize, true).InvalidateSitesOnOverride(); RubyMethodInfo overriddenInitializer = initializer as RubyMethodInfo; // check the version of this class to ensure the initializer won't be changed without rebuilding the site: metaBuilder.AddCondition( Ast.Equal(Ast.Property(Ast.Constant(this), RubyModule.VersionProperty), Ast.Constant(this.Version)) ); // Initializer is overridden => initializer is invoked on an uninitialized instance. // Is user class (defined in Ruby code) => construct it as if it had initializer that calls super immediately // (we need to "inherit" factories/constructors from the base class (e.g. class S < String; self; end.new('foo')). if (overriddenInitializer != null || (_isRubyClass && _structInfo == null)) { metaBuilder.Result = MakeAllocatorCall(args, () => Ast.Constant(Name)); if (overriddenInitializer != null || (_isRubyClass && initializer != null && !initializer.IsEmpty)) { BuildOverriddenInitializerCall(metaBuilder, args, initializer); } } else if (type.IsSubclassOf(typeof(Delegate))) { metaBuilder.Result = MakeDelegateConstructorCall(type, args); } else { MethodBase[] constructionOverloads; bool includeSelf; if (_structInfo != null) { constructionOverloads = new MethodBase[] { Methods.CreateStructInstance }; includeSelf = true; } else if (_factories != null) { constructionOverloads = (MethodBase[])ReflectionUtils.GetMethodInfos(_factories); includeSelf = true; } else { constructionOverloads = type.GetConstructors(); if (constructionOverloads.Length == 0) { throw RubyExceptions.CreateTypeError(String.Format("allocator undefined for {0}", Name)); } includeSelf = false; } RubyMethodGroupInfo.BuildCallNoFlow(metaBuilder, args, methodName, constructionOverloads, includeSelf, false); RubyMethodGroupInfo.ApplyBlockFlowHandlingInternal(metaBuilder, args); } }
internal UnboundMethod(RubyModule /*!*/ targetConstraint, string /*!*/ name, RubyMemberInfo /*!*/ info) { Assert.NotNull(targetConstraint, name, info); _name = name; _info = info; _targetConstraint = targetConstraint; }
public static RubyMemberInfo InvalidateSitesOnOverride(this RubyMemberInfo member) { if (member != null) { member.InvalidateSitesOnOverride = true; } return(member); }
public RubyMethod(object target, RubyMemberInfo /*!*/ info, string /*!*/ name) { ContractUtils.RequiresNotNull(info, "info"); ContractUtils.RequiresNotNull(name, "name"); _target = target; _info = info; _name = name; }
internal static RubyMemberInfo /*!*/ BindGenericParameters(RubyContext /*!*/ context, RubyMemberInfo /*!*/ info, string /*!*/ name, object[] /*!*/ typeArgs) { RubyMemberInfo result = info.TryBindGenericParameters(Protocols.ToTypes(context, typeArgs)); if (result == null) { throw RubyExceptions.CreateArgumentError("wrong number of generic arguments for `{0}'", name); } return(result); }
internal static RubyArray GetSourceLocation(RubyMemberInfo /*!*/ info) { RubyMethodInfo rubyInfo = info as RubyMethodInfo; return((rubyInfo == null) ? null : new RubyArray(2) { rubyInfo.DeclaringModule.Context.EncodePath(rubyInfo.Document.FileName), rubyInfo.SourceSpan.Start.Line }); }
internal static RubyMemberInfo /*!*/ SelectOverload(RubyContext /*!*/ context, RubyMemberInfo /*!*/ info, string /*!*/ name, object[] /*!*/ typeArgs) { RubyMemberInfo result = info.TrySelectOverload(Protocols.ToTypes(context, typeArgs)); if (result == null) { throw RubyExceptions.CreateArgumentError("no overload of `{0}' matches given parameter types", name); } return(result); }
public static RubyModule /*!*/ UndefineMethod(RubyModule /*!*/ self, [DefaultProtocol] string /*!*/ methodName) { RubyMemberInfo method = self.ResolveMethod(methodName, true); if (method == null) { throw RubyExceptions.CreateUndefinedMethodError(self, methodName); } self.UndefineMethod(methodName); return(self); }
public static UnboundMethod /*!*/ GetInstanceMethod(RubyModule /*!*/ self, [DefaultProtocol] string /*!*/ methodName) { RubyMemberInfo method = self.ResolveMethod(methodName, true); if (method == null) { throw RubyExceptions.CreateUndefinedMethodError(self, methodName); } // unbound method binable to any class with "self" mixin: return(new UnboundMethod(self, methodName, method)); }
public static RubyModule /*!*/ AliasMethod(RubyModule /*!*/ self, [DefaultProtocol] string /*!*/ newName, [DefaultProtocol] string /*!*/ oldName) { RubyMemberInfo method = self.ResolveMethodFallbackToObject(oldName, true); if (method == null) { throw RubyExceptions.CreateUndefinedMethodError(self, oldName); } self.AddMethodAlias(newName, method); return(self); }
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) ); }
protected override Node /*!*/ CreateNode(object data) { RubyMemberInfo method = Context.GetImmediateClassOf(data).ResolveMethodForSite("to_yaml", VisibilityContext.AllVisible).Info; if (method == _siteStorage.ObjectToYamlMethod) { var site = _siteStorage.ToYamlNode; return(ToNode(site.Target(site, data, this))); } else { var site = _siteStorage.ToYaml; return(ToNode(site.Target(site, data, this))); } }
protected override Node CreateNode(object data) { RubyMemberInfo method = _context.ResolveMethod(data, "to_yaml", false).InvalidateSitesOnOverride(); if (method == _objectToYamlMethod) { return(_ToYamlNode.Target(_ToYamlNode, _context, data, this)); } else { // TODO: this doesn't seem right // (we're passing the extra argument, but the callee might not take it?) return(_ToYaml.Target(_ToYaml, _context, data, this)); } }
private static void SetClassMethodsVisibility(RubyModule /*!*/ module, string[] /*!*/ methodNames, RubyMethodVisibility visibility) { var methods = new RubyMemberInfo[methodNames.Length]; for (int i = 0; i < methods.Length; i++) { RubyMemberInfo method = module.SingletonClass.ResolveMethod(methodNames[i], true); if (method == null) { throw RubyExceptions.CreateUndefinedMethodError(module, methodNames[i]); } methods[i] = method; } for (int i = 0; i < methods.Length; i++) { module.SingletonClass.SetMethodVisibility(methodNames[i], methods[i], visibility); } }
public static UnboundMethod /*!*/ GetInstanceMethod(RubyModule /*!*/ self, [DefaultProtocol, NotNull] string /*!*/ methodName) { RubyMemberInfo method = self.ResolveMethod(methodName, VisibilityContext.AllVisible).Info; if (method == null) { throw RubyExceptions.CreateUndefinedMethodError(self, methodName); } RubyModule constraint = self; if (self.IsSingletonClass && method.DeclaringModule != self) { constraint = ((RubyClass)self).SuperClass; } // unbound method binable to any class with "constraint" mixin: return(new UnboundMethod(constraint, methodName, method)); }
public RubyRepresenter(RubyContext /*!*/ context, ISerializer /*!*/ serializer, YamlOptions /*!*/ opts) : base(serializer, opts) { _context = context; _objectToYamlMethod = context.GetClass(typeof(object)).ResolveMethod("to_yaml", false); }
protected override bool TryGetClrMember(Type /*!*/ type, string /*!*/ name, out RubyMemberInfo method) { string unmangled; if (IsFailureCached(type, name)) { method = null; return(false); } BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; bindingFlags |= (_isSingletonClass) ? BindingFlags.Static : BindingFlags.Instance; if (name.EndsWith("=")) { string propertyName = name.Substring(0, name.Length - 1); // property setter: if (TryGetClrMethod(type, bindingFlags, "set_" + propertyName, out method)) { return(true); } unmangled = RubyUtils.TryUnmangleName(propertyName); if (unmangled != null && TryGetClrMethod(type, bindingFlags, "set_" + unmangled, out method)) { return(true); } // writeable field: if (TryGetClrField(type, bindingFlags, propertyName, true, out method)) { return(true); } if (unmangled != null && TryGetClrField(type, bindingFlags, unmangled, true, out method)) { return(true); } } else { // method: if (TryGetClrMethod(type, bindingFlags, name, out method)) { return(true); } unmangled = RubyUtils.TryUnmangleName(name); if (unmangled != null && TryGetClrMethod(type, bindingFlags, unmangled, out method)) { return(true); } // getter: if (TryGetClrMethod(type, bindingFlags, "get_" + name, out method)) { return(true); } if (unmangled != null && TryGetClrMethod(type, bindingFlags, "get_" + unmangled, out method)) { return(true); } // event: if (TryGetClrEvent(type, bindingFlags, name, out method)) { return(true); } if (unmangled != null && TryGetClrEvent(type, bindingFlags, unmangled, out method)) { return(true); } // field: if (TryGetClrField(type, bindingFlags, name, false, out method)) { return(true); } if (unmangled != null && TryGetClrField(type, bindingFlags, unmangled, false, out method)) { return(true); } } CacheFailure(type, name); method = null; return(false); }
public static bool PublicMethodDefined(RubyModule /*!*/ self, [DefaultProtocol] string /*!*/ methodName) { RubyMemberInfo method = self.ResolveMethod(methodName, true); return(method != null && method.Visibility == RubyMethodVisibility.Public); }
private bool TryGetClrMethod(Type /*!*/ type, BindingFlags bindingFlags, string /*!*/ name, out RubyMemberInfo method) { Assert.NotNull(type, name); MemberInfo[] members = type.GetMember(name, MemberTypes.Method, bindingFlags | BindingFlags.InvokeMethod); if (members.Length > 0) { method = new RubyMethodGroupInfo(SelectNonPrivateMethods(members), this, _isSingletonClass); return(true); } else { method = null; return(false); } }
private bool TryGetClrField(Type /*!*/ type, BindingFlags bindingFlags, string /*!*/ name, bool isWrite, out RubyMemberInfo method) { Assert.NotNull(type, name); FieldInfo fieldInfo = type.GetField(name, bindingFlags); if (fieldInfo != null && !fieldInfo.IsPrivate && (!isWrite || !fieldInfo.IsInitOnly && !fieldInfo.IsLiteral)) { method = new RubyFieldInfo(fieldInfo, RubyMemberFlags.Public, this, isWrite); return(true); } method = null; return(false); }
private bool TryGetClrEvent(Type /*!*/ type, BindingFlags bindingFlags, string /*!*/ name, out RubyMemberInfo method) { Assert.NotNull(type, name); EventInfo eventInfo = type.GetEvent(name, bindingFlags); if (eventInfo != null) { method = new RubyEventInfo(eventInfo, RubyMemberFlags.Public, this); return(true); } method = null; return(false); }
public YamlCallSiteStorage(RubyContext /*!*/ context) : base(context) { _objectToYamlMethod = context.ObjectClass.ResolveMethod("to_yaml", VisibilityContext.AllVisible).Info; }
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) ); } }
private static void DefineMethod(RubyScope /*!*/ scope, RubyModule /*!*/ self, string /*!*/ methodName, RubyMemberInfo /*!*/ info, RubyModule /*!*/ targetConstraint) { var visibility = GetDefinedMethodVisibility(scope, self, methodName); 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( "bind argument must be a subclass of {0}", targetConstraint.GetName(scope.RubyContext) ); } self.SetDefinedMethodNoEventNoLock(self.Context, methodName, info, visibility); } self.MethodAdded(methodName); }
public static bool PublicMethodDefined(RubyModule /*!*/ self, [DefaultProtocol, NotNull] string /*!*/ methodName) { RubyMemberInfo method = self.ResolveMethod(methodName, VisibilityContext.AllVisible).Info; return(method != null && method.Visibility == RubyMethodVisibility.Public); }
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); } }
internal Curried(object target, RubyMemberInfo /*!*/ info, string /*!*/ methodNameArg) : base(target, info, "method_missing") { _methodNameArg = methodNameArg; }
// thread-safe: private static void SetLibraryMethod(RubyModule /*!*/ module, string /*!*/ name, RubyMemberInfo /*!*/ method, bool noEvent) { var context = module.Context; // trigger event only for non-builtins: if (noEvent) { // TODO: hoist lock? using (context.ClassHierarchyLocker()) { module.SetMethodNoMutateNoEventNoLock(context, name, method); } } else { module.AddMethod(context, name, method); } }