1 // =================================
   2 // Copyright (c) 2020 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 #include <gendoc/html/HtmlSourceCodeGenerator.hpp>
   7 #include <sngcpp/symbols/ClassTemplateSpecializationSymbol.hpp>
   8 #include <sngcpp/symbols/ExternalTypeSymbol.hpp>
   9 #include <sngcpp/ast/Class.hpp>
  10 #include <sngcpp/ast/Expression.hpp>
  11 #include <sngcpp/ast/TypeExpr.hpp>
  12 #include <sngcpp/ast/Template.hpp>
  13 #include <sngcpp/parser/SourceLineParser.hpp>
  14 #include <sngxml/dom/CharacterData.hpp>
  15 #include <soulng/util/Path.hpp>
  16 #include <soulng/util/Unicode.hpp>
  17 #include <soulng/util/TextUtils.hpp>
  18 #include <soulng/util/Util.hpp>
  19 #include <fstream>
  20 
  21 namespace gendoc { namespace html {
  22 
  23 using namespace sngcpp::ast;
  24 using namespace soulng::util;
  25 using namespace soulng::unicode;
  26 
  27 HtmlSourceCodeGenerator::HtmlSourceCodeGenerator(const std::u32string& projectName_const std::std::vector<std::u32string>&inputLines_intnumDigits_
  28     const std::string& styleDirName_const std::string& styleFileName_SymbolTable& symbolTable_int inlineCodeLimit_
  29     std::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap_
  30     HtmlContentFilePathResolver* contentFilePathResolver_) :
  31     projectName(projectName_)symbolTable(symbolTable_)currentFunction(nullptr)invokeSymbol(nullptr)inputLines(inputLines_)numDigits(numDigits_)
  32     currentSourceLineNumber(1)styleFilePath(Path::Combine(Path::Combine("../.."styleDirName_)styleFileName_))contentDirPath("..")
  33     lineStarts(nullptr)firstBaseClass(false)firstParam(false)firstTemplateParameter(false)firstTemplateArgument(false)
  34     firstMemberInitializer(false)firstInitializer(false)firstEnumerator(false)rangeForDeclaration(false)blockLevel(0)
  35     currentAccess(Specifier::private_)inlineCodeLimit(inlineCodeLimit_)inlineCodeOffset(0)inlineCodeMap(inlineCodeMap_)skip(false)
  36     inBlockComment(false)contentFilePathResolver(contentFilePathResolver_)
  37 {
  38     htmlElement.reset(new sngxml::dom::Element(U"html"));
  39 }
  40 
  41 void HtmlSourceCodeGenerator::WriteDocument()
  42 {
  43     std::ofstream htmlFile(htmlFilePath);
  44     CodeFormatter formatter(htmlFile);
  45     formatter.SetIndentSize(1);
  46     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(bodyElement.release()));
  47     htmlSourceFileDocument.AppendChild(std::unique_ptr<sngxml::dom::Node>(htmlElement.release()));
  48     htmlSourceFileDocument.Write(formatter);
  49 }
  50 
  51 void HtmlSourceCodeGenerator::Visit(SourceFileNode& sourceFileNode)
  52 {
  53     if (sourceFileNode.SourceFilePath().find("Json.hpp") != std::string::npos)
  54     {
  55         int x = 0;
  56     }
  57     lineStarts = sourceFileNode.LineStarts();
  58     htmlFilePath = sourceFileNode.HtmlSourceFilePath();
  59     std::unique_ptr<sngxml::dom::Element> headElement(new sngxml::dom::Element(U"head"));
  60     std::unique_ptr<sngxml::dom::Element> metaElement(new sngxml::dom::Element(U"meta"));
  61     metaElement->SetAttribute(U"charset"U"utf-8");
  62     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(metaElement.release()));
  63     std::unique_ptr<sngxml::dom::Element> titleElement(new sngxml::dom::Element(U"title"));
  64     titleElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(sourceFileNode.ProjectName() + U"/" + ToUtf32(sourceFileNode.RelativeSourceFilePath()))));
  65     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"link"));
  66     linkElement->SetAttribute(U"rel"U"stylesheet");
  67     linkElement->SetAttribute(U"type"U"text/css");
  68     std::u32string relativeStyleFilePath = ToUtf32(styleFilePath);
  69     linkElement->SetAttribute(U"href"relativeStyleFilePath);
  70     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
  71     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(headElement.release()));
  72     bodyElement.reset(new sngxml::dom::Element(U"body"));
  73     sourceFileNode.GlobalNs()->Accept(*this);
  74     if (lineElement)
  75     {
  76         CloseLine();
  77     }
  78     WriteRestOfInput();
  79 }
  80 
  81 std::u32string HtmlSourceCodeGenerator::MakeSymbolRef(Symbol* symbol)
  82 {
  83     if (!symbol) return std::u32string();
  84     if (symbol->IsParentSymbol())
  85     {
  86         if (symbol->IsClassTemplateSpecializationSymbol())
  87         {
  88             ClassTemplateSpecializationSymbol* specialization = static_cast<ClassTemplateSpecializationSymbol*>(symbol);
  89             return MakeSymbolRef(specialization->PrimaryClassTemplateSymbol());
  90         }
  91         else if (symbol->IsNamespaceSymbol())
  92         {
  93             if (symbol->ProjectName() == projectName)
  94             {
  95                 return ToUtf32(Path::Combine(contentDirPathToUtf8(symbol->Id()) + ".html"));
  96             }
  97             else
  98             {
  99                 NamespaceSymbol* ns = static_cast<NamespaceSymbol*>(symbol);
 100                 if (ns->HasProject(projectName))
 101                 {
 102                     return ToUtf32(Path::Combine(contentDirPathToUtf8(symbol->Id()) + ".html"));
 103                 }
 104                 else
 105                 {
 106                     std::u32string project = ns->FirstProject();
 107                     if (project.empty()) return std::u32string();
 108                     return ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameprojectcontentDirPathsymbol->Id()));
 109                 }
 110             }
 111         }
 112         else
 113         {
 114             return ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNamesymbol->ProjectName()contentDirPathsymbol->Id()));
 115         }
 116     }
 117     else if (symbol->IsFunctionGroupSymbol() || symbol->IsClassGroupSymbol() || !symbol->Parent() || 
 118         symbol->Parent()->IsDeclarationBlockSymbol() || symbol->Parent()->IsFunctionSymbol())
 119     {
 120         return std::u32string();
 121     }
 122     else
 123     {
 124         return MakeSymbolRef(symbol->Parent()) + U"#" + symbol->Id();
 125     }
 126 }
 127 
 128 std::u32string HtmlSourceCodeGenerator::MakeInlineSymbolRef(Symbol* symbol)
 129 {
 130     if (!symbol) return std::u32string();
 131     if (symbol->IsParentSymbol())
 132     {
 133         if (symbol->IsClassTemplateSpecializationSymbol())
 134         {
 135             ClassTemplateSpecializationSymbol* specialization = static_cast<ClassTemplateSpecializationSymbol*>(symbol);
 136             return MakeInlineSymbolRef(specialization->PrimaryClassTemplateSymbol());
 137         }
 138         else if (symbol->IsNamespaceSymbol())
 139         {
 140             if (symbol->ProjectName() == projectName)
 141             {
 142                 return ToUtf32(Path::Combine("."ToUtf8(symbol->Id()) + ".html"));
 143             }
 144             else
 145             {
 146                 NamespaceSymbol* ns = static_cast<NamespaceSymbol*>(symbol);
 147                 if (ns->HasProject(projectName))
 148                 {
 149                     return ToUtf32(Path::Combine("."ToUtf8(symbol->Id()) + ".html"));
 150                 }
 151                 else
 152                 {
 153                     std::u32string project = ns->FirstProject();
 154                     if (project.empty()) return std::u32string();
 155                     return ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameproject"."symbol->Id()));
 156                 }
 157             }
 158         }
 159         else
 160         {
 161             return ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNamesymbol->ProjectName()"."symbol->Id()));
 162         }
 163     }
 164     else if (symbol->IsFunctionGroupSymbol() || symbol->IsClassGroupSymbol() || !symbol->Parent() || 
 165         symbol->Parent()->IsDeclarationBlockSymbol() || symbol->Parent()->IsFunctionSymbol())
 166     {
 167         return std::u32string();
 168     }
 169     else
 170     {
 171         return MakeInlineSymbolRef(symbol->Parent()) + U"#" + symbol->Id();
 172     }
 173 }
 174 
 175 void HtmlSourceCodeGenerator::WriteId(IdentifierNode* idSymbol* symbolbool writeType)
 176 {
 177     if (id->Identifier() == U"ReadBool")
 178     {
 179         int x = 0;
 180     }
 181     MoveTo(id->GetSpan());
 182     if (symbol)
 183     {
 184         if (symbol->IsClassGroupSymbol())
 185         {
 186             ClassGroupSymbol* group = static_cast<ClassGroupSymbol*>(symbol);
 187             symbol = group->GetClass(0);
 188         }
 189         else if (symbol->IsFunctionDeclarationSymbol())
 190         {
 191             FunctionDeclarationSymbol* functionDeclarationSymbol = static_cast<FunctionDeclarationSymbol*>(symbol);
 192             if (functionDeclarationSymbol->FunctionDefinition())
 193             {
 194                 symbol = functionDeclarationSymbol->FunctionDefinition();
 195             }
 196             else
 197             {
 198                 symbol = nullptr;
 199             }
 200         }
 201         writer.WriteLink(id->Identifier()MakeSymbolRef(symbol));
 202         writer.WriteInlineLink(id->Identifier()MakeInlineSymbolRef(symbol));
 203     }
 204     else if (writeType)
 205     {
 206         writer.WriteType(id->Identifier());
 207     }
 208     else
 209     {
 210         if (id->IsDtorIdNode())
 211         {
 212             writer.WriteOther(U"~");
 213             writer.WriteIdentifier(id->Identifier());
 214         }
 215         else if (id->IsOperatorFunctionIdNode())
 216         {
 217             OperatorFunctionIdNode* operatorFunctionIdNode = static_cast<OperatorFunctionIdNode*>(id);
 218             writer.WriteKeyword(U"operator");
 219             writer.WriteOther(operatorFunctionIdNode->OpStr());
 220         }
 221         else if (id->IsConversionFunctionIdNode())
 222         {
 223             writer.WriteKeyword(U"operator");
 224             writer.WriteSpace(1);
 225         }
 226         else
 227         {
 228             writer.WriteIdentifier(id->Identifier());
 229         }
 230     }
 231 }
 232 
 233 void HtmlSourceCodeGenerator::WriteIdSequence(bool writeTypeSymbol* terminalSymbol)
 234 {
 235     if (invokeSymbol && terminalSymbol && invokeSymbol != terminalSymbol&&(
 236          terminalSymbol->IsClassGroupSymbol() || terminalSymbol->IsClassTypeSymbol() || terminalSymbol->IsFunctionGroupSymbol())) return;
 237     int n = idSequence.size();
 238     if (n > 0)
 239     {
 240         for (int i = 0; i < n - 1; ++i)
 241         {
 242             if (idSequence[i].first)
 243             {
 244                 WriteId(idSequence[i].firstidSequence[i].secondfalse);
 245             }
 246             writer.WriteOther(U"::");
 247         }
 248         if (!terminalSymbol)
 249         {
 250             terminalSymbol = idSequence.back().second;
 251         }
 252         WriteId(idSequence.back().firstterminalSymbolwriteType);
 253         idSequence.clear();
 254     }
 255 }
 256 
 257 void HtmlSourceCodeGenerator::WriteType(TypeSymbol* typeconst std::std::vector<IdentifierNode*>&idNodeSequenceTemplateIdNode*templateIdNode)
 258 {
 259     int n = idNodeSequence.size();
 260     if (type->IsExternalTypeSymbol())
 261     {
 262         ExternalTypeSymbol* externalTypeSymbol = static_cast<ExternalTypeSymbol*>(type);
 263         if (externalTypeSymbol->GetClassKey() != ClassKey::none)
 264         {
 265             writer.WriteKeyword(ToString(externalTypeSymbol->GetClassKey()));
 266             writer.WriteSpace(1);
 267         }
 268         for (int i = 0; i < n - 1; ++i)
 269         {
 270             IdentifierNode* idNode = idNodeSequence[i];
 271             if (idNode)
 272             {
 273                 writer.WriteIdentifier(idNode->Identifier());
 274             }
 275             writer.WriteOther(U"::");
 276         }
 277         if (n > 0)
 278         {
 279             writer.WriteType(idNodeSequence.back()->Identifier());
 280         }
 281         else
 282         {
 283             writer.WriteType(type->Name());
 284         }
 285     }
 286     else if (type->IsSimpleTypeSymbol())
 287     {
 288         SimpleTypeSymbol* simpleTypeSymbol = static_cast<SimpleTypeSymbol*>(type);
 289         std::vector<std::u32string> components = Split(simpleTypeSymbol->Name()' ');
 290         bool first = true;
 291         for (const std::u32string& component : components)
 292         {
 293             if (first)
 294             {
 295                 first = false;
 296             }
 297             else
 298             {
 299                 writer.WriteSpace(1);
 300             }
 301             writer.WriteKeyword(component);
 302         }
 303     }
 304     else if (type->IsDerivedTypeSymbol())
 305     {
 306         DerivedTypeSymbol* derivedTypeSymbol = static_cast<DerivedTypeSymbol*>(type);
 307         for (Derivation derivation : derivedTypeSymbol->Derivations())
 308         {
 309             switch (derivation)
 310             {
 311             case Derivation::const_:
 312             {
 313                 writer.WriteKeyword(U"const ");
 314                 break;
 315             }
 316             case Derivation::volatile_:
 317             {
 318                 writer.WriteKeyword(U"volatile ");
 319                 break;
 320             }
 321             case Derivation::ptr:
 322             {
 323                 writer.WriteOther(U"*");
 324                 break;
 325             }
 326             case Derivation::lvalueRef:
 327             {
 328                 writer.WriteOther(U"&");
 329                 break;
 330             }
 331             case Derivation::rvalueRef:
 332             {
 333                 writer.WriteOther(U"&&");
 334                 break;
 335             }
 336             case Derivation::base:
 337             {
 338                 TypeSymbol* baseType = derivedTypeSymbol->BaseType();
 339                 WriteType(baseTypeidNodeSequencetemplateIdNode);
 340                 break;
 341             }
 342             }
 343         }
 344     }
 345     else if (type->IsClassTemplateSpecializationSymbol())
 346     {
 347         ClassTemplateSpecializationSymbol* classTemplateSpecializationSymbol = static_cast<ClassTemplateSpecializationSymbol*>(type);
 348         TypeSymbol* primaryType = classTemplateSpecializationSymbol->PrimaryClassTemplateSymbol();
 349         WriteType(primaryTypesymbolTable.GetIdNodeSequence(templateIdNode)templateIdNode);
 350         writer.WriteOther(U"<");
 351         int n = classTemplateSpecializationSymbol->TemplateArgumentSymbols().size();
 352         std::vector<Node*> templateArgumentNodes = symbolTable.GetTemplateArgumentNodes(templateIdNode);
 353         for (int i = 0; i < n; ++i)
 354         {
 355             if (i > 0)
 356             {
 357                 writer.WriteOther(U", ");
 358             }
 359             TypeSymbol* templateArgumentSymbol = classTemplateSpecializationSymbol->TemplateArgumentSymbols()[i];
 360             Node* templateArgumentNode = templateArgumentNodes[i];
 361             templateArgumentNode->Accept(*this);
 362         }
 363         writer.WriteOther(U">");
 364     }
 365     else if (type->IsElaborateClassTypeSymbol())
 366     {
 367         ElaborateClassTypeSymbol* elaborateClassTypeSymbol = static_cast<ElaborateClassTypeSymbol*>(type);
 368         writer.WriteKeyword(ToString(elaborateClassTypeSymbol->GetClassKey()));
 369         writer.WriteSpace(1);
 370         WriteType(elaborateClassTypeSymbol->GetClassType()idNodeSequencetemplateIdNode);
 371     }
 372     else
 373     {
 374         for (int i = 0; i < n - 1; ++i)
 375         {
 376             IdentifierNode* idNode = idNodeSequence[i];
 377             writer.WriteIdentifier(idNode->Identifier());
 378             writer.WriteOther(U"::");
 379         }
 380         writer.WriteLink(type->Name()MakeSymbolRef(type));
 381         writer.WriteInlineLink(type->Name()MakeInlineSymbolRef(type));
 382     }
 383 }
 384 
 385 void HtmlSourceCodeGenerator::MoveTo(const Span& span)
 386 {
 387     int lineNumber = span.line;
 388     if (lineNumber == 77)
 389     {
 390         int x = 0;
 391     }
 392     while (lineNumber > currentSourceLineNumber)
 393     {
 394         if (!lineElement)
 395         {
 396             UseInputLine();
 397         }
 398         else
 399         {
 400             CloseLine();
 401         }
 402     }
 403     if (!lineElement)
 404     {
 405         OpenLine();
 406     }
 407     if (inlineCodeElement && !inlineLineElement)
 408     {
 409         OpenInlineLine();
 410     }
 411     writer.MoveTo(span);
 412 }
 413 
 414 void HtmlSourceCodeGenerator::OpenLine()
 415 {
 416     lineElement.reset(new sngxml::dom::Element(U"span"));
 417     writer.SetLineElement(lineElement.get());
 418     lineElement->SetAttribute(U"class"U"code");
 419     lineElement->SetAttribute(U"xml:space"U"preserve");
 420     lineElement->SetAttribute(U"id"ToUtf32(std::to_string(currentSourceLineNumber)));
 421     std::u32string lineNumberText = FormatNumber(currentSourceLineNumbernumDigits);
 422     writer.WriteLineNumberKind(lineNumberTextWriteKind::line);
 423     writer.WriteSpaceKind(1WriteKind::line);
 424     if (lineStarts->size() < currentSourceLineNumber)
 425     {
 426         throw std::runtime_error("invalid line starts vector");
 427     }
 428     int lineStart = (*lineStarts)[currentSourceLineNumber - 1];
 429     writer.SetCurrentPos(lineStart);
 430 }
 431 
 432 void HtmlSourceCodeGenerator::OpenInlineLine()
 433 {
 434     inlineLineElement.reset(new sngxml::dom::Element(U"span"));
 435     inlineLineElement->SetAttribute(U"class"U"code");
 436     inlineLineElement->SetAttribute(U"xml:space"U"preserve");
 437     writer.SetInlineLineElement(inlineLineElement.get());
 438     std::u32string lineNumberText = FormatNumber(currentSourceLineNumbernumDigits);
 439     writer.WriteLineNumberKind(lineNumberTextWriteKind::inlineLine);
 440     writer.WriteSpaceKind(1WriteKind::inlineLine);
 441     if (lineStarts->size() < currentSourceLineNumber)
 442     {
 443         throw std::runtime_error("invalid line starts vector");
 444     }
 445     int inlineLineStart = (*lineStarts)[currentSourceLineNumber - 1] + inlineCodeOffset;
 446     writer.SetInlineCurrentPos(inlineLineStart);
 447 }
 448 
 449 void HtmlSourceCodeGenerator::CloseLine()
 450 {
 451     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(lineElement.release()));
 452     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
 453     if (inlineCodeElement && inlineLineElement)
 454     {
 455         inlineCodeElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(inlineLineElement.release()));
 456         inlineCodeElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
 457         writer.SetInlineLineElement(nullptr);
 458     }
 459     ++currentSourceLineNumber;
 460 }
 461 
 462 void HtmlSourceCodeGenerator::UseInputLine()
 463 {
 464     const std::u32string& line = inputLines[currentSourceLineNumber - 1];
 465     OpenLine();
 466     ParseSourceLine(linewriterinBlockComment);
 467     CloseLine();
 468 }
 469 
 470 void HtmlSourceCodeGenerator::WriteRestOfInput()
 471 {
 472     int n = inputLines.size();
 473     while (currentSourceLineNumber <= n)
 474     {
 475         UseInputLine();
 476     }
 477 }
 478 
 479 void HtmlSourceCodeGenerator::WriteSpecifiers(Specifier specifiers)
 480 {
 481     if (specifiers != Specifier::none)
 482     {
 483         std::u32string specifierStr = SpecifierStr(specifiers);
 484         std::vector<std::u32string> s = Split(specifierStr' ');
 485         if (!s.empty())
 486         {
 487             bool first = true;
 488             for (const std::u32string& sp : s)
 489             {
 490                 if (first)
 491                 {
 492                     first = false;
 493                 }
 494                 else
 495                 {
 496                     writer.WriteOther(U", ");
 497                 }
 498                 if (sp == U"pure")
 499                 {
 500                     writer.WriteOther(U"= 0");
 501                 }
 502                 else if (sp == U"default" || sp == U"delete")
 503                 {
 504                     writer.WriteOther(U" = ");
 505                     writer.WriteKeyword(sp);
 506                 }
 507                 else
 508                 {
 509                     writer.WriteKeyword(sp);
 510                 }
 511             }
 512         }
 513     }
 514 }
 515 
 516 void HtmlSourceCodeGenerator::WriteAccess(const Span& spanSpecifier access)
 517 {
 518     MoveTo(span);
 519     std::u32string accessStr = SpecifierStr(access & Specifier::access);
 520     writer.WriteKeyword(accessStr);
 521     writer.WriteOther(U":");
 522 }
 523 
 524 void HtmlSourceCodeGenerator::Visit(NamespaceNode& namespaceNode)
 525 {
 526     if (namespaceNode.Child())
 527     {
 528         namespaceNode.Child()->Accept(*this);
 529     }
 530 }
 531 
 532 void HtmlSourceCodeGenerator::Visit(SimpleDeclarationNode& simpleDeclarationNode)
 533 {
 534     MoveTo(simpleDeclarationNode.GetSpan());
 535     Specifier declSpecifiers = simpleDeclarationNode.Specifiers() & DeclSpecifierMask();
 536     WriteSpecifiers(declSpecifiers);
 537     simpleDeclarationNode.TypeExpr()->Accept(*this);
 538     if (simpleDeclarationNode.Declarator())
 539     {
 540         simpleDeclarationNode.Declarator()->Accept(*this);
 541     }
 542     if (!rangeForDeclaration)
 543     {
 544         writer.WriteOther(U";");
 545     }
 546 }
 547 
 548 void HtmlSourceCodeGenerator::Visit(AliasDeclarationNode& aliasDeclarationNode)
 549 {
 550     MoveTo(aliasDeclarationNode.GetSpan());
 551     writer.WriteKeyword(U"using ");
 552     writer.WriteIdentifier(aliasDeclarationNode.Id());
 553     writer.WriteOther(U" = ");
 554     aliasDeclarationNode.TypeExpr()->Accept(*this);
 555     writer.WriteOther(U";");
 556 }
 557 
 558 void HtmlSourceCodeGenerator::Visit(DeclarationSequenceNode& declarationSequenceNode)
 559 {
 560     declarationSequenceNode.Left()->Accept(*this);
 561     declarationSequenceNode.Right()->Accept(*this);
 562 }
 563 
 564 void HtmlSourceCodeGenerator::Visit(ForwardClassDeclarationNode& forwardClassDeclarationNode)
 565 {
 566     MoveTo(forwardClassDeclarationNode.GetSpan());
 567     writer.WriteKeyword(ToString(forwardClassDeclarationNode.GetClassKey()));
 568     writer.WriteSpace(1);
 569     forwardClassDeclarationNode.ClassName()->Accept(*this);
 570     writer.WriteOther(U";");
 571 }
 572 
 573 void HtmlSourceCodeGenerator::Visit(ElaborateClassNameNode& elaborateClassNameNode)
 574 {
 575     MoveTo(elaborateClassNameNode.GetSpan());
 576     writer.WriteKeyword(ToString(elaborateClassNameNode.GetClassKey()));
 577     writer.WriteSpace(1);
 578     elaborateClassNameNode.ClassName()->Accept(*this);
 579 }
 580 
 581 void HtmlSourceCodeGenerator::Visit(ClassNode& classNode)
 582 {
 583     MoveTo(classNode.GetSpan());
 584     writer.WriteKeyword(ToString(classNode.GetClassKey()));
 585     writer.WriteSpace(1);
 586     classNode.ClassName()->Accept(*this);
 587     WriteSpecifiers(classNode.ClassVirtSpecifiers());
 588     writer.WriteSpace(1);
 589     if (classNode.BaseClasses())
 590     {
 591         firstBaseClass = true;
 592         classNode.BaseClasses()->Accept(*this);
 593     }
 594     MoveTo(classNode.OpenBraceSpan());
 595     writer.WriteOther(U"{");
 596     if (classNode.Declarations())
 597     {
 598         currentAccess = Specifier::none;
 599         classNode.Declarations()->Accept(*this);
 600     }
 601     MoveTo(classNode.CloseBraceSpan());
 602     writer.WriteOther(U"};");
 603 }
 604 
 605 void HtmlSourceCodeGenerator::Visit(BaseClassSpecifierNode& baseClassSpecifierNode)
 606 {
 607     if (firstBaseClass)
 608     {
 609         firstBaseClass = false;
 610         writer.WriteOther(U": ");
 611     }
 612     else
 613     {
 614         writer.WriteOther(U", ");
 615     }
 616     MoveTo(baseClassSpecifierNode.GetSpan());
 617     WriteSpecifiers(baseClassSpecifierNode.BaseSpecifiers());
 618     writer.WriteSpace(1);
 619     Symbol* symbol = symbolTable.GetSymbol(&baseClassSpecifierNode);
 620     if (symbol && symbol->IsTypeSymbol() && !symbol->IsClassTemplateSpecializationSymbol())
 621     {
 622         TypeSymbol* type = static_cast<TypeSymbol*>(symbol);
 623         std::vector<IdentifierNode*> idNodeSequence = symbolTable.GetIdNodeSequence(baseClassSpecifierNode.ClassName());
 624         WriteType(typeidNodeSequencenullptr);
 625     }
 626     else
 627     {
 628         baseClassSpecifierNode.ClassName()->Accept(*this);
 629     }
 630 }
 631 
 632 void HtmlSourceCodeGenerator::Visit(BaseClassSpecifierSequenceNode& baseClassSpecifierSequenceNode)
 633 {
 634     baseClassSpecifierSequenceNode.Left()->Accept(*this);
 635     baseClassSpecifierSequenceNode.Right()->Accept(*this);
 636 }
 637 
 638 void HtmlSourceCodeGenerator::Visit(MemberAccessDeclarationNode& memberAccessDeclarationNode)
 639 {
 640     if (currentAccess != memberAccessDeclarationNode.AccessSpecifier())
 641     {
 642         if (memberAccessDeclarationNode.ExplicitAccess())
 643         {
 644             WriteAccess(memberAccessDeclarationNode.GetSpan()memberAccessDeclarationNode.AccessSpecifier());
 645         }
 646         currentAccess = memberAccessDeclarationNode.AccessSpecifier();
 647     }
 648     if (memberAccessDeclarationNode.Declaration())
 649     {
 650         memberAccessDeclarationNode.Declaration()->Accept(*this);
 651     }
 652 }
 653 
 654 void HtmlSourceCodeGenerator::Visit(MemberDeclarationNode& memberDeclarationNode)
 655 {
 656     MoveTo(memberDeclarationNode.GetSpan());
 657     WriteSpecifiers(memberDeclarationNode.Specifiers() & DeclSpecifierMask());
 658     if (memberDeclarationNode.TypeExpr())
 659     {
 660         memberDeclarationNode.TypeExpr()->Accept(*this);
 661     }
 662     memberDeclarationNode.Declarator()->Accept(*this);
 663     Specifier virtPureSpecifiers = memberDeclarationNode.Specifiers() & VirtPureSpecifierMask();
 664     if (virtPureSpecifiers != Specifier::none)
 665     {
 666         writer.WriteSpace(1);
 667         WriteSpecifiers(virtPureSpecifiers);
 668     }
 669     if (memberDeclarationNode.Initializer())
 670     {
 671         memberDeclarationNode.Initializer()->Accept(*this);
 672     }
 673     writer.WriteOther(U";");
 674 }
 675 
 676 void HtmlSourceCodeGenerator::Visit(FloatingLiteralNode& floatingLiteralNode)
 677 {
 678     MoveTo(floatingLiteralNode.GetSpan());
 679     writer.WriteOther(floatingLiteralNode.Rep());
 680 }
 681 
 682 void HtmlSourceCodeGenerator::Visit(IntegerLiteralNode& integerLiteralNode)
 683 {
 684     MoveTo(integerLiteralNode.GetSpan());
 685     writer.WriteOther(integerLiteralNode.Rep());
 686 }
 687 
 688 void HtmlSourceCodeGenerator::Visit(CharacterLiteralNode& characterLiteralNode)
 689 {
 690     MoveTo(characterLiteralNode.GetSpan());
 691     writer.WriteString(characterLiteralNode.Rep());
 692 }
 693 
 694 void HtmlSourceCodeGenerator::Visit(StringLiteralNode& stringLiteralNode)
 695 {
 696     MoveTo(stringLiteralNode.GetSpan());
 697     writer.WriteString(stringLiteralNode.Rep());
 698 }
 699 
 700 void HtmlSourceCodeGenerator::Visit(BooleanLiteralNode& booleanLiteralNode)
 701 {
 702     MoveTo(booleanLiteralNode.GetSpan());
 703     writer.WriteKeyword(booleanLiteralNode.Rep());
 704 }
 705 
 706 void HtmlSourceCodeGenerator::Visit(NullPtrLiteralNode& nullPtrLiteralNode)
 707 {
 708     MoveTo(nullPtrLiteralNode.GetSpan());
 709     writer.WriteKeyword(nullPtrLiteralNode.Rep());
 710 }
 711 
 712 void HtmlSourceCodeGenerator::Visit(FunctionNode& functionNode)
 713 {
 714     if ((functionNode.Specifiers() & (Specifier::delete_ | Specifier::default_)) != Specifier::none) return;
 715     FunctionSymbol* prevFunction = currentFunction;
 716     Symbol* symbol = symbolTable.GetSymbolNothrow(&functionNode);
 717     if (symbol && symbol->IsFunctionSymbol())
 718     {
 719         currentFunction = static_cast<FunctionSymbol*>(symbol);
 720     }
 721     MoveTo(functionNode.GetSpan());
 722     WriteSpecifiers(functionNode.Specifiers() & DeclSpecifierMask());
 723     if (functionNode.TypeExpr())
 724     {
 725         functionNode.TypeExpr()->Accept(*this);
 726     }
 727     functionNode.Declarator()->Accept(*this);
 728     Specifier virtPureSpecifiers = functionNode.Specifiers() & VirtPureSpecifierMask();
 729     if (virtPureSpecifiers != Specifier::none)
 730     {
 731         writer.WriteSpace(1);
 732         WriteSpecifiers(virtPureSpecifiers);
 733     }
 734     if (functionNode.Body())
 735     {
 736         blockLevel = 0;
 737         functionNode.Body()->Accept(*this);
 738         if (inlineCodeElement)
 739         {
 740             if (inlineLineElement)
 741             {
 742                 inlineCodeElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(inlineLineElement.release()));
 743                 writer.SetInlineLineElement(nullptr);
 744             }
 745             Symbol* symbol = symbolTable.GetSymbolNothrow(&functionNode);
 746             if (symbol)
 747             {
 748                 inlineCodeMap[symbol->Id()] = std::move(inlineCodeElement);
 749             }
 750             else
 751             {
 752                 inlineCodeElement.reset();
 753             }
 754         }
 755     }
 756     else
 757     {
 758         Specifier defaultOrDeleteSpecifier = functionNode.Specifiers() & DefaultDeleteSpecifierMask();
 759         if (defaultOrDeleteSpecifier != Specifier::none)
 760         {
 761             if (virtPureSpecifiers != Specifier::none)
 762             {
 763                 writer.WriteSpace(1);
 764             }
 765             WriteSpecifiers(defaultOrDeleteSpecifier);
 766             writer.WriteOther(U";");
 767         }
 768     }
 769     currentFunction = prevFunction;
 770 }
 771 
 772 void HtmlSourceCodeGenerator::Visit(SpecialMemberFunctionNode& specialMemberFunctionNode)
 773 {
 774     if ((specialMemberFunctionNode.Specifiers() & (Specifier::delete_ | Specifier::default_)) != Specifier::none) return;
 775     FunctionSymbol* prevFunction = currentFunction;
 776     Symbol* symbol = symbolTable.GetSymbolNothrow(&specialMemberFunctionNode);
 777     if (symbol && symbol->IsFunctionSymbol())
 778     {
 779         currentFunction = static_cast<FunctionSymbol*>(symbol);
 780     }
 781     MoveTo(specialMemberFunctionNode.GetSpan());
 782     WriteSpecifiers(specialMemberFunctionNode.Specifiers() & DeclSpecifierMask());
 783     specialMemberFunctionNode.Declarator()->Accept(*this);
 784     blockLevel = 0;
 785     if (specialMemberFunctionNode.CtorInitializer())
 786     {
 787         int firstLineNumber = specialMemberFunctionNode.CtorInitializer()->GetSpan().line;
 788         int lastLineNumber = specialMemberFunctionNode.FunctionBody()->EndBraceSpan().line;
 789         if (lastLineNumber - firstLineNumber + 1 <= inlineCodeLimit)
 790         {
 791             inlineCodeElement.reset(new sngxml::dom::Element(U"span"));
 792             inlineCodeElement->SetAttribute(U"class"U"code");
 793             inlineCodeOffset = specialMemberFunctionNode.CtorInitializer()->GetSpan().start - (*lineStarts)[firstLineNumber - 1];
 794         }
 795         blockLevel = 1;
 796         specialMemberFunctionNode.CtorInitializer()->Accept(*this);
 797     }
 798     if (specialMemberFunctionNode.FunctionBody())
 799     {
 800         if (inlineCodeElement)
 801         {
 802             inlineCodeOffset = specialMemberFunctionNode.FunctionBody()->GetSpan().start - (*lineStarts)[specialMemberFunctionNode.FunctionBody()->GetSpan().line - 1];
 803         }
 804         specialMemberFunctionNode.FunctionBody()->Accept(*this);
 805         if (inlineCodeElement)
 806         {
 807             if (inlineLineElement)
 808             {
 809                 inlineCodeElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(inlineLineElement.release()));
 810                 writer.SetInlineLineElement(nullptr);
 811             }
 812             Symbol* symbol = symbolTable.GetSymbolNothrow(&specialMemberFunctionNode);
 813             if (symbol)
 814             {
 815                 inlineCodeMap[symbol->Id()] = std::move(inlineCodeElement);
 816             }
 817             else
 818             {
 819                 inlineCodeElement.reset();
 820             }
 821         }
 822     }
 823     else
 824     {
 825         Specifier defaultOrDeleteSpecifier = specialMemberFunctionNode.Specifiers() & DefaultDeleteSpecifierMask();
 826         if (defaultOrDeleteSpecifier != Specifier::none)
 827         {
 828             WriteSpecifiers(defaultOrDeleteSpecifier);
 829             writer.WriteOther(U";");
 830         }
 831     }
 832     currentFunction = prevFunction;
 833 }
 834 
 835 void HtmlSourceCodeGenerator::Visit(LabeledStatementNode& labeledStatementNode)
 836 {
 837     MoveTo(labeledStatementNode.GetSpan());
 838     writer.WriteIdentifier(labeledStatementNode.Label());
 839     writer.WriteOther(U":");
 840     labeledStatementNode.Child()->Accept(*this);
 841 }
 842 
 843 void HtmlSourceCodeGenerator::Visit(CaseStatementNode& caseStatementNode)
 844 {
 845     MoveTo(caseStatementNode.GetSpan());
 846     writer.WriteKeyword(U"case");
 847     caseStatementNode.CaseExpr()->Accept(*this);
 848     writer.WriteOther(U":");
 849     caseStatementNode.Child()->Accept(*this);
 850 }
 851 
 852 void HtmlSourceCodeGenerator::Visit(DefaultStatementNode& defaultStatementNode)
 853 {
 854     MoveTo(defaultStatementNode.GetSpan());
 855     writer.WriteKeyword(U"default");
 856     writer.WriteOther(U":");
 857     defaultStatementNode.Child()->Accept(*this);
 858 }
 859 
 860 void HtmlSourceCodeGenerator::Visit(ExpressionStatementNode& expressionStatementNode)
 861 {
 862     MoveTo(expressionStatementNode.GetSpan());
 863     if (expressionStatementNode.Child())
 864     {
 865         firstInitializer = true;
 866         expressionStatementNode.Child()->Accept(*this);
 867     }
 868     writer.WriteOther(U";");
 869 }
 870 
 871 void HtmlSourceCodeGenerator::Visit(CompoundStatementNode& compoundStatementNode)
 872 {
 873     if (blockLevel == 0)
 874     {
 875         int firstLineNumber = compoundStatementNode.GetSpan().line;
 876         int lastLineNumber = compoundStatementNode.EndBraceSpan().line;
 877         if (lastLineNumber - firstLineNumber + 1 <= inlineCodeLimit)
 878         {
 879             inlineCodeElement.reset(new sngxml::dom::Element(U"span"));
 880             inlineCodeElement->SetAttribute(U"class"U"code");
 881             inlineCodeOffset = compoundStatementNode.GetSpan().start - (*lineStarts)[firstLineNumber - 1];
 882         }
 883         else
 884         {
 885             inlineCodeElement.reset();
 886         }
 887     }
 888     MoveTo(compoundStatementNode.GetSpan());
 889     writer.WriteOther(U"{");
 890     if (compoundStatementNode.Child())
 891     {
 892         ++blockLevel;
 893         compoundStatementNode.Child()->Accept(*this);
 894         --blockLevel;
 895     }
 896     MoveTo(compoundStatementNode.EndBraceSpan());
 897     writer.WriteOther(U"}");
 898 }
 899 
 900 void HtmlSourceCodeGenerator::Visit(StatementSequenceNode& statementSequenceNode)
 901 {
 902     statementSequenceNode.Left()->Accept(*this);
 903     statementSequenceNode.Right()->Accept(*this);
 904 }
 905 
 906 void HtmlSourceCodeGenerator::Visit(IfStatementNode& ifStatementNode)
 907 {
 908     MoveTo(ifStatementNode.GetSpan());
 909     writer.WriteKeyword(U"if ");
 910     writer.WriteOther(U"(");
 911     ifStatementNode.Condition()->Accept(*this);
 912     writer.WriteOther(U")");
 913     ifStatementNode.ThenS()->Accept(*this);
 914     if (ifStatementNode.ElseS())
 915     {
 916         MoveTo(ifStatementNode.ElseSpan());
 917         writer.WriteKeyword(U"else");
 918         ifStatementNode.ElseS()->Accept(*this);
 919     }
 920 }
 921 
 922 void HtmlSourceCodeGenerator::Visit(SwitchStatementNode& switchStatementNode)
 923 {
 924     MoveTo(switchStatementNode.GetSpan());
 925     writer.WriteKeyword(U"switch ");
 926     writer.WriteOther(U"(");
 927     switchStatementNode.Condition()->Accept(*this);
 928     writer.WriteOther(U")");
 929     switchStatementNode.Statement()->Accept(*this);
 930 }
 931 
 932 void HtmlSourceCodeGenerator::Visit(WhileStatementNode& whileStatementNode)
 933 {
 934     MoveTo(whileStatementNode.GetSpan());
 935     writer.WriteKeyword(U"while ");
 936     writer.WriteOther(U"(");
 937     whileStatementNode.Condition()->Accept(*this);
 938     writer.WriteOther(U")");
 939     whileStatementNode.Statement()->Accept(*this);
 940 }
 941 
 942 void HtmlSourceCodeGenerator::Visit(DoStatementNode& doStatementNode)
 943 {
 944     MoveTo(doStatementNode.GetSpan());
 945     writer.WriteKeyword(U"do");
 946     doStatementNode.Statement()->Accept(*this);
 947     MoveTo(doStatementNode.WhileSpan());
 948     writer.WriteKeyword(U"while");
 949     writer.WriteSpace(1);
 950     writer.WriteOther(U"(");
 951     doStatementNode.Condition()->Accept(*this);
 952     writer.WriteOther(U");");
 953 }
 954 
 955 void HtmlSourceCodeGenerator::Visit(RangeForStatementNode& rangeForStatementNode)
 956 {
 957     MoveTo(rangeForStatementNode.GetSpan());
 958     writer.WriteKeyword(U"for ");
 959     writer.WriteOther(U"(");
 960     bool prevRangeForDeclaration = rangeForDeclaration;
 961     rangeForDeclaration = true;
 962     rangeForStatementNode.ForRangeDeclaration()->Accept(*this);
 963     rangeForDeclaration = prevRangeForDeclaration;
 964     writer.WriteOther(U" : ");
 965     rangeForStatementNode.ForRangeInitializer()->Accept(*this);
 966     writer.WriteOther(U")");
 967     rangeForStatementNode.Statement()->Accept(*this);
 968 }
 969 
 970 void HtmlSourceCodeGenerator::Visit(ForStatementNode& forStatementNode)
 971 {
 972     MoveTo(forStatementNode.GetSpan());
 973     writer.WriteKeyword(U"for ");
 974     writer.WriteOther(U"(");
 975     if (forStatementNode.InitS())
 976     {
 977         forStatementNode.InitS()->Accept(*this);
 978     }
 979     else
 980     {
 981         writer.WriteOther(U";");
 982     }
 983     if (forStatementNode.Condition())
 984     {
 985         forStatementNode.Condition()->Accept(*this);
 986     }
 987     writer.WriteOther(U";");
 988     if (forStatementNode.LoopExpr())
 989     {
 990         forStatementNode.LoopExpr()->Accept(*this);
 991     }
 992     writer.WriteOther(U")");
 993     forStatementNode.ActionS()->Accept(*this);
 994 }
 995 
 996 void HtmlSourceCodeGenerator::Visit(BreakStatementNode& breakStatementNode)
 997 {
 998     MoveTo(breakStatementNode.GetSpan());
 999     writer.WriteKeyword(U"break");
1000     writer.WriteOther(U";");
1001 }
1002 
1003 void HtmlSourceCodeGenerator::Visit(ContinueStatementNode& continueStatementNode)
1004 {
1005     MoveTo(continueStatementNode.GetSpan());
1006     writer.WriteKeyword(U"continue");
1007     writer.WriteOther(U";");
1008 }
1009 
1010 void HtmlSourceCodeGenerator::Visit(ReturnStatementNode& returnStatementNode)
1011 {
1012     MoveTo(returnStatementNode.GetSpan());
1013     writer.WriteKeyword(U"return");
1014     if (returnStatementNode.ReturnExpr())
1015     {
1016         returnStatementNode.ReturnExpr()->Accept(*this);
1017     }
1018     writer.WriteOther(U";");
1019 }
1020 
1021 void HtmlSourceCodeGenerator::Visit(GotoStatementNode& gotoStatementNode)
1022 {
1023     MoveTo(gotoStatementNode.GetSpan());
1024     writer.WriteKeyword(U"goto");
1025     writer.WriteSpace(1);
1026     writer.WriteIdentifier(gotoStatementNode.Target());
1027     writer.WriteOther(U";");
1028 }
1029 
1030 void HtmlSourceCodeGenerator::Visit(DeclarationStatementNode& declarationStatementNode)
1031 {
1032     MoveTo(declarationStatementNode.GetSpan());
1033     declarationStatementNode.Child()->Accept(*this);
1034 }
1035 
1036 void HtmlSourceCodeGenerator::Visit(TryStatementNode& tryStatementNode)
1037 {
1038     MoveTo(tryStatementNode.GetSpan());
1039     writer.WriteKeyword(U"try");
1040     tryStatementNode.TryBlock()->Accept(*this);
1041     tryStatementNode.Handlers()->Accept(*this);
1042 }
1043 
1044 void HtmlSourceCodeGenerator::Visit(HandlerNode& handlerNode)
1045 {
1046     MoveTo(handlerNode.GetSpan());
1047     writer.WriteKeyword(U"catch ");
1048     writer.WriteOther(U"(");
1049     handlerNode.ExceptionDeclaration()->Accept(*this);
1050     writer.WriteOther(U")");
1051     handlerNode.CatchBlock()->Accept(*this);
1052 }
1053 
1054 void HtmlSourceCodeGenerator::Visit(HandlerSequenceNode& handlerSequenceNode)
1055 {
1056     handlerSequenceNode.Left()->Accept(*this);
1057     handlerSequenceNode.Right()->Accept(*this);
1058 }
1059 
1060 void HtmlSourceCodeGenerator::Visit(CatchAllNode& catchAllNode)
1061 {
1062     MoveTo(catchAllNode.GetSpan());
1063     writer.WriteOther(U"...");
1064 }
1065 
1066 void HtmlSourceCodeGenerator::Visit(CtorInitializerNode& ctorInitializerNode)
1067 {
1068     MoveTo(ctorInitializerNode.GetSpan());
1069     writer.WriteOther(U":");
1070     firstMemberInitializer = true;
1071     ctorInitializerNode.Child()->Accept(*this);
1072 }
1073 
1074 void HtmlSourceCodeGenerator::Visit(ExpressionListInitializerNode& expressionListInitializer)
1075 {
1076     MoveTo(expressionListInitializer.GetSpan());
1077     writer.WriteOther(U"(");
1078     if (expressionListInitializer.Child())
1079     {
1080         firstInitializer = true;
1081         expressionListInitializer.Child()->Accept(*this);
1082     }
1083     writer.WriteOther(U")");
1084 }
1085 
1086 void HtmlSourceCodeGenerator::Visit(ExpressionInitializerNode& expressionInitializerNode)
1087 {
1088     if (firstInitializer)
1089     {
1090         firstInitializer = false;
1091     }
1092     else
1093     {
1094         writer.WriteOther(U", ");
1095     }
1096     MoveTo(expressionInitializerNode.GetSpan());
1097     expressionInitializerNode.Child()->Accept(*this);
1098 }
1099 
1100 void HtmlSourceCodeGenerator::Visit(EnumTypeNode& enumTypeNode)
1101 {
1102     MoveTo(enumTypeNode.GetSpan());
1103     EnumKey enumKey = enumTypeNode.GetEnumKey();
1104     writer.WriteKeyword(ToString(enumKey));
1105     writer.WriteSpace(1);
1106     enumTypeNode.EnumName()->Accept(*this);
1107     if (enumTypeNode.EnumBase())
1108     {
1109         writer.WriteOther(U" : ");
1110         enumTypeNode.EnumBase()->Accept(*this);
1111         writer.WriteSpace(1);
1112     }
1113     MoveTo(enumTypeNode.OpenBraceSpan());
1114     writer.WriteOther(U"{");
1115     if (enumTypeNode.Enumerators())
1116     {
1117         firstEnumerator = true;
1118         enumTypeNode.Enumerators()->Accept(*this);
1119     }
1120     MoveTo(enumTypeNode.CloseBraceSpan());
1121     writer.WriteOther(U"};");
1122 }
1123 
1124 void HtmlSourceCodeGenerator::Visit(EnumeratorNode& enumeratorNode)
1125 {
1126     if (firstEnumerator)
1127     {
1128         firstEnumerator = false;
1129     }
1130     else
1131     {
1132         writer.WriteOther(U", ");
1133     }
1134     MoveTo(enumeratorNode.GetSpan());
1135     writer.WriteIdentifier(enumeratorNode.Enumerator());
1136     if (enumeratorNode.Value())
1137     {
1138         MoveTo(enumeratorNode.AssignmentSignSpan());
1139         writer.WriteOther(U"=");
1140         MoveTo(enumeratorNode.Value()->GetSpan());
1141         writer.WriteOther(enumeratorNode.ValueStr());
1142     }
1143 }
1144 
1145 void HtmlSourceCodeGenerator::Visit(EnumeratorSequenceNode& enumeratorSequenceNode)
1146 {
1147     enumeratorSequenceNode.Left()->Accept(*this);
1148     enumeratorSequenceNode.Right()->Accept(*this);
1149 }
1150 
1151 void HtmlSourceCodeGenerator::Visit(AssignmentInitializerNode& assignmentInitializerNode)
1152 {
1153     MoveTo(assignmentInitializerNode.GetSpan());
1154     writer.WriteOther(U"=");
1155     firstInitializer = true;
1156     assignmentInitializerNode.Child()->Accept(*this);
1157 }
1158 
1159 void HtmlSourceCodeGenerator::Visit(BracedInitializerListNode& bracedInitializerListNode)
1160 {
1161     MoveTo(bracedInitializerListNode.GetSpan());
1162     writer.WriteOther(U"{");
1163     if (bracedInitializerListNode.Child())
1164     {
1165         bool prevFirstInitializer = firstInitializer;
1166         firstInitializer = true;
1167         bracedInitializerListNode.Child()->Accept(*this);
1168         firstInitializer = prevFirstInitializer;
1169     }
1170     MoveTo(bracedInitializerListNode.EndBraceSpan());
1171     writer.WriteOther(U"}");
1172 }
1173 
1174 void HtmlSourceCodeGenerator::Visit(MemberInitializerNode& memberInitializerNode)
1175 {
1176     if (firstMemberInitializer)
1177     {
1178         firstMemberInitializer = false;
1179     }
1180     else
1181     {
1182         writer.WriteOther(U", ");
1183     }
1184     MoveTo(memberInitializerNode.GetSpan());
1185     Symbol* symbol = symbolTable.GetSymbolNothrow(memberInitializerNode.Id());
1186     if (symbol && symbol->IsTypeSymbol())
1187     {
1188         TypeSymbol* type = static_cast<TypeSymbol*>(symbol);
1189         std::vector<IdentifierNode*> idNodeSequence = symbolTable.GetIdNodeSequence(memberInitializerNode.Id());
1190         TemplateIdNode* templateIdNode = nullptr;
1191         if (memberInitializerNode.Id()->IsTemplateIdNode())
1192         {
1193             templateIdNode = static_cast<TemplateIdNode*>(memberInitializerNode.Id());
1194         }
1195         WriteType(typeidNodeSequencetemplateIdNode);
1196     }
1197     else
1198     {
1199         memberInitializerNode.Id()->Accept(*this);
1200     }
1201     memberInitializerNode.Initializer()->Accept(*this);
1202 }
1203 
1204 void HtmlSourceCodeGenerator::Visit(MemberInitializerSequenceNode& memberInitializerSequenceNode)
1205 {
1206     memberInitializerSequenceNode.Left()->Accept(*this);
1207     memberInitializerSequenceNode.Right()->Accept(*this);
1208 }
1209 
1210 void HtmlSourceCodeGenerator::Visit(FunctionDeclaratorNode& functionDeclaratorNode)
1211 {
1212     MoveTo(functionDeclaratorNode.GetSpan());
1213     skip = false;
1214     functionDeclaratorNode.Declarator()->Accept(*this);
1215     if (!skip)
1216     {
1217         writer.WriteOther(U"(");
1218         if (functionDeclaratorNode.Parameters())
1219         {
1220             firstParam = true;
1221             functionDeclaratorNode.Parameters()->Accept(*this);
1222         }
1223         writer.WriteOther(U")");
1224         if (functionDeclaratorNode.CVSpecifiers() != Specifier::none)
1225         {
1226             writer.WriteSpace(1);
1227             WriteSpecifiers(functionDeclaratorNode.CVSpecifiers());
1228         }
1229     }
1230 }
1231 
1232 void HtmlSourceCodeGenerator::Visit(FunctionPtrIdNode& functionPtrIdNode)
1233 {
1234     MoveTo(functionPtrIdNode.GetSpan());
1235     writer.WriteOther(U"(*");
1236     writer.WriteIdentifier(functionPtrIdNode.Id());
1237     writer.WriteOther(U")");
1238     skip = true;
1239 }
1240 
1241 void HtmlSourceCodeGenerator::Visit(MemberFunctionPtrIdNode& memberFunctionPtrIdNode)
1242 {
1243     MoveTo(memberFunctionPtrIdNode.GetSpan());
1244     writer.WriteOther(U"(");
1245     memberFunctionPtrIdNode.ClassNameNode()->Accept(*this);
1246     writer.WriteOther(U"::*");
1247     writer.WriteIdentifier(memberFunctionPtrIdNode.Id());
1248     writer.WriteOther(U")");
1249     skip = true;
1250 }
1251 
1252 void HtmlSourceCodeGenerator::Visit(ArrayDeclaratorNode& arrayDeclaratorNode)
1253 {
1254     MoveTo(arrayDeclaratorNode.GetSpan());
1255     arrayDeclaratorNode.Declarator()->Accept(*this);
1256     writer.WriteOther(U"[");
1257     if (arrayDeclaratorNode.Size())
1258     {
1259         arrayDeclaratorNode.Size()->Accept(*this);
1260     }
1261     writer.WriteOther(U"]");
1262 }
1263 
1264 void HtmlSourceCodeGenerator::Visit(InitDeclaratorNode& initDeclaratorNode)
1265 {
1266     MoveTo(initDeclaratorNode.GetSpan());
1267     initDeclaratorNode.Declarator()->Accept(*this);
1268     initDeclaratorNode.Initializer()->Accept(*this);
1269 }
1270 
1271 void HtmlSourceCodeGenerator::Visit(IdDeclaratorNode& idDeclaratorNode)
1272 {
1273     MoveTo(idDeclaratorNode.GetSpan());
1274     idDeclaratorNode.IdNode()->Accept(*this);
1275 }
1276 
1277 void HtmlSourceCodeGenerator::Visit(ParameterNode& parameterNode)
1278 {
1279     if (firstParam)
1280     {
1281         firstParam = false;
1282     }
1283     else
1284     {
1285         writer.WriteOther(U", ");
1286     }
1287     MoveTo(parameterNode.GetSpan());
1288     parameterNode.TypeExpr()->Accept(*this);
1289     if (parameterNode.Declarator())
1290     {
1291         parameterNode.Declarator()->Accept(*this);
1292     }
1293 }
1294 
1295 void HtmlSourceCodeGenerator::Visit(ParameterSequenceNode& parameterSequenceNode)
1296 {
1297     parameterSequenceNode.Left()->Accept(*this);
1298     parameterSequenceNode.Right()->Accept(*this);
1299 }
1300 
1301 void HtmlSourceCodeGenerator::Visit(SimpleTypeNode& simpleTypeNode)
1302 {
1303     MoveTo(simpleTypeNode.GetSpan());
1304     std::u32string str = simpleTypeNode.Str();
1305     std::vector<std::u32string> s = Split(str' ');
1306     bool first = true;
1307     for (const std::u32string& sp : s)
1308     {
1309         if (first)
1310         {
1311             first = false;
1312         }
1313         else
1314         {
1315             writer.WriteSpace(1);
1316         }
1317         writer.WriteKeyword(sp);
1318     }
1319 }
1320 
1321 void HtmlSourceCodeGenerator::Visit(TypeParameterNode& typeParameterNode)
1322 {
1323     MoveTo(typeParameterNode.GetSpan());
1324     if (typeParameterNode.TypenameUsed())
1325     {
1326         writer.WriteKeyword(U"typename");
1327     }
1328     else
1329     {
1330         writer.WriteKeyword(U"class");
1331     }
1332     writer.WriteSpace(1);
1333     writer.WriteIdentifier(typeParameterNode.Id());
1334     if (typeParameterNode.DefaultTemplateParameter())
1335     {
1336         writer.WriteOther(U" = ");
1337         typeParameterNode.DefaultTemplateParameter()->Accept(*this);
1338     }
1339 }
1340 
1341 void HtmlSourceCodeGenerator::Visit(TemplateParameterSequenceNode& templateParameterSequenceNode)
1342 {
1343     templateParameterSequenceNode.Left()->Accept(*this);
1344     templateParameterSequenceNode.Right()->Accept(*this);
1345 }
1346 
1347 void HtmlSourceCodeGenerator::Visit(TemplateDeclarationNode& templateDeclarationNode)
1348 {
1349     MoveTo(templateDeclarationNode.GetSpan());
1350     writer.WriteKeyword(U"template");
1351     writer.WriteOther(U"<");
1352     if (templateDeclarationNode.TemplateParameters())
1353     {
1354         firstTemplateParameter = true;
1355         templateDeclarationNode.TemplateParameters()->Accept(*this);
1356     }
1357     writer.WriteOther(U">");
1358     templateDeclarationNode.Declaration()->Accept(*this);
1359 }
1360 
1361 void HtmlSourceCodeGenerator::Visit(TemplateArgumentSequenceNode& templateArgumentSequenceNode)
1362 {
1363     MoveTo(templateArgumentSequenceNode.GetSpan());
1364     templateArgumentSequenceNode.Left()->Accept(*this);
1365     templateArgumentSequenceNode.Right()->Accept(*this);
1366 }
1367 
1368 void HtmlSourceCodeGenerator::Visit(TemplateIdNode& templateIdNode)
1369 {
1370     MoveTo(templateIdNode.GetSpan());
1371     Symbol* symbol = symbolTable.GetSymbolNothrow(&templateIdNode);
1372     if (symbol && symbol->IsClassTemplateSpecializationSymbol())
1373     {
1374         ClassTemplateSpecializationSymbol* specialization = static_cast<ClassTemplateSpecializationSymbol*>(symbol);
1375         WriteType(specializationsymbolTable.GetIdNodeSequence(&templateIdNode)&templateIdNode);
1376         return;
1377     }
1378     templateIdNode.Id()->Accept(*this);
1379     writer.WriteOther(U"<");
1380     if (templateIdNode.TemplateArguments())
1381     {
1382         firstTemplateArgument = true;
1383         templateIdNode.TemplateArguments()->Accept(*this);
1384     }
1385     writer.WriteOther(U">");
1386 }
1387 
1388 void HtmlSourceCodeGenerator::Visit(TemplateArgumentNode& templateArgumentNode)
1389 {
1390     if (firstTemplateArgument)
1391     {
1392         firstTemplateArgument = false;
1393     }
1394     else
1395     {
1396         writer.WriteOther(U", ");
1397     }
1398     MoveTo(templateArgumentNode.GetSpan());
1399     templateArgumentNode.Arg()->Accept(*this);
1400 }
1401 
1402 void HtmlSourceCodeGenerator::Visit(IdentifierNode& identifierNode)
1403 {
1404     Symbol* symbol = symbolTable.GetSymbolNothrow(&identifierNode);
1405     bool isType = symbol && symbol->IsTypeSymbol();
1406     WriteId(&identifierNodesymbolisType);
1407 }
1408 
1409 void HtmlSourceCodeGenerator::Visit(NestedIdNode& nestedIdNode)
1410 {
1411     if (nestedIdNode.Left())
1412     {
1413         nestedIdNode.Left()->Accept(*this);
1414         writer.WriteOther(U"::");
1415     }
1416     else
1417     {
1418         writer.WriteOther(U"::");
1419     }
1420     nestedIdNode.Right()->Accept(*this);
1421 }
1422 
1423 void HtmlSourceCodeGenerator::Visit(OperatorFunctionIdNode& operatorFunctionIdNode)
1424 {
1425     WriteId(&operatorFunctionIdNodesymbolTable.GetSymbolNothrow(&operatorFunctionIdNode)false);
1426     //idSequence.push_back(std::make_pair(&operatorFunctionIdNode, symbolTable.GetSymbolNothrow(&operatorFunctionIdNode)));
1427 }
1428 
1429 void HtmlSourceCodeGenerator::Visit(ConversionFunctionIdNode& conversionFunctionIdNode)
1430 {
1431     WriteId(&conversionFunctionIdNodesymbolTable.GetSymbolNothrow(&conversionFunctionIdNode)false);
1432     conversionFunctionIdNode.TypeExpr()->Accept(*this);
1433 }
1434 
1435 void HtmlSourceCodeGenerator::Visit(DtorIdNode& dtorIdNode)
1436 {
1437     WriteId(&dtorIdNodesymbolTable.GetSymbolNothrow(&dtorIdNode)false);
1438 }
1439 
1440 void HtmlSourceCodeGenerator::Visit(ExpressionSequenceNode& expressionSequenceNode)
1441 {
1442     expressionSequenceNode.Left()->Accept(*this);
1443     expressionSequenceNode.Right()->Accept(*this);
1444 }
1445 
1446 void HtmlSourceCodeGenerator::Visit(CommaExpressionNode& commaExpressionNode)
1447 {
1448     MoveTo(commaExpressionNode.GetSpan());
1449     commaExpressionNode.Left()->Accept(*this);
1450     writer.WriteOther(U", ");
1451     commaExpressionNode.Right()->Accept(*this);
1452 }
1453 
1454 void HtmlSourceCodeGenerator::Visit(AssignmentExpressionNode& assignmentExpressionNode)
1455 {
1456     MoveTo(assignmentExpressionNode.GetSpan());
1457     assignmentExpressionNode.Left()->Accept(*this);
1458     writer.WriteOther(OpStr(assignmentExpressionNode.Op()));
1459     firstInitializer = true;
1460     assignmentExpressionNode.Right()->Accept(*this);
1461 }
1462 
1463 void HtmlSourceCodeGenerator::Visit(ConditionalExpressionNode& conditionalExpressionNode)
1464 {
1465     MoveTo(conditionalExpressionNode.GetSpan());
1466     conditionalExpressionNode.Condition()->Accept(*this);
1467     writer.WriteOther(U" ? ");
1468     conditionalExpressionNode.ThenExpr()->Accept(*this);
1469     writer.WriteOther(U" : ");
1470     conditionalExpressionNode.ElseExpr()->Accept(*this);
1471 }
1472 
1473 void HtmlSourceCodeGenerator::Visit(ThrowExpressionNode& throwExpressionNode)
1474 {
1475     MoveTo(throwExpressionNode.GetSpan());
1476     writer.WriteKeyword(U"throw ");
1477     if (throwExpressionNode.Child())
1478     {
1479         throwExpressionNode.Child()->Accept(*this);
1480     }
1481 }
1482 
1483 void HtmlSourceCodeGenerator::Visit(LogicalOrExpressionNode& logicalOrExpressionNode)
1484 {
1485     MoveTo(logicalOrExpressionNode.GetSpan());
1486     logicalOrExpressionNode.Left()->Accept(*this);
1487     writer.WriteOther(U" || ");
1488     logicalOrExpressionNode.Right()->Accept(*this);
1489 }
1490 
1491 void HtmlSourceCodeGenerator::Visit(LogicalAndExpressionNode& logicalAndExpressionNode)
1492 {
1493     MoveTo(logicalAndExpressionNode.GetSpan());
1494     logicalAndExpressionNode.Left()->Accept(*this);
1495     writer.WriteOther(U" && ");
1496     logicalAndExpressionNode.Right()->Accept(*this);
1497 }
1498 
1499 void HtmlSourceCodeGenerator::Visit(InclusiveOrExpressionNode& inclusiveOrExpressionNode)
1500 {
1501     MoveTo(inclusiveOrExpressionNode.GetSpan());
1502     inclusiveOrExpressionNode.Left()->Accept(*this);
1503     writer.WriteOther(U" | ");
1504     inclusiveOrExpressionNode.Right()->Accept(*this);
1505 }
1506 
1507 void HtmlSourceCodeGenerator::Visit(ExclusiveOrExpressionNode& exclusiveOrExpressionNode)
1508 {
1509     MoveTo(exclusiveOrExpressionNode.GetSpan());
1510     exclusiveOrExpressionNode.Left()->Accept(*this);
1511     writer.WriteOther(U" ^ ");
1512     exclusiveOrExpressionNode.Right()->Accept(*this);
1513 }
1514 
1515 void HtmlSourceCodeGenerator::Visit(AndExpressionNode& andExpressionNode)
1516 {
1517     MoveTo(andExpressionNode.GetSpan());
1518     andExpressionNode.Left()->Accept(*this);
1519     writer.WriteOther(U" & ");
1520     andExpressionNode.Right()->Accept(*this);
1521 }
1522 
1523 void HtmlSourceCodeGenerator::Visit(EqualityExpressionNode& equalityExpressionNode)
1524 {
1525     MoveTo(equalityExpressionNode.GetSpan());
1526     equalityExpressionNode.Left()->Accept(*this);
1527     writer.WriteOther(OpStr(equalityExpressionNode.Op()));
1528     equalityExpressionNode.Right()->Accept(*this);
1529 }
1530 
1531 void HtmlSourceCodeGenerator::Visit(RelationalExpressionNode& relationalExpressionNode)
1532 {
1533     MoveTo(relationalExpressionNode.GetSpan());
1534     relationalExpressionNode.Left()->Accept(*this);
1535     writer.WriteOther(OpStr(relationalExpressionNode.Op()));
1536     relationalExpressionNode.Right()->Accept(*this);
1537 }
1538 
1539 void HtmlSourceCodeGenerator::Visit(ShiftExpressionNode& shiftExpressionNode)
1540 {
1541     MoveTo(shiftExpressionNode.GetSpan());
1542     shiftExpressionNode.Left()->Accept(*this);
1543     writer.WriteOther(OpStr(shiftExpressionNode.Op()));
1544     shiftExpressionNode.Right()->Accept(*this);
1545 }
1546 
1547 void HtmlSourceCodeGenerator::Visit(AdditiveExpressionNode& additiveExpressionNode)
1548 {
1549     MoveTo(additiveExpressionNode.GetSpan());
1550     additiveExpressionNode.Left()->Accept(*this);
1551     writer.WriteOther(OpStr(additiveExpressionNode.Op()));
1552     additiveExpressionNode.Right()->Accept(*this);
1553 }
1554 
1555 void HtmlSourceCodeGenerator::Visit(MultiplicativeExpressionNode& multiplicativeExpressionNode)
1556 {
1557     MoveTo(multiplicativeExpressionNode.GetSpan());
1558     multiplicativeExpressionNode.Left()->Accept(*this);
1559     writer.WriteOther(OpStr(multiplicativeExpressionNode.Op()));
1560     multiplicativeExpressionNode.Right()->Accept(*this);
1561 }
1562 
1563 void HtmlSourceCodeGenerator::Visit(PMExpressionNode& pmExpressionNode)
1564 {
1565     MoveTo(pmExpressionNode.GetSpan());
1566     pmExpressionNode.Left()->Accept(*this);
1567     writer.WriteOther(OpStr(pmExpressionNode.Op()));
1568     pmExpressionNode.Right()->Accept(*this);
1569 }
1570 
1571 void HtmlSourceCodeGenerator::Visit(CastExpressionNode& castExpressionNode)
1572 {
1573     MoveTo(castExpressionNode.GetSpan());
1574     writer.WriteOther(U"(");
1575     castExpressionNode.TypeExpr()->Accept(*this);
1576     writer.WriteOther(U")");
1577     castExpressionNode.Expr()->Accept(*this);
1578 }
1579 
1580 void HtmlSourceCodeGenerator::Visit(UnaryExpressionNode& unaryExpressionNode)
1581 {
1582     MoveTo(unaryExpressionNode.GetSpan());
1583     writer.WriteOther(OpStr(unaryExpressionNode.Op()));
1584     unaryExpressionNode.Child()->Accept(*this);
1585 }
1586 
1587 void HtmlSourceCodeGenerator::Visit(NewExpressionNode& newExpressionNode)
1588 {
1589     MoveTo(newExpressionNode.GetSpan());
1590     writer.WriteKeyword(U"new ");
1591     if (newExpressionNode.Placement())
1592     {
1593         writer.WriteOther(U"(");
1594         firstInitializer = true;
1595         newExpressionNode.Placement()->Accept(*this);
1596         writer.WriteOther(U")");
1597     }
1598     newExpressionNode.TypeExpr()->Accept(*this);
1599     writer.WriteOther(U"(");
1600     if (newExpressionNode.Initializer())
1601     {
1602         firstInitializer = true;
1603         newExpressionNode.Initializer()->Accept(*this);
1604     }
1605     writer.WriteOther(U")");
1606 }
1607 
1608 void HtmlSourceCodeGenerator::Visit(DeleteExpressionNode& deleteExpressionNode)
1609 {
1610     MoveTo(deleteExpressionNode.GetSpan());
1611     writer.WriteKeyword(U"delete");
1612     if (deleteExpressionNode.Array())
1613     {
1614         writer.WriteOther(U"[]");
1615     }
1616     writer.WriteSpace(1);
1617     deleteExpressionNode.Child()->Accept(*this);
1618 }
1619 
1620 void HtmlSourceCodeGenerator::Visit(SubscriptExpressionNode& subscriptExpressionNode)
1621 {
1622     MoveTo(subscriptExpressionNode.GetSpan());
1623     subscriptExpressionNode.Child()->Accept(*this);
1624     writer.WriteOther(U"[");
1625     subscriptExpressionNode.Index()->Accept(*this);
1626     writer.WriteOther(U"]");
1627 }
1628 
1629 void HtmlSourceCodeGenerator::Visit(InvokeExpressionNode& invokeExpressionNode)
1630 {
1631     MoveTo(invokeExpressionNode.GetSpan());
1632     Symbol* prevInvokeSymbol = invokeSymbol;
1633     invokeSymbol = symbolTable.GetSymbolNothrow(&invokeExpressionNode);
1634     invokeExpressionNode.Child()->Accept(*this);
1635     invokeSymbol = prevInvokeSymbol;
1636     writer.WriteOther(U"(");
1637     if (invokeExpressionNode.Arguments())
1638     {
1639         firstInitializer = true;
1640         invokeExpressionNode.Arguments()->Accept(*this);
1641     }
1642     writer.WriteOther(U")");
1643 }
1644 
1645 void HtmlSourceCodeGenerator::Visit(DotNode& dotNode)
1646 {
1647     MoveTo(dotNode.GetSpan());
1648     dotNode.Child()->Accept(*this);
1649     writer.WriteOther(U".");
1650     dotNode.Id()->Accept(*this);
1651 }
1652 
1653 void HtmlSourceCodeGenerator::Visit(ArrowNode& arrowNode)
1654 {
1655     MoveTo(arrowNode.GetSpan());
1656     arrowNode.Child()->Accept(*this);
1657     writer.WriteOther(U"->");
1658     arrowNode.Id()->Accept(*this);
1659 }
1660 
1661 void HtmlSourceCodeGenerator::Visit(PostfixIncNode& postfixIncNode)
1662 {
1663     MoveTo(postfixIncNode.GetSpan());
1664     postfixIncNode.Child()->Accept(*this);
1665     writer.WriteOther(U"++");
1666 }
1667 
1668 void HtmlSourceCodeGenerator::Visit(PostfixDecNode& postfixDecNode)
1669 {
1670     MoveTo(postfixDecNode.GetSpan());
1671     postfixDecNode.Child()->Accept(*this);
1672     writer.WriteOther(U"--");
1673 }
1674 
1675 void HtmlSourceCodeGenerator::Visit(CppCastExpressionNode& cppCastExpressionNode)
1676 {
1677     MoveTo(cppCastExpressionNode.GetSpan());
1678     writer.WriteKeyword(OpStr(cppCastExpressionNode.Op()));
1679     writer.WriteOther(U"<");
1680     cppCastExpressionNode.TypeExpr()->Accept(*this);
1681     writer.WriteOther(U">");
1682     writer.WriteOther(U"(");
1683     firstInitializer = true;
1684     cppCastExpressionNode.Expr()->Accept(*this);
1685     writer.WriteOther(U")");
1686 }
1687 
1688 void HtmlSourceCodeGenerator::Visit(TypeIdExpressionNode& typeIdExpressionNode)
1689 {
1690     MoveTo(typeIdExpressionNode.GetSpan());
1691     writer.WriteKeyword(U"typeid");
1692     writer.WriteOther(U" (");
1693     typeIdExpressionNode.Child()->Accept(*this);
1694     writer.WriteOther(U")");
1695 }
1696 
1697 void HtmlSourceCodeGenerator::Visit(ThisNode& thisNode)
1698 {
1699     MoveTo(thisNode.GetSpan());
1700     writer.WriteKeyword(U"this");
1701 }
1702 
1703 void HtmlSourceCodeGenerator::Visit(ParenthesizedExprNode& parenthesizedExprNode)
1704 {
1705     MoveTo(parenthesizedExprNode.GetSpan());
1706     writer.WriteOther(U"(");
1707     parenthesizedExprNode.Child()->Accept(*this);
1708     writer.WriteOther(U")");
1709 }
1710 
1711 void HtmlSourceCodeGenerator::Visit(LambdaExpressionNode& lambdaExpressionNode)
1712 {
1713     MoveTo(lambdaExpressionNode.GetSpan());
1714     writer.WriteOther(U"[");
1715     if (lambdaExpressionNode.Captures())
1716     {
1717         lambdaExpressionNode.Captures()->Accept(*this);
1718     }
1719     writer.WriteOther(U"]");
1720     if (lambdaExpressionNode.Parameters())
1721     {
1722         firstParam = true;
1723         writer.WriteOther(U"(");
1724         lambdaExpressionNode.Parameters()->Accept(*this);
1725         writer.WriteOther(U")");
1726     }
1727     lambdaExpressionNode.Body()->Accept(*this);
1728 }
1729 
1730 void HtmlSourceCodeGenerator::Visit(CaptureSequenceNode& captureSequenceNode)
1731 {
1732     captureSequenceNode.Left()->Accept(*this);
1733     captureSequenceNode.Right()->Accept(*this);
1734 }
1735 
1736 void HtmlSourceCodeGenerator::Visit(AssignCaptureNode& assignCaptureNode)
1737 {
1738     MoveTo(assignCaptureNode.GetSpan());
1739     writer.WriteOther(U"=");
1740 }
1741 
1742 void HtmlSourceCodeGenerator::Visit(RefCaptureNode& refCaptureNode)
1743 {
1744     MoveTo(refCaptureNode.GetSpan());
1745     writer.WriteOther(U"&");
1746 }
1747 
1748 void HtmlSourceCodeGenerator::Visit(ThisCaptureNode& thisCaptureNode)
1749 {
1750     MoveTo(thisCaptureNode.GetSpan());
1751     writer.WriteKeyword(U"this");
1752 }
1753 
1754 void HtmlSourceCodeGenerator::Visit(IdentifierCaptureNode& identifierCaptureNode)
1755 {
1756     MoveTo(identifierCaptureNode.GetSpan());
1757     identifierCaptureNode.Child()->Accept(*this);
1758 }
1759 
1760 void HtmlSourceCodeGenerator::Visit(ConstNode& constNode)
1761 {
1762     MoveTo(constNode.GetSpan());
1763     writer.WriteKeyword(U"const");
1764     constNode.Child()->Accept(*this);
1765 }
1766 
1767 void HtmlSourceCodeGenerator::Visit(VolatileNode& volatileNode)
1768 {
1769     MoveTo(volatileNode.GetSpan());
1770     writer.WriteKeyword(U"volatile");
1771     volatileNode.Child()->Accept(*this);
1772 }
1773 
1774 void HtmlSourceCodeGenerator::Visit(PointerNode& pointerNode)
1775 {
1776     MoveTo(pointerNode.GetSpan());
1777     pointerNode.Child()->Accept(*this);
1778     writer.WriteOther(U"*");
1779 }
1780 
1781 void HtmlSourceCodeGenerator::Visit(RValueRefNode& rValueRefNode)
1782 {
1783     MoveTo(rValueRefNode.GetSpan());
1784     rValueRefNode.Child()->Accept(*this);
1785     writer.WriteOther(U"&&");
1786 }
1787 
1788 void HtmlSourceCodeGenerator::Visit(LValueRefNode& lValueRefNode)
1789 {
1790     MoveTo(lValueRefNode.GetSpan());
1791     lValueRefNode.Child()->Accept(*this);
1792     writer.WriteOther(U"&");
1793 }
1794 
1795 } } // namespace gendoc::html