Exemplo n.º 1
0
 // for debugging
 static void WriteAllNamespaces(TypeAggregator types)
 {
     foreach (var type in types.AllTypes)
     {
         Console.WriteLine(type.Namespace);
     }
 }
Exemplo n.º 2
0
        static SLImportModules ImportsForPlatform(PlatformName platform, TypeDefinition [] types)
        {
            var imports     = new SLImportModules();
            var modulesUsed = new HashSet <string> ();

            foreach (var type in types)
            {
                var moduleName = type.Namespace;
                var name       = "ThisShouldNeverGetFiltered";
                if (TypeAggregator.FilterModuleAndName(platform, type.Namespace, ref name))
                {
                    TypeAggregator.RemapModuleAndName(platform, ref moduleName, ref name, TypeType.None);
                    if (String.IsNullOrEmpty(moduleName))
                    {
                        continue;
                    }
                    if (modulesUsed.Contains(moduleName))
                    {
                        continue;
                    }
                    modulesUsed.Add(moduleName);
                    imports.Add(new SLImport(moduleName));
                }
            }
            return(imports);
        }
Exemplo n.º 3
0
        static SLAttribute AvailableAttributeForType(PlatformName platform, TypeDefinition type)
        {
            var    map = TypeAggregator.AvailableMapForPlatform(platform);
            string available;

            if (map != null && map.TryGetValue(type.FullName, out available))
            {
                return(new SLAttribute("available", true, new SLIdentifier(available)));
            }
            if (type.HasCustomAttributes)
            {
                foreach (var customAttribute in type.CustomAttributes)
                {
                    if (customAttribute.AttributeType.Name == "IntroducedAttribute")
                    {
                        var platformValue = PlatformValueForPlatform(platform);
                        if (!customAttribute.HasConstructorArguments)
                        {
                            continue;
                        }
                        if (customAttribute.ConstructorArguments [0].Value.ToString() != platformValue)
                        {
                            continue;
                        }
                        var attr = AvailableAttributeFromIntroducedAttributeType(platform, customAttribute);
                        if (attr != null)
                        {
                            return(attr);
                        }
                    }
                    else
                    {
                        var attributeName = AttributeNameForPlatform(platform);
                        if (attributeName == null)
                        {
                            continue;
                        }
                        if (customAttribute.AttributeType.Name != attributeName)
                        {
                            continue;
                        }
                        var attr = AvailableAttributeFromAttributeType(platform, customAttribute);
                        if (attr != null)
                        {
                            return(attr);
                        }
                    }
                }
            }
            return(null);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Determines if a type should be included. Types are included if they are in namespaces, they do not have
        /// generic parameters, and they pass TypeAggregator's filter.
        /// </summary>
        /// <param name="type">The type to check</param>
        /// <param name="namespaces">The namespaces to include</param>
        /// <param name="platform">The platform being targeted</param>
        /// <returns>true if type should be included, false otherwise</returns>
        static bool IncludeType(TypeDefinition type, List <string> namespaces, PlatformName platform)
        {
            if (!namespaces.Contains(type.Namespace))
            {
                return(false);
            }
            if (type.HasGenericParameters)
            {
                return(false);
            }
            var name = type.Name;

            if (TypeAggregator.FilterModuleAndName(platform, type.Namespace, ref name))
            {
                return(true);
            }
            return(false);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Makes body of map, where each line is of form:
        /// "Swift.Int": Int.self
        /// </summary>
        /// <param name="types">List of type definitions to put in map body</param>
        /// <param name="platform">Platform for compilation</param>
        /// <returns>String containing map body, one mapping per line.</returns>
        static string MapBodyForTypes(List <TypeDefinition> types, PlatformName platform)
        {
            StringBuilder result = new StringBuilder();

            foreach (var type in types)
            {
                var cSharpName = type.Name;
                var swiftName  = type.Name;
                var moduleName = type.Namespace;
                TypeAggregator.RemapModuleAndName(platform, ref moduleName, ref swiftName, TypeType.None);
                result.AppendLine($"	\"{moduleName}.{cSharpName}\": {swiftName}.self,");
            }
            if (result.Length == 0)
            {
                return("");
            }
            return(result.ToString().Substring(0, result.Length - 1));
        }
Exemplo n.º 6
0
        static SLFile GenerateStubsFromTypes(TypeAggregator types, PlatformName platform, List <string> namespaces)
        {
            var imports = ImportsForPlatform(platform, types.AllTypes);

            SLConditionalCompilation.If(PlatformCondition(platform)).AttachBefore(imports);
            new SLComment(kRobotText, true).AttachBefore(imports);
            var slfile = new SLFile(imports);

            slfile.Functions.AddRange(MetaWrapperForFunc(platform, types.PublicEnums, TypeType.Enum, namespaces));
            slfile.Functions.AddRange(MetaWrapperForFunc(platform, types.PublicStructs, TypeType.Struct, namespaces));

            // can't do ordinal because function names can have Bockovers
            slfile.Functions.Sort((func1, func2) => String.Compare(func1.Name.Name, func2.Name.Name, StringComparison.InvariantCulture));

            slfile.Trailer.Add(SLConditionalCompilation.Endif);
            // can't do ordinal because module names can have Bockovers
            imports.Sort((import1, import2) => String.Compare(import1.Module, import2.Module, StringComparison.InvariantCulture));
            return(slfile);
        }
Exemplo n.º 7
0
 static IEnumerable <SLFunc> MetaWrapperForFunc(PlatformName platform, IEnumerable <TypeDefinition> types,
                                                TypeType entityType, List <string> namespaces)
 {
     foreach (var type in types)
     {
         if (namespaces.Count > 0 && !namespaces.Contains(type.Namespace))
         {
             continue;
         }
         if (type.HasGenericParameters)
         {
             continue;
         }
         var moduleName = type.Namespace;
         var name       = type.Name;
         if (TypeAggregator.FilterModuleAndName(platform, moduleName, ref name))
         {
             yield return(MetadataFuncForType(platform, type, entityType));
         }
     }
 }
Exemplo n.º 8
0
        static SLFunc MetadataFuncForType(PlatformName platform, TypeDefinition type, TypeType entityType)
        {
            var name       = type.Name;
            var moduleName = type.Namespace;
            // typename based on C# type name, not remapped name
            var funcID = new SLIdentifier(FuncIDForTypeDefinition(type));

            TypeAggregator.RemapModuleAndName(platform, ref moduleName, ref name, entityType);
            var value      = new SLIdentifier($"{name}.self");
            var returnLine = SLReturn.ReturnLine(value);
            var body       = new SLCodeBlock(null);

            body.Add(returnLine);
            var func = new SLFunc(Visibility.Public, new SLSimpleType("Any.Type"), funcID, null, body);

            new SLComment(type.FullName, true).AttachBefore(func);
            var attr = AvailableAttributeForType(platform, type);

            if (attr != null)
            {
                attr.AttachBefore(func);
            }
            return(func);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Creates a hash table for all types, and a function to access them.
        /// </summary>
        /// <param name="types">Aggregated types, a subset of which are included</param>
        /// <param name="platform">Platform targeted (typically iOS or Mac)</param>
        /// <param name="namespaces">Namespaces to include</param>
        /// <returns>SLFile which, when written, has hash table and function as described in summary</returns>
        static SLFile GenerateSwiftHashTableFromTypes(TypeAggregator types, PlatformName platform, List <string> namespaces)
        {
            var imports = ImportsForPlatform(platform, types.AllTypes);

            SLConditionalCompilation.If(PlatformCondition(platform)).AttachBefore(imports);
            new SLComment(kRobotText, true).AttachBefore(imports);
            var slfile = new SLFile(imports);

            // collect and filter types
            var selectedTypes = new List <TypeDefinition> ();

            selectedTypes.AddRange(types.PublicEnums);
            selectedTypes.AddRange(types.PublicStructs);
            selectedTypes = selectedTypes.FindAll(type => IncludeType(type, namespaces, platform));
            selectedTypes.Sort((type1, type2) => String.CompareOrdinal(type1.FullName, type2.FullName));

            // sort types into respective availability categories
            var availableCategories = new Dictionary <string, List <TypeDefinition> > ();

            foreach (var type in selectedTypes)
            {
                var typeAttributeObj = AvailableAttributeForType(platform, type);
                var typeAttribute    = typeAttributeObj == null ? "" : typeAttributeObj.StringRep;
                List <TypeDefinition> otherTypes;
                if (availableCategories.TryGetValue(typeAttribute, out otherTypes))
                {
                    otherTypes.Add(type);
                }
                else
                {
                    otherTypes = new List <TypeDefinition> {
                        type
                    };
                    availableCategories.Add(typeAttribute, otherTypes);
                }
            }

            // debug
            //foreach (var pair in availableCategories) {
            //	Console.WriteLine ($"Available attribute \"{pair.Key}\": {pair.Value.Aggregate("", (str, type) => str + ", " + type.Name).Substring(2)} (length: {pair.Value.Count})");
            //}

            // add map for each availability status
            var maps     = new StringBuilder();
            var mergeFns = new StringBuilder();

            mergeFns.AppendLine("private func addToTypes() {");
            foreach (var category in availableCategories)
            {
                var availableInfo = category.Key;
                var modifier      = "public";
                var prefix        = "";
                var header        = "";
                if (availableInfo != "")
                {
                    modifier = "private";
                    prefix   = AvailableDictPrefix(availableInfo);
                    header   = $"@{availableInfo}";
                }
                if (header != "")
                {
                    maps.AppendLine(header);
                }
                maps.AppendLine($"{modifier} var {prefix}types: [String:Any.Type] = [");
                maps.AppendLine(MapBodyForTypes(category.Value, platform));
                maps.AppendLine("]");
                maps.AppendLine();

                if (availableInfo != "")
                {
                    mergeFns.AppendLine($"	if #{availableInfo} {{");
                    mergeFns.AppendLine($"		types.merge({AvailableDictPrefix (availableInfo)}types) {{ (_, newer) in newer }}");
                    mergeFns.AppendLine("	}");
                }
            }
            if (!availableCategories.ContainsKey(""))
            {
                maps.AppendLine("public var types = [String:Any.Type]()");
            }
            mergeFns.AppendLine("}");
            slfile.Declarations.Add(new SLLine(new SLIdentifier(maps.ToString()), false));
            slfile.Declarations.Add(new SLLine(new SLIdentifier(mergeFns.ToString()), false));

            // add function to fetch type
            var handleTranslation = @"
private var merged = false

public func getSwiftType(str: UnsafeMutablePointer<String>, result: UnsafeMutablePointer<Any.Type>) -> Bool {
	if !merged {
		merged = true
		addToTypes()
	}
	if let mt = types[str.pointee] {
		result.initialize(to: mt)
		return true
	}
	return false
}";

            slfile.Declarations.Add(new SLLine(new SLIdentifier(handleTranslation), false));

            slfile.Trailer.Add(SLConditionalCompilation.Endif);
            // can't do ordinal because module names can have Bockovers
            imports.Sort((import1, import2) => String.Compare(import1.Module, import2.Module, StringComparison.InvariantCulture));
            return(slfile);
        }
Exemplo n.º 10
0
        static CSFile GeneratePInvokesFromTypes(TypeAggregator types, PlatformName platform, string framework)
        {
            var fileName  = Path.GetFileNameWithoutExtension(framework);             // /path/XamGlue.framework -> XamGlue
            var dylibFile = Path.Combine(framework, fileName);
            var funcs     = TLFunctionsForFile(dylibFile, platform);

            var ns  = new CSNamespace("SwiftRuntimeLibrary.SwiftMarshal");
            var use = new CSUsingPackages();

            use.And(new CSUsing("System.Runtime.InteropServices"))
            .And(new CSUsing("System"))
            .And(new CSUsing("System.Collections.Generic"))
            .And(new CSUsing("SwiftRuntimeLibrary"));

            var csFile  = new CSFile(use, new CSNamespace [] { ns });
            var csClass = new CSClass(CSVisibility.Internal, $"{fileName}Metadata");

            new CSComment(kRobotText).AttachBefore(use);

            CSConditionalCompilation.If(PlatformToCSCondition(platform)).AttachBefore(use);
            CSConditionalCompilation.Endif.AttachAfter(ns);
            ns.Block.Add(csClass);

            var typeOntoPinvoke = new List <KeyValuePair <CSBaseExpression, CSBaseExpression> > ();

            var typesToProcess = new List <TypeDefinition> ();

            typesToProcess.AddRange(types.PublicEnums);
            typesToProcess.AddRange(types.PublicStructs);

            // pre-sort by function name
            typesToProcess.Sort((type1, type2) => String.CompareOrdinal(FuncIDForTypeDefinition(type1), FuncIDForTypeDefinition(type2)));

            foreach (var type in typesToProcess)
            {
                if (type.HasGenericParameters)
                {
                    continue;
                }
                var moduleName = type.Namespace;
                var name       = type.Name;
                if (TypeAggregator.FilterModuleAndName(platform, moduleName, ref name))
                {
                    var pinvoke = PInvokeForType(type, funcs);
                    if (pinvoke != null)
                    {
                        csClass.Methods.Add(pinvoke);
                        use.AddIfNotPresent(type.Namespace);
                        var typeOf   = new CSSimpleType(type.FullName).Typeof();
                        var funcName = pinvoke.Name;
                        typeOntoPinvoke.Add(new KeyValuePair <CSBaseExpression, CSBaseExpression> (typeOf, funcName));
                    }
                }
            }

            var initializers = typeOntoPinvoke.Select(typeAndFunc => new CSInitializer(new CSBaseExpression [] { typeAndFunc.Key, typeAndFunc.Value }, false));
            var bindingExpr  = new CSInitializedType(new CSFunctionCall("Dictionary<Type, Func<SwiftMetatype>>", true), new CSInitializer(initializers, true));
            var bindingDecl  = new CSFieldDeclaration(new CSSimpleType("Dictionary<Type, Func<SwiftMetatype>>"), "ObjCBindingSwiftMetatypes", bindingExpr, CSVisibility.Internal, true);

            csClass.Fields.Add(new CSLine(bindingDecl));

            use.Sort((package1, package2) => String.CompareOrdinal(package1.Package, package2.Package));

            return(csFile);
        }
Exemplo n.º 11
0
        public static int Main(string [] args)
        {
            TypeOMaticOptions options = new TypeOMaticOptions();
            var extra = options.ParseCommandLine(args);

            if (options.PrintHelp)
            {
                options.PrintUsage(Console.Out);
                return(0);
            }

            if (extra.Count > 0)
            {
                // Warn about extra params that are ignored.
                Console.WriteLine($"WARNING: The following extra parameters will be ignored: '{ String.Join (",", extra) }'");
            }

            if (string.IsNullOrEmpty(options.SwiftLibPath))
            {
                Console.WriteLine("Unable to find the custom swift compiler libraries. Try using --swift-lib-path.");
                return(1);
            }

            if (options.Platform == PlatformName.None)
            {
                Console.WriteLine($"Unknown platform {options.Platform}");
                options.PrintUsage(Console.Out);
                return(1);
            }

            var targetDirectory = Path.Combine(options.SwiftLibPath, PlaformToDirectoryName(options.Platform));

            if (!Directory.Exists(targetDirectory))
            {
                Console.WriteLine($"Unable to find library directory {targetDirectory}");
                return(1);
            }

            if (options.ToGenerate == null || !String.Equals(options.ToGenerate, "swift") && !String.Equals(options.ToGenerate, "csharp"))
            {
                Console.WriteLine("You need to specify what type of code you want to generate, either 'swift' or 'csharp'.");
                return(1);
            }

            if (options.Namespaces.Count == 0)
            {
                Console.WriteLine("You need to select input namespaces.");
                return(1);
            }

            if (String.Equals(options.ToGenerate, "csharp") && options.Framework == null)
            {
                Console.WriteLine("You need to select a XamGlue.framework to generate C#");
                return(1);
            }

            if (options.Framework != null && !Directory.Exists(options.Framework))
            {
                Console.WriteLine($"Unable to find XamGlue framework at {options.Framework}.");
                return(1);
            }

            var aggregatedTypes = new TypeAggregator(options.Platform);

            aggregatedTypes.Aggregate();

            var writer = new CodeWriter(options.OutputWriter);

            if (String.Equals(options.ToGenerate, "swift"))
            {
                var slFile = GenerateSwiftHashTableFromTypes(aggregatedTypes, options.Platform, options.Namespaces);
                slFile.WriteAll(writer);
            }
            else
            {
                var csFile = GenerateCSharpHashTableFromTypes(aggregatedTypes, options.Platform, options.Namespaces, options.Framework);
                csFile.WriteAll(writer);
            }
            writer.TextWriter.Flush();
            if (options.OutputWriter != Console.Out)
            {
                options.OutputWriter.Close();
                options.OutputWriter.Dispose();
            }

            return(0);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Creates a list of all types, and a hash table which is initialized on first lookup from C# type
        /// to Swift types.
        /// </summary>
        /// <param name="types">Aggregated types, a subset of which are included</param>
        /// <param name="platform">Platform targeted (typically iOS or Mac)</param>
        /// <param name="namespaces">Namespaces to include</param>
        /// <param name="framework">Name of framework used (typically XamGlue)</param>
        /// <returns>CSFile which, when written, has function looking up in hash table as described in summary</returns>
        static CSFile GenerateCSharpHashTableFromTypes(TypeAggregator types, PlatformName platform, List <string> namespaces, string framework)
        {
            var fileName = Path.GetFileNameWithoutExtension(framework);
            var ns       = new CSNamespace("SwiftRuntimeLibrary.SwiftMarshal");
            var use      = new CSUsingPackages();

            use.And(new CSUsing("System.Runtime.InteropServices"))
            .And(new CSUsing("System"))
            .And(new CSUsing("System.Collections.Generic"))
            .And(new CSUsing("SwiftRuntimeLibrary"));

            var csFile  = new CSFile(use, new CSNamespace [] { ns });
            var csClass = new CSClass(CSVisibility.Internal, $"{fileName}Metadata");

            new CSComment(kRobotText).AttachBefore(use);

            CSConditionalCompilation.If(PlatformToCSCondition(platform)).AttachBefore(use);
            CSConditionalCompilation.Endif.AttachAfter(ns);
            ns.Block.Add(csClass);

            // collect all possible types, filter and sort
            var selectedTypes = new List <TypeDefinition> ();

            selectedTypes.AddRange(types.PublicEnums);
            selectedTypes.AddRange(types.PublicStructs);
            selectedTypes = selectedTypes.FindAll(type => IncludeType(type, namespaces, platform));
            selectedTypes.Sort((type1, type2) => String.CompareOrdinal(type1.FullName, type2.FullName));

            // add used namespaces to import list, sort list
            foreach (var type in selectedTypes)
            {
                use.AddIfNotPresent(type.Namespace);
            }
            use.Sort((package1, package2) => String.CompareOrdinal(package1.Package, package2.Package));

            // create list of types to translate
            var typesForList       = selectedTypes.Select(type => new CSSimpleType(type.FullName).Typeof());
            var listInitializeExpr = new CSInitializedType(
                new CSFunctionCall("List<Type>", true),
                new CSInitializer(typesForList, true)
                );
            var listBindingDecl = new CSFieldDeclaration(new CSSimpleType("List<Type>"), "csImportTypes", listInitializeExpr, CSVisibility.Internal, true);

            csClass.Fields.Add(new CSLine(listBindingDecl));

            // create pinvoke for function
            var dylibFile = Path.Combine(framework, fileName);
            var funcs     = TLFunctionsForFile(dylibFile, platform);

            var handleTranslationCode = new CSIdentifier(@"
		public static unsafe bool GetSwiftType (Type t, out SwiftMetatype md) {
			using (var swiftStr = new SwiftString (t.FullName)) {
				return SwiftCore.GetEnumMetadataByName (swiftStr.SwiftData, out md);
			}
		}

		internal static Dictionary<Type, SwiftMetatype> csImportMeta = null;
		internal static bool TryGetImportedMetadata (Type cSharpType, out SwiftMetatype md) {
			if (csImportMeta == null) {
				csImportMeta = new Dictionary<Type, SwiftMetatype> (csImportTypes.Count);
				foreach (var t in csImportTypes) {
					SwiftMetatype meta;
					GetSwiftType(t, out meta);
					csImportMeta [t] = meta;
				}
			}
			return csImportMeta.TryGetValue (cSharpType, out md);
		}"        );

            csClass.Fields.Add(new CSLine(handleTranslationCode, false));

            return(csFile);
        }