<commit_before>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

using IKVM.Reflection;
using Type = IKVM.Reflection.Type;

using Embeddinator;

namespace ObjC {
	
	public partial class ObjCGenerator : Generator {

		SourceWriter headers = new SourceWriter ();
		SourceWriter implementation = new SourceWriter ();

		public override void Generate ()
		{
			headers.WriteLine ("#include \"embeddinator.h\"");
			headers.WriteLine ("#import <Foundation/Foundation.h>");
			headers.WriteLine ();
			headers.WriteLine ();
			headers.WriteLine ("#if !__has_feature(objc_arc)");
			headers.WriteLine ("#error Embeddinator code must be built with ARC.");
			headers.WriteLine ("#endif");
			headers.WriteLine ();

			headers.WriteLine ("// forward declarations");
			foreach (var t in types)
				headers.WriteLine ($"@class {t.TypeName};");
			headers.WriteLine ();
			headers.WriteLine ("NS_ASSUME_NONNULL_BEGIN");
			headers.WriteLine ();

			implementation.WriteLine ("#include \"bindings.h\"");
			implementation.WriteLine ("#include \"glib.h\"");
			implementation.WriteLine ("#include \"objc-support.h\"");
			implementation.WriteLine ("#include \"mono_embeddinator.h\"");
			implementation.WriteLine ("#include \"mono-support.h\"");
			implementation.WriteLine ();

			implementation.WriteLine ("mono_embeddinator_context_t __mono_context;");
			implementation.WriteLine ();

			foreach (var a in assemblies)
				implementation.WriteLine ($"MonoImage* __{a.SafeName}_image;");
			implementation.WriteLine ();

			foreach (var t in types)
				implementation.WriteLine ($"static MonoClass* {t.ObjCName}_class = nil;");
			foreach (var t in protocols) {
				var pname = t.TypeName;
				headers.WriteLine ($"@protocol {pname};");
				implementation.WriteLine ($"@class __{pname}Wrapper;");
			}
			implementation.WriteLine ();

			implementation.WriteLine ("static void __initialize_mono ()");
			implementation.WriteLine ("{");
			implementation.Indent++;
			implementation.WriteLine ("if (__mono_context.domain)");
			implementation.Indent++;
			implementation.WriteLine ("return;");
			implementation.Indent--;
			implementation.WriteLine ("mono_embeddinator_init (&__mono_context, \"mono_embeddinator_binding\");");
			implementation.Indent--;
			implementation.WriteLine ("}");
			implementation.WriteLine ();

			// The generated registrar code calls this method on every entry point.
			implementation.WriteLine ("void xamarin_embeddinator_initialize ()");
			implementation.WriteLine ("{");
			implementation.WriteLine ("\t__initialize_mono ();");
			implementation.WriteLine ("}");
			implementation.WriteLine ();

			base.Generate ();

			headers.WriteLine ("NS_ASSUME_NONNULL_END");
			headers.WriteLine ();
		}

		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 ();

			foreach (var t in enums) {
				GenerateEnum (t);
			}

			foreach (var t in protocols) {
				GenerateProtocol (t);
			}

			foreach (var t in types) {
				Generate (t);
			}

			foreach (var extension in extensions_methods) {
				var defining_type = extension.Key;
				foreach (var category in extension.Value)
					GenerateCategory (defining_type, category.Key, category.Value);
			}
		}

