Esempio n. 1
0
        static void Main(string[] args)
        {
            var input = new Dictionary <string, GlobalDecl>();

            for (int i = 0; i < args.Length / 2; i++)
            {
                var tag      = args[i * 2];
                var fileName = args[i * 2 + 1];
                Console.WriteLine("Reading " + fileName + " ...");
                var xml  = XDocument.Load(fileName);
                var decl = (GlobalDecl)SymbolDecl.Deserialize(xml.Root);
                decl.BuildSymbolTree(null, tag);
                input.Add(tag, decl);
            }

            Console.WriteLine("De-duplicating ...");
            var symbolGroup = new Dictionary <string, List <SymbolDecl> >();

            GroupSymbolsByOverloadKey(input.Values, symbolGroup);
            foreach (var pair in symbolGroup)
            {
                var groups = pair.Value
                             .GroupBy(x => x.ContentKey)
                             .ToArray();
                foreach (var group in groups)
                {
                    var decls = group.ToArray();
                    var tags  = decls
                                .Select(x => x.Tags)
                                .OrderBy(x => x)
                                .Aggregate((a, b) => a + ";" + b);
                    foreach (var decl in decls)
                    {
                        decl.Tags = tags;
                    }
                }
            }

            Console.WriteLine("Resolving Symbols ...");
            var symbolResolving = symbolGroup
                                  .SelectMany(x => x.Value)
                                  .ToArray();
            var environment = new ResolveEnvironment(input.Values);

            foreach (var symbol in symbolResolving)
            {
                symbol.Resolve(environment);
            }

            var output    = args[args.Length - 1];
            var xmlErrors = environment.Errors.Where(x => x.StartsWith("(Xml)")).ToArray();
            var warnings  = environment.Errors.Where(x => x.StartsWith("(Warning)")).ToArray();
            var errors    = environment.Errors.Where(x => x.StartsWith("(Error)")).ToArray();

            Console.WriteLine("Xml Errors: " + xmlErrors.Length);
            Console.WriteLine("Warnings: " + warnings.Length);
            Console.WriteLine("Errors: " + errors.Length);

            using (var writer = new StreamWriter(output + ".errors.txt", false, Encoding.UTF8))
            {
                writer.WriteLine("=======================XML ERROR=======================");
                foreach (var message in xmlErrors)
                {
                    writer.WriteLine(message);
                }
                writer.WriteLine();

                writer.WriteLine("========================WARNING========================");
                foreach (var message in warnings)
                {
                    writer.WriteLine(message);
                }

                writer.WriteLine();
                writer.WriteLine("=========================ERROR=========================");
                foreach (var message in errors)
                {
                    writer.WriteLine(message);
                }
            }

            Console.WriteLine("Saving ...");
            var symbolSaving = symbolGroup
                               .ToDictionary(
                x => x.Key,
                x => x.Value
                .GroupBy(y => y.Tags)
                .Select(y => y.First())
                .ToArray()
                )
                               .GroupBy(x => GetNamespaceSymbol(x.Value.First()))
                               .ToDictionary(
                x => x.Key,
                x => x.ToDictionary(
                    y => y.Key,
                    y => y.Value
                    )
                )
            ;
            var outputXml = new XDocument(
                new XElement("CppXmlDocument",
                             symbolSaving.Select(x => new XElement("Namespace",
                                                                   new XAttribute("Name", x.Key is GlobalDecl ? "" : (x.Key as NamespaceDecl).NameKey),
                                                                   x.Value.Select(y => new XElement("Symbol",
                                                                                                    new XAttribute("OverloadKey", y.Key),
                                                                                                    y.Value
                                                                                                    .Select(z => z.Parent is TemplateDecl ? z.Parent : z)
                                                                                                    .Select(z => z.Serialize())
                                                                                                    ))
                                                                   ))
                             )
                );

            outputXml.Save(output);
        }
