/// <summary> /// Generates the user types. /// </summary> private void GenerateUserTypes() { // Verify that included files exist if (!string.IsNullOrEmpty(xmlConfig.GeneratedAssemblyName)) { foreach (var file in includedFiles) { if (!File.Exists(file.Path)) { throw new FileNotFoundException("Included file not found", file.Path); } } } // Loading modules Module[] modulesArray = new Module[xmlModules.Length]; logger.Write("Loading modules..."); Parallel.For(0, xmlModules.Length, (i) => { Module module = moduleProvider.Open(xmlModules[i]); modulesArray[i] = module; }); Dictionary <Module, XmlModule> modules = new Dictionary <Module, XmlModule>(); for (int i = 0; i < modulesArray.Length; i++) { modules.Add(modulesArray[i], xmlModules[i]); } logger.WriteLine(" {0}", stopwatch.Elapsed); // Enumerating symbols Symbol[][] globalTypesPerModule = new Symbol[xmlModules.Length][]; logger.Write("Enumerating symbols..."); Parallel.For(0, xmlModules.Length, (i) => { XmlModule xmlModule = xmlModules[i]; Module module = modulesArray[i]; string moduleName = xmlModule.Name; string nameSpace = xmlModule.Namespace; HashSet <Symbol> symbols = new HashSet <Symbol>(); foreach (var type in typeNames) { Symbol[] foundSymbols = module.FindGlobalTypeWildcard(type.NameWildcard); if (foundSymbols.Length == 0) { errorLogger.WriteLine("Symbol not found: {0}", type.Name); } else { foreach (Symbol symbol in foundSymbols) { symbols.Add(symbol); } } if (type.ExportDependentTypes) { foreach (Symbol symbol in foundSymbols) { symbol.ExtractDependentSymbols(symbols, xmlConfig.Transformations); } } } if (symbols.Count == 0) { foreach (Symbol symbol in module.GetAllTypes()) { symbols.Add(symbol); } } globalTypesPerModule[i] = symbols.Where(t => t.Tag == CodeTypeTag.Class || t.Tag == CodeTypeTag.Structure || t.Tag == CodeTypeTag.Union || t.Tag == CodeTypeTag.Enum).ToArray(); // Cache global scope if (generationOptions.HasFlag(UserTypeGenerationFlags.InitializeSymbolCaches)) { var globalScope = module.GlobalScope; globalScope.InitializeCache(); } }); List <Symbol> allSymbols = globalTypesPerModule.SelectMany(ss => ss).ToList(); logger.WriteLine(" {0}", stopwatch.Elapsed); // Initialize symbol fields and base classes if (generationOptions.HasFlag(UserTypeGenerationFlags.InitializeSymbolCaches)) { logger.Write("Initializing symbol values..."); Parallel.ForEach(Partitioner.Create(allSymbols), symbol => symbol.InitializeCache()); logger.WriteLine(" {0}", stopwatch.Elapsed); } logger.Write("Deduplicating symbols..."); // Group duplicated symbols Dictionary <string, List <Symbol> > symbolsByName = new Dictionary <string, List <Symbol> >(); Dictionary <Symbol, List <Symbol> > duplicatedSymbols = new Dictionary <Symbol, List <Symbol> >(); foreach (var symbol in allSymbols) { List <Symbol> symbols; if (!symbolsByName.TryGetValue(symbol.Name, out symbols)) { symbolsByName.Add(symbol.Name, symbols = new List <Symbol>()); } bool found = false; for (int i = 0; i < symbols.Count; i++) { Symbol s = symbols[i]; if (s.Size != 0 && symbol.Size != 0 && s.Size != symbol.Size) { #if DEBUG logger.WriteLine("{0}!{1} ({2}) {3}!{4} ({5})", s.Module.Name, s.Name, s.Size, symbol.Module.Name, symbol.Name, symbol.Size); #endif continue; } if (s.Size == 0 && symbol.Size != 0) { List <Symbol> duplicates; if (!duplicatedSymbols.TryGetValue(s, out duplicates)) { duplicatedSymbols.Add(s, duplicates = new List <Symbol>()); } duplicatedSymbols.Remove(s); duplicates.Add(s); duplicatedSymbols.Add(symbol, duplicates); symbols.Remove(s); symbols.Add(symbol); } else { List <Symbol> duplicates; if (!duplicatedSymbols.TryGetValue(s, out duplicates)) { duplicatedSymbols.Add(s, duplicates = new List <Symbol>()); } duplicates.Add(symbol); } found = true; break; } if (!found) { symbols.Add(symbol); } } // Unlink duplicated symbols if two or more are named the same foreach (var symbols in symbolsByName.Values) { if (symbols.Count <= 1) { continue; } for (int i = 0, n = symbols.Count; i < n; i++) { Symbol s = symbols[i]; List <Symbol> duplicates; if (!duplicatedSymbols.TryGetValue(s, out duplicates)) { continue; } symbols.AddRange(duplicates); duplicatedSymbols.Remove(s); } } // Extracting deduplicated symbols Dictionary <string, Symbol[]> deduplicatedSymbols = new Dictionary <string, Symbol[]>(); Dictionary <Symbol, string> symbolNamespaces = new Dictionary <Symbol, string>(); foreach (var symbols in symbolsByName.Values) { if (symbols.Count != 1 || modules.Count == 1) { foreach (var s in symbols) { symbolNamespaces.Add(s, modules[s.Module].Namespace); } } else { Symbol symbol = symbols.First(); List <Symbol> duplicates; if (!duplicatedSymbols.TryGetValue(symbol, out duplicates)) { duplicates = new List <Symbol>(); } duplicates.Insert(0, symbol); deduplicatedSymbols.Add(symbol.Name, duplicates.ToArray()); foreach (var s in duplicates) { symbolNamespaces.Add(s, xmlConfig.CommonTypesNamespace); } } } var globalTypes = symbolsByName.SelectMany(s => s.Value).ToArray(); logger.WriteLine(" {0}", stopwatch.Elapsed); logger.WriteLine(" Total symbols: {0}", globalTypesPerModule.Sum(gt => gt.Length)); logger.WriteLine(" Unique symbol names: {0}", symbolsByName.Count); logger.WriteLine(" Dedupedlicated symbols: {0}", globalTypes.Length); // Initialize GlobalCache with deduplicatedSymbols GlobalCache.Update(deduplicatedSymbols); // Collecting types logger.Write("Collecting types..."); foreach (var module in modules.Keys) { userTypes.Add(userTypeFactory.AddSymbol(module.GlobalScope, null, modules[module].Namespace, generationOptions)); } ConcurrentBag <Symbol> simpleSymbols = new ConcurrentBag <Symbol>(); Dictionary <Tuple <string, string>, List <Symbol> > templateSymbols = new Dictionary <Tuple <string, string>, List <Symbol> >(); Parallel.ForEach(Partitioner.Create(globalTypes), (symbol) => { string symbolName = symbol.Name; // TODO: Add configurable filter // if (symbolName.StartsWith("$") || symbolName.StartsWith("__vc_attributes") || symbolName.Contains("`anonymous-namespace'") || symbolName.Contains("`anonymous namespace'") || symbolName.Contains("::$") || symbolName.Contains("`")) { return; } // Do not handle template referenced arguments if (symbolName.Contains("&")) { // TODO: Convert this to function pointer return; } // TODO: For now remove all unnamed-type symbols string scopedClassName = symbol.Namespaces.Last(); if (scopedClassName.StartsWith("<") || symbolName.Contains("::<")) { return; } // Check if symbol contains template type. if ((symbol.Tag == CodeTypeTag.Class || symbol.Tag == CodeTypeTag.Structure || symbol.Tag == CodeTypeTag.Union) && SymbolNameHelper.ContainsTemplateType(symbolName)) { List <string> namespaces = symbol.Namespaces; string className = namespaces.Last(); var symbolId = Tuple.Create(symbolNamespaces[symbol], SymbolNameHelper.CreateLookupNameForSymbol(symbol)); lock (templateSymbols) { if (!templateSymbols.ContainsKey(symbolId)) { templateSymbols[symbolId] = new List <Symbol>() { symbol } } ; else { templateSymbols[symbolId].Add(symbol); } } // TODO: // Do not add physical types for template specialization (not now) // do if types contains static fields // nested in templates } else { simpleSymbols.Add(symbol); } }); logger.WriteLine(" {0}", stopwatch.Elapsed); // Populate Templates logger.Write("Populating templates..."); foreach (List <Symbol> symbols in templateSymbols.Values) { Symbol symbol = symbols.First(); userTypes.AddRange(userTypeFactory.AddTemplateSymbols(symbols, symbolNamespaces[symbol], generationOptions)); } logger.WriteLine(" {0}", stopwatch.Elapsed); // Specialized class logger.Write("Populating specialized classes..."); foreach (Symbol symbol in simpleSymbols) { userTypes.Add(userTypeFactory.AddSymbol(symbol, null, symbolNamespaces[symbol], generationOptions)); } logger.WriteLine(" {0}", stopwatch.Elapsed); // To solve template dependencies. Update specialization arguments once all the templates has been populated. logger.Write("Updating template arguments..."); foreach (TemplateUserType templateUserType in userTypes.OfType <TemplateUserType>()) { foreach (SpecializedTemplateUserType specializedTemplateUserType in templateUserType.Specializations) { if (!specializedTemplateUserType.UpdateTemplateArguments(userTypeFactory)) { #if DEBUG logger.WriteLine("Template user type cannot be updated: {0}", specializedTemplateUserType.Symbol.Name); #endif } } } logger.WriteLine(" {0}", stopwatch.Elapsed); // Post processing user types (filling DeclaredInType) logger.Write("Post processing user types..."); var namespaceTypes = userTypeFactory.ProcessTypes(userTypes, symbolNamespaces, xmlConfig.CommonTypesNamespace ?? modules.First().Key.Namespace).ToArray(); userTypes.AddRange(namespaceTypes); logger.WriteLine(" {0}", stopwatch.Elapsed); }
/// <summary> /// Creates the lookup name for the specified symbol. /// This helps grouping template symbols together. /// </summary> /// <param name="symbol">The symbol.</param> public static string CreateLookupNameForSymbol(Symbol symbol) { return(string.Join("::", symbol.Namespaces.Select(r => SymbolNameHelper.CreateLookupForNamespace(r)))); }