		void GenerateCategory (Type definedType, Type extendedType, List<MethodInfo> methods)
		{
			var etn = NameGenerator.GetTypeName (extendedType).Replace (" *", String.Empty);
			var name = $"{etn} ({NameGenerator.GetTypeName (definedType)})";
			headers.WriteLine ($"/** Category {name}");
			headers.WriteLine ($" *  Corresponding .NET Qualified Name: `{definedType.AssemblyQualifiedName}`");
			headers.WriteLine (" */");
			headers.WriteLine ($"@interface {name}");
			headers.WriteLine ();

			implementation.WriteLine ($"@implementation {name}");
			implementation.WriteLine ();

			foreach (var mi in methods) {
				ImplementMethod (mi, mi.Name.CamelCase (), true);
			}
<commit_msg>[objc] Don't generate _all_ types for every assembly processed (#220)<commit_after>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

using IKVM.Reflection;
using Type = IKVM.Reflection.Type;

using Embeddinator;

namespace ObjC {
	
	public partial class ObjCGenerator : Generator {

		SourceWriter headers = new SourceWriter ();
		SourceWriter implementation = new SourceWriter ();

		public override void Generate ()
		{
			headers.WriteLine ("#include \"embeddinator.h\"");
			headers.WriteLine ("#import <Foundation/Foundation.h>");
			headers.WriteLine ();
			headers.WriteLine ();
			headers.WriteLine ("#if !__has_feature(objc_arc)");
			headers.WriteLine ("#error Embeddinator code must be built with ARC.");
			headers.WriteLine ("#endif");
			headers.WriteLine ();

			headers.WriteLine ("// forward declarations");
			foreach (var t in types)
				headers.WriteLine ($"@class {t.TypeName};");
			headers.WriteLine ();
			headers.WriteLine ("NS_ASSUME_NONNULL_BEGIN");
			headers.WriteLine ();

			implementation.WriteLine ("#include \"bindings.h\"");
			implementation.WriteLine ("#include \"glib.h\"");
			implementation.WriteLine ("#include \"objc-support.h\"");
			implementation.WriteLine ("#include \"mono_embeddinator.h\"");
			implementation.WriteLine ("#include \"mono-support.h\"");
			implementation.WriteLine ();

			implementation.WriteLine ("mono_embeddinator_context_t __mono_context;");
			implementation.WriteLine ();

			foreach (var a in assemblies)
				implementation.WriteLine ($"MonoImage* __{a.SafeName}_image;");
			implementation.WriteLine ();

			foreach (var t in types)
				implementation.WriteLine ($"static MonoClass* {t.ObjCName}_class = nil;");
			foreach (var t in protocols) {
				var pname = t.TypeName;
				headers.WriteLine ($"@protocol {pname};");
				implementation.WriteLine ($"@class __{pname}Wrapper;");
			}
			implementation.WriteLine ();

			implementation.WriteLine ("static void __initialize_mono ()");
			implementation.WriteLine ("{");
			implementation.Indent++;
			implementation.WriteLine ("if (__mono_context.domain)");
			implementation.Indent++;
			implementation.WriteLine ("return;");
			implementation.Indent--;
			implementation.WriteLine ("mono_embeddinator_init (&__mono_context, \"mono_embeddinator_binding\");");
			implementation.Indent--;
			implementation.WriteLine ("}");
			implementation.WriteLine ();

			// The generated registrar code calls this method on every entry point.
			implementation.WriteLine ("void xamarin_embeddinator_initialize ()");
			implementation.WriteLine ("{");
			implementation.WriteLine ("\t__initialize_mono ();");
			implementation.WriteLine ("}");
			implementation.WriteLine ();

			base.Generate ();

			headers.WriteLine ("NS_ASSUME_NONNULL_END");
			headers.WriteLine ();
		}

		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 ((Type arg) => arg.Assembly == assembly)) {
				GenerateEnum (t);
			}

			foreach (var t in protocols.Where ((Type arg) => arg.Assembly == assembly)) {
				GenerateProtocol (t);
			}

			foreach (var t in types.Where ((Type arg) => arg.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);
			}
		}

		void GenerateCategory (Type definedType, Type extendedType, List<MethodInfo> methods)
		{
			var etn = NameGenerator.GetTypeName (extendedType).Replace (" *", String.Empty);
			var name = $"{etn} ({NameGenerator.GetTypeName (definedType)})";
			headers.WriteLine ($"/** Category {name}");
			headers.WriteLine ($" *  Corresponding .NET Qualified Name: `{definedType.AssemblyQualifiedName}`");
			headers.WriteLine (" */");
			headers.WriteLine ($"@interface {name}");
			headers.WriteLine ();

			implementation.WriteLine ($"@implementation {name}");
			implementation.WriteLine ();

			foreach (var mi in methods) {
				ImplementMethod (mi, mi.Name.CamelCase (), true);
			}

{'fraction_non_alphanumeric': 0.14225611359453064, 'fraction_numerical': 0.0007888509071785432, 'mean_word_length': 4.51207729468599, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4705471', 'n_tokens_mistral': 3782, 'n_tokens_neox': 3085, 'n_words': 754}