Esempio n. 2
0
        static SymbolDecl[] ParseSymbolInternal(string[] tokens, ref int index)
        {
            if (CppParser.Token(tokens, ref index, "public") || CppParser.Token(tokens, ref index, "protected") || CppParser.Token(tokens, ref index, "private"))
            {
                index--;
                return(null);
            }
            TemplateDecl templateDecl = null;

            if (CppParser.Token(tokens, ref index, "template"))
            {
                templateDecl = new TemplateDecl
                {
                    TypeParameters = new List <TypeParameterDecl>(),
                    Specialization = new List <TypeDecl>(),
                };
                CppParser.EnsureToken(tokens, ref index, "<");
                if (!CppParser.Token(tokens, ref index, ">"))
                {
                    while (true)
                    {
                        string token = null;
                        CppParser.SkipUntilInTemplate(tokens, ref index, out token, ",", ">", "=");

                        index -= 2;
                        templateDecl.TypeParameters.Add(new TypeParameterDecl
                        {
                            Name = CppParser.EnsureId(tokens, ref index),
                        });
                        index++;

                        if (token == "=")
                        {
                            CppParser.SkipUntilInTemplate(tokens, ref index, out token, ",", ">");
                        }

                        if (token == ">")
                        {
                            break;
                        }
                    }
                }
            }

            if (CppParser.Token(tokens, ref index, "friend"))
            {
                int    oldIndex = index - 1;
                string token    = null;
                CppParser.SkipUntil(tokens, ref index, out token, ";", "{");
                if (token == ";")
                {
                    return(null);
                }
                else
                {
                    index         = oldIndex;
                    tokens[index] = "static";
                }
            }

            if (CppParser.Token(tokens, ref index, "namespace"))
            {
                if (templateDecl != null)
                {
                    throw new ArgumentException("Failed to parse.");
                }
                var decl = new NamespaceDecl();
                decl.Name = CppParser.EnsureId(tokens, ref index);

                CppParser.EnsureToken(tokens, ref index, "{");
                ParseSymbols(tokens, ref index, decl);
                CppParser.EnsureToken(tokens, ref index, "}");

                return(new SymbolDecl[] { decl });
            }
            else if (CppParser.Token(tokens, ref index, "using"))
            {
                if (CppParser.Token(tokens, ref index, "namespace"))
                {
                    if (templateDecl != null)
                    {
                        throw new ArgumentException("Failed to parse.");
                    }
                    var decl = new UsingNamespaceDecl();
                    decl.Path = new List <string>();
                    decl.Path.Add(CppParser.EnsureId(tokens, ref index));

                    while (!CppParser.Token(tokens, ref index, ";"))
                    {
                        CppParser.EnsureToken(tokens, ref index, ":");
                        CppParser.EnsureToken(tokens, ref index, ":");
                        decl.Path.Add(CppParser.EnsureId(tokens, ref index));
                    }

                    return(new SymbolDecl[] { decl });
                }
                else
                {
                    string name = null;
                    if (CppParser.Id(tokens, ref index, out name))
                    {
                        if (templateDecl != null)
                        {
                            if (CppParser.Token(tokens, ref index, "<"))
                            {
                                while (true)
                                {
                                    templateDecl.Specialization.Add(CppTypeParser.EnsureTypeWithoutNameInTemplate(tokens, ref index));
                                    if (CppParser.Token(tokens, ref index, ">"))
                                    {
                                        break;
                                    }
                                    CppParser.EnsureToken(tokens, ref index, ",");
                                }
                            }
                        }
                        if (CppParser.Token(tokens, ref index, "="))
                        {
                            SymbolDecl decl = new TypedefDecl
                            {
                                Name = name,
                                Type = CppTypeParser.EnsureTypeWithoutName(tokens, ref index),
                            };
                            CppParser.EnsureToken(tokens, ref index, ";");

                            if (templateDecl != null)
                            {
                                templateDecl.Element = decl;
                                decl = templateDecl;
                            }
                            return(new SymbolDecl[] { decl });
                        }
                    }
                    if (templateDecl != null)
                    {
                        throw new ArgumentException("Failed to parse.");
                    }
                    CppParser.SkipUntil(tokens, ref index, ";");
                }
            }
            else if (CppParser.Token(tokens, ref index, "typedef"))
            {
                if (templateDecl != null)
                {
                    throw new ArgumentException("Failed to parse.");
                }
                string name = null;
                var    type = CppTypeParser.EnsureTypeWithName(tokens, ref index, out name);
                CppParser.EnsureToken(tokens, ref index, ";");

                var decl = new TypedefDecl();
                decl.Name = name;
                decl.Type = type;
                return(new SymbolDecl[] { decl });
            }
            else if (CppParser.Token(tokens, ref index, "enum"))
            {
                if (templateDecl != null)
                {
                    throw new ArgumentException("Failed to parse.");
                }
                bool   enumClass = CppParser.Token(tokens, ref index, "class");
                string name      = CppParser.EnsureId(tokens, ref index);
                if (CppParser.Token(tokens, ref index, ":"))
                {
                    CppTypeParser.EnsureTypeWithoutName(tokens, ref index);
                }
                if (!CppParser.Token(tokens, ref index, ";"))
                {
                    CppParser.EnsureToken(tokens, ref index, "{");
                    var decl = new EnumDecl
                    {
                        Name      = name,
                        EnumClass = enumClass,
                        Children  = new List <SymbolDecl>(),
                    };

                    while (true)
                    {
                        if (CppParser.Token(tokens, ref index, "}"))
                        {
                            break;
                        }

                        string document = null;
                        while (index < tokens.Length && tokens[index].Length >= 3 && tokens[index].StartsWith("///"))
                        {
                            var line = tokens[index];
                            if (document == null)
                            {
                                document = "";
                            }
                            document += line.StartsWith("/// ") || line.StartsWith("///\t")
                                ? line.Substring(4)
                                : line.Substring(3);
                            document += "\r\n";
                            index++;
                        }
                        decl.Children.Add(new EnumItemDecl
                        {
                            Name     = CppParser.EnsureId(tokens, ref index),
                            Document = document,
                        });

                        string token = null;
                        CppParser.SkipUntil(tokens, ref index, out token, ",", "}");
                        if (token == "}")
                        {
                            break;
                        }
                    }

                    if (CppParser.Id(tokens, ref index, out name))
                    {
                        var varDecl = new VarDecl
                        {
                            Static = false,
                            Name   = name,
                            Type   = new RefTypeDecl
                            {
                                Name = decl.Name,
                            },
                        };
                        CppParser.EnsureToken(tokens, ref index, ";");
                        return(new SymbolDecl[] { decl, varDecl });
                    }
                    else
                    {
                        CppParser.EnsureToken(tokens, ref index, ";");
                        return(new SymbolDecl[] { decl });
                    }
                }
            }
            else if (CppParser.Token(tokens, ref index, "struct") || CppParser.Token(tokens, ref index, "class") || CppParser.Token(tokens, ref index, "union"))
            {
                if (CppParser.Token(tokens, ref index, "{"))
                {
                    if (tokens[index - 2] == "class")
                    {
                        throw new ArgumentException("Failed to parse.");
                    }

                    var decl = new GroupedFieldDecl
                    {
                        Grouping = tokens[index - 2] == "struct" ? Grouping.Struct : Grouping.Union,
                    };
                    ParseSymbols(tokens, ref index, decl);
                    CppParser.EnsureToken(tokens, ref index, "}");
                    CppParser.EnsureToken(tokens, ref index, ";");
                    return(new SymbolDecl[] { decl });
                }
                else
                {
                    string name = CppParser.EnsureId(tokens, ref index);
                    if (!CppParser.Token(tokens, ref index, ";"))
                    {
                        var classDecl = new ClassDecl
                        {
                            ClassType =
                                tokens[index - 2] == "struct" ? ClassType.Struct :
                                tokens[index - 2] == "class" ? ClassType.Class :
                                ClassType.Union,
                            BaseTypes = new List <BaseTypeDecl>(),
                            Name      = name,
                        };

                        if (templateDecl != null)
                        {
                            if (CppParser.Token(tokens, ref index, "<"))
                            {
                                if (!CppParser.Token(tokens, ref index, ">"))
                                {
                                    while (true)
                                    {
                                        int oldIndex = index;
                                        templateDecl.Specialization.Add(CppTypeParser.EnsureTypeWithoutNameInTemplate(tokens, ref index));
                                        if (CppParser.Token(tokens, ref index, ">"))
                                        {
                                            break;
                                        }
                                        CppParser.EnsureToken(tokens, ref index, ",");
                                    }
                                }
                            }
                        }

                        CppParser.Token(tokens, ref index, "abstract");
                        if (CppParser.Token(tokens, ref index, ":"))
                        {
                            while (true)
                            {
                                Access access = classDecl.ClassType == ClassType.Class ? Access.Private : Access.Public;
                                CppParser.Token(tokens, ref index, "virtual");
                                if (CppParser.Token(tokens, ref index, "private"))
                                {
                                    access = Access.Private;
                                }
                                else if (CppParser.Token(tokens, ref index, "protected"))
                                {
                                    access = Access.Protected;
                                }
                                else if (CppParser.Token(tokens, ref index, "public"))
                                {
                                    access = Access.Public;
                                }
                                CppParser.Token(tokens, ref index, "virtual");
                                classDecl.BaseTypes.Add(new BaseTypeDecl
                                {
                                    Access = access,
                                    Type   = CppTypeParser.EnsureTypeWithoutName(tokens, ref index),
                                });
                                if (!CppParser.Token(tokens, ref index, ","))
                                {
                                    break;
                                }
                            }
                        }

                        CppParser.EnsureToken(tokens, ref index, "{");
                        while (true)
                        {
                            if (CppParser.Token(tokens, ref index, "}"))
                            {
                                break;
                            }

                            Access access = classDecl.ClassType == ClassType.Class ? Access.Private : Access.Public;
                            if (CppParser.Token(tokens, ref index, "private"))
                            {
                                access = Access.Private;
                                CppParser.EnsureToken(tokens, ref index, ":");
                            }
                            else if (CppParser.Token(tokens, ref index, "protected"))
                            {
                                access = Access.Protected;
                                CppParser.EnsureToken(tokens, ref index, ":");
                            }
                            else if (CppParser.Token(tokens, ref index, "public"))
                            {
                                access = Access.Public;
                                CppParser.EnsureToken(tokens, ref index, ":");
                            }
                            ParseSymbols(tokens, ref index, classDecl, access);
                        }

                        SymbolDecl decl = classDecl;
                        if (templateDecl != null)
                        {
                            templateDecl.Element = decl;
                            decl = templateDecl;
                        }

                        if (CppParser.Id(tokens, ref index, out name))
                        {
                            var varDecl = new VarDecl
                            {
                                Static = false,
                                Name   = name,
                                Type   = new RefTypeDecl
                                {
                                    Name = classDecl.Name,
                                },
                            };
                            CppParser.EnsureToken(tokens, ref index, ";");
                            return(new SymbolDecl[] { decl, varDecl });
                        }
                        else
                        {
                            CppParser.EnsureToken(tokens, ref index, ";");
                            return(new SymbolDecl[] { decl });
                        }
                    }
                }
            }
            else if (!CppParser.Token(tokens, ref index, ";"))
            {
                Function function = Function.Function;
                {
                    int    oldIndex = index;
                    string name     = null;
                    if (CppParser.Id(tokens, ref index, out name))
                    {
                        if (CppParser.Token(tokens, ref index, "("))
                        {
                            CppParser.SkipUntil(tokens, ref index, ")");
                            if (CppParser.Token(tokens, ref index, ";") || CppParser.Token(tokens, ref index, "=") || CppParser.Token(tokens, ref index, ":") || CppParser.Token(tokens, ref index, "{"))
                            {
                                function = Function.Constructor;
                            }
                        }
                        index = oldIndex;
                    }
                    else if (CppParser.Token(tokens, ref index, "~"))
                    {
                        function = Function.Destructor;
                    }
                }

                if (function == Function.Function)
                {
                    Virtual virtualFunction = Virtual.Normal;
                    CppParser.Token(tokens, ref index, "extern");
                    CppParser.Token(tokens, ref index, "mutable");
                    if (CppParser.Token(tokens, ref index, "virtual"))
                    {
                        virtualFunction = Virtual.Virtual;
                    }
                    else if (CppParser.Token(tokens, ref index, "static"))
                    {
                        virtualFunction = Virtual.Static;
                    }
                    CppParser.Token(tokens, ref index, "inline");
                    CppParser.Token(tokens, ref index, "__forceinline");

                    if (CppParser.Token(tokens, ref index, "operator"))
                    {
                        TypeDecl returnType = null;
                        {
                            int oldIndex = index;
                            CppParser.SkipUntilInTemplate(tokens, ref index, "(");
                            int modify = --index;

                            tokens[modify] = "$";
                            index          = oldIndex;
                            returnType     = CppTypeParser.EnsureTypeWithoutName(tokens, ref index);
                            if (index != modify)
                            {
                                throw new ArgumentException("Failed to parse.");
                            }
                            tokens[modify] = "(";
                        }
                        var decl = new FuncDecl
                        {
                            Virtual  = Virtual.Normal,
                            Name     = "operator",
                            Function = function,
                        };

                        TypeDecl          functionType      = null;
                        Action <TypeDecl> continuation      = null;
                        CallingConvention callingConvention = CallingConvention.Default;
                        CppTypeParser.ParseTypeContinueAfterName(tokens, ref index, ref callingConvention, out functionType, out continuation);
                        continuation(returnType);
                        decl.Type = functionType;

                        if (!CppParser.Token(tokens, ref index, ";"))
                        {
                            CppParser.EnsureToken(tokens, ref index, "{");
                            CppParser.SkipUntil(tokens, ref index, "}");
                        }

                        if (templateDecl != null)
                        {
                            templateDecl.Element = decl;
                            return(new SymbolDecl[] { templateDecl });
                        }
                        else
                        {
                            return(new SymbolDecl[] { decl });
                        }
                    }
                    else
                    {
                        string   name = null;
                        TypeDecl type = null;
                        if (CppTypeParser.ParseType(tokens, ref index, out type, out name))
                        {
                            if (name == null)
                            {
                                throw new ArgumentException("Failed to parse.");
                            }

                            if (type is FunctionTypeDecl)
                            {
                                if (CppParser.Token(tokens, ref index, "="))
                                {
                                    if (CppParser.Token(tokens, ref index, "0"))
                                    {
                                        virtualFunction = Virtual.Abstract;
                                    }
                                    else
                                    {
                                        CppParser.EnsureToken(tokens, ref index, "default", "delete");
                                    }
                                }

                                var decl = new FuncDecl
                                {
                                    Virtual  = virtualFunction,
                                    Name     = name,
                                    Type     = type,
                                    Function = Function.Function,
                                };

                                {
                                    var funcType   = (FunctionTypeDecl)type;
                                    var returnType = funcType.ReturnType as RefTypeDecl;
                                    if (returnType != null && returnType.Name == "auto")
                                    {
                                        if (CppParser.Token(tokens, ref index, "-"))
                                        {
                                            CppParser.EnsureToken(tokens, ref index, ">");

                                            TypeDecl newReturnType = CppTypeParser.EnsureTypeWithoutName(tokens, ref index);
                                            funcType.ReturnType = newReturnType;
                                        }
                                    }

                                    if (!CppParser.Token(tokens, ref index, ";"))
                                    {
                                        CppParser.EnsureToken(tokens, ref index, "{");
                                        CppParser.SkipUntil(tokens, ref index, "}");
                                    }
                                }

                                if (templateDecl != null)
                                {
                                    templateDecl.Element = decl;
                                    return(new SymbolDecl[] { templateDecl });
                                }
                                else
                                {
                                    return(new SymbolDecl[] { decl });
                                }
                            }
                            else
                            {
                                if (virtualFunction != Virtual.Normal && virtualFunction != Virtual.Static)
                                {
                                    throw new ArgumentException("Failed to parse.");
                                }
                                if (CppParser.Token(tokens, ref index, "="))
                                {
                                    CppParser.SkipUntil(tokens, ref index, ";");
                                }
                                else if (CppParser.Token(tokens, ref index, "{"))
                                {
                                    CppParser.SkipUntil(tokens, ref index, "}");
                                }
                                else
                                {
                                    CppParser.EnsureToken(tokens, ref index, ";");
                                }

                                if (!(type is ClassMemberTypeDecl))
                                {
                                    var decl = new VarDecl
                                    {
                                        Static = virtualFunction == Virtual.Static,
                                        Name   = name,
                                        Type   = type,
                                    };
                                    return(new SymbolDecl[] { decl });
                                }
                            }
                        }
                    }
                }
                else
                {
                    var decl = new FuncDecl
                    {
                        Virtual  = Virtual.Normal,
                        Name     = (function == Function.Constructor ? "" : "~") + CppParser.EnsureId(tokens, ref index),
                        Function = function,
                    };

                    TypeDecl          functionType      = null;
                    Action <TypeDecl> continuation      = null;
                    CallingConvention callingConvention = CallingConvention.Default;
                    CppTypeParser.ParseTypeContinueAfterName(tokens, ref index, ref callingConvention, out functionType, out continuation);
                    continuation(new RefTypeDecl
                    {
                        Name = "void"
                    });
                    decl.Type = functionType;

                    if (CppParser.Token(tokens, ref index, "="))
                    {
                        CppParser.EnsureToken(tokens, ref index, "default", "delete");
                    }

                    if (!CppParser.Token(tokens, ref index, ";"))
                    {
                        if (CppParser.Token(tokens, ref index, ":"))
                        {
                            do
                            {
                                CppTypeParser.EnsureMiniType(tokens, ref index);
                                if (CppParser.Token(tokens, ref index, "("))
                                {
                                    CppParser.SkipUntil(tokens, ref index, ")");
                                }
                                else if (CppParser.Token(tokens, ref index, "{"))
                                {
                                    CppParser.SkipUntil(tokens, ref index, "}");
                                }
                                else
                                {
                                    throw new ArgumentException("Failed to parse.");
                                }
                            }while (CppParser.Token(tokens, ref index, ","));
                        }
                        CppParser.EnsureToken(tokens, ref index, "{");
                        CppParser.SkipUntil(tokens, ref index, "}");
                    }

                    if (templateDecl != null)
                    {
                        templateDecl.Element = decl;
                        return(new SymbolDecl[] { templateDecl });
                    }
                    else
                    {
                        return(new SymbolDecl[] { decl });
                    }
                }
            }
            return(null);
        }
