public static string GetArrayCreator(string parameterName, Type type) { string arrayCreator = $"MonoArray* __{parameterName}arr = mono_array_new (__mono_context.domain, {{0}}, __{parameterName}length);"; switch (Type.GetTypeCode(type)) { case TypeCode.String: return(string.Format(arrayCreator, "mono_get_string_class ()")); case TypeCode.Boolean: return(string.Format(arrayCreator, "mono_get_boolean_class ()")); case TypeCode.Char: return(string.Format(arrayCreator, "mono_get_char_class ()")); case TypeCode.SByte: return(string.Format(arrayCreator, "mono_get_sbyte_class ()")); case TypeCode.Int16: return(string.Format(arrayCreator, "mono_get_int16_class ()")); case TypeCode.Int32: return(string.Format(arrayCreator, "mono_get_int32_class ()")); case TypeCode.Int64: return(string.Format(arrayCreator, "mono_get_int64_class ()")); case TypeCode.Byte: return(string.Format(arrayCreator, "mono_get_byte_class ()")); case TypeCode.UInt16: return(string.Format(arrayCreator, "mono_get_uint16_class ()")); case TypeCode.UInt32: return(string.Format(arrayCreator, "mono_get_uint32_class ()")); case TypeCode.UInt64: return(string.Format(arrayCreator, "mono_get_uint64_class ()")); case TypeCode.Single: return(string.Format(arrayCreator, "mono_get_single_class ()")); case TypeCode.Double: return(string.Format(arrayCreator, "mono_get_double_class ()")); case TypeCode.Object: return(string.Format(arrayCreator, $"{NameGenerator.GetObjCName (type)}_class")); case TypeCode.Decimal: return(string.Format(arrayCreator, "mono_embeddinator_get_decimal_class ()")); default: throw new NotImplementedException($"Converting type {type.FullName} to mono class"); } }
// TODO override with attribute ? e.g. [ObjC.Selector ("foo")] string ImplementMethod(MethodInfo info, string name, bool isExtension = false, PropertyInfo pi = null, bool useTypeNames = false) { var type = info.DeclaringType; var managed_type_name = NameGenerator.GetObjCName(type); string objcsig; string monosig; var managed_name = info.Name; var parametersInfo = info.GetParameters(); GetSignatures(name, managed_name, (MemberInfo)pi ?? info, parametersInfo, useTypeNames, isExtension, out objcsig, out monosig); var builder = new MethodHelper(headers, implementation) { AssemblySafeName = type.Assembly.GetName().Name.Sanitize(), IsStatic = info.IsStatic, IsExtension = isExtension, ReturnType = GetReturnType(type, info.ReturnType), ManagedTypeName = type.FullName, MetadataToken = info.MetadataToken, MonoSignature = monosig, ObjCSignature = objcsig, ObjCTypeName = managed_type_name, IsValueType = type.IsValueType, IsVirtual = info.IsVirtual, }; if (pi == null) { builder.WriteHeaders(); } builder.BeginImplementation(); builder.WriteMethodLookup(); string postInvoke = String.Empty; var args = "nil"; if (parametersInfo.Length > 0) { Generate(parametersInfo, isExtension, out postInvoke); args = "__args"; } builder.WriteInvoke(args); // ref and out parameters might need to be converted back implementation.Write(postInvoke); ReturnValue(info.ReturnType); builder.EndImplementation(); return(objcsig); }
void GenerateDefaultValuesWrapper(string name, MethodBase mb, ParameterInfo[] parameters, int start) { MethodInfo mi = mb as MethodInfo; string objcsig; string monosig; var parametersInfo = parameters; var plist = new List <ParameterInfo> (); StringBuilder arguments = new StringBuilder(); headers.WriteLine("/** This is an helper method that inlines the following default values:"); foreach (var p in parameters) { string pName = NameGenerator.GetExtendedParameterName(p, parameters); if (arguments.Length == 0) { arguments.Append(p.Name.PascalCase()).Append(':'); } else { arguments.Append(' ').Append(p.Name.CamelCase()).Append(':'); } if (p.Position >= start && p.HasDefaultValue) { var raw = FormatRawValue(p.ParameterType, p.RawDefaultValue); headers.WriteLine($" * ({NameGenerator.GetTypeName (p.ParameterType)}) {pName} = {raw};"); arguments.Append(raw); } else { arguments.Append(pName); plist.Add(p); } } headers.WriteLine(" *"); headers.WriteLine($" * @see {name}"); headers.WriteLine(" */"); if (mi == null) { name = start == 0 ? "init" : "initWith"; } else { name = mb.Name.CamelCase(); } GetSignatures(name, mb.Name, mb, plist.ToArray(), false, false, out objcsig, out monosig); var type = mb.DeclaringType; var builder = new MethodHelper(headers, implementation) { IsStatic = mb.IsStatic, ReturnType = mi == null ? "nullable instancetype" : GetReturnType(type, mi.ReturnType), ObjCSignature = objcsig, }; builder.WriteHeaders(); headers.WriteLine(); builder.BeginImplementation(); if (mi == null || !mi.ReturnType.Is("System", "Void")) { implementation.Write("return ["); } if (mb.IsStatic) { implementation.Write(NameGenerator.GetObjCName(mi.DeclaringType)); implementation.Write(' '); } else { implementation.Write("self "); } if (mi == null) { name = "initWith"; } implementation.WriteLine($"{name}{arguments}];"); builder.EndImplementation(); }
protected override void Generate(ProcessedAssembly a) { var originalName = a.Name; var name = a.SafeName; implementation.WriteLine($"static void __lookup_assembly_{name} ()"); implementation.WriteLine("{"); implementation.Indent++; implementation.WriteLine($"if (__{name}_image)"); implementation.Indent++; implementation.WriteLine("return;"); implementation.Indent--; implementation.WriteLine("__initialize_mono ();"); implementation.WriteLine($"__{name}_image = mono_embeddinator_load_assembly (&__mono_context, \"{originalName}.dll\");"); implementation.WriteLine($"assert (__{name}_image && \"Could not load the assembly '{originalName}.dll'.\");"); var categories = extensions_methods.Keys; if (categories.Count > 0) { implementation.WriteLine("// we cannot use `+initialize` inside categories as they would replace the original type code"); implementation.WriteLine("// since there should not be tons of them we're pre-loading them when loading the assembly"); foreach (var definedType in extensions_methods.Keys) { var managed_name = NameGenerator.GetObjCName(definedType); implementation.WriteLineUnindented("#if TOKENLOOKUP"); implementation.WriteLine($"{managed_name}_class = mono_class_get (__{name}_image, 0x{definedType.MetadataToken:X8});"); implementation.WriteLineUnindented("#else"); implementation.WriteLine($"{managed_name}_class = mono_class_from_name (__{name}_image, \"{definedType.Namespace}\", \"{definedType.Name}\");"); implementation.WriteLineUnindented("#endif"); } } implementation.Indent--; implementation.WriteLine("}"); implementation.WriteLine(); var assembly = a.Assembly; foreach (var t in enums.Where((ProcessedType arg) => arg.Type.Assembly == assembly)) { GenerateEnum(t); } foreach (var t in protocols.Where((ProcessedType arg) => arg.Type.Assembly == assembly)) { GenerateProtocol(t); } foreach (var t in types.Where((ProcessedType arg) => arg.Type.Assembly == assembly)) { Generate(t); } foreach (var extension in extensions_methods) { var defining_type = extension.Key; if (defining_type.Assembly != assembly) { continue; } foreach (var category in extension.Value) { GenerateCategory(defining_type, category.Key, category.Value); } } }
protected void Generate(ProcessedFieldInfo field) { FieldInfo fi = field.Field; bool read_only = fi.IsInitOnly || fi.IsLiteral; headers.Write("@property (nonatomic"); if (fi.IsStatic) { headers.Write(", class"); } if (read_only) { headers.Write(", readonly"); } var ft = fi.FieldType; var bound = types.Contains(ft); if (bound && ft.IsValueType) { headers.Write(", nonnull"); } var field_type = NameGenerator.GetTypeName(ft); if (bound) { field_type += " *"; } var name = fi.Name.CamelCase(); var spacing = field_type [field_type.Length - 1] == '*' ? string.Empty : " "; headers.WriteLine($") {field_type}{spacing}{name};"); // it's similar, but different from implementing a method var type = fi.DeclaringType; var managed_type_name = NameGenerator.GetObjCName(type); var return_type = GetReturnType(type, fi.FieldType); implementation.Write(fi.IsStatic ? '+' : '-'); implementation.WriteLine($" ({return_type}) {name}"); implementation.WriteLine("{"); implementation.Indent++; implementation.WriteLine("static MonoClassField* __field = nil;"); implementation.WriteLine("if (!__field) {"); implementation.Indent++; implementation.WriteLineUnindented("#if TOKENLOOKUP"); implementation.WriteLine($"__field = mono_class_get_field ({managed_type_name}_class, 0x{fi.MetadataToken:X8});"); implementation.WriteLineUnindented("#else"); implementation.WriteLine($"const char __field_name [] = \"{fi.Name}\";"); implementation.WriteLine($"__field = mono_class_get_field_from_name ({managed_type_name}_class, __field_name);"); implementation.WriteLineUnindented("#endif"); implementation.Indent--; implementation.WriteLine("}"); var instance = "nil"; if (!fi.IsStatic) { implementation.WriteLine($"MonoObject* __instance = mono_gchandle_get_target (_object->_handle);"); instance = "__instance"; } implementation.WriteLine($"MonoObject* __result = mono_field_get_value_object (__mono_context.domain, __field, {instance});"); if (types.Contains(ft)) { implementation.WriteLine("if (!__result)"); implementation.Indent++; implementation.WriteLine("return nil;"); implementation.Indent--; } ReturnValue(fi.FieldType); implementation.Indent--; implementation.WriteLine("}"); implementation.WriteLine(); if (read_only) { return; } implementation.Write(fi.IsStatic ? '+' : '-'); implementation.WriteLine($" (void) set{fi.Name}:({field_type})value"); implementation.WriteLine("{"); implementation.Indent++; implementation.WriteLine("static MonoClassField* __field = nil;"); implementation.WriteLine("if (!__field) {"); implementation.Indent++; implementation.WriteLineUnindented("#if TOKENLOOKUP"); implementation.WriteLine($"__field = mono_class_get_field ({managed_type_name}_class, 0x{fi.MetadataToken:X8});"); implementation.WriteLineUnindented("#else"); implementation.WriteLine($"const char __field_name [] = \"{fi.Name}\";"); implementation.WriteLine($"__field = mono_class_get_field_from_name ({managed_type_name}_class, __field_name);"); implementation.WriteLineUnindented("#endif"); implementation.Indent--; implementation.WriteLine("}"); StringBuilder sb = null; implementation.WriteLine($"void* __value;"); GenerateArgument("value", "__value", fi.FieldType, ref sb); if (fi.IsStatic) { implementation.WriteLine($"MonoVTable *__vtable = mono_class_vtable (__mono_context.domain, {managed_type_name}_class);"); implementation.WriteLine("mono_field_static_set_value (__vtable, __field, __value);"); } else { implementation.WriteLine($"MonoObject* __instance = mono_gchandle_get_target (_object->_handle);"); implementation.WriteLine("mono_field_set_value (__instance, __field, __value);"); } implementation.Indent--; implementation.WriteLine("}"); implementation.WriteLine(); }
protected override void Generate(ProcessedType type) { Type t = type.Type; var aname = t.Assembly.GetName().Name.Sanitize(); var static_type = t.IsSealed && t.IsAbstract; var managed_name = NameGenerator.GetObjCName(t); List <string> conformed_protocols = new List <string> (); foreach (var i in t.GetInterfaces()) { if (protocols.Contains(i)) { conformed_protocols.Add(NameGenerator.GetObjCName(i)); } } var tbuilder = new ClassHelper(headers, implementation) { AssemblyQualifiedName = t.AssemblyQualifiedName, AssemblyName = aname, BaseTypeName = NameGenerator.GetTypeName(t.BaseType), Name = NameGenerator.GetTypeName(t), Namespace = t.Namespace, ManagedName = t.Name, Protocols = conformed_protocols, IsBaseTypeBound = types.Contains(t.BaseType), IsStatic = t.IsSealed && t.IsAbstract, MetadataToken = t.MetadataToken, }; tbuilder.BeginHeaders(); tbuilder.BeginImplementation(); var default_init = false; List <ProcessedConstructor> constructors; if (ctors.TryGetValue(t, out constructors)) { // First get the unavailable init ctor selectors in parent class var unavailableCtors = GetUnavailableParentCtors(t, constructors); if (unavailableCtors.Count() > 0) { // TODO: Print a #pragma mark once we have a well defined header structure http://nshipster.com/pragma/ foreach (var uctor in unavailableCtors) { var ctorparams = uctor.Constructor.GetParameters(); string name = "init"; string signature = ".ctor()"; if (ctorparams.Length > 0) { GetSignatures("initWith", uctor.Constructor.Name, uctor.Constructor, ctorparams, uctor.FallBackToTypeName, false, out name, out signature); } headers.WriteLine("/** This initializer is not available as it was not re-exposed from the base type"); headers.WriteLine(" * For more details consult https://github.com/mono/Embeddinator-4000/blob/master/docs/ObjC.md#constructors-vs-initializers"); headers.WriteLine(" */"); headers.WriteLine($"- (nullable instancetype){name} NS_UNAVAILABLE;"); headers.WriteLine(); } } foreach (var ctor in constructors) { var pcount = ctor.Constructor.ParameterCount; default_init |= pcount == 0; var parameters = ctor.Constructor.GetParameters(); string name = "init"; string signature = ".ctor()"; if (parameters.Length > 0) { GetSignatures("initWith", ctor.Constructor.Name, ctor.Constructor, parameters, ctor.FallBackToTypeName, false, out name, out signature); } var builder = new MethodHelper(headers, implementation) { AssemblySafeName = aname, ReturnType = "nullable instancetype", ManagedTypeName = t.FullName, MetadataToken = ctor.Constructor.MetadataToken, MonoSignature = signature, ObjCSignature = name, ObjCTypeName = managed_name, IsConstructor = true, IsValueType = t.IsValueType, IgnoreException = true, }; builder.WriteHeaders(); builder.BeginImplementation(); builder.WriteMethodLookup(); // TODO: this logic will need to be update for managed NSObject types (e.g. from XI / XM) not to call [super init] implementation.WriteLine("if (!_object) {"); implementation.Indent++; implementation.WriteLine($"MonoObject* __instance = mono_object_new (__mono_context.domain, {managed_name}_class);"); string postInvoke = String.Empty; var args = "nil"; if (pcount > 0) { Generate(parameters, false, out postInvoke); args = "__args"; } builder.WriteInvoke(args); implementation.Write(postInvoke); implementation.WriteLine("_object = mono_embeddinator_create_object (__instance);"); implementation.Indent--; implementation.WriteLine("}"); if (types.Contains(t.BaseType)) { implementation.WriteLine("return self = [super initForSuper];"); } else { implementation.WriteLine("return self = [super init];"); } builder.EndImplementation(); headers.WriteLine(); if (members_with_default_values.Contains(ctor.Constructor)) { default_init |= GenerateDefaultValuesWrappers(name, ctor.Constructor); } } } // generate an `init` for a value type (even if none was defined, the default one is usable) if (!default_init && t.IsValueType) { var builder = new MethodHelper(headers, implementation) { AssemblySafeName = aname, ReturnType = "nullable instancetype", ManagedTypeName = t.FullName, MonoSignature = ".ctor()", ObjCSignature = "init", ObjCTypeName = managed_name, IsConstructor = true, IsValueType = t.IsValueType, IgnoreException = true, }; builder.WriteHeaders(); builder.BeginImplementation(); // no call to `WriteMethodLookup` since there is not such method if we reached this case implementation.WriteLine("if (!_object) {"); implementation.Indent++; implementation.WriteLine($"MonoObject* __instance = mono_object_new (__mono_context.domain, {managed_name}_class);"); // no call to `WriteInvoke` since there is not such method if we reached this case implementation.WriteLine("_object = mono_embeddinator_create_object (__instance);"); implementation.Indent--; implementation.WriteLine("}"); if (types.Contains(t.BaseType)) { implementation.WriteLine("return self = [super initForSuper];"); } else { implementation.WriteLine("return self = [super init];"); } builder.EndImplementation(); headers.WriteLine(); default_init = true; } if (!default_init || static_type) { tbuilder.DefineNoDefaultInit(); } List <ProcessedProperty> props; if (properties.TryGetValue(t, out props)) { headers.WriteLine(); foreach (var pi in props) { Generate(pi); } } List <ProcessedFieldInfo> f; if (fields.TryGetValue(t, out f)) { headers.WriteLine(); foreach (var fi in f) { Generate(fi); } } List <ProcessedProperty> s; if (subscriptProperties.TryGetValue(t, out s)) { headers.WriteLine(); foreach (var si in s) { GenerateSubscript(si); } } List <ProcessedMethod> meths; if (methods.TryGetValue(t, out meths)) { headers.WriteLine(); foreach (var mi in meths) { Generate(mi); } } MethodInfo m; if (icomparable.TryGetValue(t, out m)) { var pt = m.GetParameters() [0].ParameterType; var builder = new ComparableHelper(headers, implementation) { ObjCSignature = $"compare:({managed_name} * _Nullable)other", AssemblySafeName = aname, MetadataToken = m.MetadataToken, ObjCTypeName = managed_name, ManagedTypeName = t.FullName, MonoSignature = $"CompareTo({NameGenerator.GetMonoName (pt)})", }; builder.WriteHeaders(); builder.WriteImplementation(); } if (equals.TryGetValue(t, out m)) { var builder = new EqualsHelper(headers, implementation) { AssemblySafeName = aname, MetadataToken = m.MetadataToken, ObjCTypeName = managed_name, ManagedTypeName = t.FullName, }; builder.WriteHeaders(); builder.WriteImplementation(); } if (hashes.TryGetValue(t, out m)) { var builder = new HashHelper(headers, implementation) { AssemblySafeName = aname, MetadataToken = m.MetadataToken, ObjCTypeName = managed_name, ManagedTypeName = t.FullName, }; builder.WriteHeaders(); builder.WriteImplementation(); } tbuilder.EndHeaders(); tbuilder.EndImplementation(); }