Beispiel #1
0
        /// <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
            ConcurrentDictionary <Module, XmlModule>   modules = new ConcurrentDictionary <Module, XmlModule>();
            ConcurrentDictionary <XmlModule, Symbol[]> globalTypesPerModule = new ConcurrentDictionary <XmlModule, Symbol[]>();

            logger.Write("Loading modules...");
            Parallel.ForEach(xmlModules, (xmlModule) =>
            {
                Module module = moduleProvider.Open(xmlModule);

                modules.TryAdd(module, xmlModule);
            });

            logger.WriteLine(" {0}", stopwatch.Elapsed);

            // Enumerating symbols
            logger.Write("Enumerating symbols...");
            Parallel.ForEach(modules, (mm) =>
            {
                XmlModule xmlModule      = mm.Value;
                Module module            = mm.Key;
                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.TryAdd(
                    xmlModule,
                    symbols.Where(t => t.Tag == CodeTypeTag.Class || t.Tag == CodeTypeTag.Structure || t.Tag == CodeTypeTag.Union || t.Tag == CodeTypeTag.Enum).ToArray());
            });

            List <Symbol> allSymbols = new List <Symbol>();

            Symbol[][] symbolsPerModule = globalTypesPerModule.Select(ss => ss.Value).ToArray();
            int        maxSymbols       = symbolsPerModule.Max(ss => ss.Length);

            for (int i = 0; i < maxSymbols; i++)
            {
                for (int j = 0; j < symbolsPerModule.Length; j++)
                {
                    if (i < symbolsPerModule[j].Length)
                    {
                        allSymbols.Add(symbolsPerModule[j][i]);
                    }
                }
            }

            logger.WriteLine(" {0}", stopwatch.Elapsed);

#if false
            // Initialize symbol fields and base classes
            logger.Write("Initializing symbol values...");

            Parallel.ForEach(Partitioner.Create(allSymbols), (symbol) =>
            {
                var fields      = symbol.Fields;
                var baseClasses = symbol.BaseClasses;
            });

            logger.WriteLine(" {0}", sw.Elapsed);
#endif

            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;

                foreach (var s in symbols.ToArray())
                {
                    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;
                }

                foreach (var s in symbols.ToArray())
                {
                    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.Value.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, new XmlType()
                {
                    Name = "ModuleGlobals"
                }, 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 (SymbolNameHelper.ContainsTemplateType(symbolName) && (symbol.Tag == CodeTypeTag.Class || symbol.Tag == CodeTypeTag.Structure || symbol.Tag == CodeTypeTag.Union))
                {
                    List <string> namespaces = symbol.Namespaces;
                    string className         = namespaces.Last();
                    var symbolId             = Tuple.Create(symbolNamespaces[symbol], SymbolNameHelper.CreateLookupNameForSymbol(symbol));

                    lock (templateSymbols)
                    {
                        if (templateSymbols.ContainsKey(symbolId) == false)
                        {
                            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();
                string symbolName = SymbolNameHelper.CreateLookupNameForSymbol(symbol);

                XmlType type = new XmlType()
                {
                    Name = symbolName
                };

                userTypes.AddRange(userTypeFactory.AddSymbols(symbols, type, 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 (TemplateUserType specializedTemplateUserType in templateUserType.SpecializedTypes)
                {
                    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).ToArray();
            userTypes.AddRange(namespaceTypes);

            logger.WriteLine(" {0}", stopwatch.Elapsed);
        }