Esempio n. 3
0
        static string GetDisplayName(SymbolDecl decl)
        {
            {
                var templateDecl = decl as TemplateDecl;
                if (templateDecl != null)
                {
                    decl = templateDecl.Element;
                }
            }

            if (decl is ClassDecl)
            {
                switch (((ClassDecl)decl).ClassType)
                {
                case ClassType.Class:
                    return(decl.Name + " class");

                case ClassType.Struct:
                    return(decl.Name + " struct");

                case ClassType.Union:
                    return(decl.Name + " union");

                default:
                    throw new ArgumentException();
                }
            }
            else if (decl is EnumDecl)
            {
                return(decl.Name + " enum");
            }
            else if (decl is FuncDecl)
            {
                var parent = decl.Parent as ClassDecl;
                if (parent != null)
                {
                    if (parent.Name == decl.Name)
                    {
                        return(decl.Name + " constructor");
                    }
                    else if ("~" + parent.Name == decl.Name)
                    {
                        return(decl.Name + " destructor");
                    }
                    else
                    {
                        return(decl.Name + " method");
                    }
                }
                else
                {
                    return(decl.Name + " function");
                }
            }
            else if (decl is VarDecl)
            {
                if (decl.Parent is ClassDecl || decl.Parent is GroupedFieldDecl)
                {
                    return(decl.Name + " field");
                }
                else if (decl.Parent is FuncDecl)
                {
                    return(decl.Name + " parameter");
                }
                else
                {
                    return(decl.Name + " variable");
                }
            }
            else if (decl is TypedefDecl)
            {
                return(decl.Name + " typedecl");
            }
            else
            {
                throw new ArgumentException();
            }
        }
Esempio n. 4
0
 static void FixSymbolLinks(SymbolDecl decl, Dictionary <string, string> symbolFileMapping)
 {
     FixSymbolDeclVisitor.Execute(decl, symbolFileMapping);
 }
Esempio n. 5
0
        static void Main(string[] args)
        {
            Console.WriteLine("Reading " + args[0] + " ...");
            var xml    = XDocument.Load(args[0]);
            var xmlNss = xml.Root
                         .Elements("Namespace")
                         .GroupBy(xmlNs => xmlNs.Attribute("Name").Value)
                         .ToDictionary(
                g => g.Key,
                g => g.SelectMany(xmlNs => xmlNs.Elements("Symbol")).ToArray()
                );

            var symbols = xml.Root
                          .Elements("Namespace")
                          .GroupBy(xmlNs => xmlNs.Attribute("Name").Value)
                          .ToDictionary(
                g => g.Key,
                g =>
            {
                return(g
                       .SelectMany(xmlNs => xmlNs.Elements("Symbol"))
                       .Select(xmlSymbol =>
                {
                    var key = xmlSymbol.Attribute("OverloadKey").Value;
                    var symbolDecls = xmlSymbol
                                      .Elements()
                                      .Select(xmlDecl =>
                    {
                        var decl = SymbolDecl.Deserialize(xmlDecl);
                        decl.BuildSymbolTree(null, null);
                        return decl;
                    })
                                      .ToArray();
                    return Tuple.Create(key, symbolDecls);
                })
                       .ToArray());
            }
                );

            var output = Path.GetFullPath(args[1]);

            if (!output.EndsWith("\\"))
            {
                output += "\\";
            }

            Console.WriteLine("Writing nss.xml ...");
            var namespaceNames = symbols.Keys
                                 .ToDictionary(
                ns => ns,
                ns => ns
                .Split(new[] { "::" }, StringSplitOptions.RemoveEmptyEntries)
                .Aggregate("", (a, b) => a == "" ? b : a + "." + b)
                );
            var outputNss = new XDocument(
                new XElement("Namespaces",
                             namespaceNames
                             .OrderBy(p => p.Key)
                             .Select(p =>
                                     new XElement("Namespace",
                                                  new XAttribute("Key", p.Key),
                                                  new XAttribute("DisplayName", (p.Key == "" ? "::" : p.Key.Substring(2)) + " namespace"),
                                                  new XAttribute("UrlName", p.Value),
                                                  new XAttribute("Doc", symbols[p.Key].SelectMany(t => t.Item2.Select(s => s)).Any(ContainsDocument))
                                                  )
                                     )
                             )
                );

            outputNss.Save(output + "nss.xml");

            Console.WriteLine("Writing ns(*).xml ...");
            var symbolNames = symbols
                              .SelectMany(x => x.Value.Select(t => t.Item1))
                              .ToDictionary(
                x => x,
                x => x
                .Replace("::", ".")
                .Replace(":", "#")
                .Replace("|", "$")
                .Replace("/", "%")
                .Replace("*", "^")
                .Replace("<", "{")
                .Replace(">", "}")
                .Substring(1)
                );

            foreach (var nsp in symbols)
            {
                var outputNs = new XDocument(
                    new XElement("Namespace",
                                 new XAttribute("DisplayName", nsp.Key),
                                 nsp.Value
                                 .GroupBy(t => GetDisplayName(t.Item2[0]))
                                 .OrderBy(g => g.Key)
                                 .Select(g => new XElement("Overloads",
                                                           new XAttribute("DisplayName", g.Key),
                                                           g
                                                           .Select(t => new XElement("Symbol",
                                                                                     new XAttribute("Key", t.Item2.First().OverloadKey ?? t.Item2.First().Children[0].OverloadKey),
                                                                                     new XAttribute("UrlName", symbolNames[t.Item1]),
                                                                                     new XAttribute("Doc", t.Item2.Any(ContainsDocument))
                                                                                     )
                                                                   )
                                                           )
                                         )
                                 )
                    );
                outputNs.Save(output + "ns(" + namespaceNames[nsp.Key] + ").xml");
            }

            Console.WriteLine("Writing t(*).xml ...");
            var symbolFileMapping = new Dictionary <string, string>();

            foreach (var nsp in symbols)
            {
                Console.WriteLine("t(*).xml: " + nsp.Key);
                var stGroup = nsp.Value
                              .GroupBy(st => GetUrlNameForKey(symbolNames[st.Item1]))
                              .ToDictionary(g => g.Key, g => g.ToArray());

                foreach (var stGroupPair in stGroup)
                {
                    var urlName      = stGroupPair.Key;
                    var outputSymbol = new XDocument(
                        new XElement("OverloadingSymbolTrees",
                                     stGroupPair.Value
                                     .Select(st =>
                                             new XElement("OverloadingSymbolTree",
                                                          new XAttribute("Key", symbolNames[st.Item1]),
                                                          CreateSymbolTree(namespaceNames[nsp.Key], symbolNames[st.Item1], st.Item2, symbolFileMapping).Root
                                                          )
                                             )
                                     )
                        );
                    outputSymbol.Save(output + "t(" + urlName + ").xml");
                }
            }

            Console.WriteLine("Writing s(*).xml ...");
            foreach (var nss in namespaceNames)
            {
                symbolFileMapping.Add(nss.Key, "ns:" + nss.Value);
            }
            foreach (var nsp in symbols)
            {
                Console.WriteLine("s(*).xml: " + nsp.Key);
                var stGroup = nsp.Value
                              .GroupBy(st => GetUrlNameForKey(symbolNames[st.Item1]))
                              .ToDictionary(g => g.Key, g => g.ToArray());

                foreach (var stGroupPair in stGroup)
                {
                    foreach (var st in stGroupPair.Value)
                    {
                        foreach (var decl in st.Item2)
                        {
                            FixSymbolLinks(decl, symbolFileMapping);
                        }
                    }
                    var urlName      = stGroupPair.Key;
                    var outputSymbol = new XDocument(
                        new XElement("OverloadingSymbols",
                                     stGroupPair.Value
                                     .Select(st =>
                                             new XElement("Symbols",
                                                          new XAttribute("Key", symbolNames[st.Item1]),
                                                          st.Item2.Select(decl => decl.Serialize())
                                                          )
                                             )
                                     )
                        );
                    outputSymbol.Save(output + "s(" + urlName + ").xml");
                }
            }
        }