[clang-tools-extra] [llvm] [WIP] add a mustache backend (PR #108653)

via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 10 10:09:26 PDT 2024


https://github.com/PeterChou1 updated https://github.com/llvm/llvm-project/pull/108653

>From ac1c7b5cbf3024bf8cd4021174a47b914d7f7dea Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 30 Jul 2024 23:58:27 -0400
Subject: [PATCH 01/57] [clang-doc] add suport for clang-doc enum generation

---
 clang-tools-extra/clang-doc/BitcodeReader.cpp |   4 +
 clang-tools-extra/clang-doc/BitcodeWriter.cpp |   2 +
 clang-tools-extra/clang-doc/HTMLGenerator.cpp |  88 ++++++++++++--
 .../clang-doc/Representation.cpp              |   2 +
 clang-tools-extra/clang-doc/Representation.h  |   4 +
 clang-tools-extra/clang-doc/Serialize.cpp     |  14 ++-
 clang-tools-extra/test/clang-doc/enum.cpp     | 113 +++++++++++++-----
 7 files changed, 181 insertions(+), 46 deletions(-)

diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index bfb04e7407b380..1f2fb0a8b2b855 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -415,6 +415,10 @@ template <> llvm::Expected<CommentInfo *> getCommentInfo(TypedefInfo *I) {
   return &I->Description.emplace_back();
 }
 
+template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumValueInfo *I) {
+  return &I->Description.emplace_back();
+}
+
 template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
   I->Children.emplace_back(std::make_unique<CommentInfo>());
   return I->Children.back().get();
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 7e5a11783d303a..06f30f76e33d8c 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -536,6 +536,8 @@ void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
   emitRecord(I.Name, ENUM_VALUE_NAME);
   emitRecord(I.Value, ENUM_VALUE_VALUE);
   emitRecord(I.ValueExpr, ENUM_VALUE_EXPR);
+  for (const auto &CI : I.Description)
+    emitBlock(CI);
 }
 
 void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index aef22453035c30..a37192d6ceb9b0 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -48,6 +48,12 @@ class HTMLTag {
     TAG_SPAN,
     TAG_TITLE,
     TAG_UL,
+    TAG_TABLE,
+    TAG_THEAD,
+    TAG_TBODY,
+    TAG_TR,
+    TAG_TD,
+    TAG_TH
   };
 
   HTMLTag() = default;
@@ -133,6 +139,12 @@ bool HTMLTag::isSelfClosing() const {
   case HTMLTag::TAG_SPAN:
   case HTMLTag::TAG_TITLE:
   case HTMLTag::TAG_UL:
+  case HTMLTag::TAG_TABLE:
+  case HTMLTag::TAG_THEAD:
+  case HTMLTag::TAG_TBODY:
+  case HTMLTag::TAG_TR:
+  case HTMLTag::TAG_TD:
+  case HTMLTag::TAG_TH:
     return false;
   }
   llvm_unreachable("Unhandled HTMLTag::TagType");
@@ -174,6 +186,18 @@ StringRef HTMLTag::toString() const {
     return "title";
   case HTMLTag::TAG_UL:
     return "ul";
+  case HTMLTag::TAG_TABLE:
+    return "table";
+  case HTMLTag::TAG_THEAD:
+    return "thead";
+  case HTMLTag::TAG_TBODY:
+    return "tbody";
+  case HTMLTag::TAG_TR:
+    return "tr";
+  case HTMLTag::TAG_TD:
+    return "td";
+  case HTMLTag::TAG_TH:
+    return "th";
   }
   llvm_unreachable("Unhandled HTMLTag::TagType");
 }
@@ -352,6 +376,7 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx);
 static std::vector<std::unique_ptr<TagNode>>
 genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
         StringRef ParentInfoDir);
+static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C);
 
 static std::vector<std::unique_ptr<TagNode>>
 genEnumsBlock(const std::vector<EnumInfo> &Enums,
@@ -372,14 +397,33 @@ genEnumsBlock(const std::vector<EnumInfo> &Enums,
 }
 
 static std::unique_ptr<TagNode>
-genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
+genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members,
+                    bool HasComments) {
   if (Members.empty())
     return nullptr;
 
-  auto List = std::make_unique<TagNode>(HTMLTag::TAG_UL);
-  for (const auto &M : Members)
-    List->Children.emplace_back(
-        std::make_unique<TagNode>(HTMLTag::TAG_LI, M.Name));
+  auto List = std::make_unique<TagNode>(HTMLTag::TAG_TBODY);
+
+  for (const auto &M : Members) {
+    auto TRNode = std::make_unique<TagNode>(HTMLTag::TAG_TR);
+    TRNode->Children.emplace_back(
+        std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Name));
+    // Use user supplied value if it exists, otherwise use the value
+    if (!M.ValueExpr.empty()) {
+      TRNode->Children.emplace_back(
+          std::make_unique<TagNode>(HTMLTag::TAG_TD, M.ValueExpr));
+    } else {
+      TRNode->Children.emplace_back(
+          std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
+    }
+
+    if (HasComments) {
+      auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
+      TD->Children.emplace_back(genHTML(M.Description));
+      TRNode->Children.emplace_back(std::move(TD));
+    }
+    List->Children.emplace_back(std::move(TRNode));
+  }
   return List;
 }
 
@@ -653,15 +697,35 @@ static std::vector<std::unique_ptr<TagNode>>
 genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
   std::vector<std::unique_ptr<TagNode>> Out;
   std::string EnumType = I.Scoped ? "enum class " : "enum ";
+  // Determine if enum members have comments attached
+  bool HasComments = false;
+  for (const auto &M : I.Members) {
+    if (!M.Description.empty()) {
+      HasComments = true;
+      break;
+    }
+  }
+  std::unique_ptr<TagNode> Table =
+      std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
+  std::unique_ptr<TagNode> Thead =
+      std::make_unique<TagNode>(HTMLTag::TAG_THEAD);
+  std::unique_ptr<TagNode> TRow = std::make_unique<TagNode>(HTMLTag::TAG_TR);
+  std::unique_ptr<TagNode> TD =
+      std::make_unique<TagNode>(HTMLTag::TAG_TH, EnumType + I.Name);
+  // Span 3 columns if enum has comments
+  TD->Attributes.emplace_back("colspan", HasComments ? "3" : "2");
+
+  Table->Attributes.emplace_back("id", llvm::toHex(llvm::toStringRef(I.USR)));
+  TRow->Children.emplace_back(std::move(TD));
+  Thead->Children.emplace_back(std::move(TRow));
+  Table->Children.emplace_back(std::move(Thead));
+
+  std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members, HasComments);
 
-  Out.emplace_back(
-      std::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
-  Out.back()->Attributes.emplace_back("id",
-                                      llvm::toHex(llvm::toStringRef(I.USR)));
-
-  std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
   if (Node)
-    Out.emplace_back(std::move(Node));
+    Table->Children.emplace_back(std::move(Node));
+
+  Out.emplace_back(std::move(Table));
 
   if (I.DefLoc) {
     if (!CDCtx.RepositoryUrl)
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index d08afbb9621890..028dffc21793ae 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -266,6 +266,8 @@ void EnumInfo::merge(EnumInfo &&Other) {
     Scoped = Other.Scoped;
   if (Members.empty())
     Members = std::move(Other.Members);
+  if (Other.HasComments || HasComments)
+    HasComments = true;
   SymbolInfo::merge(std::move(Other));
 }
 
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index d70c279f7a2bdc..db3aff2d60a1b5 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -431,6 +431,8 @@ struct EnumValueInfo {
   // Stores the user-supplied initialization expression for this enumeration
   // constant. This will be empty for implicit enumeration values.
   SmallString<16> ValueExpr;
+
+  std::vector<CommentInfo> Description; // Comment description of this field.
 };
 
 // TODO: Expand to allow for documenting templating.
@@ -443,6 +445,8 @@ struct EnumInfo : public SymbolInfo {
 
   // Indicates whether this enum is scoped (e.g. enum class).
   bool Scoped = false;
+  // Indicates whether or not enum members have comments attached
+  bool HasComments = false;
 
   // Set to nonempty to the type when this is an explicitly typed enum. For
   //   enum Foo : short { ... };
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 3b074d849e8a9c..78b7041368d6df 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -394,10 +394,20 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
     std::string ValueExpr;
     if (const Expr *InitExpr = E->getInitExpr())
       ValueExpr = getSourceCode(D, InitExpr->getSourceRange());
-
     SmallString<16> ValueStr;
     E->getInitVal().toString(ValueStr);
-    I.Members.emplace_back(E->getNameAsString(), ValueStr, ValueExpr);
+    I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
+    ASTContext &Context = E->getASTContext();
+    RawComment *Comment = E->getASTContext().getRawCommentForDeclNoCache(E);
+    if (Comment) {
+      CommentInfo CInfo;
+      Comment->setAttached();
+      if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
+        EnumValueInfo &Member = I.Members.back();
+        Member.Description.emplace_back();
+        parseFullComment(Fc, Member.Description.back());
+      }
+    }
   }
 }
 
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp b/clang-tools-extra/test/clang-doc/enum.cpp
index e559940a31de69..fd7bbcb53f2d2b 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -21,9 +21,9 @@
 enum Color {
 // MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
 // HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-  Red, ///< Red
-  Green, ///< Green
-  Blue ///< Blue
+  Red, ///< Comment 1
+  Green, ///< Comment 2
+  Blue ///< Comment 3
 };
 
 // MD-INDEX: ## Enums
@@ -34,11 +34,16 @@ enum Color {
 // MD-INDEX: | Blue |
 // MD-INDEX: **brief** For specifying RGB colors
 
-// HTML-INDEX: <h2 id="Enums">Enums</h2>
-// HTML-INDEX: <h3 id="{{([0-9A-F]{40})}}">enum Color</h3>
-// HTML-INDEX: <li>Red</li>
-// HTML-INDEX: <li>Green</li>
-// HTML-INDEX: <li>Blue</li>
+// HTML-INDEX: <th colspan="3">enum Color</th>
+// HTML-INDEX: <td>Red</td>
+// HTML-INDEX: <td>0</td>
+// HTML-INDEX: <p> Comment 1</p>
+// HTML-INDEX: <td>Green</td>
+// HTML-INDEX: <td>1</td>
+// HTML-INDEX: <p> Comment 2</p>
+// HTML-INDEX: <td>Blue</td>
+// HTML-INDEX: <td>2</td>
+// HTML-INDEX: <p> Comment 3</p>
 
 /**
  * @brief Shape Types
@@ -46,11 +51,12 @@ enum Color {
 enum class Shapes {
 // MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
 // HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-  /// Circle
+
+  /// Comment 1
   Circle,
-  /// Rectangle
+  /// Comment 2
   Rectangle,
-  /// Triangle
+  /// Comment 3
   Triangle
 };
 // MD-INDEX: | enum class Shapes |
@@ -60,10 +66,17 @@ enum class Shapes {
 // MD-INDEX: | Triangle |
 // MD-INDEX: **brief** Shape Types
 
-// HTML-INDEX: <h3 id="{{([0-9A-F]{40})}}">enum class Shapes</h3>
-// HTML-INDEX: <li>Circle</li>
-// HTML-INDEX: <li>Rectangle</li>
-// HTML-INDEX: <li>Triangle</li>
+// HTML-INDEX: <th colspan="3">enum class Shapes</th>
+// HTML-INDEX: <td>Circle</td>
+// HTML-INDEX: <td>0</td>
+// HTML-INDEX: <p> Comment 1</p>
+// HTML-INDEX: <td>Rectangle</td>
+// HTML-INDEX: <td>1</td>
+// HTML-INDEX: <p> Comment 2</p>
+// HTML-INDEX: <td>Triangle</td>
+// HTML-INDEX: <td>2</td>
+// HTML-INDEX: <p> Comment 3</p>
+
 
 
 class Animals {
@@ -76,18 +89,25 @@ class Animals {
       enum AnimalType {
 // MD-ANIMAL-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
 // HTML-ANIMAL-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-          Dog, /// Man's best friend
-          Cat, /// Man's other best friend
-          Iguana /// A lizard
+          Dog, ///< Man's best friend
+          Cat, ///< Man's other best friend
+          Iguana ///< A lizard
       };
 };
 
 // HTML-ANIMAL: <h1>class Animals</h1>
 // HTML-ANIMAL: <h2 id="Enums">Enums</h2>
-// HTML-ANIMAL: <h3 id="{{([0-9A-F]{40})}}">enum AnimalType</h3>
-// HTML-ANIMAL: <li>Dog</li>
-// HTML-ANIMAL: <li>Cat</li>
-// HTML-ANIMAL: <li>Iguana</li>
+// HTML-ANIMAL: <th colspan="3">enum AnimalType</th>
+// HTML-ANIMAL: <td>Dog</td>
+// HTML-ANIMAL: <td>0</td>
+// HTML-ANIMAL: <p> Man's best friend</p>
+// HTML-ANIMAL: <td>Cat</td>
+// HTML-ANIMAL: <td>1</td>
+// HTML-ANIMAL: <p> Man's other best friend</p>
+// HTML-ANIMAL: <td>Iguana</td>
+// HTML-ANIMAL: <td>2</td>
+// HTML-ANIMAL: <p> A lizard</p>
+
 
 // MD-ANIMAL: # class Animals
 // MD-ANIMAL: ## Enums
@@ -106,10 +126,11 @@ namespace Vehicles {
     enum Car {
 // MD-VEHICLES-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
 // HTML-VEHICLES-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-       Sedan, /// Sedan
-       SUV, /// SUV
-       Pickup, /// Pickup
-       Hatchback /// Hatchback
+
+       Sedan, ///< Comment 1
+       SUV, ///< Comment 2
+       Pickup, ///< Comment 3
+       Hatchback ///< Comment 4
     };
 }
 
@@ -124,9 +145,37 @@ namespace Vehicles {
 // MD-VEHICLES: **brief** specify type of car
 
 // HTML-VEHICLES: <h1>namespace Vehicles</h1>
-// HTML-VEHICLES: <h2 id="Enums">Enums</h2>
-// HTML-VEHICLES: <h3 id="{{([0-9A-F]{40})}}">enum Car</h3>
-// HTML-VEHICLES: <li>Sedan</li>
-// HTML-VEHICLES: <li>SUV</li>
-// HTML-VEHICLES: <li>Pickup</li>
-// HTML-VEHICLES: <li>Hatchback</li>
\ No newline at end of file
+// HTML-VEHICLES: <th colspan="3">enum Car</th>
+// HTML-VEHICLES: <td>Sedan</td>
+// HTML-VEHICLES: <td>0</td>
+// HTML-VEHICLES: <p> Comment 1</p>
+// HTML-VEHICLES: <td>SUV</td>
+// HTML-VEHICLES: <td>1</td>
+// HTML-VEHICLES: <p> Comment 2</p>
+// HTML-VEHICLES: <td>Pickup</td>
+// HTML-VEHICLES: <td>2</td>
+// HTML-VEHICLES: <p> Comment 3</p>
+// HTML-VEHICLES: <td>Hatchback</td>
+// HTML-VEHICLES: <td>3</td>
+// HTML-VEHICLES: <p> Comment 4</p>
+
+
+enum ColorUserSpecified {
+  RedUserSpecified = 'A',
+  GreenUserSpecified = 2,
+  BlueUserSpecified = 'C'
+};
+
+// MD-INDEX: | enum ColorUserSpecified |
+// MD-INDEX: --
+// MD-INDEX: | RedUserSpecified |
+// MD-INDEX: | GreenUserSpecified |
+// MD-INDEX: | BlueUserSpecified |
+
+// HTML-INDEX: <th colspan="2">enum ColorUserSpecified</th>
+// HTML-INDEX: <td>RedUserSpecified</td>
+// HTML-INDEX: <td>'A'</td>
+// HTML-INDEX: <td>GreenUserSpecified</td>
+// HTML-INDEX: <td>2</td>
+// HTML-INDEX: <td>BlueUserSpecified</td>
+// HTML-INDEX: <td>'C'</td>
\ No newline at end of file

>From bcc4b0dc8b3b0216e6249c4de6f2cbcf14006bf6 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Wed, 31 Jul 2024 00:02:13 -0400
Subject: [PATCH 02/57] [clang-doc] remove useless code

---
 clang-tools-extra/clang-doc/Representation.cpp | 2 --
 clang-tools-extra/clang-doc/Representation.h   | 2 --
 2 files changed, 4 deletions(-)

diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 028dffc21793ae..d08afbb9621890 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -266,8 +266,6 @@ void EnumInfo::merge(EnumInfo &&Other) {
     Scoped = Other.Scoped;
   if (Members.empty())
     Members = std::move(Other.Members);
-  if (Other.HasComments || HasComments)
-    HasComments = true;
   SymbolInfo::merge(std::move(Other));
 }
 
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index db3aff2d60a1b5..bd5254b0a84657 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -445,8 +445,6 @@ struct EnumInfo : public SymbolInfo {
 
   // Indicates whether this enum is scoped (e.g. enum class).
   bool Scoped = false;
-  // Indicates whether or not enum members have comments attached
-  bool HasComments = false;
 
   // Set to nonempty to the type when this is an explicitly typed enum. For
   //   enum Foo : short { ... };

>From 5fe47ca87f8dd592fee7a45401eed2620152e5c1 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Wed, 31 Jul 2024 00:33:48 -0400
Subject: [PATCH 03/57] [clang-doc] modify unittest

---
 .../unittests/clang-doc/HTMLGeneratorTest.cpp | 33 +++++++++++++++----
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
index e4a7340318b934..7ee482e275149d 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -92,7 +92,13 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) {
     </div>
     <h2 id="Enums">Enums</h2>
     <div>
-      <h3 id="0000000000000000000000000000000000000000">enum OneEnum</h3>
+      <table id="0000000000000000000000000000000000000000">
+        <thead>
+          <tr>
+            <th colspan="2">enum OneEnum</th>
+          </tr>
+        </thead>
+      </table>
     </div>
   </div>
   <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
@@ -212,7 +218,13 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
     </div>
     <h2 id="Enums">Enums</h2>
     <div>
-      <h3 id="0000000000000000000000000000000000000000">enum OneEnum</h3>
+      <table id="0000000000000000000000000000000000000000">
+        <thead>
+          <tr>
+            <th colspan="2">enum OneEnum</th>
+          </tr>
+        </thead>
+      </table>
     </div>
   </div>
   <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
@@ -346,10 +358,19 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
 <main>
   <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
   <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-    <h3 id="0000000000000000000000000000000000000000">enum class e</h3>
-    <ul>
-      <li>X</li>
-    </ul>
+    <table id="0000000000000000000000000000000000000000">
+      <thead>
+        <tr>
+          <th colspan="2">enum class e</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td>X</td>
+          <td>0</td>
+        </tr>
+      </tbody>
+    </table>
     <p>
       Defined at line 
       <a href="https://www.repository.com/test.cpp#10">10</a>

>From 28fb40f0cdbe37257d8aea9f05519519d9f2c470 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 17:12:48 -0400
Subject: [PATCH 04/57] [clang-doc] address pr comments

---
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 38 ++++++++-----------
 .../clang-doc/Representation.cpp              |  2 +-
 clang-tools-extra/clang-doc/Representation.h  |  4 +-
 clang-tools-extra/clang-doc/Serialize.cpp     |  8 ++--
 4 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index a37192d6ceb9b0..ad7e08667e5cbc 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -397,8 +397,7 @@ genEnumsBlock(const std::vector<EnumInfo> &Enums,
 }
 
 static std::unique_ptr<TagNode>
-genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members,
-                    bool HasComments) {
+genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
   if (Members.empty())
     return nullptr;
 
@@ -416,8 +415,7 @@ genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members,
       TRNode->Children.emplace_back(
           std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
     }
-
-    if (HasComments) {
+    if (M.Description.empty()) {
       auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
       TD->Children.emplace_back(genHTML(M.Description));
       TRNode->Children.emplace_back(std::move(TD));
@@ -663,7 +661,7 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
     }
     return std::move(FullComment);
   }
- 
+
   if (I.Kind == "ParagraphComment") {
     auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
     for (const auto &Child : I.Children) {
@@ -698,16 +696,12 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
   std::vector<std::unique_ptr<TagNode>> Out;
   std::string EnumType = I.Scoped ? "enum class " : "enum ";
   // Determine if enum members have comments attached
-  bool HasComments = false;
-  for (const auto &M : I.Members) {
-    if (!M.Description.empty()) {
-      HasComments = true;
-      break;
-    }
-  }
+  bool HasComments =
+      std::any_of(I.Members.begin(), I.Members.end(),
+                  [](const EnumValueInfo &M) { return M.Description.empty(); });
   std::unique_ptr<TagNode> Table =
       std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
-  std::unique_ptr<TagNode> Thead =
+  std::unique_ptr<TagNode> THead =
       std::make_unique<TagNode>(HTMLTag::TAG_THEAD);
   std::unique_ptr<TagNode> TRow = std::make_unique<TagNode>(HTMLTag::TAG_TR);
   std::unique_ptr<TagNode> TD =
@@ -717,10 +711,10 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
 
   Table->Attributes.emplace_back("id", llvm::toHex(llvm::toStringRef(I.USR)));
   TRow->Children.emplace_back(std::move(TD));
-  Thead->Children.emplace_back(std::move(TRow));
-  Table->Children.emplace_back(std::move(Thead));
+  THead->Children.emplace_back(std::move(TRow));
+  Table->Children.emplace_back(std::move(THead));
 
-  std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members, HasComments);
+  std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
 
   if (Node)
     Table->Children.emplace_back(std::move(Node));
@@ -731,8 +725,8 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(writeFileDefinition(
-          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(
+          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
@@ -780,8 +774,8 @@ genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(writeFileDefinition(
-          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(
+          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
@@ -847,8 +841,8 @@ genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(writeFileDefinition(
-          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(
+          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index d08afbb9621890..da948ee74c9d63 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -221,7 +221,7 @@ void SymbolInfo::merge(SymbolInfo &&Other) {
 }
 
 NamespaceInfo::NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)
-      : Info(InfoType::IT_namespace, USR, Name, Path) {}
+    : Info(InfoType::IT_namespace, USR, Name, Path) {}
 
 void NamespaceInfo::merge(NamespaceInfo &&Other) {
   assert(mergeable(Other));
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index bd5254b0a84657..873ac728066261 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -48,7 +48,7 @@ enum class InfoType {
 // A representation of a parsed comment.
 struct CommentInfo {
   CommentInfo() = default;
-  CommentInfo(CommentInfo &Other) = delete;
+  CommentInfo(CommentInfo &Other) = default;
   CommentInfo(CommentInfo &&Other) = default;
   CommentInfo &operator=(CommentInfo &&Other) = default;
 
@@ -432,7 +432,7 @@ struct EnumValueInfo {
   // constant. This will be empty for implicit enumeration values.
   SmallString<16> ValueExpr;
 
-  std::vector<CommentInfo> Description; // Comment description of this field.
+  std::vector<CommentInfo> Description; /// Comment description of this field.
 };
 
 // TODO: Expand to allow for documenting templating.
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 78b7041368d6df..273bc10d3b55d8 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -398,8 +398,8 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
     E->getInitVal().toString(ValueStr);
     I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
     ASTContext &Context = E->getASTContext();
-    RawComment *Comment = E->getASTContext().getRawCommentForDeclNoCache(E);
-    if (Comment) {
+    if (RawComment *Comment =
+            E->getASTContext().getRawCommentForDeclNoCache(E)) {
       CommentInfo CInfo;
       Comment->setAttached();
       if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
@@ -568,7 +568,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
 static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
   assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
 
-  ASTContext& Context = D->getASTContext();
+  ASTContext &Context = D->getASTContext();
   // TODO investigate whether we can use ASTContext::getCommentForDecl instead
   // of this logic. See also similar code in Mapper.cpp.
   RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
@@ -576,7 +576,7 @@ static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
     return;
 
   Comment->setAttached();
-  if (comments::FullComment* fc = Comment->parse(Context, nullptr, D)) {
+  if (comments::FullComment *fc = Comment->parse(Context, nullptr, D)) {
     I.Description.emplace_back();
     parseFullComment(fc, I.Description.back());
   }

>From 0d150ea08af767017e108096533f0c0d8b31668a Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 17:24:55 -0400
Subject: [PATCH 05/57] [clang-doc] revert CommentInfo change

---
 clang-tools-extra/clang-doc/Representation.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 873ac728066261..8f2bba786316fe 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -48,7 +48,7 @@ enum class InfoType {
 // A representation of a parsed comment.
 struct CommentInfo {
   CommentInfo() = default;
-  CommentInfo(CommentInfo &Other) = default;
+  CommentInfo(CommentInfo &Other) = delete;
   CommentInfo(CommentInfo &&Other) = default;
   CommentInfo &operator=(CommentInfo &&Other) = default;
 

>From e5e70b87003e4e7b8e68d23fc89f7edd6961764f Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 18:29:39 -0400
Subject: [PATCH 06/57] [clang-doc] fix test

---
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index ad7e08667e5cbc..00f94788ced44c 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -415,7 +415,7 @@ genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
       TRNode->Children.emplace_back(
           std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
     }
-    if (M.Description.empty()) {
+    if (!M.Description.empty()) {
       auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
       TD->Children.emplace_back(genHTML(M.Description));
       TRNode->Children.emplace_back(std::move(TD));

>From 1c4f631df65c1560523ea63c82229102f3d99f54 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 19:19:39 -0400
Subject: [PATCH 07/57] [clang-doc] fix unittest

---
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index 00f94788ced44c..6baed082af4a81 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -698,7 +698,7 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
   // Determine if enum members have comments attached
   bool HasComments =
       std::any_of(I.Members.begin(), I.Members.end(),
-                  [](const EnumValueInfo &M) { return M.Description.empty(); });
+                  [](const EnumValueInfo &M) { return !M.Description.empty(); });
   std::unique_ptr<TagNode> Table =
       std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
   std::unique_ptr<TagNode> THead =

>From b8f3f9c97ccd503c07387f1364cb3b357fa92821 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 19:35:15 -0400
Subject: [PATCH 08/57] [clang-doc] address pr comments

---
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 20 +++++++++----------
 clang-tools-extra/clang-doc/Serialize.cpp     |  2 +-
 clang-tools-extra/test/clang-doc/enum.cpp     |  2 +-
 3 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index 6baed082af4a81..5b023a409c364f 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -696,9 +696,9 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
   std::vector<std::unique_ptr<TagNode>> Out;
   std::string EnumType = I.Scoped ? "enum class " : "enum ";
   // Determine if enum members have comments attached
-  bool HasComments =
-      std::any_of(I.Members.begin(), I.Members.end(),
-                  [](const EnumValueInfo &M) { return !M.Description.empty(); });
+  bool HasComments = std::any_of(
+      I.Members.begin(), I.Members.end(),
+      [](const EnumValueInfo &M) { return !M.Description.empty(); });
   std::unique_ptr<TagNode> Table =
       std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
   std::unique_ptr<TagNode> THead =
@@ -713,10 +713,8 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
   TRow->Children.emplace_back(std::move(TD));
   THead->Children.emplace_back(std::move(TRow));
   Table->Children.emplace_back(std::move(THead));
-
-  std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
-
-  if (Node)
+  
+  if (std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members))
     Table->Children.emplace_back(std::move(Node));
 
   Out.emplace_back(std::move(Table));
@@ -774,8 +772,8 @@ genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(
-          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(writeFileDefinition(
+          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
@@ -841,8 +839,8 @@ genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(
-          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(writeFileDefinition(
+          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 273bc10d3b55d8..b9db78cf7d688f 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -568,7 +568,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
 static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
   assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
 
-  ASTContext &Context = D->getASTContext();
+  ASTContext& Context = D->getASTContext();
   // TODO investigate whether we can use ASTContext::getCommentForDecl instead
   // of this logic. See also similar code in Mapper.cpp.
   RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp b/clang-tools-extra/test/clang-doc/enum.cpp
index fd7bbcb53f2d2b..ef768e33b45668 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -178,4 +178,4 @@ enum ColorUserSpecified {
 // HTML-INDEX: <td>GreenUserSpecified</td>
 // HTML-INDEX: <td>2</td>
 // HTML-INDEX: <td>BlueUserSpecified</td>
-// HTML-INDEX: <td>'C'</td>
\ No newline at end of file
+// HTML-INDEX: <td>'C'</td>

>From bb98aad362353e44267f2df6ffb985005e67f147 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 19:45:02 -0400
Subject: [PATCH 09/57] [clang-doc] clang-format

---
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index 5b023a409c364f..0ced83f91724ff 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -713,7 +713,7 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
   TRow->Children.emplace_back(std::move(TD));
   THead->Children.emplace_back(std::move(TRow));
   Table->Children.emplace_back(std::move(THead));
-  
+
   if (std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members))
     Table->Children.emplace_back(std::move(Node));
 

>From c60e2b505e27cebffac27b0085fee12d68bbedf7 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 23 Aug 2024 17:39:16 -0400
Subject: [PATCH 10/57] [llvm] implement support for mustache template language

---
 llvm/include/llvm/Support/Mustache.h    | 109 ++++++++++
 llvm/lib/Support/CMakeLists.txt         |   1 +
 llvm/lib/Support/Mustache.cpp           | 276 ++++++++++++++++++++++++
 llvm/unittests/Support/CMakeLists.txt   |   1 +
 llvm/unittests/Support/MustacheTest.cpp | 135 ++++++++++++
 5 files changed, 522 insertions(+)
 create mode 100644 llvm/include/llvm/Support/Mustache.h
 create mode 100644 llvm/lib/Support/Mustache.cpp
 create mode 100644 llvm/unittests/Support/MustacheTest.cpp

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
new file mode 100644
index 00000000000000..a1ce9d945a37c5
--- /dev/null
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -0,0 +1,109 @@
+//===--- Mustache.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the Mustache templating language supports version 1.4.2
+// (https://mustache.github.io/mustache.5.html).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MUSTACHE
+#define LLVM_SUPPORT_MUSTACHE
+
+#include "Error.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/JSON.h"
+#include <string>
+#include <variant>
+#include <vector>
+
+namespace llvm {
+namespace mustache {
+
+using Accessor = std::vector<std::string>;
+
+class Token {
+public:
+  enum class Type {
+    Text,
+    Variable,
+    Partial,
+    SectionOpen,
+    SectionClose,
+    InvertSectionOpen,
+    UnescapeVariable,
+    Comment,
+  };
+
+  Token(std::string Str);
+
+  Token(std::string Str, char Identifier);
+
+  std::string getTokenBody() const { return TokenBody; };
+
+  Accessor getAccessor() const { return Accessor; };
+
+  Type getType() const { return TokenType; };
+
+private:
+  Type TokenType;
+  Accessor Accessor;
+  std::string TokenBody;
+};
+
+class ASTNode {
+public:
+  enum Type {
+    Root,
+    Text,
+    Partial,
+    Variable,
+    UnescapeVariable,
+    Section,
+    InvertSection,
+  };
+
+  ASTNode() : T(Type::Root), LocalContext(nullptr){};
+
+  ASTNode(std::string Body, std::shared_ptr<ASTNode> Parent)
+      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr){};
+
+  // Constructor for Section/InvertSection/Variable/UnescapeVariable
+  ASTNode(Type T, Accessor Accessor, std::shared_ptr<ASTNode> Parent)
+      : T(T), Accessor(Accessor), Parent(Parent), LocalContext(nullptr),
+        Children({}){};
+
+  void addChild(std::shared_ptr<ASTNode> Child) {
+    Children.emplace_back(Child);
+  };
+
+  std::string render(llvm::json::Value Data);
+
+  llvm::json::Value findContext();
+
+  Type T;
+  std::string Body;
+  std::weak_ptr<ASTNode> Parent;
+  std::vector<std::shared_ptr<ASTNode>> Children;
+  Accessor Accessor;
+  llvm::json::Value LocalContext;
+};
+
+class Template {
+public:
+  static Expected<Template> createTemplate(std::string TemplateStr);
+
+  std::string render(llvm::json::Value Data);
+
+private:
+  Template(std::shared_ptr<ASTNode> Tree) : Tree(Tree){};
+  std::shared_ptr<ASTNode> Tree;
+};
+
+} // namespace mustache
+} // end namespace llvm
+#endif // LLVM_SUPPORT_MUSTACHE
\ No newline at end of file
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index f653379e303349..91c8c3fd7de0e6 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -207,6 +207,7 @@ add_llvm_component_library(LLVMSupport
   MD5.cpp
   MSP430Attributes.cpp
   MSP430AttributeParser.cpp
+  Mustache.cpp      
   NativeFormatting.cpp
   OptimizedStructLayout.cpp
   Optional.cpp
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
new file mode 100644
index 00000000000000..19a0ccffe87acc
--- /dev/null
+++ b/llvm/lib/Support/Mustache.cpp
@@ -0,0 +1,276 @@
+//===-- Mustache.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "llvm/Support/Error.h"
+#include <iostream>
+#include <regex>
+#include <sstream>
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+std::string escapeHtml(const std::string &Input) {
+  DenseMap<char, std::string> HtmlEntities = {{'&', "&"},
+                                              {'<', "<"},
+                                              {'>', ">"},
+                                              {'"', """},
+                                              {'"', "'"}};
+  std::string EscapedString;
+  EscapedString.reserve(Input.size());
+
+  for (char C : Input) {
+    if (HtmlEntities.find(C) != HtmlEntities.end()) {
+      EscapedString += HtmlEntities[C];
+    } else {
+      EscapedString += C;
+    }
+  }
+
+  return EscapedString;
+}
+
+std::vector<std::string> split(const std::string &Str, char Delimiter) {
+  std::vector<std::string> Tokens;
+  std::string Token;
+  std::stringstream SS(Str);
+  if (Str == ".") {
+    Tokens.push_back(Str);
+    return Tokens;
+  }
+  while (std::getline(SS, Token, Delimiter)) {
+    Tokens.push_back(Token);
+  }
+  return Tokens;
+}
+
+Token::Token(std::string Str, char Identifier) {
+  switch (Identifier) {
+  case '#':
+    TokenType = Type::SectionOpen;
+    break;
+  case '/':
+    TokenType = Type::SectionClose;
+    break;
+  case '^':
+    TokenType = Type::InvertSectionOpen;
+    break;
+  case '!':
+    TokenType = Type::Comment;
+    break;
+  case '>':
+    TokenType = Type::Partial;
+    break;
+  case '&':
+    TokenType = Type::UnescapeVariable;
+    break;
+  default:
+    TokenType = Type::Variable;
+  }
+  if (TokenType == Type::Comment)
+    return;
+
+  TokenBody = Str;
+  std::string AccessorStr = Str;
+  if (TokenType != Type::Variable) {
+    AccessorStr = Str.substr(1);
+  }
+  Accessor = split(StringRef(AccessorStr).trim().str(), '.');
+}
+
+Token::Token(std::string Str)
+    : TokenType(Type::Text), TokenBody(Str), Accessor({}) {}
+
+std::vector<Token> tokenize(std::string Template) {
+  std::vector<Token> Tokens;
+  std::regex Re(R"(\{\{(.*?)\}\})");
+  std::sregex_token_iterator Iter(Template.begin(), Template.end(), Re,
+                                  {-1, 0});
+  std::sregex_token_iterator End;
+
+  for (; Iter != End; ++Iter) {
+    if (!Iter->str().empty()) {
+      std::string Token = *Iter;
+      std::smatch Match;
+      if (std::regex_match(Token, Match, Re)) {
+        std::string Group = Match[1];
+        Tokens.emplace_back(Group, Group[0]);
+      } else {
+        Tokens.emplace_back(Token);
+      }
+    }
+  }
+
+  return Tokens;
+}
+
+class Parser {
+public:
+  Parser(std::string TemplateStr) : TemplateStr(TemplateStr) {}
+
+  std::shared_ptr<ASTNode> parse();
+
+private:
+  void parseMustache(std::shared_ptr<ASTNode> Parent);
+
+  std::vector<Token> Tokens;
+  std::size_t CurrentPtr;
+  std::string TemplateStr;
+};
+
+std::shared_ptr<ASTNode> Parser::parse() {
+  Tokens = tokenize(TemplateStr);
+  CurrentPtr = 0;
+  std::shared_ptr<ASTNode> Root = std::make_shared<ASTNode>();
+  parseMustache(Root);
+  return Root;
+}
+
+void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
+
+  while (CurrentPtr < Tokens.size()) {
+    Token CurrentToken = Tokens[CurrentPtr];
+    CurrentPtr++;
+    Accessor A = CurrentToken.getAccessor();
+    std::shared_ptr<ASTNode> CurrentNode;
+
+    switch (CurrentToken.getType()) {
+    case Token::Type::Text: {
+      CurrentNode =
+          std::make_shared<ASTNode>(CurrentToken.getTokenBody(), Parent);
+      Parent->addChild(CurrentNode);
+      break;
+    }
+    case Token::Type::Variable: {
+      CurrentNode = std::make_shared<ASTNode>(ASTNode::Variable, A, Parent);
+      Parent->addChild(CurrentNode);
+      break;
+    }
+    case Token::Type::UnescapeVariable: {
+      CurrentNode =
+          std::make_shared<ASTNode>(ASTNode::UnescapeVariable, A, Parent);
+      Parent->addChild(CurrentNode);
+      break;
+    }
+    case Token::Type::Partial: {
+      CurrentNode = std::make_shared<ASTNode>(ASTNode::Partial, A, Parent);
+      Parent->addChild(CurrentNode);
+      break;
+    }
+    case Token::Type::SectionOpen: {
+      CurrentNode = std::make_shared<ASTNode>(ASTNode::Section, A, Parent);
+      parseMustache(CurrentNode);
+      Parent->addChild(CurrentNode);
+      break;
+    }
+    case Token::Type::InvertSectionOpen: {
+      CurrentNode =
+          std::make_shared<ASTNode>(ASTNode::InvertSection, A, Parent);
+      parseMustache(CurrentNode);
+      Parent->addChild(CurrentNode);
+      break;
+    }
+    case Token::Type::SectionClose: {
+      return;
+    }
+    default:
+      break;
+    }
+  }
+}
+
+Expected<Template> Template::createTemplate(std::string TemplateStr) {
+  Parser P = Parser(TemplateStr);
+  Expected<std::shared_ptr<ASTNode>> MustacheTree = P.parse();
+  if (!MustacheTree)
+    return MustacheTree.takeError();
+  return Template(MustacheTree.get());
+}
+std::string Template::render(Value Data) { return Tree->render(Data); }
+
+std::string printJson(Value &Data) {
+  if (Data.getAsNull().has_value()) {
+    return "";
+  }
+  if (auto *Arr = Data.getAsArray()) {
+    if (Arr->empty()) {
+      return "";
+    }
+  }
+  if (Data.getAsString().has_value()) {
+    return Data.getAsString()->str();
+  }
+  return llvm::formatv("{0:2}", Data);
+}
+
+std::string ASTNode::render(Value Data) {
+  LocalContext = Data;
+  Value Context = T == Root ? Data : findContext();
+  switch (T) {
+  case Root: {
+    std::string Result = "";
+    for (std::shared_ptr<ASTNode> Child : Children) {
+      Result += Child->render(Context);
+    }
+    return Result;
+  }
+  case Text:
+    return escapeHtml(Body);
+  case Partial:
+    break;
+  case Variable:
+    return escapeHtml(printJson(Context));
+  case UnescapeVariable:
+    return printJson(Context);
+  case Section:
+    break;
+  case InvertSection:
+    break;
+  }
+
+  return std::string();
+}
+
+Value ASTNode::findContext() {
+  if (Accessor.empty()) {
+    return nullptr;
+  }
+  if (Accessor[0] == ".") {
+    return LocalContext;
+  }
+  json::Object *CurrentContext = LocalContext.getAsObject();
+  std::string &CurrentAccessor = Accessor[0];
+  std::weak_ptr<ASTNode> CurrentParent = Parent;
+
+  while (!CurrentContext || !CurrentContext->get(CurrentAccessor)) {
+    if (auto Ptr = CurrentParent.lock()) {
+      CurrentContext = Ptr->LocalContext.getAsObject();
+      CurrentParent = Ptr->Parent;
+      continue;
+    }
+    return nullptr;
+  }
+  Value Context = nullptr;
+  for (std::size_t i = 0; i < Accessor.size(); i++) {
+    CurrentAccessor = Accessor[i];
+    Value *CurrentValue = CurrentContext->get(CurrentAccessor);
+    if (!CurrentValue) {
+      return nullptr;
+    }
+    if (i < Accessor.size() - 1) {
+      CurrentContext = CurrentValue->getAsObject();
+      if (!CurrentContext) {
+        return nullptr;
+      }
+    } else {
+      Context = *CurrentValue;
+    }
+  }
+  return Context;
+}
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 631f2e6bf00df0..63a6a13019bdcf 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -60,6 +60,7 @@ add_llvm_unittest(SupportTests
   MemoryBufferRefTest.cpp
   MemoryBufferTest.cpp
   MemoryTest.cpp
+  MustacheTest.cpp      
   NativeFormatTests.cpp
   OptimizedStructLayoutTest.cpp
   ParallelTest.cpp
diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp
new file mode 100644
index 00000000000000..7479e29816e944
--- /dev/null
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -0,0 +1,135 @@
+//===- llvm/unittest/Support/MustacheTest.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Test conforming to Mustache 1.4.2 spec found here:
+// https://github.com/mustache/spec
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::mustache;
+using namespace llvm::json;
+
+TEST(MustacheInterpolation, NoInterpolation) {
+  // Mustache-free templates should render as-is.
+  Value D = {};
+  auto T = Template::createTemplate("Hello from {Mustache}!\n");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("Hello from {Mustache}!\n", Out);
+}
+
+TEST(MustacheInterpolation, BasicInterpolation) {
+  // Unadorned tags should interpolate content into the template.
+  Value D = Object{{"subject", "World"}};
+  auto T = Template::createTemplate("Hello, {{subject}}!");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("Hello, World!", Out);
+}
+
+TEST(MustacheInterpolation, NoReinterpolation) {
+  // Interpolated tag output should not be re-interpolated.
+  Value D = Object{{"template", "{{planet}}"}, {"planet", "Earth"}};
+  auto T = Template::createTemplate("{{template}}: {{planet}}");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("{{planet}}: Earth", Out);
+}
+
+TEST(MustacheInterpolation, HTMLEscaping) {
+  // Interpolated tag output should not be re-interpolated.
+  Value D = Object{
+      {"forbidden", "& \" < >"},
+  };
+  auto T = Template::createTemplate(
+      "These characters should be HTML escaped: {{forbidden}}\n");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("These characters should be HTML escaped: & " < >\n",
+            Out);
+}
+
+TEST(MustacheInterpolation, Ampersand) {
+  // Interpolated tag output should not be re-interpolated.
+  Value D = Object{
+      {"forbidden", "& \" < >"},
+  };
+  auto T = Template::createTemplate(
+      "These characters should not be HTML escaped: {{&forbidden}}\n");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("These characters should not be HTML escaped: & \" < >\n", Out);
+}
+
+TEST(MustacheInterpolation, BasicIntegerInterpolation) {
+  Value D = Object{{"mph", 85}};
+  auto T = Template::createTemplate("{{mph}} miles an hour!");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("85 miles an hour!", Out);
+}
+
+TEST(MustacheInterpolation, BasicDecimalInterpolation) {
+  Value D = Object{{"power", 1.21}};
+  auto T = Template::createTemplate("{{power}} jiggawatts!");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("1.21 jiggawatts!", Out);
+}
+
+TEST(MustacheInterpolation, BasicNullInterpolation) {
+  Value D = Object{{"cannot", nullptr}};
+  auto T = Template::createTemplate("I ({{cannot}}) be seen!");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("I () be seen!", Out);
+}
+
+TEST(MustacheInterpolation, BasicContextMissInterpolation) {
+  Value D = Object{};
+  auto T = Template::createTemplate("I ({{cannot}}) be seen!");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("I () be seen!", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesBasicInterpolation) {
+  Value D = Object{{"person", Object{{"name", "Joe"}}}};
+  auto T = Template::createTemplate(
+      "{{person.name}} == {{#person}}{{name}}{{/person}}");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("Joe == Joe", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesArbitraryDepth) {
+  Value D = Object{
+      {"a",
+       Object{{"b",
+               Object{{"c",
+                       Object{{"d",
+                               Object{{"e", Object{{"name", "Phil"}}}}}}}}}}}};
+  auto T = Template::createTemplate("{{a.b.c.d.e.name}} == Phil");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("Phil == Phil", Out);
+}
+
+TEST(MustacheInterpolation, ImplicitIteratorsBasicInterpolation) {
+  Value D = "world";
+  auto T = Template::createTemplate("Hello, {{.}}!\n");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("Hello, world!\n", Out);
+}
+
+TEST(MustacheInterpolation, InterpolationSurroundingWhitespace) {
+  Value D = Object{{"string", "---"}};
+  auto T = Template::createTemplate("| {{string}} |");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("| --- |", Out);
+}
+
+TEST(MustacheInterpolation, InterpolationWithPadding) {
+  Value D = Object{{"string", "---"}};
+  auto T = Template::createTemplate("|{{ string }}|");
+  auto Out = T.get().render(D);
+  EXPECT_EQ("|---|", Out);
+}

>From 8290c381a099864db4c827e6102c015f09cfed5c Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 02:35:33 -0400
Subject: [PATCH 11/57] [llvm][Support] Finish implementation of Mustache

---
 llvm/include/llvm/Support/Mustache.h    |  63 +-
 llvm/lib/Support/Mustache.cpp           | 383 ++++++++---
 llvm/unittests/Support/MustacheTest.cpp | 877 +++++++++++++++++++++++-
 3 files changed, 1204 insertions(+), 119 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index a1ce9d945a37c5..cb7d80e47809e8 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -24,7 +24,9 @@
 namespace llvm {
 namespace mustache {
 
-using Accessor = std::vector<std::string>;
+using Accessor = std::vector<SmallString<128>>;
+using Lambda = std::function<llvm::json::Value()>;
+using SectionLambda = std::function<llvm::json::Value(StringRef)>;
 
 class Token {
 public:
@@ -39,20 +41,27 @@ class Token {
     Comment,
   };
 
-  Token(std::string Str);
+  Token(StringRef Str);
 
-  Token(std::string Str, char Identifier);
+  Token(StringRef RawBody, StringRef Str, char Identifier);
 
-  std::string getTokenBody() const { return TokenBody; };
+  StringRef getTokenBody() const { return TokenBody; };
+
+  StringRef getRawBody() const { return RawBody; };
+
+  void setTokenBody(SmallString<128> NewBody) { TokenBody = NewBody; };
 
   Accessor getAccessor() const { return Accessor; };
 
   Type getType() const { return TokenType; };
 
+  static Type getTokenType(char Identifier);
+
 private:
   Type TokenType;
+  SmallString<128> RawBody;
   Accessor Accessor;
-  std::string TokenBody;
+  SmallString<128> TokenBody;
 };
 
 class ASTNode {
@@ -69,7 +78,7 @@ class ASTNode {
 
   ASTNode() : T(Type::Root), LocalContext(nullptr){};
 
-  ASTNode(std::string Body, std::shared_ptr<ASTNode> Parent)
+  ASTNode(StringRef Body, std::shared_ptr<ASTNode> Parent)
       : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr){};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
@@ -81,26 +90,56 @@ class ASTNode {
     Children.emplace_back(Child);
   };
 
-  std::string render(llvm::json::Value Data);
+  SmallString<128> getBody() const { return Body; };
 
-  llvm::json::Value findContext();
+  void setBody(StringRef NewBody) { Body = NewBody; };
+
+  void setRawBody(StringRef NewBody) { RawBody = NewBody; };
+
+  SmallString<128> getRawBody() const { return RawBody; };
+
+  std::shared_ptr<ASTNode> getLastChild() const {
+    return Children.empty() ? nullptr : Children.back();
+  };
 
+  SmallString<128>
+  render(llvm::json::Value Data,
+         DenseMap<StringRef, std::shared_ptr<ASTNode>> &Partials,
+         DenseMap<StringRef, Lambda> &Lambdas,
+         DenseMap<StringRef, SectionLambda> &SectionLambdas,
+         DenseMap<char, StringRef> &Escapes);
+
+private:
+  llvm::json::Value findContext();
   Type T;
-  std::string Body;
+  SmallString<128> RawBody;
+  SmallString<128> Body;
   std::weak_ptr<ASTNode> Parent;
   std::vector<std::shared_ptr<ASTNode>> Children;
-  Accessor Accessor;
+  const Accessor Accessor;
   llvm::json::Value LocalContext;
 };
 
 class Template {
 public:
-  static Expected<Template> createTemplate(std::string TemplateStr);
+  static Template createTemplate(StringRef TemplateStr);
+
+  SmallString<128> render(llvm::json::Value Data);
+
+  void registerPartial(StringRef Name, StringRef Partial);
+
+  void registerLambda(StringRef Name, Lambda Lambda);
+
+  void registerLambda(StringRef Name, SectionLambda Lambda);
 
-  std::string render(llvm::json::Value Data);
+  void registerEscape(DenseMap<char, StringRef> Escapes);
 
 private:
   Template(std::shared_ptr<ASTNode> Tree) : Tree(Tree){};
+  DenseMap<StringRef, std::shared_ptr<ASTNode>> Partials;
+  DenseMap<StringRef, Lambda> Lambdas;
+  DenseMap<StringRef, SectionLambda> SectionLambdas;
+  DenseMap<char, StringRef> Escapes;
   std::shared_ptr<ASTNode> Tree;
 };
 
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 19a0ccffe87acc..80b3d8bc53651b 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -16,103 +16,172 @@ using namespace llvm;
 using namespace llvm::json;
 using namespace llvm::mustache;
 
-std::string escapeHtml(const std::string &Input) {
-  DenseMap<char, std::string> HtmlEntities = {{'&', "&"},
-                                              {'<', "<"},
-                                              {'>', ">"},
-                                              {'"', """},
-                                              {'"', "'"}};
-  std::string EscapedString;
-  EscapedString.reserve(Input.size());
-
+SmallString<128> escapeString(StringRef Input,
+                              DenseMap<char, StringRef> &Escape) {
+  SmallString<128> EscapedString("");
   for (char C : Input) {
-    if (HtmlEntities.find(C) != HtmlEntities.end()) {
-      EscapedString += HtmlEntities[C];
+    if (Escape.find(C) != Escape.end()) {
+      EscapedString += Escape[C];
     } else {
       EscapedString += C;
     }
   }
-
   return EscapedString;
 }
 
-std::vector<std::string> split(const std::string &Str, char Delimiter) {
-  std::vector<std::string> Tokens;
-  std::string Token;
-  std::stringstream SS(Str);
+std::vector<SmallString<128>> split(StringRef Str, char Delimiter) {
+  std::vector<SmallString<128>> Tokens;
   if (Str == ".") {
     Tokens.push_back(Str);
     return Tokens;
   }
-  while (std::getline(SS, Token, Delimiter)) {
-    Tokens.push_back(Token);
+  StringRef Ref(Str);
+  while (!Ref.empty()) {
+    llvm::StringRef Part;
+    std::tie(Part, Ref) = Ref.split(Delimiter);
+    Tokens.push_back(Part.trim());
   }
   return Tokens;
 }
 
-Token::Token(std::string Str, char Identifier) {
+Token::Token(StringRef RawBody, StringRef InnerBody, char Identifier)
+    : RawBody(RawBody), TokenBody(InnerBody) {
+
+  TokenType = getTokenType(Identifier);
+  if (TokenType == Type::Comment)
+    return;
+
+  StringRef AccessorStr = InnerBody;
+  if (TokenType != Type::Variable) {
+    AccessorStr = InnerBody.substr(1);
+  }
+  Accessor = split(AccessorStr.trim(), '.');
+}
+
+Token::Token(StringRef Str)
+    : RawBody(Str), TokenType(Type::Text), TokenBody(Str), Accessor({}) {}
+
+Token::Type Token::getTokenType(char Identifier) {
   switch (Identifier) {
   case '#':
-    TokenType = Type::SectionOpen;
-    break;
+    return Type::SectionOpen;
   case '/':
-    TokenType = Type::SectionClose;
-    break;
+    return Type::SectionClose;
   case '^':
-    TokenType = Type::InvertSectionOpen;
-    break;
+    return Type::InvertSectionOpen;
   case '!':
-    TokenType = Type::Comment;
-    break;
+    return Type::Comment;
   case '>':
-    TokenType = Type::Partial;
-    break;
+    return Type::Partial;
   case '&':
-    TokenType = Type::UnescapeVariable;
-    break;
+    return Type::UnescapeVariable;
   default:
-    TokenType = Type::Variable;
+    return Type::Variable;
   }
-  if (TokenType == Type::Comment)
-    return;
+}
 
-  TokenBody = Str;
-  std::string AccessorStr = Str;
-  if (TokenType != Type::Variable) {
-    AccessorStr = Str.substr(1);
+std::vector<Token> tokenize(StringRef Template) {
+  // Simple tokenizer that splits the template into tokens
+  // the mustache spec allows {{{ }}} to unescape variables
+  // but we don't support that here unescape variable
+  // is represented only by {{& variable}}
+  std::vector<Token> Tokens;
+  SmallString<128> Open("{{");
+  SmallString<128> Close("}}");
+  std::size_t Start = 0;
+  std::size_t DelimiterStart = Template.find(Open);
+  if (DelimiterStart == StringRef::npos) {
+    Tokens.push_back(Token(Template));
+    return Tokens;
   }
-  Accessor = split(StringRef(AccessorStr).trim().str(), '.');
-}
+  while (DelimiterStart != StringRef::npos) {
+    if (DelimiterStart != Start) {
+      Token TextToken = Token(Template.substr(Start, DelimiterStart - Start));
+      Tokens.push_back(TextToken);
+    }
+
+    std::size_t DelimiterEnd = Template.find(Close, DelimiterStart);
+    if (DelimiterEnd == StringRef::npos) {
+      break;
+    }
 
-Token::Token(std::string Str)
-    : TokenType(Type::Text), TokenBody(Str), Accessor({}) {}
+    SmallString<128> Interpolated =
+        Template.substr(DelimiterStart + Open.size(),
+                        DelimiterEnd - DelimiterStart - Close.size());
+    SmallString<128> RawBody;
+    RawBody += Open;
+    RawBody += Interpolated;
+    RawBody += Close;
 
-std::vector<Token> tokenize(std::string Template) {
-  std::vector<Token> Tokens;
-  std::regex Re(R"(\{\{(.*?)\}\})");
-  std::sregex_token_iterator Iter(Template.begin(), Template.end(), Re,
-                                  {-1, 0});
-  std::sregex_token_iterator End;
-
-  for (; Iter != End; ++Iter) {
-    if (!Iter->str().empty()) {
-      std::string Token = *Iter;
-      std::smatch Match;
-      if (std::regex_match(Token, Match, Re)) {
-        std::string Group = Match[1];
-        Tokens.emplace_back(Group, Group[0]);
-      } else {
-        Tokens.emplace_back(Token);
+    Tokens.push_back(Token(RawBody, Interpolated, Interpolated[0]));
+    Start = DelimiterEnd + Close.size();
+    DelimiterStart = Template.find(Open, Start);
+  }
+
+  if (Start < Template.size()) {
+    Tokens.push_back(Token(Template.substr(Start)));
+  }
+
+  // fix up white spaces for
+  // open sections/inverted sections/close section/comment
+  for (std::size_t I = 0; I < Tokens.size(); I++) {
+    Token::Type CurrentType = Tokens[I].getType();
+    bool RequiresCleanUp = CurrentType == Token::Type::SectionOpen ||
+                           CurrentType == Token::Type::InvertSectionOpen ||
+                           CurrentType == Token::Type::SectionClose ||
+                           CurrentType == Token::Type::Comment ||
+                           CurrentType == Token::Type::Partial;
+
+    bool NoTextBehind = false;
+    bool NoTextAhead = false;
+    if (I > 0 && Tokens[I - 1].getType() == Token::Type::Text &&
+        RequiresCleanUp) {
+      Token &PrevToken = Tokens[I - 1];
+      StringRef TokenBody = PrevToken.getTokenBody().rtrim(" \t\v\t");
+      if (TokenBody.ends_with("\n") || TokenBody.ends_with("\r\n") ||
+          TokenBody.empty()) {
+        NoTextBehind = true;
+      }
+    }
+    if (I < Tokens.size() - 1 && Tokens[I + 1].getType() == Token::Type::Text &&
+        RequiresCleanUp) {
+      Token &NextToken = Tokens[I + 1];
+      StringRef TokenBody = NextToken.getTokenBody().ltrim(" ");
+      if (TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n")) {
+        NoTextAhead = true;
       }
     }
-  }
 
+    if (NoTextBehind && NoTextAhead) {
+      Token &PrevToken = Tokens[I - 1];
+      Token &NextToken = Tokens[I + 1];
+      StringRef NextTokenBody = NextToken.getTokenBody();
+      PrevToken.setTokenBody(PrevToken.getTokenBody().rtrim(" \t\v\t"));
+      if (NextTokenBody.starts_with("\r\n")) {
+        NextToken.setTokenBody(NextTokenBody.substr(2));
+      } else if (NextToken.getTokenBody().starts_with("\n")) {
+        NextToken.setTokenBody(NextTokenBody.substr(1));
+      }
+    } else if (NoTextAhead && I == 0) {
+      Token &NextToken = Tokens[I + 1];
+      StringRef NextTokenBody = NextToken.getTokenBody();
+      if (NextTokenBody.starts_with("\r\n")) {
+        NextToken.setTokenBody(NextTokenBody.substr(2));
+      } else if (NextToken.getTokenBody().starts_with("\n")) {
+        NextToken.setTokenBody(NextTokenBody.substr(1));
+      }
+    } else if (NoTextBehind && I == Tokens.size() - 1) {
+      Token &PrevToken = Tokens[I - 1];
+      StringRef PrevTokenBody = PrevToken.getTokenBody();
+      PrevToken.setTokenBody(PrevTokenBody.rtrim(" \t\v\t"));
+    }
+  }
   return Tokens;
 }
 
 class Parser {
 public:
-  Parser(std::string TemplateStr) : TemplateStr(TemplateStr) {}
+  Parser(StringRef TemplateStr) : TemplateStr(TemplateStr) {}
 
   std::shared_ptr<ASTNode> parse();
 
@@ -121,7 +190,7 @@ class Parser {
 
   std::vector<Token> Tokens;
   std::size_t CurrentPtr;
-  std::string TemplateStr;
+  StringRef TemplateStr;
 };
 
 std::shared_ptr<ASTNode> Parser::parse() {
@@ -165,14 +234,34 @@ void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
     }
     case Token::Type::SectionOpen: {
       CurrentNode = std::make_shared<ASTNode>(ASTNode::Section, A, Parent);
+      std::size_t Start = CurrentPtr;
       parseMustache(CurrentNode);
+      std::size_t End = CurrentPtr;
+      SmallString<128> RawBody;
+      if (Start + 1 < End - 1)
+        for (std::size_t I = Start + 1; I < End - 1; I++) {
+          RawBody += Tokens[I].getRawBody();
+        }
+      else if (Start + 1 == End - 1)
+        RawBody = Tokens[Start].getRawBody();
+      CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
       break;
     }
     case Token::Type::InvertSectionOpen: {
       CurrentNode =
           std::make_shared<ASTNode>(ASTNode::InvertSection, A, Parent);
+      std::size_t Start = CurrentPtr;
       parseMustache(CurrentNode);
+      std::size_t End = CurrentPtr;
+      SmallString<128> RawBody;
+      if (Start + 1 < End - 1)
+        for (std::size_t I = Start + 1; I < End - 1; I++) {
+          RawBody += Tokens[I].getRawBody();
+        }
+      else if (Start + 1 == End - 1)
+        RawBody = Tokens[Start].getRawBody();
+      CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
       break;
     }
@@ -185,59 +274,167 @@ void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
   }
 }
 
-Expected<Template> Template::createTemplate(std::string TemplateStr) {
+Template Template::createTemplate(StringRef TemplateStr) {
   Parser P = Parser(TemplateStr);
-  Expected<std::shared_ptr<ASTNode>> MustacheTree = P.parse();
-  if (!MustacheTree)
-    return MustacheTree.takeError();
-  return Template(MustacheTree.get());
+  std::shared_ptr<ASTNode> MustacheTree = P.parse();
+  Template T = Template(MustacheTree);
+  // the default behaviour is to escape html entities
+  DenseMap<char, StringRef> HtmlEntities = {{'&', "&"},
+                                            {'<', "<"},
+                                            {'>', ">"},
+                                            {'"', """},
+                                            {'\'', "'"}};
+  T.registerEscape(HtmlEntities);
+  return T;
+}
+
+SmallString<128> Template::render(Value Data) {
+  return Tree->render(Data, Partials, Lambdas, SectionLambdas, Escapes);
+}
+
+void Template::registerPartial(StringRef Name, StringRef Partial) {
+  Parser P = Parser(Partial);
+  std::shared_ptr<ASTNode> PartialTree = P.parse();
+  Partials[Name] = PartialTree;
+}
+
+void Template::registerLambda(StringRef Name, Lambda L) { Lambdas[Name] = L; }
+
+void Template::registerLambda(StringRef Name, SectionLambda L) {
+  SectionLambdas[Name] = L;
 }
-std::string Template::render(Value Data) { return Tree->render(Data); }
 
-std::string printJson(Value &Data) {
-  if (Data.getAsNull().has_value()) {
-    return "";
+void Template::registerEscape(DenseMap<char, StringRef> E) { Escapes = E; }
+
+SmallString<128> printJson(Value &Data) {
+
+  SmallString<128> Result;
+  if (Data.getAsNull()) {
+    return Result;
   }
   if (auto *Arr = Data.getAsArray()) {
     if (Arr->empty()) {
-      return "";
+      return Result;
     }
   }
-  if (Data.getAsString().has_value()) {
-    return Data.getAsString()->str();
+  if (Data.getAsString()) {
+    Result += Data.getAsString()->str();
+    return Result;
   }
   return llvm::formatv("{0:2}", Data);
 }
 
-std::string ASTNode::render(Value Data) {
+bool isFalsey(Value &V) {
+  return V.getAsNull() || (V.getAsBoolean() && !V.getAsBoolean().value()) ||
+         (V.getAsArray() && V.getAsArray()->empty()) ||
+         (V.getAsObject() && V.getAsObject()->empty());
+}
+
+SmallString<128>
+ASTNode::render(Value Data,
+                DenseMap<StringRef, std::shared_ptr<ASTNode>> &Partials,
+                DenseMap<StringRef, Lambda> &Lambdas,
+                DenseMap<StringRef, SectionLambda> &SectionLambdas,
+                DenseMap<char, StringRef> &Escapes) {
   LocalContext = Data;
   Value Context = T == Root ? Data : findContext();
+  SmallString<128> Result;
   switch (T) {
   case Root: {
-    std::string Result = "";
-    for (std::shared_ptr<ASTNode> Child : Children) {
-      Result += Child->render(Context);
-    }
+    for (std::shared_ptr<ASTNode> Child : Children)
+      Result +=
+          Child->render(Context, Partials, Lambdas, SectionLambdas, Escapes);
     return Result;
   }
   case Text:
-    return escapeHtml(Body);
-  case Partial:
-    break;
-  case Variable:
-    return escapeHtml(printJson(Context));
-  case UnescapeVariable:
+    return Body;
+  case Partial: {
+    if (Partials.find(Accessor[0]) != Partials.end()) {
+      std::shared_ptr<ASTNode> Partial = Partials[Accessor[0]];
+      Result +=
+          Partial->render(Data, Partials, Lambdas, SectionLambdas, Escapes);
+      return Result;
+    }
+  }
+  case Variable: {
+    if (Lambdas.find(Accessor[0]) != Lambdas.end()) {
+      Lambda &L = Lambdas[Accessor[0]];
+      Value LambdaResult = L();
+      StringRef LambdaStr = printJson(LambdaResult);
+      Parser P = Parser(LambdaStr);
+      std::shared_ptr<ASTNode> LambdaNode = P.parse();
+      return LambdaNode->render(Data, Partials, Lambdas, SectionLambdas,
+                                Escapes);
+    }
+    return escapeString(printJson(Context), Escapes);
+  }
+  case UnescapeVariable: {
+    if (Lambdas.find(Accessor[0]) != Lambdas.end()) {
+      Lambda &L = Lambdas[Accessor[0]];
+      Value LambdaResult = L();
+      StringRef LambdaStr = printJson(LambdaResult);
+      Parser P = Parser(LambdaStr);
+      std::shared_ptr<ASTNode> LambdaNode = P.parse();
+      DenseMap<char, StringRef> EmptyEscapes;
+      return LambdaNode->render(Data, Partials, Lambdas, SectionLambdas,
+                                EmptyEscapes);
+    }
     return printJson(Context);
-  case Section:
-    break;
-  case InvertSection:
-    break;
   }
+  case Section: {
+    // Sections are not rendered if the context is falsey
+    bool IsLambda = SectionLambdas.find(Accessor[0]) != SectionLambdas.end();
+
+    if (isFalsey(Context) && !IsLambda)
+      return Result;
+
+    if (IsLambda) {
+      SectionLambda &Lambda = SectionLambdas[Accessor[0]];
+      Value Return = Lambda(RawBody);
+      if (isFalsey(Return))
+        return Result;
+      StringRef LambdaStr = printJson(Return);
+      Parser P = Parser(LambdaStr);
+      std::shared_ptr<ASTNode> LambdaNode = P.parse();
+      return LambdaNode->render(Data, Partials, Lambdas, SectionLambdas,
+                                Escapes);
+    }
+
+    if (Context.getAsArray()) {
+      json::Array *Arr = Context.getAsArray();
+      for (Value &V : *Arr) {
+        for (std::shared_ptr<ASTNode> Child : Children)
+          Result +=
+              Child->render(V, Partials, Lambdas, SectionLambdas, Escapes);
+      }
+      return Result;
+    }
 
-  return std::string();
+    for (std::shared_ptr<ASTNode> Child : Children)
+      Result +=
+          Child->render(Context, Partials, Lambdas, SectionLambdas, Escapes);
+
+    return Result;
+  }
+  case InvertSection: {
+    bool IsLambda = SectionLambdas.find(Accessor[0]) != SectionLambdas.end();
+    if (!isFalsey(Context) || IsLambda)
+      return Result;
+    for (std::shared_ptr<ASTNode> Child : Children)
+      Result +=
+          Child->render(Context, Partials, Lambdas, SectionLambdas, Escapes);
+    return Result;
+  }
+  }
+  llvm_unreachable("Invalid ASTNode type");
 }
 
 Value ASTNode::findContext() {
+  // The mustache spec allows for dot notation to access nested values
+  // a single dot refers to the current context
+  // We attempt to find the JSON context in the current node if it is not found
+  // we traverse the parent nodes to find the context until we reach the root
+  // node or the context is found
   if (Accessor.empty()) {
     return nullptr;
   }
@@ -245,7 +442,7 @@ Value ASTNode::findContext() {
     return LocalContext;
   }
   json::Object *CurrentContext = LocalContext.getAsObject();
-  std::string &CurrentAccessor = Accessor[0];
+  SmallString<128> CurrentAccessor = Accessor[0];
   std::weak_ptr<ASTNode> CurrentParent = Parent;
 
   while (!CurrentContext || !CurrentContext->get(CurrentAccessor)) {
@@ -257,13 +454,13 @@ Value ASTNode::findContext() {
     return nullptr;
   }
   Value Context = nullptr;
-  for (std::size_t i = 0; i < Accessor.size(); i++) {
-    CurrentAccessor = Accessor[i];
+  for (std::size_t I = 0; I < Accessor.size(); I++) {
+    CurrentAccessor = Accessor[I];
     Value *CurrentValue = CurrentContext->get(CurrentAccessor);
     if (!CurrentValue) {
       return nullptr;
     }
-    if (i < Accessor.size() - 1) {
+    if (I < Accessor.size() - 1) {
       CurrentContext = CurrentValue->getAsObject();
       if (!CurrentContext) {
         return nullptr;
diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp
index 7479e29816e944..ceee8942f88f4e 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -22,7 +22,7 @@ TEST(MustacheInterpolation, NoInterpolation) {
   // Mustache-free templates should render as-is.
   Value D = {};
   auto T = Template::createTemplate("Hello from {Mustache}!\n");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("Hello from {Mustache}!\n", Out);
 }
 
@@ -30,7 +30,7 @@ TEST(MustacheInterpolation, BasicInterpolation) {
   // Unadorned tags should interpolate content into the template.
   Value D = Object{{"subject", "World"}};
   auto T = Template::createTemplate("Hello, {{subject}}!");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("Hello, World!", Out);
 }
 
@@ -38,7 +38,7 @@ TEST(MustacheInterpolation, NoReinterpolation) {
   // Interpolated tag output should not be re-interpolated.
   Value D = Object{{"template", "{{planet}}"}, {"planet", "Earth"}};
   auto T = Template::createTemplate("{{template}}: {{planet}}");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("{{planet}}: Earth", Out);
 }
 
@@ -49,7 +49,7 @@ TEST(MustacheInterpolation, HTMLEscaping) {
   };
   auto T = Template::createTemplate(
       "These characters should be HTML escaped: {{forbidden}}\n");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("These characters should be HTML escaped: & " < >\n",
             Out);
 }
@@ -61,47 +61,78 @@ TEST(MustacheInterpolation, Ampersand) {
   };
   auto T = Template::createTemplate(
       "These characters should not be HTML escaped: {{&forbidden}}\n");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("These characters should not be HTML escaped: & \" < >\n", Out);
 }
 
 TEST(MustacheInterpolation, BasicIntegerInterpolation) {
+  // Integers should interpolate seamlessly.
   Value D = Object{{"mph", 85}};
   auto T = Template::createTemplate("{{mph}} miles an hour!");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
+  EXPECT_EQ("85 miles an hour!", Out);
+}
+
+TEST(MustacheInterpolation, AmpersandIntegerInterpolation) {
+  // Integers should interpolate seamlessly.
+  Value D = Object{{"mph", 85}};
+  auto T = Template::createTemplate("{{&mph}} miles an hour!");
+  auto Out = T.render(D);
   EXPECT_EQ("85 miles an hour!", Out);
 }
 
 TEST(MustacheInterpolation, BasicDecimalInterpolation) {
+  // Decimals should interpolate seamlessly with proper significance.
   Value D = Object{{"power", 1.21}};
   auto T = Template::createTemplate("{{power}} jiggawatts!");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("1.21 jiggawatts!", Out);
 }
 
 TEST(MustacheInterpolation, BasicNullInterpolation) {
+  // Nulls should interpolate as the empty string.
   Value D = Object{{"cannot", nullptr}};
   auto T = Template::createTemplate("I ({{cannot}}) be seen!");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
+  EXPECT_EQ("I () be seen!", Out);
+}
+
+TEST(MustacheInterpolation, AmpersandNullInterpolation) {
+  // Nulls should interpolate as the empty string.
+  Value D = Object{{"cannot", nullptr}};
+  auto T = Template::createTemplate("I ({{&cannot}}) be seen!");
+  auto Out = T.render(D);
   EXPECT_EQ("I () be seen!", Out);
 }
 
 TEST(MustacheInterpolation, BasicContextMissInterpolation) {
+  // Failed context lookups should default to empty strings.
   Value D = Object{};
   auto T = Template::createTemplate("I ({{cannot}}) be seen!");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("I () be seen!", Out);
 }
 
 TEST(MustacheInterpolation, DottedNamesBasicInterpolation) {
+  // Dotted names should be considered a form of shorthand for sections.
   Value D = Object{{"person", Object{{"name", "Joe"}}}};
   auto T = Template::createTemplate(
       "{{person.name}} == {{#person}}{{name}}{{/person}}");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
+  EXPECT_EQ("Joe == Joe", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesAmpersandInterpolation) {
+  // Dotted names should be considered a form of shorthand for sections.
+  Value D = Object{{"person", Object{{"name", "Joe"}}}};
+  auto T = Template::createTemplate(
+      "{{&person.name}} == {{#person}}{{&name}}{{/person}}");
+  auto Out = T.render(D);
   EXPECT_EQ("Joe == Joe", Out);
 }
 
 TEST(MustacheInterpolation, DottedNamesArbitraryDepth) {
+  // Dotted names should be functional to any level of nesting.
   Value D = Object{
       {"a",
        Object{{"b",
@@ -109,27 +140,845 @@ TEST(MustacheInterpolation, DottedNamesArbitraryDepth) {
                        Object{{"d",
                                Object{{"e", Object{{"name", "Phil"}}}}}}}}}}}};
   auto T = Template::createTemplate("{{a.b.c.d.e.name}} == Phil");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("Phil == Phil", Out);
 }
 
+TEST(MustacheInterpolation, DottedNamesBrokenChains) {
+  // Any falsey value prior to the last part of the name should yield ''.
+  Value D = Object{{"a", Object{}}};
+  auto T = Template::createTemplate("{{a.b.c}} == ");
+  auto Out = T.render(D);
+  EXPECT_EQ(" == ", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesBrokenChainResolution) {
+  // Each part of a dotted name should resolve only against its parent.
+  Value D =
+      Object{{"a", Object{{"b", Object{}}}}, {"c", Object{{"name", "Jim"}}}};
+  auto T = Template::createTemplate("{{a.b.c.name}} == ");
+  auto Out = T.render(D);
+  EXPECT_EQ(" == ", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesInitialResolution) {
+  // The first part of a dotted name should resolve as any other name.
+  Value D = Object{
+      {"a",
+       Object{
+           {"b",
+            Object{{"c",
+                    Object{{"d", Object{{"e", Object{{"name", "Phil"}}}}}}}}}}},
+      {"b",
+       Object{{"c", Object{{"d", Object{{"e", Object{{"name", "Wrong"}}}}}}}}}};
+  auto T = Template::createTemplate("{{#a}}{{b.c.d.e.name}}{{/a}} == Phil");
+  auto Out = T.render(D);
+  EXPECT_EQ("Phil == Phil", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesContextPrecedence) {
+  // Dotted names should be resolved against former resolutions.
+  Value D =
+      Object{{"a", Object{{"b", Object{}}}}, {"b", Object{{"c", "ERROR"}}}};
+  auto T = Template::createTemplate("{{#a}}{{b.c}}{{/a}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesAreNotSingleKeys) {
+  // Dotted names shall not be parsed as single, atomic keys
+  Value D = Object{{"a.b", "c"}};
+  auto T = Template::createTemplate("{{a.b}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheInterpolation, DottedNamesNoMasking) {
+  // Dotted Names in a given context are unavailable due to dot splitting
+  Value D = Object{{"a.b", "c"}, {"a", Object{{"b", "d"}}}};
+  auto T = Template::createTemplate("{{a.b}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("d", Out);
+}
+
 TEST(MustacheInterpolation, ImplicitIteratorsBasicInterpolation) {
+  // Unadorned tags should interpolate content into the template.
   Value D = "world";
   auto T = Template::createTemplate("Hello, {{.}}!\n");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("Hello, world!\n", Out);
 }
 
+TEST(MustacheInterpolation, ImplicitIteratorsAmersand) {
+  // Basic interpolation should be HTML escaped.
+  Value D = "& \" < >";
+  auto T = Template::createTemplate(
+      "These characters should not be HTML escaped: {{&.}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("These characters should not be HTML escaped: & \" < >\n", Out);
+}
+
+TEST(MustacheInterpolation, ImplicitIteratorsInteger) {
+  // Integers should interpolate seamlessly.
+  Value D = 85;
+  auto T = Template::createTemplate("{{.}} miles an hour!\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("85 miles an hour!\n", Out);
+}
+
 TEST(MustacheInterpolation, InterpolationSurroundingWhitespace) {
+  // Interpolation should not alter surrounding whitespace.
   Value D = Object{{"string", "---"}};
   auto T = Template::createTemplate("| {{string}} |");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
   EXPECT_EQ("| --- |", Out);
 }
 
+TEST(MustacheInterpolation, AmersandSurroundingWhitespace) {
+  // Interpolation should not alter surrounding whitespace.
+  Value D = Object{{"string", "---"}};
+  auto T = Template::createTemplate("| {{&string}} |");
+  auto Out = T.render(D);
+  EXPECT_EQ("| --- |", Out);
+}
+
+TEST(MustacheInterpolation, StandaloneInterpolationWithWhitespace) {
+  // Standalone interpolation should not alter surrounding whitespace.
+  Value D = Object{{"string", "---"}};
+  auto T = Template::createTemplate("  {{string}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("  ---\n", Out);
+}
+
+TEST(MustacheInterpolation, StandaloneAmpersandWithWhitespace) {
+  // Standalone interpolation should not alter surrounding whitespace.
+  Value D = Object{{"string", "---"}};
+  auto T = Template::createTemplate("  {{&string}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("  ---\n", Out);
+}
+
 TEST(MustacheInterpolation, InterpolationWithPadding) {
+  // Superfluous in-tag whitespace should be ignored.
   Value D = Object{{"string", "---"}};
   auto T = Template::createTemplate("|{{ string }}|");
-  auto Out = T.get().render(D);
+  auto Out = T.render(D);
+  EXPECT_EQ("|---|", Out);
+}
+
+TEST(MustacheInterpolation, AmpersandWithPadding) {
+  // Superfluous in-tag whitespace should be ignored.
+  Value D = Object{{"string", "---"}};
+  auto T = Template::createTemplate("|{{& string }}|");
+  auto Out = T.render(D);
+  EXPECT_EQ("|---|", Out);
+}
+
+TEST(MustacheInterpolation, InterpolationWithPaddingAndNewlines) {
+  // Superfluous in-tag whitespace should be ignored.
+  Value D = Object{{"string", "---"}};
+  auto T = Template::createTemplate("|{{ string \n\n\n }}|");
+  auto Out = T.render(D);
   EXPECT_EQ("|---|", Out);
 }
+
+TEST(MustacheSections, Truthy) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate(
+      "{{#boolean}}This should be rendered.{{/boolean}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("This should be rendered.", Out);
+}
+
+TEST(MustacheSections, Falsey) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate(
+      "{{#boolean}}This should not be rendered.{{/boolean}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheSections, NullIsFalsey) {
+  Value D = Object{{"null", nullptr}};
+  auto T = Template::createTemplate(
+      "{{#null}}This should not be rendered.{{/null}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheSections, Context) {
+  Value D = Object{{"context", Object{{"name", "Joe"}}}};
+  auto T = Template::createTemplate("{{#context}}Hi {{name}}.{{/context}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("Hi Joe.", Out);
+}
+
+TEST(MustacheSections, ParentContexts) {
+  Value D = Object{{"a", "foo"},
+                   {"b", "wrong"},
+                   {"sec", Object{{"b", "bar"}}},
+                   {"c", Object{{"d", "baz"}}}};
+  auto T = Template::createTemplate("{{#sec}}{{a}}, {{b}}, {{c.d}}{{/sec}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("foo, bar, baz", Out);
+}
+
+TEST(MustacheSections, VariableTest) {
+  Value D = Object{{"foo", "bar"}};
+  auto T = Template::createTemplate("{{#foo}}{{.}} is {{foo}}{{/foo}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("bar is bar", Out);
+}
+
+TEST(MustacheSections, ListContexts) {
+  Value D = Object{
+      {"tops",
+       Array{Object{
+           {"tname", Object{{"upper", "A"}, {"lower", "a"}}},
+           {"middles",
+            Array{Object{{"mname", "1"},
+                         {"bottoms", Array{Object{{"bname", "x"}},
+                                           Object{{"bname", "y"}}}}}}}}}}};
+  auto T = Template::createTemplate("{{#tops}}"
+                                    "{{#middles}}"
+                                    "{{tname.lower}}{{mname}}."
+                                    "{{#bottoms}}"
+                                    "{{tname.upper}}{{mname}}{{bname}}."
+                                    "{{/bottoms}}"
+                                    "{{/middles}}"
+                                    "{{/tops}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("a1.A1x.A1y.", Out);
+}
+
+TEST(MustacheSections, DeeplyNestedContexts) {
+  Value D = Object{
+      {"a", Object{{"one", 1}}},
+      {"b", Object{{"two", 2}}},
+      {"c", Object{{"three", 3}, {"d", Object{{"four", 4}, {"five", 5}}}}}};
+  auto T = Template::createTemplate(
+      "{{#a}}\n{{one}}\n{{#b}}\n{{one}}{{two}}{{one}}\n{{#c}}\n{{one}}{{two}}{{"
+      "three}}{{two}}{{one}}\n{{#d}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{"
+      "{two}}{{one}}\n{{#five}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{four}"
+      "}{{three}}{{two}}{{one}}\n{{one}}{{two}}{{three}}{{four}}{{.}}6{{.}}{{"
+      "four}}{{three}}{{two}}{{one}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{"
+      "four}}{{three}}{{two}}{{one}}\n{{/"
+      "five}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{/"
+      "d}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{/"
+      "c}}\n{{one}}{{two}}{{one}}\n{{/b}}\n{{one}}\n{{/a}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("1\n121\n12321\n1234321\n123454321\n12345654321\n123454321\n1234321"
+            "\n12321\n121\n1\n",
+            Out);
+}
+
+TEST(MustacheSections, List) {
+  Value D = Object{{"list", Array{Object{{"item", 1}}, Object{{"item", 2}},
+                                  Object{{"item", 3}}}}};
+  auto T = Template::createTemplate("{{#list}}{{item}}{{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("123", Out);
+}
+
+TEST(MustacheSections, EmptyList) {
+  Value D = Object{{"list", Array{}}};
+  auto T = Template::createTemplate("{{#list}}Yay lists!{{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheSections, Doubled) {
+  Value D = Object{{"bool", true}, {"two", "second"}};
+  auto T = Template::createTemplate("{{#bool}}\n* first\n{{/bool}}\n* "
+                                    "{{two}}\n{{#bool}}\n* third\n{{/bool}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("* first\n* second\n* third\n", Out);
+}
+
+TEST(MustacheSections, NestedTruthy) {
+  Value D = Object{{"bool", true}};
+  auto T = Template::createTemplate(
+      "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |");
+  auto Out = T.render(D);
+  EXPECT_EQ("| A B C D E |", Out);
+}
+
+TEST(MustacheSections, NestedFalsey) {
+  Value D = Object{{"bool", false}};
+  auto T = Template::createTemplate(
+      "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |");
+  auto Out = T.render(D);
+  EXPECT_EQ("| A  E |", Out);
+}
+
+TEST(MustacheSections, ContextMisses) {
+  Value D = Object{};
+  auto T = Template::createTemplate(
+      "[{{#missing}}Found key 'missing'!{{/missing}}]");
+  auto Out = T.render(D);
+  EXPECT_EQ("[]", Out);
+}
+
+TEST(MustacheSections, ImplicitIteratorString) {
+  Value D = Object{{"list", Array{"a", "b", "c", "d", "e"}}};
+  auto T = Template::createTemplate("{{#list}}({{.}}){{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("(a)(b)(c)(d)(e)", Out);
+}
+
+TEST(MustacheSections, ImplicitIteratorInteger) {
+  Value D = Object{{"list", Array{1, 2, 3, 4, 5}}};
+  auto T = Template::createTemplate("{{#list}}({{.}}){{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("(1)(2)(3)(4)(5)", Out);
+}
+
+TEST(MustacheSections, ImplicitIteratorArray) {
+  Value D = Object{{"list", Array{Array{1, 2, 3}, Array{"a", "b", "c"}}}};
+  auto T = Template::createTemplate("{{#list}}({{#.}}{{.}}{{/.}}){{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("(123)(abc)", Out);
+}
+
+TEST(MustacheSections, ImplicitIteratorHTMLEscaping) {
+  Value D = Object{{"list", Array{"&", "\"", "<", ">"}}};
+  auto T = Template::createTemplate("{{#list}}({{.}}){{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("(&)(")(<)(>)", Out);
+}
+
+TEST(MustacheSections, ImplicitIteratorAmpersand) {
+  Value D = Object{{"list", Array{"&", "\"", "<", ">"}}};
+  auto T = Template::createTemplate("{{#list}}({{&.}}){{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("(&)(\")(<)(>)", Out);
+}
+
+TEST(MustacheSections, ImplicitIteratorRootLevel) {
+  Value D = Array{Object{{"value", "a"}}, Object{{"value", "b"}}};
+  auto T = Template::createTemplate("{{#.}}({{value}}){{/.}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("(a)(b)", Out);
+}
+
+TEST(MustacheSections, DottedNamesTruthy) {
+  Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}};
+  auto T = Template::createTemplate("{{#a.b.c}}Here{{/a.b.c}} == Here");
+  auto Out = T.render(D);
+  EXPECT_EQ("Here == Here", Out);
+}
+
+TEST(MustacheSections, DottedNamesFalsey) {
+  Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}};
+  auto T = Template::createTemplate("{{#a.b.c}}Here{{/a.b.c}} == ");
+  auto Out = T.render(D);
+  EXPECT_EQ(" == ", Out);
+}
+
+TEST(MustacheSections, DottedNamesBrokenChains) {
+  Value D = Object{{"a", Object{}}};
+  auto T = Template::createTemplate("{{#a.b.c}}Here{{/a.b.c}} == ");
+  auto Out = T.render(D);
+  EXPECT_EQ(" == ", Out);
+}
+
+TEST(MustacheSections, SurroundingWhitespace) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate(" | {{#boolean}}\t|\t{{/boolean}} | \n");
+  auto Out = T.render(D);
+  EXPECT_EQ(" | \t|\t | \n", Out);
+}
+
+TEST(MustacheSections, InternalWhitespace) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate(
+      " | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n");
+  auto Out = T.render(D);
+  EXPECT_EQ(" |  \n  | \n", Out);
+}
+
+TEST(MustacheSections, IndentedInlineSections) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate(
+      " {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ(" YES\n GOOD\n", Out);
+}
+
+TEST(MustacheSections, StandaloneLines) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate(
+      "| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
+}
+
+TEST(MustacheSections, IndentedStandaloneLines) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate(
+      "| This Is\n  {{#boolean}}\n|\n  {{/boolean}}\n| A Line\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
+}
+
+TEST(MustacheSections, StandaloneLineEndings) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate("|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|");
+  auto Out = T.render(D);
+  EXPECT_EQ("|\r\n|", Out);
+}
+
+TEST(MustacheSections, StandaloneWithoutPreviousLine) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate("  {{#boolean}}\n#{{/boolean}}\n/");
+  auto Out = T.render(D);
+  EXPECT_EQ("#\n/", Out);
+}
+
+TEST(MustacheSections, StandaloneWithoutNewline) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate("#{{#boolean}}\n/\n  {{/boolean}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("#\n/\n", Out);
+}
+
+TEST(MustacheSections, Padding) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate("|{{# boolean }}={{/ boolean }}|");
+  auto Out = T.render(D);
+  EXPECT_EQ("|=|", Out);
+}
+
+TEST(MustacheInvertedSections, Falsey) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate(
+      "{{^boolean}}This should be rendered.{{/boolean}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("This should be rendered.", Out);
+}
+
+TEST(MustacheInvertedSections, Truthy) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate(
+      "{{^boolean}}This should not be rendered.{{/boolean}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheInvertedSections, NullIsFalsey) {
+  Value D = Object{{"null", nullptr}};
+  auto T =
+      Template::createTemplate("{{^null}}This should be rendered.{{/null}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("This should be rendered.", Out);
+}
+
+TEST(MustacheInvertedSections, Context) {
+  Value D = Object{{"context", Object{{"name", "Joe"}}}};
+  auto T = Template::createTemplate("{{^context}}Hi {{name}}.{{/context}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheInvertedSections, List) {
+  Value D = Object{
+      {"list", Array{Object{{"n", 1}}, Object{{"n", 2}}, Object{{"n", 3}}}}};
+  auto T = Template::createTemplate("{{^list}}{{n}}{{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustacheInvertedSections, EmptyList) {
+  Value D = Object{{"list", Array{}}};
+  auto T = Template::createTemplate("{{^list}}Yay lists!{{/list}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("Yay lists!", Out);
+}
+
+TEST(MustacheInvertedSections, Doubled) {
+  Value D = Object{{"bool", false}, {"two", "second"}};
+  auto T = Template::createTemplate("{{^bool}}\n* first\n{{/bool}}\n* "
+                                    "{{two}}\n{{^bool}}\n* third\n{{/bool}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("* first\n* second\n* third\n", Out);
+}
+
+TEST(MustacheInvertedSections, NestedFalsey) {
+  Value D = Object{{"bool", false}};
+  auto T = Template::createTemplate(
+      "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |");
+  auto Out = T.render(D);
+  EXPECT_EQ("| A B C D E |", Out);
+}
+
+TEST(MustacheInvertedSections, NestedTruthy) {
+  Value D = Object{{"bool", true}};
+  auto T = Template::createTemplate(
+      "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |");
+  auto Out = T.render(D);
+  EXPECT_EQ("| A  E |", Out);
+}
+
+TEST(MustacheInvertedSections, ContextMisses) {
+  Value D = Object{};
+  auto T = Template::createTemplate(
+      "[{{^missing}}Cannot find key 'missing'!{{/missing}}]");
+  auto Out = T.render(D);
+  EXPECT_EQ("[Cannot find key 'missing'!]", Out);
+}
+
+TEST(MustacheInvertedSections, DottedNamesTruthy) {
+  Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}};
+  auto T = Template::createTemplate("{{^a.b.c}}Not Here{{/a.b.c}} == ");
+  auto Out = T.render(D);
+  EXPECT_EQ(" == ", Out);
+}
+
+TEST(MustacheInvertedSections, DottedNamesFalsey) {
+  Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}};
+  auto T = Template::createTemplate("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here");
+  auto Out = T.render(D);
+  EXPECT_EQ("Not Here == Not Here", Out);
+}
+
+TEST(MustacheInvertedSections, DottedNamesBrokenChains) {
+  Value D = Object{{"a", Object{}}};
+  auto T = Template::createTemplate("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here");
+  auto Out = T.render(D);
+  EXPECT_EQ("Not Here == Not Here", Out);
+}
+
+TEST(MustacheInvertedSections, SurroundingWhitespace) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate(" | {{^boolean}}\t|\t{{/boolean}} | \n");
+  auto Out = T.render(D);
+  EXPECT_EQ(" | \t|\t | \n", Out);
+}
+
+TEST(MustacheInvertedSections, InternalWhitespace) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate(
+      " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n");
+  auto Out = T.render(D);
+  EXPECT_EQ(" |  \n  | \n", Out);
+}
+
+TEST(MustacheInvertedSections, IndentedInlineSections) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate(
+      " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ(" NO\n WAY\n", Out);
+}
+
+TEST(MustacheInvertedSections, StandaloneLines) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate(
+      "| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
+}
+
+TEST(MustacheInvertedSections, StandaloneIndentedLines) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate(
+      "| This Is\n  {{^boolean}}\n|\n  {{/boolean}}\n| A Line\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
+}
+
+TEST(MustacheInvertedSections, StandaloneLineEndings) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate("|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|");
+  auto Out = T.render(D);
+  EXPECT_EQ("|\r\n|", Out);
+}
+
+TEST(MustacheInvertedSections, StandaloneWithoutPreviousLine) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate("  {{^boolean}}\n^{{/boolean}}\n/");
+  auto Out = T.render(D);
+  EXPECT_EQ("^\n/", Out);
+}
+
+TEST(MustacheInvertedSections, StandaloneWithoutNewline) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate("^{{^boolean}}\n/\n  {{/boolean}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("^\n/\n", Out);
+}
+
+TEST(MustacheInvertedSections, Padding) {
+  Value D = Object{{"boolean", false}};
+  auto T = Template::createTemplate("|{{^ boolean }}={{/ boolean }}|");
+  auto Out = T.render(D);
+  EXPECT_EQ("|=|", Out);
+}
+
+TEST(MustachePartials, BasicBehavior) {
+  Value D = Object{};
+  auto T = Template::createTemplate("{{>text}}");
+  T.registerPartial("text", "from partial");
+  auto Out = T.render(D);
+  EXPECT_EQ("from partial", Out);
+}
+
+TEST(MustachePartials, FailedLookup) {
+  Value D = Object{};
+  auto T = Template::createTemplate("{{>text}}");
+  auto Out = T.render(D);
+  EXPECT_EQ("", Out);
+}
+
+TEST(MustachePartials, Context) {
+  Value D = Object{{"text", "content"}};
+  auto T = Template::createTemplate("{{>partial}}");
+  T.registerPartial("partial", "*{{text}}*");
+  auto Out = T.render(D);
+  EXPECT_EQ("*content*", Out);
+}
+
+TEST(MustachePartials, Recursion) {
+  Value D =
+      Object{{"content", "X"},
+             {"nodes", Array{Object{{"content", "Y"}, {"nodes", Array{}}}}}};
+  auto T = Template::createTemplate("{{>node}}");
+  T.registerPartial("node", "{{content}}({{#nodes}}{{>node}}{{/nodes}})");
+  auto Out = T.render(D);
+  EXPECT_EQ("X(Y())", Out);
+}
+
+TEST(MustachePartials, Nested) {
+  Value D = Object{{"a", "hello"}, {"b", "world"}};
+  auto T = Template::createTemplate("{{>outer}}");
+  T.registerPartial("outer", "*{{a}} {{>inner}}*");
+  T.registerPartial("inner", "{{b}}!");
+  auto Out = T.render(D);
+  EXPECT_EQ("*hello world!*", Out);
+}
+
+TEST(MustachePartials, SurroundingWhitespace) {
+  Value D = Object{};
+  auto T = Template::createTemplate("| {{>partial}} |");
+  T.registerPartial("partial", "\t|\t");
+  auto Out = T.render(D);
+  EXPECT_EQ("| \t|\t |", Out);
+}
+
+TEST(MustachePartials, InlineIndentation) {
+  Value D = Object{{"data", "|"}};
+  auto T = Template::createTemplate("  {{data}}  {{> partial}}\n");
+  T.registerPartial("partial", "(\n(");
+  auto Out = T.render(D);
+  EXPECT_EQ("  |  (\n(\n", Out);
+}
+
+TEST(MustachePartials, PaddingWhitespace) {
+  Value D = Object{{"boolean", true}};
+  auto T = Template::createTemplate("|{{> partial }}|");
+  T.registerPartial("partial", "[]");
+  auto Out = T.render(D);
+  EXPECT_EQ("|[]|", Out);
+}
+
+TEST(MustacheLambdas, BasicInterpolation) {
+  Value D = Object{};
+  auto T = Template::createTemplate("Hello, {{lambda}}!");
+  Lambda L = []() -> llvm::SmallString<128> {
+    llvm::SmallString<128> Result("World");
+    return Result;
+  };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("Hello, World!", Out);
+}
+
+TEST(MustacheLambdas, InterpolationExpansion) {
+  Value D = Object{{"planet", "World"}};
+  auto T = Template::createTemplate("Hello, {{lambda}}!");
+  Lambda L = []() -> llvm::SmallString<128> {
+    return llvm::SmallString<128>("{{planet}}");
+  };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("Hello, World!", Out);
+}
+
+TEST(MustacheLambdas, BasicMultipleCalls) {
+  Value D = Object{};
+  auto T = Template::createTemplate("{{lambda}} == {{lambda}} == {{lambda}}");
+  int I = 0;
+  Lambda L = [&I]() -> llvm::json::Value {
+    I += 1;
+    return I;
+  };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("1 == 2 == 3", Out);
+}
+
+TEST(MustacheLambdas, Escaping) {
+  Value D = Object{};
+  auto T = Template::createTemplate("<{{lambda}}{{&lambda}}");
+  Lambda L = []() -> llvm::json::Value { return ">"; };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("<>>", Out);
+}
+
+TEST(MustacheLambdas, Sections) {
+  Value D = Object{};
+  auto T = Template::createTemplate("<{{#lambda}}{{x}}{{/lambda}}>");
+  SectionLambda L = [](StringRef Text) -> llvm::json::Value {
+    if (Text == "{{x}}") {
+      return "yes";
+    }
+    return "no";
+  };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("<yes>", Out);
+}
+
+TEST(MustacheLambdas, SectionExpansion) {
+  Value D = Object{
+      {"planet", "Earth"},
+  };
+  auto T = Template::createTemplate("<{{#lambda}}-{{/lambda}}>");
+  SectionLambda L = [](StringRef Text) -> llvm::json::Value {
+    SmallString<128> Result;
+    Result += Text;
+    Result += "{{planet}}";
+    Result += Text;
+    return Result;
+  };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("<-Earth->", Out);
+}
+
+TEST(MustacheLambdas, SectionsMultipleCalls) {
+  Value D = Object{};
+  auto T = Template::createTemplate(
+      "{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}");
+  SectionLambda L = [](StringRef Text) -> llvm::json::Value {
+    SmallString<128> Result;
+    Result += "__";
+    Result += Text;
+    Result += "__";
+    return Result;
+  };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("__FILE__ != __LINE__", Out);
+}
+
+TEST(MustacheLambdas, InvertedSections) {
+  Value D = Object{{"static", "static"}};
+  auto T = Template::createTemplate("<{{^lambda}}{{static}}{{/lambda}}>");
+  SectionLambda L = [](StringRef Text) -> llvm::json::Value { return false; };
+  T.registerLambda("lambda", L);
+  auto Out = T.render(D);
+  EXPECT_EQ("<>", Out);
+}
+
+TEST(MustacheComments, Inline) {
+  // Comment blocks should be removed from the template.
+  Value D = {};
+  auto T = Template::createTemplate("12345{{! Comment Block! }}67890");
+  auto Out = T.render(D);
+  EXPECT_EQ("1234567890", Out);
+}
+
+TEST(MustacheComments, Multiline) {
+  // Multiline comments should be permitted.
+  Value D = {};
+  auto T = Template::createTemplate(
+      "12345{{!\n  This is a\n  multi-line comment...\n}}67890\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("1234567890\n", Out);
+}
+
+TEST(MustacheComments, Standalone) {
+  // All standalone comment lines should be removed.
+  Value D = {};
+  auto T = Template::createTemplate("Begin.\n{{! Comment Block! }}\nEnd.\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("Begin.\nEnd.\n", Out);
+}
+
+TEST(MustacheComments, IndentedStandalone) {
+  // All standalone comment lines should be removed.
+  Value D = {};
+  auto T = Template::createTemplate(
+      "Begin.\n  {{! Indented Comment Block! }}\nEnd.\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("Begin.\nEnd.\n", Out);
+}
+
+TEST(MustacheComments, StandaloneLineEndings) {
+  // "\r\n" should be considered a newline for standalone tags.
+  Value D = {};
+  auto T = Template::createTemplate("|\r\n{{! Standalone Comment }}\r\n|");
+  auto Out = T.render(D);
+  EXPECT_EQ("|\r\n|", Out);
+}
+
+TEST(MustacheComments, StandaloneWithoutPreviousLine) {
+  // Standalone tags should not require a newline to precede them.
+  Value D = {};
+  auto T = Template::createTemplate("  {{! I'm Still Standalone }}\n!");
+  auto Out = T.render(D);
+  EXPECT_EQ("!", Out);
+}
+
+TEST(MustacheComments, StandaloneWithoutNewline) {
+  // Standalone tags should not require a newline to follow them.
+  Value D = {};
+  auto T = Template::createTemplate("!\n  {{! I'm Still Standalone }}");
+  auto Out = T.render(D);
+  EXPECT_EQ("!\n", Out);
+}
+
+TEST(MustacheComments, MultilineStandalone) {
+  // All standalone comment lines should be removed.
+  Value D = {};
+  auto T = Template::createTemplate(
+      "Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("Begin.\nEnd.\n", Out);
+}
+
+TEST(MustacheComments, IndentedMultilineStandalone) {
+  // All standalone comment lines should be removed.
+  Value D = {};
+  auto T = Template::createTemplate(
+      "Begin.\n  {{!\n    Something's going on here...\n  }}\nEnd.\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("Begin.\nEnd.\n", Out);
+}
+
+TEST(MustacheComments, IndentedInline) {
+  // Inline comments should not strip whitespace.
+  Value D = {};
+  auto T = Template::createTemplate("  12 {{! 34 }}\n");
+  auto Out = T.render(D);
+  EXPECT_EQ("  12 \n", Out);
+}
+
+TEST(MustacheComments, SurroundingWhitespace) {
+  // Comment removal should preserve surrounding whitespace.
+  Value D = {};
+  auto T = Template::createTemplate("12345 {{! Comment Block! }} 67890");
+  auto Out = T.render(D);
+  EXPECT_EQ("12345  67890", Out);
+}
+
+TEST(MustacheComments, VariableNameCollision) {
+  // Comments must never render, even if a variable with the same name exists.
+  Value D = Object{
+      {"! comment", 1}, {"! comment ", 2}, {"!comment", 3}, {"comment", 4}};
+  auto T = Template::createTemplate("comments never show: >{{! comment }}<");
+  auto Out = T.render(D);
+  EXPECT_EQ("comments never show: ><", Out);
+}
\ No newline at end of file

>From 6e893c07ca49773825ddcb6d99107b96b37d5540 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 15:51:33 -0400
Subject: [PATCH 12/57] [llvm][support] fix mustache test

---
 llvm/lib/Support/Mustache.cpp           | 11 ++++++-----
 llvm/unittests/Support/MustacheTest.cpp |  4 ++--
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 80b3d8bc53651b..09adba4d6239ee 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -137,16 +137,16 @@ std::vector<Token> tokenize(StringRef Template) {
     if (I > 0 && Tokens[I - 1].getType() == Token::Type::Text &&
         RequiresCleanUp) {
       Token &PrevToken = Tokens[I - 1];
-      StringRef TokenBody = PrevToken.getTokenBody().rtrim(" \t\v\t");
+      StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
       if (TokenBody.ends_with("\n") || TokenBody.ends_with("\r\n") ||
-          TokenBody.empty()) {
+          (TokenBody.empty() && I == 1)) {
         NoTextBehind = true;
       }
     }
     if (I < Tokens.size() - 1 && Tokens[I + 1].getType() == Token::Type::Text &&
         RequiresCleanUp) {
       Token &NextToken = Tokens[I + 1];
-      StringRef TokenBody = NextToken.getTokenBody().ltrim(" ");
+      StringRef TokenBody = NextToken.getRawBody().ltrim(" ");
       if (TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n")) {
         NoTextAhead = true;
       }
@@ -363,8 +363,9 @@ ASTNode::render(Value Data,
       StringRef LambdaStr = printJson(LambdaResult);
       Parser P = Parser(LambdaStr);
       std::shared_ptr<ASTNode> LambdaNode = P.parse();
-      return LambdaNode->render(Data, Partials, Lambdas, SectionLambdas,
-                                Escapes);
+      SmallString<128> RenderStr =
+          LambdaNode->render(Data, Partials, Lambdas, SectionLambdas, Escapes);
+      return escapeString(RenderStr, Escapes);
     }
     return escapeString(printJson(Context), Escapes);
   }
diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp
index ceee8942f88f4e..dfd28b0b5b2377 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -768,9 +768,9 @@ TEST(MustachePartials, SurroundingWhitespace) {
 TEST(MustachePartials, InlineIndentation) {
   Value D = Object{{"data", "|"}};
   auto T = Template::createTemplate("  {{data}}  {{> partial}}\n");
-  T.registerPartial("partial", "(\n(");
+  T.registerPartial("partial", "<\n<");
   auto Out = T.render(D);
-  EXPECT_EQ("  |  (\n(\n", Out);
+  EXPECT_EQ("  |  <\n<\n", Out);
 }
 
 TEST(MustachePartials, PaddingWhitespace) {

>From 976593eff073b8741b6e3d1e4d7bcf648f6983d8 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 16:39:30 -0400
Subject: [PATCH 13/57] [llvm][support] add comments

---
 llvm/include/llvm/Support/Mustache.h | 51 +++++++++++++++++--
 llvm/lib/Support/Mustache.cpp        | 75 +++++++++-------------------
 2 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index cb7d80e47809e8..f5714c19089348 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -7,8 +7,50 @@
 //===----------------------------------------------------------------------===//
 //
 // Implementation of the Mustache templating language supports version 1.4.2
+// currently relies on llvm::json::Value for data input
+// see the Mustache spec for more information
 // (https://mustache.github.io/mustache.5.html).
 //
+// Current Features Supported:
+// - Variables
+// - Sections
+// - Inverted Sections
+// - Partials
+// - Comments
+// - Lambdas
+// - Unescaped Variables
+//
+// Features Not Supported:
+// - Set Delimiter
+// - Blocks
+// - Parents
+// - Dynamic Names
+//
+// Usage:
+// - Creating a simple template and rendering it:
+// \code
+//   auto Template = Template::createTemplate("Hello, {{name}}!");
+//   Value Data = {{"name", "World"}};
+//   StringRef Rendered = Template.render(Data);
+//   // Rendered == "Hello, World!"
+// \endcode
+// - Creating a template with a partial and rendering it:
+// \code
+//   auto Template = Template::createTemplate("{{>partial}}");
+//   Template.registerPartial("partial", "Hello, {{name}}!");
+//   Value Data = {{"name", "World"}};
+//   StringRef Rendered = Template.render(Data);
+//   // Rendered == "Hello, World!"
+// \endcode
+// - Creating a template with a lambda and rendering it:
+// \code
+//   auto Template = Template::createTemplate("{{#lambda}}Hello,
+//                                             {{name}}!{{/lambda}}");
+//   Template.registerLambda("lambda", []() { return true; });
+//   Value Data = {{"name", "World"}};
+//   StringRef Rendered = Template.render(Data);
+//   // Rendered == "Hello, World!"
+// \endcode
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_SUPPORT_MUSTACHE
@@ -17,8 +59,6 @@
 #include "Error.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/JSON.h"
-#include <string>
-#include <variant>
 #include <vector>
 
 namespace llvm {
@@ -96,8 +136,6 @@ class ASTNode {
 
   void setRawBody(StringRef NewBody) { RawBody = NewBody; };
 
-  SmallString<128> getRawBody() const { return RawBody; };
-
   std::shared_ptr<ASTNode> getLastChild() const {
     return Children.empty() ? nullptr : Children.back();
   };
@@ -120,6 +158,8 @@ class ASTNode {
   llvm::json::Value LocalContext;
 };
 
+// A Template represents the container for the AST and the partials
+// and Lambdas that are registered with it.
 class Template {
 public:
   static Template createTemplate(StringRef TemplateStr);
@@ -132,6 +172,9 @@ class Template {
 
   void registerLambda(StringRef Name, SectionLambda Lambda);
 
+  // By default the Mustache Spec Specifies that HTML special characters
+  // should be escaped. This function allows the user to specify which
+  // characters should be escaped.
   void registerEscape(DenseMap<char, StringRef> Escapes);
 
 private:
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 09adba4d6239ee..18a94f9f241c4d 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -8,9 +8,6 @@
 
 #include "llvm/Support/Mustache.h"
 #include "llvm/Support/Error.h"
-#include <iostream>
-#include <regex>
-#include <sstream>
 
 using namespace llvm;
 using namespace llvm::json;
@@ -20,11 +17,10 @@ SmallString<128> escapeString(StringRef Input,
                               DenseMap<char, StringRef> &Escape) {
   SmallString<128> EscapedString("");
   for (char C : Input) {
-    if (Escape.find(C) != Escape.end()) {
+    if (Escape.find(C) != Escape.end())
       EscapedString += Escape[C];
-    } else {
+    else
       EscapedString += C;
-    }
   }
   return EscapedString;
 }
@@ -52,9 +48,9 @@ Token::Token(StringRef RawBody, StringRef InnerBody, char Identifier)
     return;
 
   StringRef AccessorStr = InnerBody;
-  if (TokenType != Type::Variable) {
+  if (TokenType != Type::Variable)
     AccessorStr = InnerBody.substr(1);
-  }
+
   Accessor = split(AccessorStr.trim(), '.');
 }
 
@@ -118,9 +114,8 @@ std::vector<Token> tokenize(StringRef Template) {
     DelimiterStart = Template.find(Open, Start);
   }
 
-  if (Start < Template.size()) {
+  if (Start < Template.size())
     Tokens.push_back(Token(Template.substr(Start)));
-  }
 
   // fix up white spaces for
   // open sections/inverted sections/close section/comment
@@ -139,38 +134,27 @@ std::vector<Token> tokenize(StringRef Template) {
       Token &PrevToken = Tokens[I - 1];
       StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
       if (TokenBody.ends_with("\n") || TokenBody.ends_with("\r\n") ||
-          (TokenBody.empty() && I == 1)) {
+          (TokenBody.empty() && I == 1))
         NoTextBehind = true;
-      }
     }
     if (I < Tokens.size() - 1 && Tokens[I + 1].getType() == Token::Type::Text &&
         RequiresCleanUp) {
       Token &NextToken = Tokens[I + 1];
       StringRef TokenBody = NextToken.getRawBody().ltrim(" ");
-      if (TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n")) {
+      if (TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n"))
         NoTextAhead = true;
-      }
     }
 
-    if (NoTextBehind && NoTextAhead) {
-      Token &PrevToken = Tokens[I - 1];
-      Token &NextToken = Tokens[I + 1];
-      StringRef NextTokenBody = NextToken.getTokenBody();
-      PrevToken.setTokenBody(PrevToken.getTokenBody().rtrim(" \t\v\t"));
-      if (NextTokenBody.starts_with("\r\n")) {
-        NextToken.setTokenBody(NextTokenBody.substr(2));
-      } else if (NextToken.getTokenBody().starts_with("\n")) {
-        NextToken.setTokenBody(NextTokenBody.substr(1));
-      }
-    } else if (NoTextAhead && I == 0) {
+    if ((NoTextBehind && NoTextAhead) || (NoTextAhead && I == 0)) {
       Token &NextToken = Tokens[I + 1];
       StringRef NextTokenBody = NextToken.getTokenBody();
-      if (NextTokenBody.starts_with("\r\n")) {
+      if (NextTokenBody.starts_with("\r\n"))
         NextToken.setTokenBody(NextTokenBody.substr(2));
-      } else if (NextToken.getTokenBody().starts_with("\n")) {
+      else if (NextToken.getTokenBody().starts_with("\n"))
         NextToken.setTokenBody(NextTokenBody.substr(1));
-      }
-    } else if (NoTextBehind && I == Tokens.size() - 1) {
+    }
+    if ((NoTextBehind && NoTextAhead) ||
+        (NoTextBehind && I == Tokens.size() - 1)) {
       Token &PrevToken = Tokens[I - 1];
       StringRef PrevTokenBody = PrevToken.getTokenBody();
       PrevToken.setTokenBody(PrevTokenBody.rtrim(" \t\v\t"));
@@ -239,9 +223,8 @@ void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
       std::size_t End = CurrentPtr;
       SmallString<128> RawBody;
       if (Start + 1 < End - 1)
-        for (std::size_t I = Start + 1; I < End - 1; I++) {
+        for (std::size_t I = Start + 1; I < End - 1; I++)
           RawBody += Tokens[I].getRawBody();
-        }
       else if (Start + 1 == End - 1)
         RawBody = Tokens[Start].getRawBody();
       CurrentNode->setRawBody(RawBody);
@@ -256,18 +239,16 @@ void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
       std::size_t End = CurrentPtr;
       SmallString<128> RawBody;
       if (Start + 1 < End - 1)
-        for (std::size_t I = Start + 1; I < End - 1; I++) {
+        for (std::size_t I = Start + 1; I < End - 1; I++)
           RawBody += Tokens[I].getRawBody();
-        }
       else if (Start + 1 == End - 1)
         RawBody = Tokens[Start].getRawBody();
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
       break;
     }
-    case Token::Type::SectionClose: {
+    case Token::Type::SectionClose:
       return;
-    }
     default:
       break;
     }
@@ -309,14 +290,11 @@ void Template::registerEscape(DenseMap<char, StringRef> E) { Escapes = E; }
 SmallString<128> printJson(Value &Data) {
 
   SmallString<128> Result;
-  if (Data.getAsNull()) {
+  if (Data.getAsNull())
     return Result;
-  }
-  if (auto *Arr = Data.getAsArray()) {
-    if (Arr->empty()) {
+  if (auto *Arr = Data.getAsArray())
+    if (Arr->empty())
       return Result;
-    }
-  }
   if (Data.getAsString()) {
     Result += Data.getAsString()->str();
     return Result;
@@ -436,12 +414,10 @@ Value ASTNode::findContext() {
   // We attempt to find the JSON context in the current node if it is not found
   // we traverse the parent nodes to find the context until we reach the root
   // node or the context is found
-  if (Accessor.empty()) {
+  if (Accessor.empty())
     return nullptr;
-  }
-  if (Accessor[0] == ".") {
+  if (Accessor[0] == ".")
     return LocalContext;
-  }
   json::Object *CurrentContext = LocalContext.getAsObject();
   SmallString<128> CurrentAccessor = Accessor[0];
   std::weak_ptr<ASTNode> CurrentParent = Parent;
@@ -458,17 +434,14 @@ Value ASTNode::findContext() {
   for (std::size_t I = 0; I < Accessor.size(); I++) {
     CurrentAccessor = Accessor[I];
     Value *CurrentValue = CurrentContext->get(CurrentAccessor);
-    if (!CurrentValue) {
+    if (!CurrentValue)
       return nullptr;
-    }
     if (I < Accessor.size() - 1) {
       CurrentContext = CurrentValue->getAsObject();
-      if (!CurrentContext) {
+      if (!CurrentContext)
         return nullptr;
-      }
-    } else {
+    } else
       Context = *CurrentValue;
-    }
   }
   return Context;
 }

>From 6a60eabf0e28e1a43d0943b5952f2eb5865cb5b7 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 17:21:22 -0400
Subject: [PATCH 14/57] [llvm][support] add comments

---
 llvm/include/llvm/Support/Mustache.h | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index f5714c19089348..03892ea5679ca0 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -27,23 +27,21 @@
 // - Dynamic Names
 //
 // Usage:
-// - Creating a simple template and rendering it:
 // \code
+//   // Creating a simple template and rendering it
 //   auto Template = Template::createTemplate("Hello, {{name}}!");
 //   Value Data = {{"name", "World"}};
 //   StringRef Rendered = Template.render(Data);
 //   // Rendered == "Hello, World!"
-// \endcode
-// - Creating a template with a partial and rendering it:
-// \code
+//
+//   // Creating a template with a partial and rendering it
 //   auto Template = Template::createTemplate("{{>partial}}");
 //   Template.registerPartial("partial", "Hello, {{name}}!");
 //   Value Data = {{"name", "World"}};
 //   StringRef Rendered = Template.render(Data);
 //   // Rendered == "Hello, World!"
-// \endcode
-// - Creating a template with a lambda and rendering it:
-// \code
+//
+//   // Creating a template with a lambda and rendering it
 //   auto Template = Template::createTemplate("{{#lambda}}Hello,
 //                                             {{name}}!{{/lambda}}");
 //   Template.registerLambda("lambda", []() { return true; });

>From 6a1fcc8f0f4c40a35d4afff7ebd66c2c99b356c1 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 17:25:06 -0400
Subject: [PATCH 15/57] [llvm][support] use enumerate for loop

---
 llvm/lib/Support/Mustache.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 18a94f9f241c4d..ad5d30d335f626 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -431,8 +431,7 @@ Value ASTNode::findContext() {
     return nullptr;
   }
   Value Context = nullptr;
-  for (std::size_t I = 0; I < Accessor.size(); I++) {
-    CurrentAccessor = Accessor[I];
+  for (auto CurrentAccessor : Accessor) {
     Value *CurrentValue = CurrentContext->get(CurrentAccessor);
     if (!CurrentValue)
       return nullptr;

>From eb1e1a66382551ed2d65c37a2a6fc307051904a2 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 17:34:43 -0400
Subject: [PATCH 16/57] [llvm][support] clang-format

---
 llvm/include/llvm/Support/Mustache.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 03892ea5679ca0..db09089707167d 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -114,15 +114,15 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), LocalContext(nullptr){};
+  ASTNode() : T(Type::Root), LocalContext(nullptr) {};
 
   ASTNode(StringRef Body, std::shared_ptr<ASTNode> Parent)
-      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr){};
+      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr) {};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, std::shared_ptr<ASTNode> Parent)
       : T(T), Accessor(Accessor), Parent(Parent), LocalContext(nullptr),
-        Children({}){};
+        Children({}) {};
 
   void addChild(std::shared_ptr<ASTNode> Child) {
     Children.emplace_back(Child);

>From f4b052084bf41dd109213af38622fc5df581691f Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 17:43:01 -0400
Subject: [PATCH 17/57] [llvm][support] fix mustache test

---
 llvm/unittests/Support/MustacheTest.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp
index dfd28b0b5b2377..c38a2ed2823379 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -139,9 +139,9 @@ TEST(MustacheInterpolation, DottedNamesArbitraryDepth) {
                Object{{"c",
                        Object{{"d",
                                Object{{"e", Object{{"name", "Phil"}}}}}}}}}}}};
-  auto T = Template::createTemplate("{{a.b.c.d.e.name}} == Phil");
+  auto T = Template::createTemplate("{{a.b.c.d.e.name}}");
   auto Out = T.render(D);
-  EXPECT_EQ("Phil == Phil", Out);
+  EXPECT_EQ("Phil", Out);
 }
 
 TEST(MustacheInterpolation, DottedNamesBrokenChains) {
@@ -171,9 +171,9 @@ TEST(MustacheInterpolation, DottedNamesInitialResolution) {
                     Object{{"d", Object{{"e", Object{{"name", "Phil"}}}}}}}}}}},
       {"b",
        Object{{"c", Object{{"d", Object{{"e", Object{{"name", "Wrong"}}}}}}}}}};
-  auto T = Template::createTemplate("{{#a}}{{b.c.d.e.name}}{{/a}} == Phil");
+  auto T = Template::createTemplate("{{#a}}{{b.c.d.e.name}}{{/a}}");
   auto Out = T.render(D);
-  EXPECT_EQ("Phil == Phil", Out);
+  EXPECT_EQ("Phil", Out);
 }
 
 TEST(MustacheInterpolation, DottedNamesContextPrecedence) {

>From 7ffaeec649728e21687e81fc3c479def997b1d83 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 17:50:37 -0400
Subject: [PATCH 18/57] [llvm][support] clang-format

---
 llvm/include/llvm/Support/Mustache.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index db09089707167d..afde8d995cc147 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -176,7 +176,7 @@ class Template {
   void registerEscape(DenseMap<char, StringRef> Escapes);
 
 private:
-  Template(std::shared_ptr<ASTNode> Tree) : Tree(Tree){};
+  Template(std::shared_ptr<ASTNode> Tree) : Tree(Tree) {};
   DenseMap<StringRef, std::shared_ptr<ASTNode>> Partials;
   DenseMap<StringRef, Lambda> Lambdas;
   DenseMap<StringRef, SectionLambda> SectionLambdas;

>From 746fb97f94d3533b84ff674f9f7140fdc1ef5522 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 6 Sep 2024 18:22:52 -0400
Subject: [PATCH 19/57] [llvm][support] use llvm enumerate

---
 llvm/lib/Support/Mustache.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index ad5d30d335f626..f0fb6767f6fcd5 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -431,11 +431,11 @@ Value ASTNode::findContext() {
     return nullptr;
   }
   Value Context = nullptr;
-  for (auto CurrentAccessor : Accessor) {
-    Value *CurrentValue = CurrentContext->get(CurrentAccessor);
+  for (auto E : enumerate(Accessor)) {
+    Value *CurrentValue = CurrentContext->get(E.value());
     if (!CurrentValue)
       return nullptr;
-    if (I < Accessor.size() - 1) {
+    if (E.index() < Accessor.size() - 1) {
       CurrentContext = CurrentValue->getAsObject();
       if (!CurrentContext)
         return nullptr;

>From bcc86fe0ad6f55a27c3fe50231da8d152517ac17 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Wed, 11 Sep 2024 18:41:38 -0400
Subject: [PATCH 20/57] [llvm][support] fix unittest

---
 llvm/include/llvm/Support/Mustache.h    |  4 ++--
 llvm/lib/Support/Mustache.cpp           |  7 ++++---
 llvm/unittests/Support/MustacheTest.cpp | 10 +++++-----
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index afde8d995cc147..6243e29f52282d 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -121,8 +121,8 @@ class ASTNode {
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, std::shared_ptr<ASTNode> Parent)
-      : T(T), Accessor(Accessor), Parent(Parent), LocalContext(nullptr),
-        Children({}) {};
+      : T(T), Parent(Parent), Children({}), Accessor(Accessor),
+        LocalContext(nullptr) {};
 
   void addChild(std::shared_ptr<ASTNode> Child) {
     Children.emplace_back(Child);
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index f0fb6767f6fcd5..7372a248d209bc 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -55,7 +55,7 @@ Token::Token(StringRef RawBody, StringRef InnerBody, char Identifier)
 }
 
 Token::Token(StringRef Str)
-    : RawBody(Str), TokenType(Type::Text), TokenBody(Str), Accessor({}) {}
+    : TokenType(Type::Text), RawBody(Str), Accessor({}), TokenBody(Str) {}
 
 Token::Type Token::getTokenType(char Identifier) {
   switch (Identifier) {
@@ -256,7 +256,7 @@ void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
 }
 
 Template Template::createTemplate(StringRef TemplateStr) {
-  Parser P = Parser(TemplateStr);
+  Parser P = Parser(TemplateStr.str());
   std::shared_ptr<ASTNode> MustacheTree = P.parse();
   Template T = Template(MustacheTree);
   // the default behaviour is to escape html entities
@@ -333,6 +333,7 @@ ASTNode::render(Value Data,
           Partial->render(Data, Partials, Lambdas, SectionLambdas, Escapes);
       return Result;
     }
+    return Result;
   }
   case Variable: {
     if (Lambdas.find(Accessor[0]) != Lambdas.end()) {
@@ -373,7 +374,7 @@ ASTNode::render(Value Data,
       if (isFalsey(Return))
         return Result;
       StringRef LambdaStr = printJson(Return);
-      Parser P = Parser(LambdaStr);
+      Parser P = Parser(LambdaStr.str());
       std::shared_ptr<ASTNode> LambdaNode = P.parse();
       return LambdaNode->render(Data, Partials, Lambdas, SectionLambdas,
                                 Escapes);
diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp
index c38a2ed2823379..33cbad56240faf 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/Mustache.h"
+#include "llvm/Support/raw_ostream.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -784,9 +785,8 @@ TEST(MustachePartials, PaddingWhitespace) {
 TEST(MustacheLambdas, BasicInterpolation) {
   Value D = Object{};
   auto T = Template::createTemplate("Hello, {{lambda}}!");
-  Lambda L = []() -> llvm::SmallString<128> {
-    llvm::SmallString<128> Result("World");
-    return Result;
+  Lambda L = []() -> llvm::json::Value {
+    return "World";
   };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);
@@ -796,8 +796,8 @@ TEST(MustacheLambdas, BasicInterpolation) {
 TEST(MustacheLambdas, InterpolationExpansion) {
   Value D = Object{{"planet", "World"}};
   auto T = Template::createTemplate("Hello, {{lambda}}!");
-  Lambda L = []() -> llvm::SmallString<128> {
-    return llvm::SmallString<128>("{{planet}}");
+  Lambda L = []() -> llvm::json::Value {
+    return "{{planet}}";
   };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);

>From 95ad7a6a0b128128b608606bd055f386d8162a5b Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Wed, 11 Sep 2024 18:50:01 -0400
Subject: [PATCH 21/57] [llvm][support] clang-format

---
 llvm/unittests/Support/MustacheTest.cpp | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp
index 33cbad56240faf..3f3f04a9b55b13 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -785,9 +785,7 @@ TEST(MustachePartials, PaddingWhitespace) {
 TEST(MustacheLambdas, BasicInterpolation) {
   Value D = Object{};
   auto T = Template::createTemplate("Hello, {{lambda}}!");
-  Lambda L = []() -> llvm::json::Value {
-    return "World";
-  };
+  Lambda L = []() -> llvm::json::Value { return "World"; };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);
   EXPECT_EQ("Hello, World!", Out);
@@ -796,9 +794,7 @@ TEST(MustacheLambdas, BasicInterpolation) {
 TEST(MustacheLambdas, InterpolationExpansion) {
   Value D = Object{{"planet", "World"}};
   auto T = Template::createTemplate("Hello, {{lambda}}!");
-  Lambda L = []() -> llvm::json::Value {
-    return "{{planet}}";
-  };
+  Lambda L = []() -> llvm::json::Value { return "{{planet}}"; };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);
   EXPECT_EQ("Hello, World!", Out);

>From bb3b1acfedc0776e922c36ddec1ed38b7d9af5cf Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Thu, 12 Sep 2024 06:02:49 -0400
Subject: [PATCH 22/57] [llvm][support] address mustache comments

---
 llvm/include/llvm/Support/Mustache.h    |  59 ++---
 llvm/lib/Support/Mustache.cpp           | 304 +++++++++++++-----------
 llvm/unittests/Support/MustacheTest.cpp | 275 ++++++++++-----------
 3 files changed, 316 insertions(+), 322 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 6243e29f52282d..607e33b4ec2c9b 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -26,24 +26,30 @@
 // - Parents
 // - Dynamic Names
 //
+// The Template class is container class outputs the Mustache template string
+// and is main class for users. It stores all the lambdas and the ASTNode Tree.
+// When the Template is instantiated it calls tokenize the Template String into 
+// the Token class and calls a basic recursive descent parser to construct the 
+// ASTNode Tree. The ASTNodes are all stored in an arena allocator which is 
+// freed once the template class goes out of scope
+//
 // Usage:
 // \code
 //   // Creating a simple template and rendering it
-//   auto Template = Template::createTemplate("Hello, {{name}}!");
+//   auto Template = Template("Hello, {{name}}!");
 //   Value Data = {{"name", "World"}};
 //   StringRef Rendered = Template.render(Data);
 //   // Rendered == "Hello, World!"
 //
 //   // Creating a template with a partial and rendering it
-//   auto Template = Template::createTemplate("{{>partial}}");
+//   auto Template = Template("{{>partial}}");
 //   Template.registerPartial("partial", "Hello, {{name}}!");
 //   Value Data = {{"name", "World"}};
 //   StringRef Rendered = Template.render(Data);
 //   // Rendered == "Hello, World!"
 //
 //   // Creating a template with a lambda and rendering it
-//   auto Template = Template::createTemplate("{{#lambda}}Hello,
-//                                             {{name}}!{{/lambda}}");
+//   auto Template = Template("{{#lambda}}Hello, {{name}}!{{/lambda}}");
 //   Template.registerLambda("lambda", []() { return true; });
 //   Value Data = {{"name", "World"}};
 //   StringRef Rendered = Template.render(Data);
@@ -56,13 +62,14 @@
 
 #include "Error.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Allocator.h"
 #include "llvm/Support/JSON.h"
 #include <vector>
 
 namespace llvm {
 namespace mustache {
 
-using Accessor = std::vector<SmallString<128>>;
+using Accessor = SmallVector<SmallString<128>>;
 using Lambda = std::function<llvm::json::Value()>;
 using SectionLambda = std::function<llvm::json::Value(StringRef)>;
 
@@ -114,19 +121,17 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), LocalContext(nullptr) {};
+  ASTNode() : T(Type::Root), LocalContext(nullptr){};
 
-  ASTNode(StringRef Body, std::shared_ptr<ASTNode> Parent)
-      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr) {};
+  ASTNode(StringRef Body, ASTNode *Parent)
+      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr){};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
-  ASTNode(Type T, Accessor Accessor, std::shared_ptr<ASTNode> Parent)
+  ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        LocalContext(nullptr) {};
+        LocalContext(nullptr){};
 
-  void addChild(std::shared_ptr<ASTNode> Child) {
-    Children.emplace_back(Child);
-  };
+  void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 
   SmallString<128> getBody() const { return Body; };
 
@@ -134,24 +139,20 @@ class ASTNode {
 
   void setRawBody(StringRef NewBody) { RawBody = NewBody; };
 
-  std::shared_ptr<ASTNode> getLastChild() const {
-    return Children.empty() ? nullptr : Children.back();
-  };
-
-  SmallString<128>
-  render(llvm::json::Value Data,
-         DenseMap<StringRef, std::shared_ptr<ASTNode>> &Partials,
-         DenseMap<StringRef, Lambda> &Lambdas,
-         DenseMap<StringRef, SectionLambda> &SectionLambdas,
-         DenseMap<char, StringRef> &Escapes);
+  SmallString<128> render(llvm::json::Value Data,
+                          llvm::BumpPtrAllocator &Allocator,
+                          DenseMap<StringRef, ASTNode *> &Partials,
+                          DenseMap<StringRef, Lambda> &Lambdas,
+                          DenseMap<StringRef, SectionLambda> &SectionLambdas,
+                          DenseMap<char, StringRef> &Escapes);
 
 private:
   llvm::json::Value findContext();
   Type T;
   SmallString<128> RawBody;
   SmallString<128> Body;
-  std::weak_ptr<ASTNode> Parent;
-  std::vector<std::shared_ptr<ASTNode>> Children;
+  ASTNode *Parent;
+  std::vector<ASTNode *> Children;
   const Accessor Accessor;
   llvm::json::Value LocalContext;
 };
@@ -160,7 +161,7 @@ class ASTNode {
 // and Lambdas that are registered with it.
 class Template {
 public:
-  static Template createTemplate(StringRef TemplateStr);
+  Template(StringRef TemplateStr);
 
   SmallString<128> render(llvm::json::Value Data);
 
@@ -176,12 +177,12 @@ class Template {
   void registerEscape(DenseMap<char, StringRef> Escapes);
 
 private:
-  Template(std::shared_ptr<ASTNode> Tree) : Tree(Tree) {};
-  DenseMap<StringRef, std::shared_ptr<ASTNode>> Partials;
+  DenseMap<StringRef, ASTNode *> Partials;
   DenseMap<StringRef, Lambda> Lambdas;
   DenseMap<StringRef, SectionLambda> SectionLambdas;
   DenseMap<char, StringRef> Escapes;
-  std::shared_ptr<ASTNode> Tree;
+  llvm::BumpPtrAllocator Allocator;
+  ASTNode *Tree;
 };
 
 } // namespace mustache
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 7372a248d209bc..dd6e5ebb19209c 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -25,31 +25,29 @@ SmallString<128> escapeString(StringRef Input,
   return EscapedString;
 }
 
-std::vector<SmallString<128>> split(StringRef Str, char Delimiter) {
-  std::vector<SmallString<128>> Tokens;
+Accessor split(StringRef Str, char Delimiter) {
+  Accessor Tokens;
   if (Str == ".") {
-    Tokens.push_back(Str);
+    Tokens.emplace_back(Str);
     return Tokens;
   }
   StringRef Ref(Str);
   while (!Ref.empty()) {
-    llvm::StringRef Part;
+    StringRef Part;
     std::tie(Part, Ref) = Ref.split(Delimiter);
-    Tokens.push_back(Part.trim());
+    Tokens.emplace_back(Part.trim());
   }
   return Tokens;
 }
 
 Token::Token(StringRef RawBody, StringRef InnerBody, char Identifier)
     : RawBody(RawBody), TokenBody(InnerBody) {
-
   TokenType = getTokenType(Identifier);
   if (TokenType == Type::Comment)
     return;
 
-  StringRef AccessorStr = InnerBody;
-  if (TokenType != Type::Variable)
-    AccessorStr = InnerBody.substr(1);
+  StringRef AccessorStr =
+      TokenType == Type::Variable ? InnerBody : InnerBody.substr(1);
 
   Accessor = split(AccessorStr.trim(), '.');
 }
@@ -76,86 +74,106 @@ Token::Type Token::getTokenType(char Identifier) {
   }
 }
 
-std::vector<Token> tokenize(StringRef Template) {
-  // Simple tokenizer that splits the template into tokens
-  // the mustache spec allows {{{ }}} to unescape variables
-  // but we don't support that here unescape variable
-  // is represented only by {{& variable}}
-  std::vector<Token> Tokens;
-  SmallString<128> Open("{{");
-  SmallString<128> Close("}}");
+// Function to check if there's no meaningful text behind
+bool noTextBehind(size_t Idx, const SmallVector<Token, 0> &Tokens) {
+  if (Idx == 0 || Tokens[Idx - 1].getType() != Token::Type::Text)
+    return false;
+  const Token &PrevToken = Tokens[Idx - 1];
+  StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
+  return TokenBody.ends_with("\n") || TokenBody.ends_with("\r\n") ||
+         (TokenBody.empty() && Idx == 1);
+}
+// Function to check if there's no meaningful text ahead
+bool noTextAhead(size_t Idx, const SmallVector<Token, 0> &Tokens) {
+  if (Idx >= Tokens.size() - 1 ||
+      Tokens[Idx + 1].getType() != Token::Type::Text)
+    return false;
+
+  const Token &NextToken = Tokens[Idx + 1];
+  StringRef TokenBody = NextToken.getRawBody().ltrim(" ");
+  return TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n");
+}
+
+// Simple tokenizer that splits the template into tokens
+// the mustache spec allows {{{ }}} to unescape variables
+// but we don't support that here unescape variable
+// is represented only by {{& variable}}
+SmallVector<Token, 0> tokenize(StringRef Template) {
+  SmallVector<Token, 0> Tokens;
+  StringRef Open("{{");
+  StringRef Close("}}");
   std::size_t Start = 0;
   std::size_t DelimiterStart = Template.find(Open);
   if (DelimiterStart == StringRef::npos) {
-    Tokens.push_back(Token(Template));
+    Tokens.emplace_back(Template);
     return Tokens;
   }
   while (DelimiterStart != StringRef::npos) {
     if (DelimiterStart != Start) {
-      Token TextToken = Token(Template.substr(Start, DelimiterStart - Start));
-      Tokens.push_back(TextToken);
+      Tokens.emplace_back(Template.substr(Start, DelimiterStart - Start));
     }
 
-    std::size_t DelimiterEnd = Template.find(Close, DelimiterStart);
+    size_t DelimiterEnd = Template.find(Close, DelimiterStart);
     if (DelimiterEnd == StringRef::npos) {
       break;
     }
 
+    // Extract the Interpolated variable without {{ and }}
+    size_t InterpolatedStart = DelimiterStart + Open.size();
+    size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.size();
     SmallString<128> Interpolated =
-        Template.substr(DelimiterStart + Open.size(),
-                        DelimiterEnd - DelimiterStart - Close.size());
+        Template.substr(InterpolatedStart, InterpolatedEnd);
     SmallString<128> RawBody;
     RawBody += Open;
     RawBody += Interpolated;
     RawBody += Close;
 
-    Tokens.push_back(Token(RawBody, Interpolated, Interpolated[0]));
+    Tokens.emplace_back(RawBody, Interpolated, Interpolated[0]);
     Start = DelimiterEnd + Close.size();
     DelimiterStart = Template.find(Open, Start);
   }
 
   if (Start < Template.size())
-    Tokens.push_back(Token(Template.substr(Start)));
+    Tokens.emplace_back(Template.substr(Start));
 
   // fix up white spaces for
   // open sections/inverted sections/close section/comment
-  for (std::size_t I = 0; I < Tokens.size(); I++) {
-    Token::Type CurrentType = Tokens[I].getType();
-    bool RequiresCleanUp = CurrentType == Token::Type::SectionOpen ||
-                           CurrentType == Token::Type::InvertSectionOpen ||
-                           CurrentType == Token::Type::SectionClose ||
-                           CurrentType == Token::Type::Comment ||
-                           CurrentType == Token::Type::Partial;
-
-    bool NoTextBehind = false;
-    bool NoTextAhead = false;
-    if (I > 0 && Tokens[I - 1].getType() == Token::Type::Text &&
-        RequiresCleanUp) {
-      Token &PrevToken = Tokens[I - 1];
-      StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
-      if (TokenBody.ends_with("\n") || TokenBody.ends_with("\r\n") ||
-          (TokenBody.empty() && I == 1))
-        NoTextBehind = true;
-    }
-    if (I < Tokens.size() - 1 && Tokens[I + 1].getType() == Token::Type::Text &&
-        RequiresCleanUp) {
-      Token &NextToken = Tokens[I + 1];
-      StringRef TokenBody = NextToken.getRawBody().ltrim(" ");
-      if (TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n"))
-        NoTextAhead = true;
-    }
+  // This loop attempts to find standalone tokens and tries to trim out
+  // the whitespace around them
+  // for example:
+  // if you have the template string
+  //  "Line 1\n {{#section}} \n Line 2 \n {{/section}} \n Line 3"
+  // The output would be
+  //  "Line 1\n Line 2\n Line 3"
+  size_t LastIdx = Tokens.size() - 1;
+  for (size_t Idx = 0, End = Tokens.size(); Idx < End; ++Idx) {
+    Token::Type CurrentType = Tokens[Idx].getType();
+    // Check if token type requires cleanup
+    bool RequiresCleanUp = (CurrentType == Token::Type::SectionOpen ||
+                            CurrentType == Token::Type::InvertSectionOpen ||
+                            CurrentType == Token::Type::SectionClose ||
+                            CurrentType == Token::Type::Comment ||
+                            CurrentType == Token::Type::Partial);
+
+    if (!RequiresCleanUp)
+      continue;
 
-    if ((NoTextBehind && NoTextAhead) || (NoTextAhead && I == 0)) {
-      Token &NextToken = Tokens[I + 1];
+    bool NoTextBehind = noTextBehind(Idx, Tokens);
+    bool NoTextAhead = noTextAhead(Idx, Tokens);
+
+    // Adjust next token body if no text ahead
+    if ((NoTextBehind && NoTextAhead) || (NoTextAhead && Idx == 0)) {
+      Token &NextToken = Tokens[Idx + 1];
       StringRef NextTokenBody = NextToken.getTokenBody();
-      if (NextTokenBody.starts_with("\r\n"))
+      if (NextTokenBody.starts_with("\r\n")) {
         NextToken.setTokenBody(NextTokenBody.substr(2));
-      else if (NextToken.getTokenBody().starts_with("\n"))
+      } else if (NextTokenBody.starts_with("\n")) {
         NextToken.setTokenBody(NextTokenBody.substr(1));
+      }
     }
-    if ((NoTextBehind && NoTextAhead) ||
-        (NoTextBehind && I == Tokens.size() - 1)) {
-      Token &PrevToken = Tokens[I - 1];
+    // Adjust previous token body if no text behind
+    if ((NoTextBehind && NoTextAhead) || (NoTextBehind && Idx == LastIdx)) {
+      Token &PrevToken = Tokens[Idx - 1];
       StringRef PrevTokenBody = PrevToken.getTokenBody();
       PrevToken.setTokenBody(PrevTokenBody.rtrim(" \t\v\t"));
     }
@@ -165,84 +183,87 @@ std::vector<Token> tokenize(StringRef Template) {
 
 class Parser {
 public:
-  Parser(StringRef TemplateStr) : TemplateStr(TemplateStr) {}
+  Parser(StringRef TemplateStr, BumpPtrAllocator &Allocator)
+      : Allocator(Allocator), TemplateStr(TemplateStr) {}
 
-  std::shared_ptr<ASTNode> parse();
+  ASTNode *parse();
 
 private:
-  void parseMustache(std::shared_ptr<ASTNode> Parent);
+  void parseMustache(ASTNode *Parent);
 
-  std::vector<Token> Tokens;
-  std::size_t CurrentPtr;
+  BumpPtrAllocator &Allocator;
+  SmallVector<Token, 0> Tokens;
+  size_t CurrentPtr;
   StringRef TemplateStr;
 };
 
-std::shared_ptr<ASTNode> Parser::parse() {
+ASTNode *Parser::parse() {
   Tokens = tokenize(TemplateStr);
   CurrentPtr = 0;
-  std::shared_ptr<ASTNode> Root = std::make_shared<ASTNode>();
-  parseMustache(Root);
-  return Root;
+  void *Root = Allocator.Allocate(sizeof(ASTNode), alignof(ASTNode));
+  ASTNode *RootNode = new (Root) ASTNode();
+  parseMustache(RootNode);
+  return RootNode;
 }
 
-void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
+void Parser::parseMustache(ASTNode *Parent) {
 
   while (CurrentPtr < Tokens.size()) {
     Token CurrentToken = Tokens[CurrentPtr];
     CurrentPtr++;
     Accessor A = CurrentToken.getAccessor();
-    std::shared_ptr<ASTNode> CurrentNode;
+    ASTNode *CurrentNode;
+    void *Node = Allocator.Allocate(sizeof(ASTNode), alignof(ASTNode));
 
     switch (CurrentToken.getType()) {
     case Token::Type::Text: {
-      CurrentNode =
-          std::make_shared<ASTNode>(CurrentToken.getTokenBody(), Parent);
+      CurrentNode = new (Node) ASTNode(CurrentToken.getTokenBody(), Parent);
       Parent->addChild(CurrentNode);
       break;
     }
     case Token::Type::Variable: {
-      CurrentNode = std::make_shared<ASTNode>(ASTNode::Variable, A, Parent);
+      CurrentNode = new (Node) ASTNode(ASTNode::Variable, A, Parent);
       Parent->addChild(CurrentNode);
       break;
     }
     case Token::Type::UnescapeVariable: {
-      CurrentNode =
-          std::make_shared<ASTNode>(ASTNode::UnescapeVariable, A, Parent);
+      CurrentNode = new (Node) ASTNode(ASTNode::UnescapeVariable, A, Parent);
       Parent->addChild(CurrentNode);
       break;
     }
     case Token::Type::Partial: {
-      CurrentNode = std::make_shared<ASTNode>(ASTNode::Partial, A, Parent);
+      CurrentNode = new (Node) ASTNode(ASTNode::Partial, A, Parent);
       Parent->addChild(CurrentNode);
       break;
     }
     case Token::Type::SectionOpen: {
-      CurrentNode = std::make_shared<ASTNode>(ASTNode::Section, A, Parent);
-      std::size_t Start = CurrentPtr;
+      CurrentNode = new (Node) ASTNode(ASTNode::Section, A, Parent);
+      size_t Start = CurrentPtr;
       parseMustache(CurrentNode);
-      std::size_t End = CurrentPtr;
+      size_t End = CurrentPtr;
       SmallString<128> RawBody;
-      if (Start + 1 < End - 1)
+      if (Start + 1 < End - 1) {
         for (std::size_t I = Start + 1; I < End - 1; I++)
           RawBody += Tokens[I].getRawBody();
-      else if (Start + 1 == End - 1)
+      } else if (Start + 1 == End - 1) {
         RawBody = Tokens[Start].getRawBody();
+      }
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
       break;
     }
     case Token::Type::InvertSectionOpen: {
-      CurrentNode =
-          std::make_shared<ASTNode>(ASTNode::InvertSection, A, Parent);
-      std::size_t Start = CurrentPtr;
+      CurrentNode = new (Node) ASTNode(ASTNode::InvertSection, A, Parent);
+      size_t Start = CurrentPtr;
       parseMustache(CurrentNode);
-      std::size_t End = CurrentPtr;
+      size_t End = CurrentPtr;
       SmallString<128> RawBody;
-      if (Start + 1 < End - 1)
-        for (std::size_t I = Start + 1; I < End - 1; I++)
-          RawBody += Tokens[I].getRawBody();
-      else if (Start + 1 == End - 1)
+      if (Start + 1 < End - 1) {
+        for (size_t Idx = Start + 1; Idx < End - 1; Idx++)
+          RawBody += Tokens[Idx].getRawBody();
+      } else if (Start + 1 == End - 1) {
         RawBody = Tokens[Start].getRawBody();
+      }
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
       break;
@@ -255,27 +276,15 @@ void Parser::parseMustache(std::shared_ptr<ASTNode> Parent) {
   }
 }
 
-Template Template::createTemplate(StringRef TemplateStr) {
-  Parser P = Parser(TemplateStr.str());
-  std::shared_ptr<ASTNode> MustacheTree = P.parse();
-  Template T = Template(MustacheTree);
-  // the default behaviour is to escape html entities
-  DenseMap<char, StringRef> HtmlEntities = {{'&', "&"},
-                                            {'<', "<"},
-                                            {'>', ">"},
-                                            {'"', """},
-                                            {'\'', "'"}};
-  T.registerEscape(HtmlEntities);
-  return T;
-}
-
 SmallString<128> Template::render(Value Data) {
-  return Tree->render(Data, Partials, Lambdas, SectionLambdas, Escapes);
+  BumpPtrAllocator LocalAllocator;
+  return Tree->render(Data, LocalAllocator, Partials, Lambdas, SectionLambdas,
+                      Escapes);
 }
 
 void Template::registerPartial(StringRef Name, StringRef Partial) {
-  Parser P = Parser(Partial);
-  std::shared_ptr<ASTNode> PartialTree = P.parse();
+  Parser P = Parser(Partial, Allocator);
+  ASTNode *PartialTree = P.parse();
   Partials[Name] = PartialTree;
 }
 
@@ -287,6 +296,18 @@ void Template::registerLambda(StringRef Name, SectionLambda L) {
 
 void Template::registerEscape(DenseMap<char, StringRef> E) { Escapes = E; }
 
+Template::Template(StringRef TemplateStr) {
+  Parser P = Parser(TemplateStr, Allocator);
+  Tree = P.parse();
+  // the default behaviour is to escape html entities
+  DenseMap<char, StringRef> HtmlEntities = {{'&', "&"},
+                                            {'<', "<"},
+                                            {'>', ">"},
+                                            {'"', """},
+                                            {'\'', "'"}};
+  registerEscape(HtmlEntities);
+}
+
 SmallString<128> printJson(Value &Data) {
 
   SmallString<128> Result;
@@ -299,7 +320,7 @@ SmallString<128> printJson(Value &Data) {
     Result += Data.getAsString()->str();
     return Result;
   }
-  return llvm::formatv("{0:2}", Data);
+  return formatv("{0:2}", Data);
 }
 
 bool isFalsey(Value &V) {
@@ -309,8 +330,8 @@ bool isFalsey(Value &V) {
 }
 
 SmallString<128>
-ASTNode::render(Value Data,
-                DenseMap<StringRef, std::shared_ptr<ASTNode>> &Partials,
+ASTNode::render(Value Data, BumpPtrAllocator &Allocator,
+                DenseMap<StringRef, ASTNode *> &Partials,
                 DenseMap<StringRef, Lambda> &Lambdas,
                 DenseMap<StringRef, SectionLambda> &SectionLambdas,
                 DenseMap<char, StringRef> &Escapes) {
@@ -319,18 +340,18 @@ ASTNode::render(Value Data,
   SmallString<128> Result;
   switch (T) {
   case Root: {
-    for (std::shared_ptr<ASTNode> Child : Children)
-      Result +=
-          Child->render(Context, Partials, Lambdas, SectionLambdas, Escapes);
+    for (ASTNode *Child : Children)
+      Result += Child->render(Context, Allocator, Partials, Lambdas,
+                              SectionLambdas, Escapes);
     return Result;
   }
   case Text:
     return Body;
   case Partial: {
     if (Partials.find(Accessor[0]) != Partials.end()) {
-      std::shared_ptr<ASTNode> Partial = Partials[Accessor[0]];
-      Result +=
-          Partial->render(Data, Partials, Lambdas, SectionLambdas, Escapes);
+      ASTNode *Partial = Partials[Accessor[0]];
+      Result += Partial->render(Data, Allocator, Partials, Lambdas,
+                                SectionLambdas, Escapes);
       return Result;
     }
     return Result;
@@ -340,10 +361,10 @@ ASTNode::render(Value Data,
       Lambda &L = Lambdas[Accessor[0]];
       Value LambdaResult = L();
       StringRef LambdaStr = printJson(LambdaResult);
-      Parser P = Parser(LambdaStr);
-      std::shared_ptr<ASTNode> LambdaNode = P.parse();
-      SmallString<128> RenderStr =
-          LambdaNode->render(Data, Partials, Lambdas, SectionLambdas, Escapes);
+      Parser P = Parser(LambdaStr, Allocator);
+      ASTNode *LambdaNode = P.parse();
+      SmallString<128> RenderStr = LambdaNode->render(
+          Data, Allocator, Partials, Lambdas, SectionLambdas, Escapes);
       return escapeString(RenderStr, Escapes);
     }
     return escapeString(printJson(Context), Escapes);
@@ -353,56 +374,51 @@ ASTNode::render(Value Data,
       Lambda &L = Lambdas[Accessor[0]];
       Value LambdaResult = L();
       StringRef LambdaStr = printJson(LambdaResult);
-      Parser P = Parser(LambdaStr);
-      std::shared_ptr<ASTNode> LambdaNode = P.parse();
+      Parser P = Parser(LambdaStr, Allocator);
+      ASTNode *LambdaNode = P.parse();
       DenseMap<char, StringRef> EmptyEscapes;
-      return LambdaNode->render(Data, Partials, Lambdas, SectionLambdas,
-                                EmptyEscapes);
+      return LambdaNode->render(Data, Allocator, Partials, Lambdas,
+                                SectionLambdas, EmptyEscapes);
     }
     return printJson(Context);
   }
   case Section: {
     // Sections are not rendered if the context is falsey
     bool IsLambda = SectionLambdas.find(Accessor[0]) != SectionLambdas.end();
-
     if (isFalsey(Context) && !IsLambda)
       return Result;
-
     if (IsLambda) {
       SectionLambda &Lambda = SectionLambdas[Accessor[0]];
       Value Return = Lambda(RawBody);
       if (isFalsey(Return))
         return Result;
       StringRef LambdaStr = printJson(Return);
-      Parser P = Parser(LambdaStr.str());
-      std::shared_ptr<ASTNode> LambdaNode = P.parse();
-      return LambdaNode->render(Data, Partials, Lambdas, SectionLambdas,
-                                Escapes);
+      Parser P = Parser(LambdaStr.str(), Allocator);
+      ASTNode *LambdaNode = P.parse();
+      return LambdaNode->render(Data, Allocator, Partials, Lambdas,
+                                SectionLambdas, Escapes);
     }
-
     if (Context.getAsArray()) {
       json::Array *Arr = Context.getAsArray();
       for (Value &V : *Arr) {
-        for (std::shared_ptr<ASTNode> Child : Children)
-          Result +=
-              Child->render(V, Partials, Lambdas, SectionLambdas, Escapes);
+        for (ASTNode *Child : Children)
+          Result += Child->render(V, Allocator, Partials, Lambdas,
+                                  SectionLambdas, Escapes);
       }
       return Result;
     }
-
-    for (std::shared_ptr<ASTNode> Child : Children)
-      Result +=
-          Child->render(Context, Partials, Lambdas, SectionLambdas, Escapes);
-
+    for (ASTNode *Child : Children)
+      Result += Child->render(Context, Allocator, Partials, Lambdas,
+                              SectionLambdas, Escapes);
     return Result;
   }
   case InvertSection: {
     bool IsLambda = SectionLambdas.find(Accessor[0]) != SectionLambdas.end();
     if (!isFalsey(Context) || IsLambda)
       return Result;
-    for (std::shared_ptr<ASTNode> Child : Children)
-      Result +=
-          Child->render(Context, Partials, Lambdas, SectionLambdas, Escapes);
+    for (ASTNode *Child : Children)
+      Result += Child->render(Context, Allocator, Partials, Lambdas,
+                              SectionLambdas, Escapes);
     return Result;
   }
   }
@@ -420,13 +436,13 @@ Value ASTNode::findContext() {
   if (Accessor[0] == ".")
     return LocalContext;
   json::Object *CurrentContext = LocalContext.getAsObject();
-  SmallString<128> CurrentAccessor = Accessor[0];
-  std::weak_ptr<ASTNode> CurrentParent = Parent;
+  StringRef CurrentAccessor = Accessor[0];
+  ASTNode *CurrentParent = Parent;
 
   while (!CurrentContext || !CurrentContext->get(CurrentAccessor)) {
-    if (auto Ptr = CurrentParent.lock()) {
-      CurrentContext = Ptr->LocalContext.getAsObject();
-      CurrentParent = Ptr->Parent;
+    if (CurrentParent->T != Root) {
+      CurrentContext = CurrentParent->LocalContext.getAsObject();
+      CurrentParent = CurrentParent->Parent;
       continue;
     }
     return nullptr;
diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp
index 3f3f04a9b55b13..d120736be40856 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -22,7 +22,7 @@ using namespace llvm::json;
 TEST(MustacheInterpolation, NoInterpolation) {
   // Mustache-free templates should render as-is.
   Value D = {};
-  auto T = Template::createTemplate("Hello from {Mustache}!\n");
+  auto T = Template("Hello from {Mustache}!\n");
   auto Out = T.render(D);
   EXPECT_EQ("Hello from {Mustache}!\n", Out);
 }
@@ -30,7 +30,7 @@ TEST(MustacheInterpolation, NoInterpolation) {
 TEST(MustacheInterpolation, BasicInterpolation) {
   // Unadorned tags should interpolate content into the template.
   Value D = Object{{"subject", "World"}};
-  auto T = Template::createTemplate("Hello, {{subject}}!");
+  auto T = Template("Hello, {{subject}}!");
   auto Out = T.render(D);
   EXPECT_EQ("Hello, World!", Out);
 }
@@ -38,7 +38,7 @@ TEST(MustacheInterpolation, BasicInterpolation) {
 TEST(MustacheInterpolation, NoReinterpolation) {
   // Interpolated tag output should not be re-interpolated.
   Value D = Object{{"template", "{{planet}}"}, {"planet", "Earth"}};
-  auto T = Template::createTemplate("{{template}}: {{planet}}");
+  auto T = Template("{{template}}: {{planet}}");
   auto Out = T.render(D);
   EXPECT_EQ("{{planet}}: Earth", Out);
 }
@@ -48,8 +48,7 @@ TEST(MustacheInterpolation, HTMLEscaping) {
   Value D = Object{
       {"forbidden", "& \" < >"},
   };
-  auto T = Template::createTemplate(
-      "These characters should be HTML escaped: {{forbidden}}\n");
+  auto T = Template("These characters should be HTML escaped: {{forbidden}}\n");
   auto Out = T.render(D);
   EXPECT_EQ("These characters should be HTML escaped: & " < >\n",
             Out);
@@ -60,8 +59,8 @@ TEST(MustacheInterpolation, Ampersand) {
   Value D = Object{
       {"forbidden", "& \" < >"},
   };
-  auto T = Template::createTemplate(
-      "These characters should not be HTML escaped: {{&forbidden}}\n");
+  auto T =
+      Template("These characters should not be HTML escaped: {{&forbidden}}\n");
   auto Out = T.render(D);
   EXPECT_EQ("These characters should not be HTML escaped: & \" < >\n", Out);
 }
@@ -69,7 +68,7 @@ TEST(MustacheInterpolation, Ampersand) {
 TEST(MustacheInterpolation, BasicIntegerInterpolation) {
   // Integers should interpolate seamlessly.
   Value D = Object{{"mph", 85}};
-  auto T = Template::createTemplate("{{mph}} miles an hour!");
+  auto T = Template("{{mph}} miles an hour!");
   auto Out = T.render(D);
   EXPECT_EQ("85 miles an hour!", Out);
 }
@@ -77,7 +76,7 @@ TEST(MustacheInterpolation, BasicIntegerInterpolation) {
 TEST(MustacheInterpolation, AmpersandIntegerInterpolation) {
   // Integers should interpolate seamlessly.
   Value D = Object{{"mph", 85}};
-  auto T = Template::createTemplate("{{&mph}} miles an hour!");
+  auto T = Template("{{&mph}} miles an hour!");
   auto Out = T.render(D);
   EXPECT_EQ("85 miles an hour!", Out);
 }
@@ -85,7 +84,7 @@ TEST(MustacheInterpolation, AmpersandIntegerInterpolation) {
 TEST(MustacheInterpolation, BasicDecimalInterpolation) {
   // Decimals should interpolate seamlessly with proper significance.
   Value D = Object{{"power", 1.21}};
-  auto T = Template::createTemplate("{{power}} jiggawatts!");
+  auto T = Template("{{power}} jiggawatts!");
   auto Out = T.render(D);
   EXPECT_EQ("1.21 jiggawatts!", Out);
 }
@@ -93,7 +92,7 @@ TEST(MustacheInterpolation, BasicDecimalInterpolation) {
 TEST(MustacheInterpolation, BasicNullInterpolation) {
   // Nulls should interpolate as the empty string.
   Value D = Object{{"cannot", nullptr}};
-  auto T = Template::createTemplate("I ({{cannot}}) be seen!");
+  auto T = Template("I ({{cannot}}) be seen!");
   auto Out = T.render(D);
   EXPECT_EQ("I () be seen!", Out);
 }
@@ -101,7 +100,7 @@ TEST(MustacheInterpolation, BasicNullInterpolation) {
 TEST(MustacheInterpolation, AmpersandNullInterpolation) {
   // Nulls should interpolate as the empty string.
   Value D = Object{{"cannot", nullptr}};
-  auto T = Template::createTemplate("I ({{&cannot}}) be seen!");
+  auto T = Template("I ({{&cannot}}) be seen!");
   auto Out = T.render(D);
   EXPECT_EQ("I () be seen!", Out);
 }
@@ -109,7 +108,7 @@ TEST(MustacheInterpolation, AmpersandNullInterpolation) {
 TEST(MustacheInterpolation, BasicContextMissInterpolation) {
   // Failed context lookups should default to empty strings.
   Value D = Object{};
-  auto T = Template::createTemplate("I ({{cannot}}) be seen!");
+  auto T = Template("I ({{cannot}}) be seen!");
   auto Out = T.render(D);
   EXPECT_EQ("I () be seen!", Out);
 }
@@ -117,8 +116,7 @@ TEST(MustacheInterpolation, BasicContextMissInterpolation) {
 TEST(MustacheInterpolation, DottedNamesBasicInterpolation) {
   // Dotted names should be considered a form of shorthand for sections.
   Value D = Object{{"person", Object{{"name", "Joe"}}}};
-  auto T = Template::createTemplate(
-      "{{person.name}} == {{#person}}{{name}}{{/person}}");
+  auto T = Template("{{person.name}} == {{#person}}{{name}}{{/person}}");
   auto Out = T.render(D);
   EXPECT_EQ("Joe == Joe", Out);
 }
@@ -126,8 +124,7 @@ TEST(MustacheInterpolation, DottedNamesBasicInterpolation) {
 TEST(MustacheInterpolation, DottedNamesAmpersandInterpolation) {
   // Dotted names should be considered a form of shorthand for sections.
   Value D = Object{{"person", Object{{"name", "Joe"}}}};
-  auto T = Template::createTemplate(
-      "{{&person.name}} == {{#person}}{{&name}}{{/person}}");
+  auto T = Template("{{&person.name}} == {{#person}}{{&name}}{{/person}}");
   auto Out = T.render(D);
   EXPECT_EQ("Joe == Joe", Out);
 }
@@ -140,7 +137,7 @@ TEST(MustacheInterpolation, DottedNamesArbitraryDepth) {
                Object{{"c",
                        Object{{"d",
                                Object{{"e", Object{{"name", "Phil"}}}}}}}}}}}};
-  auto T = Template::createTemplate("{{a.b.c.d.e.name}}");
+  auto T = Template("{{a.b.c.d.e.name}}");
   auto Out = T.render(D);
   EXPECT_EQ("Phil", Out);
 }
@@ -148,7 +145,7 @@ TEST(MustacheInterpolation, DottedNamesArbitraryDepth) {
 TEST(MustacheInterpolation, DottedNamesBrokenChains) {
   // Any falsey value prior to the last part of the name should yield ''.
   Value D = Object{{"a", Object{}}};
-  auto T = Template::createTemplate("{{a.b.c}} == ");
+  auto T = Template("{{a.b.c}} == ");
   auto Out = T.render(D);
   EXPECT_EQ(" == ", Out);
 }
@@ -157,7 +154,7 @@ TEST(MustacheInterpolation, DottedNamesBrokenChainResolution) {
   // Each part of a dotted name should resolve only against its parent.
   Value D =
       Object{{"a", Object{{"b", Object{}}}}, {"c", Object{{"name", "Jim"}}}};
-  auto T = Template::createTemplate("{{a.b.c.name}} == ");
+  auto T = Template("{{a.b.c.name}} == ");
   auto Out = T.render(D);
   EXPECT_EQ(" == ", Out);
 }
@@ -172,7 +169,7 @@ TEST(MustacheInterpolation, DottedNamesInitialResolution) {
                     Object{{"d", Object{{"e", Object{{"name", "Phil"}}}}}}}}}}},
       {"b",
        Object{{"c", Object{{"d", Object{{"e", Object{{"name", "Wrong"}}}}}}}}}};
-  auto T = Template::createTemplate("{{#a}}{{b.c.d.e.name}}{{/a}}");
+  auto T = Template("{{#a}}{{b.c.d.e.name}}{{/a}}");
   auto Out = T.render(D);
   EXPECT_EQ("Phil", Out);
 }
@@ -181,7 +178,7 @@ TEST(MustacheInterpolation, DottedNamesContextPrecedence) {
   // Dotted names should be resolved against former resolutions.
   Value D =
       Object{{"a", Object{{"b", Object{}}}}, {"b", Object{{"c", "ERROR"}}}};
-  auto T = Template::createTemplate("{{#a}}{{b.c}}{{/a}}");
+  auto T = Template("{{#a}}{{b.c}}{{/a}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
@@ -189,7 +186,7 @@ TEST(MustacheInterpolation, DottedNamesContextPrecedence) {
 TEST(MustacheInterpolation, DottedNamesAreNotSingleKeys) {
   // Dotted names shall not be parsed as single, atomic keys
   Value D = Object{{"a.b", "c"}};
-  auto T = Template::createTemplate("{{a.b}}");
+  auto T = Template("{{a.b}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
@@ -197,7 +194,7 @@ TEST(MustacheInterpolation, DottedNamesAreNotSingleKeys) {
 TEST(MustacheInterpolation, DottedNamesNoMasking) {
   // Dotted Names in a given context are unavailable due to dot splitting
   Value D = Object{{"a.b", "c"}, {"a", Object{{"b", "d"}}}};
-  auto T = Template::createTemplate("{{a.b}}");
+  auto T = Template("{{a.b}}");
   auto Out = T.render(D);
   EXPECT_EQ("d", Out);
 }
@@ -205,7 +202,7 @@ TEST(MustacheInterpolation, DottedNamesNoMasking) {
 TEST(MustacheInterpolation, ImplicitIteratorsBasicInterpolation) {
   // Unadorned tags should interpolate content into the template.
   Value D = "world";
-  auto T = Template::createTemplate("Hello, {{.}}!\n");
+  auto T = Template("Hello, {{.}}!\n");
   auto Out = T.render(D);
   EXPECT_EQ("Hello, world!\n", Out);
 }
@@ -213,8 +210,7 @@ TEST(MustacheInterpolation, ImplicitIteratorsBasicInterpolation) {
 TEST(MustacheInterpolation, ImplicitIteratorsAmersand) {
   // Basic interpolation should be HTML escaped.
   Value D = "& \" < >";
-  auto T = Template::createTemplate(
-      "These characters should not be HTML escaped: {{&.}}\n");
+  auto T = Template("These characters should not be HTML escaped: {{&.}}\n");
   auto Out = T.render(D);
   EXPECT_EQ("These characters should not be HTML escaped: & \" < >\n", Out);
 }
@@ -222,7 +218,7 @@ TEST(MustacheInterpolation, ImplicitIteratorsAmersand) {
 TEST(MustacheInterpolation, ImplicitIteratorsInteger) {
   // Integers should interpolate seamlessly.
   Value D = 85;
-  auto T = Template::createTemplate("{{.}} miles an hour!\n");
+  auto T = Template("{{.}} miles an hour!\n");
   auto Out = T.render(D);
   EXPECT_EQ("85 miles an hour!\n", Out);
 }
@@ -230,7 +226,7 @@ TEST(MustacheInterpolation, ImplicitIteratorsInteger) {
 TEST(MustacheInterpolation, InterpolationSurroundingWhitespace) {
   // Interpolation should not alter surrounding whitespace.
   Value D = Object{{"string", "---"}};
-  auto T = Template::createTemplate("| {{string}} |");
+  auto T = Template("| {{string}} |");
   auto Out = T.render(D);
   EXPECT_EQ("| --- |", Out);
 }
@@ -238,7 +234,7 @@ TEST(MustacheInterpolation, InterpolationSurroundingWhitespace) {
 TEST(MustacheInterpolation, AmersandSurroundingWhitespace) {
   // Interpolation should not alter surrounding whitespace.
   Value D = Object{{"string", "---"}};
-  auto T = Template::createTemplate("| {{&string}} |");
+  auto T = Template("| {{&string}} |");
   auto Out = T.render(D);
   EXPECT_EQ("| --- |", Out);
 }
@@ -246,7 +242,7 @@ TEST(MustacheInterpolation, AmersandSurroundingWhitespace) {
 TEST(MustacheInterpolation, StandaloneInterpolationWithWhitespace) {
   // Standalone interpolation should not alter surrounding whitespace.
   Value D = Object{{"string", "---"}};
-  auto T = Template::createTemplate("  {{string}}\n");
+  auto T = Template("  {{string}}\n");
   auto Out = T.render(D);
   EXPECT_EQ("  ---\n", Out);
 }
@@ -254,7 +250,7 @@ TEST(MustacheInterpolation, StandaloneInterpolationWithWhitespace) {
 TEST(MustacheInterpolation, StandaloneAmpersandWithWhitespace) {
   // Standalone interpolation should not alter surrounding whitespace.
   Value D = Object{{"string", "---"}};
-  auto T = Template::createTemplate("  {{&string}}\n");
+  auto T = Template("  {{&string}}\n");
   auto Out = T.render(D);
   EXPECT_EQ("  ---\n", Out);
 }
@@ -262,7 +258,7 @@ TEST(MustacheInterpolation, StandaloneAmpersandWithWhitespace) {
 TEST(MustacheInterpolation, InterpolationWithPadding) {
   // Superfluous in-tag whitespace should be ignored.
   Value D = Object{{"string", "---"}};
-  auto T = Template::createTemplate("|{{ string }}|");
+  auto T = Template("|{{ string }}|");
   auto Out = T.render(D);
   EXPECT_EQ("|---|", Out);
 }
@@ -270,7 +266,7 @@ TEST(MustacheInterpolation, InterpolationWithPadding) {
 TEST(MustacheInterpolation, AmpersandWithPadding) {
   // Superfluous in-tag whitespace should be ignored.
   Value D = Object{{"string", "---"}};
-  auto T = Template::createTemplate("|{{& string }}|");
+  auto T = Template("|{{& string }}|");
   auto Out = T.render(D);
   EXPECT_EQ("|---|", Out);
 }
@@ -278,38 +274,35 @@ TEST(MustacheInterpolation, AmpersandWithPadding) {
 TEST(MustacheInterpolation, InterpolationWithPaddingAndNewlines) {
   // Superfluous in-tag whitespace should be ignored.
   Value D = Object{{"string", "---"}};
-  auto T = Template::createTemplate("|{{ string \n\n\n }}|");
+  auto T = Template("|{{ string \n\n\n }}|");
   auto Out = T.render(D);
   EXPECT_EQ("|---|", Out);
 }
 
 TEST(MustacheSections, Truthy) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate(
-      "{{#boolean}}This should be rendered.{{/boolean}}");
+  auto T = Template("{{#boolean}}This should be rendered.{{/boolean}}");
   auto Out = T.render(D);
   EXPECT_EQ("This should be rendered.", Out);
 }
 
 TEST(MustacheSections, Falsey) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate(
-      "{{#boolean}}This should not be rendered.{{/boolean}}");
+  auto T = Template("{{#boolean}}This should not be rendered.{{/boolean}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
 
 TEST(MustacheSections, NullIsFalsey) {
   Value D = Object{{"null", nullptr}};
-  auto T = Template::createTemplate(
-      "{{#null}}This should not be rendered.{{/null}}");
+  auto T = Template("{{#null}}This should not be rendered.{{/null}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
 
 TEST(MustacheSections, Context) {
   Value D = Object{{"context", Object{{"name", "Joe"}}}};
-  auto T = Template::createTemplate("{{#context}}Hi {{name}}.{{/context}}");
+  auto T = Template("{{#context}}Hi {{name}}.{{/context}}");
   auto Out = T.render(D);
   EXPECT_EQ("Hi Joe.", Out);
 }
@@ -319,14 +312,14 @@ TEST(MustacheSections, ParentContexts) {
                    {"b", "wrong"},
                    {"sec", Object{{"b", "bar"}}},
                    {"c", Object{{"d", "baz"}}}};
-  auto T = Template::createTemplate("{{#sec}}{{a}}, {{b}}, {{c.d}}{{/sec}}");
+  auto T = Template("{{#sec}}{{a}}, {{b}}, {{c.d}}{{/sec}}");
   auto Out = T.render(D);
   EXPECT_EQ("foo, bar, baz", Out);
 }
 
 TEST(MustacheSections, VariableTest) {
   Value D = Object{{"foo", "bar"}};
-  auto T = Template::createTemplate("{{#foo}}{{.}} is {{foo}}{{/foo}}");
+  auto T = Template("{{#foo}}{{.}} is {{foo}}{{/foo}}");
   auto Out = T.render(D);
   EXPECT_EQ("bar is bar", Out);
 }
@@ -340,14 +333,14 @@ TEST(MustacheSections, ListContexts) {
             Array{Object{{"mname", "1"},
                          {"bottoms", Array{Object{{"bname", "x"}},
                                            Object{{"bname", "y"}}}}}}}}}}};
-  auto T = Template::createTemplate("{{#tops}}"
-                                    "{{#middles}}"
-                                    "{{tname.lower}}{{mname}}."
-                                    "{{#bottoms}}"
-                                    "{{tname.upper}}{{mname}}{{bname}}."
-                                    "{{/bottoms}}"
-                                    "{{/middles}}"
-                                    "{{/tops}}");
+  auto T = Template("{{#tops}}"
+                    "{{#middles}}"
+                    "{{tname.lower}}{{mname}}."
+                    "{{#bottoms}}"
+                    "{{tname.upper}}{{mname}}{{bname}}."
+                    "{{/bottoms}}"
+                    "{{/middles}}"
+                    "{{/tops}}");
   auto Out = T.render(D);
   EXPECT_EQ("a1.A1x.A1y.", Out);
 }
@@ -357,7 +350,7 @@ TEST(MustacheSections, DeeplyNestedContexts) {
       {"a", Object{{"one", 1}}},
       {"b", Object{{"two", 2}}},
       {"c", Object{{"three", 3}, {"d", Object{{"four", 4}, {"five", 5}}}}}};
-  auto T = Template::createTemplate(
+  auto T = Template(
       "{{#a}}\n{{one}}\n{{#b}}\n{{one}}{{two}}{{one}}\n{{#c}}\n{{one}}{{two}}{{"
       "three}}{{two}}{{one}}\n{{#d}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{"
       "{two}}{{one}}\n{{#five}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{four}"
@@ -376,123 +369,120 @@ TEST(MustacheSections, DeeplyNestedContexts) {
 TEST(MustacheSections, List) {
   Value D = Object{{"list", Array{Object{{"item", 1}}, Object{{"item", 2}},
                                   Object{{"item", 3}}}}};
-  auto T = Template::createTemplate("{{#list}}{{item}}{{/list}}");
+  auto T = Template("{{#list}}{{item}}{{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("123", Out);
 }
 
 TEST(MustacheSections, EmptyList) {
   Value D = Object{{"list", Array{}}};
-  auto T = Template::createTemplate("{{#list}}Yay lists!{{/list}}");
+  auto T = Template("{{#list}}Yay lists!{{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
 
 TEST(MustacheSections, Doubled) {
   Value D = Object{{"bool", true}, {"two", "second"}};
-  auto T = Template::createTemplate("{{#bool}}\n* first\n{{/bool}}\n* "
-                                    "{{two}}\n{{#bool}}\n* third\n{{/bool}}\n");
+  auto T = Template("{{#bool}}\n* first\n{{/bool}}\n* "
+                    "{{two}}\n{{#bool}}\n* third\n{{/bool}}\n");
   auto Out = T.render(D);
   EXPECT_EQ("* first\n* second\n* third\n", Out);
 }
 
 TEST(MustacheSections, NestedTruthy) {
   Value D = Object{{"bool", true}};
-  auto T = Template::createTemplate(
-      "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |");
+  auto T = Template("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |");
   auto Out = T.render(D);
   EXPECT_EQ("| A B C D E |", Out);
 }
 
 TEST(MustacheSections, NestedFalsey) {
   Value D = Object{{"bool", false}};
-  auto T = Template::createTemplate(
-      "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |");
+  auto T = Template("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |");
   auto Out = T.render(D);
   EXPECT_EQ("| A  E |", Out);
 }
 
 TEST(MustacheSections, ContextMisses) {
   Value D = Object{};
-  auto T = Template::createTemplate(
-      "[{{#missing}}Found key 'missing'!{{/missing}}]");
+  auto T = Template("[{{#missing}}Found key 'missing'!{{/missing}}]");
   auto Out = T.render(D);
   EXPECT_EQ("[]", Out);
 }
 
 TEST(MustacheSections, ImplicitIteratorString) {
   Value D = Object{{"list", Array{"a", "b", "c", "d", "e"}}};
-  auto T = Template::createTemplate("{{#list}}({{.}}){{/list}}");
+  auto T = Template("{{#list}}({{.}}){{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("(a)(b)(c)(d)(e)", Out);
 }
 
 TEST(MustacheSections, ImplicitIteratorInteger) {
   Value D = Object{{"list", Array{1, 2, 3, 4, 5}}};
-  auto T = Template::createTemplate("{{#list}}({{.}}){{/list}}");
+  auto T = Template("{{#list}}({{.}}){{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("(1)(2)(3)(4)(5)", Out);
 }
 
 TEST(MustacheSections, ImplicitIteratorArray) {
   Value D = Object{{"list", Array{Array{1, 2, 3}, Array{"a", "b", "c"}}}};
-  auto T = Template::createTemplate("{{#list}}({{#.}}{{.}}{{/.}}){{/list}}");
+  auto T = Template("{{#list}}({{#.}}{{.}}{{/.}}){{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("(123)(abc)", Out);
 }
 
 TEST(MustacheSections, ImplicitIteratorHTMLEscaping) {
   Value D = Object{{"list", Array{"&", "\"", "<", ">"}}};
-  auto T = Template::createTemplate("{{#list}}({{.}}){{/list}}");
+  auto T = Template("{{#list}}({{.}}){{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("(&)(")(<)(>)", Out);
 }
 
 TEST(MustacheSections, ImplicitIteratorAmpersand) {
   Value D = Object{{"list", Array{"&", "\"", "<", ">"}}};
-  auto T = Template::createTemplate("{{#list}}({{&.}}){{/list}}");
+  auto T = Template("{{#list}}({{&.}}){{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("(&)(\")(<)(>)", Out);
 }
 
 TEST(MustacheSections, ImplicitIteratorRootLevel) {
   Value D = Array{Object{{"value", "a"}}, Object{{"value", "b"}}};
-  auto T = Template::createTemplate("{{#.}}({{value}}){{/.}}");
+  auto T = Template("{{#.}}({{value}}){{/.}}");
   auto Out = T.render(D);
   EXPECT_EQ("(a)(b)", Out);
 }
 
 TEST(MustacheSections, DottedNamesTruthy) {
   Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}};
-  auto T = Template::createTemplate("{{#a.b.c}}Here{{/a.b.c}} == Here");
+  auto T = Template("{{#a.b.c}}Here{{/a.b.c}} == Here");
   auto Out = T.render(D);
   EXPECT_EQ("Here == Here", Out);
 }
 
 TEST(MustacheSections, DottedNamesFalsey) {
   Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}};
-  auto T = Template::createTemplate("{{#a.b.c}}Here{{/a.b.c}} == ");
+  auto T = Template("{{#a.b.c}}Here{{/a.b.c}} == ");
   auto Out = T.render(D);
   EXPECT_EQ(" == ", Out);
 }
 
 TEST(MustacheSections, DottedNamesBrokenChains) {
   Value D = Object{{"a", Object{}}};
-  auto T = Template::createTemplate("{{#a.b.c}}Here{{/a.b.c}} == ");
+  auto T = Template("{{#a.b.c}}Here{{/a.b.c}} == ");
   auto Out = T.render(D);
   EXPECT_EQ(" == ", Out);
 }
 
 TEST(MustacheSections, SurroundingWhitespace) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate(" | {{#boolean}}\t|\t{{/boolean}} | \n");
+  auto T = Template(" | {{#boolean}}\t|\t{{/boolean}} | \n");
   auto Out = T.render(D);
   EXPECT_EQ(" | \t|\t | \n", Out);
 }
 
 TEST(MustacheSections, InternalWhitespace) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate(
+  auto T = Template(
       " | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n");
   auto Out = T.render(D);
   EXPECT_EQ(" |  \n  | \n", Out);
@@ -500,83 +490,78 @@ TEST(MustacheSections, InternalWhitespace) {
 
 TEST(MustacheSections, IndentedInlineSections) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate(
-      " {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n");
+  auto T =
+      Template(" {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n");
   auto Out = T.render(D);
   EXPECT_EQ(" YES\n GOOD\n", Out);
 }
 
 TEST(MustacheSections, StandaloneLines) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate(
-      "| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n");
+  auto T = Template("| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n");
   auto Out = T.render(D);
   EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
 }
 
 TEST(MustacheSections, IndentedStandaloneLines) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate(
-      "| This Is\n  {{#boolean}}\n|\n  {{/boolean}}\n| A Line\n");
+  auto T = Template("| This Is\n  {{#boolean}}\n|\n  {{/boolean}}\n| A Line\n");
   auto Out = T.render(D);
   EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
 }
 
 TEST(MustacheSections, StandaloneLineEndings) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate("|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|");
+  auto T = Template("|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|");
   auto Out = T.render(D);
   EXPECT_EQ("|\r\n|", Out);
 }
 
 TEST(MustacheSections, StandaloneWithoutPreviousLine) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate("  {{#boolean}}\n#{{/boolean}}\n/");
+  auto T = Template("  {{#boolean}}\n#{{/boolean}}\n/");
   auto Out = T.render(D);
   EXPECT_EQ("#\n/", Out);
 }
 
 TEST(MustacheSections, StandaloneWithoutNewline) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate("#{{#boolean}}\n/\n  {{/boolean}}");
+  auto T = Template("#{{#boolean}}\n/\n  {{/boolean}}");
   auto Out = T.render(D);
   EXPECT_EQ("#\n/\n", Out);
 }
 
 TEST(MustacheSections, Padding) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate("|{{# boolean }}={{/ boolean }}|");
+  auto T = Template("|{{# boolean }}={{/ boolean }}|");
   auto Out = T.render(D);
   EXPECT_EQ("|=|", Out);
 }
 
 TEST(MustacheInvertedSections, Falsey) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate(
-      "{{^boolean}}This should be rendered.{{/boolean}}");
+  auto T = Template("{{^boolean}}This should be rendered.{{/boolean}}");
   auto Out = T.render(D);
   EXPECT_EQ("This should be rendered.", Out);
 }
 
 TEST(MustacheInvertedSections, Truthy) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate(
-      "{{^boolean}}This should not be rendered.{{/boolean}}");
+  auto T = Template("{{^boolean}}This should not be rendered.{{/boolean}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
 
 TEST(MustacheInvertedSections, NullIsFalsey) {
   Value D = Object{{"null", nullptr}};
-  auto T =
-      Template::createTemplate("{{^null}}This should be rendered.{{/null}}");
+  auto T = Template("{{^null}}This should be rendered.{{/null}}");
   auto Out = T.render(D);
   EXPECT_EQ("This should be rendered.", Out);
 }
 
 TEST(MustacheInvertedSections, Context) {
   Value D = Object{{"context", Object{{"name", "Joe"}}}};
-  auto T = Template::createTemplate("{{^context}}Hi {{name}}.{{/context}}");
+  auto T = Template("{{^context}}Hi {{name}}.{{/context}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
@@ -584,81 +569,78 @@ TEST(MustacheInvertedSections, Context) {
 TEST(MustacheInvertedSections, List) {
   Value D = Object{
       {"list", Array{Object{{"n", 1}}, Object{{"n", 2}}, Object{{"n", 3}}}}};
-  auto T = Template::createTemplate("{{^list}}{{n}}{{/list}}");
+  auto T = Template("{{^list}}{{n}}{{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
 
 TEST(MustacheInvertedSections, EmptyList) {
   Value D = Object{{"list", Array{}}};
-  auto T = Template::createTemplate("{{^list}}Yay lists!{{/list}}");
+  auto T = Template("{{^list}}Yay lists!{{/list}}");
   auto Out = T.render(D);
   EXPECT_EQ("Yay lists!", Out);
 }
 
 TEST(MustacheInvertedSections, Doubled) {
   Value D = Object{{"bool", false}, {"two", "second"}};
-  auto T = Template::createTemplate("{{^bool}}\n* first\n{{/bool}}\n* "
-                                    "{{two}}\n{{^bool}}\n* third\n{{/bool}}\n");
+  auto T = Template("{{^bool}}\n* first\n{{/bool}}\n* "
+                    "{{two}}\n{{^bool}}\n* third\n{{/bool}}\n");
   auto Out = T.render(D);
   EXPECT_EQ("* first\n* second\n* third\n", Out);
 }
 
 TEST(MustacheInvertedSections, NestedFalsey) {
   Value D = Object{{"bool", false}};
-  auto T = Template::createTemplate(
-      "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |");
+  auto T = Template("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |");
   auto Out = T.render(D);
   EXPECT_EQ("| A B C D E |", Out);
 }
 
 TEST(MustacheInvertedSections, NestedTruthy) {
   Value D = Object{{"bool", true}};
-  auto T = Template::createTemplate(
-      "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |");
+  auto T = Template("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |");
   auto Out = T.render(D);
   EXPECT_EQ("| A  E |", Out);
 }
 
 TEST(MustacheInvertedSections, ContextMisses) {
   Value D = Object{};
-  auto T = Template::createTemplate(
-      "[{{^missing}}Cannot find key 'missing'!{{/missing}}]");
+  auto T = Template("[{{^missing}}Cannot find key 'missing'!{{/missing}}]");
   auto Out = T.render(D);
   EXPECT_EQ("[Cannot find key 'missing'!]", Out);
 }
 
 TEST(MustacheInvertedSections, DottedNamesTruthy) {
   Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}};
-  auto T = Template::createTemplate("{{^a.b.c}}Not Here{{/a.b.c}} == ");
+  auto T = Template("{{^a.b.c}}Not Here{{/a.b.c}} == ");
   auto Out = T.render(D);
   EXPECT_EQ(" == ", Out);
 }
 
 TEST(MustacheInvertedSections, DottedNamesFalsey) {
   Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}};
-  auto T = Template::createTemplate("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here");
+  auto T = Template("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here");
   auto Out = T.render(D);
   EXPECT_EQ("Not Here == Not Here", Out);
 }
 
 TEST(MustacheInvertedSections, DottedNamesBrokenChains) {
   Value D = Object{{"a", Object{}}};
-  auto T = Template::createTemplate("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here");
+  auto T = Template("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here");
   auto Out = T.render(D);
   EXPECT_EQ("Not Here == Not Here", Out);
 }
 
 TEST(MustacheInvertedSections, SurroundingWhitespace) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate(" | {{^boolean}}\t|\t{{/boolean}} | \n");
+  auto T = Template(" | {{^boolean}}\t|\t{{/boolean}} | \n");
   auto Out = T.render(D);
   EXPECT_EQ(" | \t|\t | \n", Out);
 }
 
 TEST(MustacheInvertedSections, InternalWhitespace) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate(
+  auto T = Template(
       " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n");
   auto Out = T.render(D);
   EXPECT_EQ(" |  \n  | \n", Out);
@@ -666,59 +648,57 @@ TEST(MustacheInvertedSections, InternalWhitespace) {
 
 TEST(MustacheInvertedSections, IndentedInlineSections) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate(
-      " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n");
+  auto T =
+      Template(" {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n");
   auto Out = T.render(D);
   EXPECT_EQ(" NO\n WAY\n", Out);
 }
 
 TEST(MustacheInvertedSections, StandaloneLines) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate(
-      "| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n");
+  auto T = Template("| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n");
   auto Out = T.render(D);
   EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
 }
 
 TEST(MustacheInvertedSections, StandaloneIndentedLines) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate(
-      "| This Is\n  {{^boolean}}\n|\n  {{/boolean}}\n| A Line\n");
+  auto T = Template("| This Is\n  {{^boolean}}\n|\n  {{/boolean}}\n| A Line\n");
   auto Out = T.render(D);
   EXPECT_EQ("| This Is\n|\n| A Line\n", Out);
 }
 
 TEST(MustacheInvertedSections, StandaloneLineEndings) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate("|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|");
+  auto T = Template("|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|");
   auto Out = T.render(D);
   EXPECT_EQ("|\r\n|", Out);
 }
 
 TEST(MustacheInvertedSections, StandaloneWithoutPreviousLine) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate("  {{^boolean}}\n^{{/boolean}}\n/");
+  auto T = Template("  {{^boolean}}\n^{{/boolean}}\n/");
   auto Out = T.render(D);
   EXPECT_EQ("^\n/", Out);
 }
 
 TEST(MustacheInvertedSections, StandaloneWithoutNewline) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate("^{{^boolean}}\n/\n  {{/boolean}}");
+  auto T = Template("^{{^boolean}}\n/\n  {{/boolean}}");
   auto Out = T.render(D);
   EXPECT_EQ("^\n/\n", Out);
 }
 
 TEST(MustacheInvertedSections, Padding) {
   Value D = Object{{"boolean", false}};
-  auto T = Template::createTemplate("|{{^ boolean }}={{/ boolean }}|");
+  auto T = Template("|{{^ boolean }}={{/ boolean }}|");
   auto Out = T.render(D);
   EXPECT_EQ("|=|", Out);
 }
 
 TEST(MustachePartials, BasicBehavior) {
   Value D = Object{};
-  auto T = Template::createTemplate("{{>text}}");
+  auto T = Template("{{>text}}");
   T.registerPartial("text", "from partial");
   auto Out = T.render(D);
   EXPECT_EQ("from partial", Out);
@@ -726,14 +706,14 @@ TEST(MustachePartials, BasicBehavior) {
 
 TEST(MustachePartials, FailedLookup) {
   Value D = Object{};
-  auto T = Template::createTemplate("{{>text}}");
+  auto T = Template("{{>text}}");
   auto Out = T.render(D);
   EXPECT_EQ("", Out);
 }
 
 TEST(MustachePartials, Context) {
   Value D = Object{{"text", "content"}};
-  auto T = Template::createTemplate("{{>partial}}");
+  auto T = Template("{{>partial}}");
   T.registerPartial("partial", "*{{text}}*");
   auto Out = T.render(D);
   EXPECT_EQ("*content*", Out);
@@ -743,7 +723,7 @@ TEST(MustachePartials, Recursion) {
   Value D =
       Object{{"content", "X"},
              {"nodes", Array{Object{{"content", "Y"}, {"nodes", Array{}}}}}};
-  auto T = Template::createTemplate("{{>node}}");
+  auto T = Template("{{>node}}");
   T.registerPartial("node", "{{content}}({{#nodes}}{{>node}}{{/nodes}})");
   auto Out = T.render(D);
   EXPECT_EQ("X(Y())", Out);
@@ -751,7 +731,7 @@ TEST(MustachePartials, Recursion) {
 
 TEST(MustachePartials, Nested) {
   Value D = Object{{"a", "hello"}, {"b", "world"}};
-  auto T = Template::createTemplate("{{>outer}}");
+  auto T = Template("{{>outer}}");
   T.registerPartial("outer", "*{{a}} {{>inner}}*");
   T.registerPartial("inner", "{{b}}!");
   auto Out = T.render(D);
@@ -760,7 +740,7 @@ TEST(MustachePartials, Nested) {
 
 TEST(MustachePartials, SurroundingWhitespace) {
   Value D = Object{};
-  auto T = Template::createTemplate("| {{>partial}} |");
+  auto T = Template("| {{>partial}} |");
   T.registerPartial("partial", "\t|\t");
   auto Out = T.render(D);
   EXPECT_EQ("| \t|\t |", Out);
@@ -768,7 +748,7 @@ TEST(MustachePartials, SurroundingWhitespace) {
 
 TEST(MustachePartials, InlineIndentation) {
   Value D = Object{{"data", "|"}};
-  auto T = Template::createTemplate("  {{data}}  {{> partial}}\n");
+  auto T = Template("  {{data}}  {{> partial}}\n");
   T.registerPartial("partial", "<\n<");
   auto Out = T.render(D);
   EXPECT_EQ("  |  <\n<\n", Out);
@@ -776,7 +756,7 @@ TEST(MustachePartials, InlineIndentation) {
 
 TEST(MustachePartials, PaddingWhitespace) {
   Value D = Object{{"boolean", true}};
-  auto T = Template::createTemplate("|{{> partial }}|");
+  auto T = Template("|{{> partial }}|");
   T.registerPartial("partial", "[]");
   auto Out = T.render(D);
   EXPECT_EQ("|[]|", Out);
@@ -784,7 +764,7 @@ TEST(MustachePartials, PaddingWhitespace) {
 
 TEST(MustacheLambdas, BasicInterpolation) {
   Value D = Object{};
-  auto T = Template::createTemplate("Hello, {{lambda}}!");
+  auto T = Template("Hello, {{lambda}}!");
   Lambda L = []() -> llvm::json::Value { return "World"; };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);
@@ -793,7 +773,7 @@ TEST(MustacheLambdas, BasicInterpolation) {
 
 TEST(MustacheLambdas, InterpolationExpansion) {
   Value D = Object{{"planet", "World"}};
-  auto T = Template::createTemplate("Hello, {{lambda}}!");
+  auto T = Template("Hello, {{lambda}}!");
   Lambda L = []() -> llvm::json::Value { return "{{planet}}"; };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);
@@ -802,7 +782,7 @@ TEST(MustacheLambdas, InterpolationExpansion) {
 
 TEST(MustacheLambdas, BasicMultipleCalls) {
   Value D = Object{};
-  auto T = Template::createTemplate("{{lambda}} == {{lambda}} == {{lambda}}");
+  auto T = Template("{{lambda}} == {{lambda}} == {{lambda}}");
   int I = 0;
   Lambda L = [&I]() -> llvm::json::Value {
     I += 1;
@@ -815,7 +795,7 @@ TEST(MustacheLambdas, BasicMultipleCalls) {
 
 TEST(MustacheLambdas, Escaping) {
   Value D = Object{};
-  auto T = Template::createTemplate("<{{lambda}}{{&lambda}}");
+  auto T = Template("<{{lambda}}{{&lambda}}");
   Lambda L = []() -> llvm::json::Value { return ">"; };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);
@@ -824,7 +804,7 @@ TEST(MustacheLambdas, Escaping) {
 
 TEST(MustacheLambdas, Sections) {
   Value D = Object{};
-  auto T = Template::createTemplate("<{{#lambda}}{{x}}{{/lambda}}>");
+  auto T = Template("<{{#lambda}}{{x}}{{/lambda}}>");
   SectionLambda L = [](StringRef Text) -> llvm::json::Value {
     if (Text == "{{x}}") {
       return "yes";
@@ -840,7 +820,7 @@ TEST(MustacheLambdas, SectionExpansion) {
   Value D = Object{
       {"planet", "Earth"},
   };
-  auto T = Template::createTemplate("<{{#lambda}}-{{/lambda}}>");
+  auto T = Template("<{{#lambda}}-{{/lambda}}>");
   SectionLambda L = [](StringRef Text) -> llvm::json::Value {
     SmallString<128> Result;
     Result += Text;
@@ -855,8 +835,7 @@ TEST(MustacheLambdas, SectionExpansion) {
 
 TEST(MustacheLambdas, SectionsMultipleCalls) {
   Value D = Object{};
-  auto T = Template::createTemplate(
-      "{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}");
+  auto T = Template("{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}");
   SectionLambda L = [](StringRef Text) -> llvm::json::Value {
     SmallString<128> Result;
     Result += "__";
@@ -871,7 +850,7 @@ TEST(MustacheLambdas, SectionsMultipleCalls) {
 
 TEST(MustacheLambdas, InvertedSections) {
   Value D = Object{{"static", "static"}};
-  auto T = Template::createTemplate("<{{^lambda}}{{static}}{{/lambda}}>");
+  auto T = Template("<{{^lambda}}{{static}}{{/lambda}}>");
   SectionLambda L = [](StringRef Text) -> llvm::json::Value { return false; };
   T.registerLambda("lambda", L);
   auto Out = T.render(D);
@@ -881,7 +860,7 @@ TEST(MustacheLambdas, InvertedSections) {
 TEST(MustacheComments, Inline) {
   // Comment blocks should be removed from the template.
   Value D = {};
-  auto T = Template::createTemplate("12345{{! Comment Block! }}67890");
+  auto T = Template("12345{{! Comment Block! }}67890");
   auto Out = T.render(D);
   EXPECT_EQ("1234567890", Out);
 }
@@ -889,8 +868,8 @@ TEST(MustacheComments, Inline) {
 TEST(MustacheComments, Multiline) {
   // Multiline comments should be permitted.
   Value D = {};
-  auto T = Template::createTemplate(
-      "12345{{!\n  This is a\n  multi-line comment...\n}}67890\n");
+  auto T =
+      Template("12345{{!\n  This is a\n  multi-line comment...\n}}67890\n");
   auto Out = T.render(D);
   EXPECT_EQ("1234567890\n", Out);
 }
@@ -898,7 +877,7 @@ TEST(MustacheComments, Multiline) {
 TEST(MustacheComments, Standalone) {
   // All standalone comment lines should be removed.
   Value D = {};
-  auto T = Template::createTemplate("Begin.\n{{! Comment Block! }}\nEnd.\n");
+  auto T = Template("Begin.\n{{! Comment Block! }}\nEnd.\n");
   auto Out = T.render(D);
   EXPECT_EQ("Begin.\nEnd.\n", Out);
 }
@@ -906,8 +885,7 @@ TEST(MustacheComments, Standalone) {
 TEST(MustacheComments, IndentedStandalone) {
   // All standalone comment lines should be removed.
   Value D = {};
-  auto T = Template::createTemplate(
-      "Begin.\n  {{! Indented Comment Block! }}\nEnd.\n");
+  auto T = Template("Begin.\n  {{! Indented Comment Block! }}\nEnd.\n");
   auto Out = T.render(D);
   EXPECT_EQ("Begin.\nEnd.\n", Out);
 }
@@ -915,7 +893,7 @@ TEST(MustacheComments, IndentedStandalone) {
 TEST(MustacheComments, StandaloneLineEndings) {
   // "\r\n" should be considered a newline for standalone tags.
   Value D = {};
-  auto T = Template::createTemplate("|\r\n{{! Standalone Comment }}\r\n|");
+  auto T = Template("|\r\n{{! Standalone Comment }}\r\n|");
   auto Out = T.render(D);
   EXPECT_EQ("|\r\n|", Out);
 }
@@ -923,7 +901,7 @@ TEST(MustacheComments, StandaloneLineEndings) {
 TEST(MustacheComments, StandaloneWithoutPreviousLine) {
   // Standalone tags should not require a newline to precede them.
   Value D = {};
-  auto T = Template::createTemplate("  {{! I'm Still Standalone }}\n!");
+  auto T = Template("  {{! I'm Still Standalone }}\n!");
   auto Out = T.render(D);
   EXPECT_EQ("!", Out);
 }
@@ -931,7 +909,7 @@ TEST(MustacheComments, StandaloneWithoutPreviousLine) {
 TEST(MustacheComments, StandaloneWithoutNewline) {
   // Standalone tags should not require a newline to follow them.
   Value D = {};
-  auto T = Template::createTemplate("!\n  {{! I'm Still Standalone }}");
+  auto T = Template("!\n  {{! I'm Still Standalone }}");
   auto Out = T.render(D);
   EXPECT_EQ("!\n", Out);
 }
@@ -939,8 +917,7 @@ TEST(MustacheComments, StandaloneWithoutNewline) {
 TEST(MustacheComments, MultilineStandalone) {
   // All standalone comment lines should be removed.
   Value D = {};
-  auto T = Template::createTemplate(
-      "Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n");
+  auto T = Template("Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n");
   auto Out = T.render(D);
   EXPECT_EQ("Begin.\nEnd.\n", Out);
 }
@@ -948,8 +925,8 @@ TEST(MustacheComments, MultilineStandalone) {
 TEST(MustacheComments, IndentedMultilineStandalone) {
   // All standalone comment lines should be removed.
   Value D = {};
-  auto T = Template::createTemplate(
-      "Begin.\n  {{!\n    Something's going on here...\n  }}\nEnd.\n");
+  auto T =
+      Template("Begin.\n  {{!\n    Something's going on here...\n  }}\nEnd.\n");
   auto Out = T.render(D);
   EXPECT_EQ("Begin.\nEnd.\n", Out);
 }
@@ -957,7 +934,7 @@ TEST(MustacheComments, IndentedMultilineStandalone) {
 TEST(MustacheComments, IndentedInline) {
   // Inline comments should not strip whitespace.
   Value D = {};
-  auto T = Template::createTemplate("  12 {{! 34 }}\n");
+  auto T = Template("  12 {{! 34 }}\n");
   auto Out = T.render(D);
   EXPECT_EQ("  12 \n", Out);
 }
@@ -965,7 +942,7 @@ TEST(MustacheComments, IndentedInline) {
 TEST(MustacheComments, SurroundingWhitespace) {
   // Comment removal should preserve surrounding whitespace.
   Value D = {};
-  auto T = Template::createTemplate("12345 {{! Comment Block! }} 67890");
+  auto T = Template("12345 {{! Comment Block! }} 67890");
   auto Out = T.render(D);
   EXPECT_EQ("12345  67890", Out);
 }
@@ -974,7 +951,7 @@ TEST(MustacheComments, VariableNameCollision) {
   // Comments must never render, even if a variable with the same name exists.
   Value D = Object{
       {"! comment", 1}, {"! comment ", 2}, {"!comment", 3}, {"comment", 4}};
-  auto T = Template::createTemplate("comments never show: >{{! comment }}<");
+  auto T = Template("comments never show: >{{! comment }}<");
   auto Out = T.render(D);
   EXPECT_EQ("comments never show: ><", Out);
 }
\ No newline at end of file

>From d8aa85c2e87b9ae9c40ea0758969f5bc5720820e Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Thu, 12 Sep 2024 06:24:27 -0400
Subject: [PATCH 23/57] [llvm][support] clang-format

---
 llvm/include/llvm/Support/Mustache.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 607e33b4ec2c9b..98843897707a82 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -28,10 +28,10 @@
 //
 // The Template class is container class outputs the Mustache template string
 // and is main class for users. It stores all the lambdas and the ASTNode Tree.
-// When the Template is instantiated it calls tokenize the Template String into 
-// the Token class and calls a basic recursive descent parser to construct the 
-// ASTNode Tree. The ASTNodes are all stored in an arena allocator which is 
-// freed once the template class goes out of scope
+// When the Template is instantiated it tokenize the Template String and creates 
+// a vector of Tokens. Then it calls a basic recursive descent parser to 
+// construct the ASTNode Tree. The ASTNodes are all stored in an arena
+// allocator which is freed once the template class goes out of scope
 //
 // Usage:
 // \code
@@ -121,15 +121,15 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), LocalContext(nullptr){};
+  ASTNode() : T(Type::Root), LocalContext(nullptr) {};
 
   ASTNode(StringRef Body, ASTNode *Parent)
-      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr){};
+      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr) {};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        LocalContext(nullptr){};
+        LocalContext(nullptr) {};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 

>From 0534a054574ec18980e130a1d54a98af2bc59d5d Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Thu, 12 Sep 2024 06:54:19 -0400
Subject: [PATCH 24/57] [llvm][support] clang-format

---
 llvm/include/llvm/Support/Mustache.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 98843897707a82..88a2cb0d988097 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -28,9 +28,9 @@
 //
 // The Template class is container class outputs the Mustache template string
 // and is main class for users. It stores all the lambdas and the ASTNode Tree.
-// When the Template is instantiated it tokenize the Template String and creates 
-// a vector of Tokens. Then it calls a basic recursive descent parser to 
-// construct the ASTNode Tree. The ASTNodes are all stored in an arena
+// When the Template is instantiated it tokenize the Template String and 
+// creates a vector of Tokens. Then it calls a basic recursive descent parser
+// to construct the ASTNode Tree. The ASTNodes are all stored in an arena
 // allocator which is freed once the template class goes out of scope
 //
 // Usage:

>From 06da7a5897347f2d22e406e2bec7800cbb29fd1d Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Thu, 12 Sep 2024 07:46:30 -0400
Subject: [PATCH 25/57] [llvm][support] clang-format

---
 llvm/include/llvm/Support/Mustache.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 88a2cb0d988097..073e3d0148dcc4 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -28,7 +28,7 @@
 //
 // The Template class is container class outputs the Mustache template string
 // and is main class for users. It stores all the lambdas and the ASTNode Tree.
-// When the Template is instantiated it tokenize the Template String and 
+// When the Template is instantiated it tokenize the Template String and
 // creates a vector of Tokens. Then it calls a basic recursive descent parser
 // to construct the ASTNode Tree. The ASTNodes are all stored in an arena
 // allocator which is freed once the template class goes out of scope

>From 1e2b68a28a346af3aeb0cae7dcf287c51796d419 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 02:26:22 -0400
Subject: [PATCH 26/57] [clang-doc] init mustache implementation

---
 clang-tools-extra/clang-doc/CMakeLists.txt    |   1 +
 clang-tools-extra/clang-doc/HTMLGenerator.cpp |   3 +-
 .../clang-doc/HTMLMustacheGenerator.cpp       | 349 ++++++++++++++++++
 clang-tools-extra/clang-doc/Representation.h  |   4 +-
 .../clang-doc/assets/template.mustache        |  23 ++
 .../clang-doc/tool/CMakeLists.txt             |   1 +
 .../clang-doc/tool/ClangDocMain.cpp           |  31 ++
 7 files changed, 410 insertions(+), 2 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
 create mode 100644 clang-tools-extra/clang-doc/assets/template.mustache

diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt
index 975ad8e242e490..82aded940222db 100644
--- a/clang-tools-extra/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -15,6 +15,7 @@ add_clang_library(clangDoc
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
+  HTMLMustacheGenerator.cpp
 
   DEPENDS
   omp_gen
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index e3532559a32fcc..ed65ac965114b5 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -1133,7 +1133,8 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-static llvm::Error copyFile(StringRef FilePath, StringRef OutDirectory) {
+static llvm::Error 
+copyFile(StringRef FilePath, StringRef OutDirectory) {
   llvm::SmallString<128> PathWrite;
   llvm::sys::path::native(OutDirectory, PathWrite);
   llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
new file mode 100644
index 00000000000000..63def07c5fa804
--- /dev/null
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -0,0 +1,349 @@
+//===-- HTMLMustacheGenerator.cpp - HTML Mustache Generator -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "Generators.h"
+#include "Representation.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Mustache.h"
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+namespace clang {
+namespace doc {
+
+
+class MustacheHTMLGenerator : public Generator {
+public:
+  static const char *Format;
+  llvm::Error generateDocs(StringRef RootDir,
+                           llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
+                           const ClangDocContext &CDCtx) override;
+  llvm::Error createResources(ClangDocContext &CDCtx) override;
+  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
+                                 const ClangDocContext &CDCtx) override;
+  
+};
+
+class MustacheTemplateFile : public Template {
+public:
+  static ErrorOr<std::unique_ptr<MustacheTemplateFile>> createMustacheFile
+      (StringRef FileName) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
+        MemoryBuffer::getFile(FileName);
+    
+    if (auto EC = BufferOrError.getError()) {
+      return EC;
+    }
+    std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+    llvm::StringRef FileContent = Buffer->getBuffer();
+    return std::make_unique<MustacheTemplateFile>(FileContent);
+  }
+  
+  Error registerPartialFile(StringRef Name, StringRef FileName) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
+        MemoryBuffer::getFile(FileName);
+    if (auto EC = BufferOrError.getError()) {
+      return llvm::createFileError("cannot open file", EC);
+    }
+    std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+    llvm::StringRef FileContent = Buffer->getBuffer();
+    registerPartial(Name, FileContent);
+  }
+
+  MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
+};
+
+static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
+
+static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
+
+
+llvm::Error 
+setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
+  auto TemplateFilePath = CDCtx.MustacheTemplates.lookup("template");
+  auto Template = MustacheTemplateFile::createMustacheFile(TemplateFilePath);
+  if (auto EC = Template.getError()) {
+    return llvm::createFileError("cannot open file", EC);
+  }
+  NamespaceTemplate = std::move(Template.get());
+}
+
+llvm::Error 
+MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir, 
+                                    llvm::StringMap<std::unique_ptr<doc::Info>> Infos, 
+                                    const clang::doc::ClangDocContext &CDCtx) {
+  if (auto Err = setupTemplateFiles(CDCtx)) {
+    return Err;
+  }
+  // Track which directories we already tried to create.
+  llvm::StringSet<> CreatedDirs;
+  // Collect all output by file name and create the necessary directories.
+  llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
+  for (const auto &Group : Infos) {
+    doc::Info *Info = Group.getValue().get();
+    
+    llvm::SmallString<128> Path;
+    llvm::sys::path::native(RootDir, Path);
+    llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
+    if (!CreatedDirs.contains(Path)) {
+      if (std::error_code Err = llvm::sys::fs::create_directories(Path);
+          Err != std::error_code()) {
+        return llvm::createStringError(Err, "Failed to create directory '%s'.",
+                                       Path.c_str());
+      }
+      CreatedDirs.insert(Path);
+    }
+
+    llvm::sys::path::append(Path, Info->getFileBaseName() + ".html");
+    FileToInfos[Path].push_back(Info);
+  }
+  
+  for (const auto &Group : FileToInfos) {
+    std::error_code FileErr;
+    llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
+                                llvm::sys::fs::OF_None);
+    if (FileErr) {
+      return llvm::createStringError(FileErr, "Error opening file '%s'",
+                                     Group.getKey().str().c_str());
+    }
+    for (const auto &Info : Group.getValue()) {
+      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
+        return Err;
+      }
+    }
+  }
+}
+
+Value extractValue(const Location &L, 
+                   std::optional<StringRef> RepositoryUrl = std::nullopt) {
+  Object Obj = Object();
+  if (!L.IsFileInRootDir || !RepositoryUrl) {
+    Obj.insert({"LineNumber", L.LineNumber});
+    Obj.insert({"Filename", L.Filename});
+  }
+  SmallString<128> FileURL(*RepositoryUrl);
+  llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
+  Obj.insert({"FileURL", FileURL});
+}
+
+Value extractValue(const Reference &I, StringRef CurrentDirectory) {
+  llvm::SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory);
+  llvm::sys::path::append(Path, I.getFileBaseName() + ".html");
+  llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
+  Object Obj = Object();
+  Obj.insert({"Link", Path});
+  Obj.insert({"Name", I.Name});
+  return Obj;
+}
+
+
+Value extractValue(const TypedefInfo &I) {
+  // Not Supported
+  return nullptr;
+}
+
+Value extractValue(const CommentInfo &I) {
+  Object Obj = Object();
+  Value Child = Object();
+  
+  if (I.Kind == "FullComment") {
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"FullComment", Child});
+  }
+  if (I.Kind == "ParagraphComment") {
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"ParagraphComment", Child});
+  }
+  if (I.Kind == "BlockCommandComment") {
+    Child.getAsObject()->insert({"Command", I.Name});
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"BlockCommandComment", Child});
+  }
+  if (I.Kind == "TextComment")
+    Obj.insert({"TextComment", I.Text});
+  
+  return Obj;
+}
+
+Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
+                   const ClangDocContext &CDCtx) {
+  Object Obj = Object();
+  Obj.insert({"Name", I.Name});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
+  Obj.insert({"Access", getAccessSpelling(I.Access).str()});
+  Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
+  
+  Value ParamArr = Array();
+  for (const auto &P : I.Params) {
+    ParamArr.getAsArray()->emplace_back(extractValue(P.Type, ParentInfoDir));
+  }
+  Obj.insert({"Params", ParamArr});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    Obj.insert({"FunctionComments", ArrDesc});
+  }
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
+    else
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
+  }
+  return Obj;
+}
+
+Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
+  Object Obj = Object();
+  std::string EnumType = I.Scoped ? "enum class " : "enum ";
+  EnumType += I.Name;
+  bool HasComment = std::any_of(
+      I.Members.begin(), I.Members.end(),
+      [](const EnumValueInfo &M) { return !M.Description.empty(); });
+  Obj.insert({"EnumName", EnumType});
+  Obj.insert({"HasComment", HasComment});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
+  
+  Value Arr = Array();
+  for (const EnumValueInfo& M: I.Members) {
+    Value EnumValue = Object();
+    EnumValue.getAsObject()->insert({"Name", M.Name});
+    if (!M.ValueExpr.empty())
+      EnumValue.getAsObject()->insert({"ValueExpr", M.ValueExpr});
+    else
+      EnumValue.getAsObject()->insert({"Value", M.Value});
+    
+    if (!M.Description.empty()) {
+      Value ArrDesc = Array();
+      for (const CommentInfo& Child : M.Description) 
+        ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+      EnumValue.getAsObject()->insert({"EnumValueComments", ArrDesc});
+    }
+    Arr.getAsArray()->emplace_back(EnumValue);
+  }
+  Obj.insert({"EnumValues", Arr});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    Obj.insert({"EnumComments", ArrDesc});
+  }
+  
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
+    else
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
+  }
+  
+  return Obj;
+}
+
+Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
+  Object NamespaceValue = Object();
+  std::string InfoTitle;
+  if (I.Name.str() == "")
+    InfoTitle = "Global Namespace";
+  else
+    InfoTitle = ("namespace " + I.Name).str();  
+  
+  StringRef BasePath = I.getRelativeFilePath("");
+  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
+  NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    NamespaceValue.insert({"NamespaceComments", ArrDesc });
+  }
+
+  Value ArrNamespace = Array();
+  for (const Reference& Child : I.Children.Namespaces)
+    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Namespace", ArrNamespace});
+  
+  Value ArrRecord = Array();
+  for (const Reference& Child : I.Children.Records)
+    ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Record", ArrRecord});
+  
+  Value ArrFunction = Array();
+  for (const FunctionInfo& Child : I.Children.Functions)
+    ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
+                                                        CDCtx));
+  NamespaceValue.insert({"Function", ArrRecord});
+  
+  Value ArrEnum = Array();
+  for (const EnumInfo& Child : I.Children.Enums)
+    ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
+  NamespaceValue.insert({"Enums", ArrEnum });
+  
+  Value ArrTypedefs = Array();
+  for (const TypedefInfo& Child : I.Children.Typedefs) 
+    ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
+  NamespaceValue.insert({"Typedefs", ArrTypedefs });
+  
+}
+
+
+
+llvm::Error
+MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
+                                          const ClangDocContext &CDCtx) {
+  switch (I->IT) {
+  case InfoType::IT_namespace: {
+    Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+    OS << NamespaceTemplate->render(V);
+    break;
+  }
+  case InfoType::IT_record:
+    break;
+  case InfoType::IT_enum:
+    break;
+  case InfoType::IT_function:
+    break;
+  case InfoType::IT_typedef:
+    break;
+  case InfoType::IT_default:
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "unexpected InfoType");
+  }
+  return llvm::Error::success();
+}
+
+llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
+  
+}
+
+const char *MustacheHTMLGenerator::Format = "mustache";
+
+
+static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
+                                                  "Generator for mustache HTML output.");
+
+// This anchor is used to force the linker to link in the generated object
+// file and thus register the generator.
+volatile int HTMLGeneratorAnchorSource = 0;
+
+} // namespace doc
+} // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index bb0c534af7b740..3175b8209e3be3 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -521,8 +521,10 @@ struct ClangDocContext {
   // Path of CSS stylesheets that will be copied to OutDirectory and used to
   // style all HTML files.
   std::vector<std::string> UserStylesheets;
-  // JavaScript files that will be imported in allHTML file.
+  // JavaScript files that will be imported in all HTML file.
   std::vector<std::string> JsScripts;
+  // Mustache Template files
+  llvm::StringMap<std::string> MustacheTemplates;
   Index Idx;
 };
 
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
new file mode 100644
index 00000000000000..af4c60182ae52c
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -0,0 +1,23 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+    <head>
+        <meta charset="utf-8"/>
+        <title>{{NamespaceTitle}}</title>
+    </head>
+    {{#NamespaceComments}}
+    <p>Namespace Comment Present!</p>
+    {{/NamespaceComments}}
+    {{#Namespace}}
+    <p>Namespace Present!</p>
+    {{/Namespace}}
+    {{#Record}}
+    <p>Record Present!</p>
+    {{/Record}}
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
index 601a0460d76b38..8eb067dbe6de87 100644
--- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -21,6 +21,7 @@ target_link_libraries(clang-doc
 
 set(assets
   index.js
+  template.mustache
   clang-doc-default-stylesheet.css
 )
 
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 04773fb8a6e721..fc5a9529111b16 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -205,6 +205,30 @@ llvm::Error getHtmlAssetFiles(const char *Argv0,
   return getDefaultAssetFiles(Argv0, CDCtx);
 }
 
+llvm::Error getMustacheHtmlFiles(const char *Argv0,
+                                 clang::doc::ClangDocContext &CDCtx) {
+  if (!UserAssetPath.empty() &&
+      !llvm::sys::fs::is_directory(std::string(UserAssetPath)))
+    llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath
+                 << " falling back to default\n";
+  if (llvm::sys::fs::is_directory(std::string(UserAssetPath)))
+    return getAssetFiles(CDCtx);
+  
+  void *MainAddr = (void *)(intptr_t)getExecutablePath;
+  std::string ClangDocPath = getExecutablePath(Argv0, MainAddr);
+  llvm::SmallString<128> NativeClangDocPath;
+  llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
+  
+  llvm::SmallString<128> AssetsPath;
+  AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
+  llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
+  
+  llvm::SmallString<128> MustacheTemplate;
+  llvm::sys::path::native(AssetsPath, MustacheTemplate);
+  llvm::sys::path::append(MustacheTemplate, "template.mustache");
+  CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+}
+
 /// Make the output of clang-doc deterministic by sorting the children of
 /// namespaces and records.
 void sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> &USRToInfo) {
@@ -277,6 +301,13 @@ Example usage for a project using a compile commands database:
       return 1;
     }
   }
+  
+  if (Format == "mhtml") {
+    if (auto Err = getMustacheHtmlFiles(argv[0], CDCtx)) {
+      llvm::errs() << toString(std::move(Err)) << "\n";
+      return 1;
+    }
+  }
 
   // Mapping phase
   llvm::outs() << "Mapping decls...\n";

>From 8d141ba80297ce024b0144f2522f7d662bf36568 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 17:50:03 -0400
Subject: [PATCH 27/57] [clang-doc] add a mustache backend init implementation

---
 clang-tools-extra/clang-doc/Generators.cpp    |  4 +-
 .../clang-doc/HTMLMustacheGenerator.cpp       | 32 ++++++++++++----
 .../clang-doc/assets/template.mustache        | 37 +++++++++++++++++--
 .../clang-doc/tool/ClangDocMain.cpp           |  9 ++++-
 .../Inputs/basic-project/include/Shape.h      |  2 -
 5 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp
index a3986b66f3c742..ae5b556d17063b 100644
--- a/clang-tools-extra/clang-doc/Generators.cpp
+++ b/clang-tools-extra/clang-doc/Generators.cpp
@@ -100,12 +100,14 @@ void Generator::addInfoToIndex(Index &Idx, const doc::Info *Info) {
 extern volatile int YAMLGeneratorAnchorSource;
 extern volatile int MDGeneratorAnchorSource;
 extern volatile int HTMLGeneratorAnchorSource;
+extern volatile int MHTMLGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED YAMLGeneratorAnchorDest =
     YAMLGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED MDGeneratorAnchorDest =
     MDGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED HTMLGeneratorAnchorDest =
     HTMLGeneratorAnchorSource;
-
+static int LLVM_ATTRIBUTE_UNUSED MHTMLGeneratorAnchorDest =
+    MHTMLGeneratorAnchorSource;
 } // namespace doc
 } // namespace clang
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 63def07c5fa804..bfa563ebdc7b37 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -54,6 +54,7 @@ class MustacheTemplateFile : public Template {
     std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
     llvm::StringRef FileContent = Buffer->getBuffer();
     registerPartial(Name, FileContent);
+    return llvm::Error::success();
   }
 
   MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
@@ -72,6 +73,7 @@ setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
     return llvm::createFileError("cannot open file", EC);
   }
   NamespaceTemplate = std::move(Template.get());
+  return llvm::Error::success();
 }
 
 llvm::Error 
@@ -118,6 +120,7 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
       }
     }
   }
+  return llvm::Error::success();
 }
 
 Value extractValue(const Location &L, 
@@ -130,6 +133,8 @@ Value extractValue(const Location &L,
   SmallString<128> FileURL(*RepositoryUrl);
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
   Obj.insert({"FileURL", FileURL});
+  
+  return Obj;
 }
 
 Value extractValue(const Reference &I, StringRef CurrentDirectory) {
@@ -280,29 +285,39 @@ Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
   Value ArrNamespace = Array();
   for (const Reference& Child : I.Children.Namespaces)
     ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Namespace", ArrNamespace});
+  
+  if (!ArrNamespace.getAsArray()->empty())
+    NamespaceValue.insert({"Namespace", Object{{"Links", ArrNamespace}}});
   
   Value ArrRecord = Array();
   for (const Reference& Child : I.Children.Records)
     ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Record", ArrRecord});
+  
+  if (!ArrRecord.getAsArray()->empty())
+    NamespaceValue.insert({"Record", Object{{"Links", ArrRecord}}});
   
   Value ArrFunction = Array();
   for (const FunctionInfo& Child : I.Children.Functions)
     ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
                                                         CDCtx));
-  NamespaceValue.insert({"Function", ArrRecord});
+  if (!ArrFunction.getAsArray()->empty())
+    NamespaceValue.insert({"Function", Object{{"Obj", ArrFunction}}});
   
   Value ArrEnum = Array();
   for (const EnumInfo& Child : I.Children.Enums)
     ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
-  NamespaceValue.insert({"Enums", ArrEnum });
+  
+  if (!ArrEnum.getAsArray()->empty())
+    NamespaceValue.insert({"Enums", Object{{"Obj", ArrEnum }}});
   
   Value ArrTypedefs = Array();
   for (const TypedefInfo& Child : I.Children.Typedefs) 
     ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
-  NamespaceValue.insert({"Typedefs", ArrTypedefs });
   
+  if (!ArrTypedefs.getAsArray()->empty())
+    NamespaceValue.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+  
+  return NamespaceValue;
 }
 
 
@@ -313,6 +328,7 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+    llvm::outs() << V << "\n";
     OS << NamespaceTemplate->render(V);
     break;
   }
@@ -332,10 +348,10 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
 }
 
 llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
-  
+  return llvm::Error::success();
 }
 
-const char *MustacheHTMLGenerator::Format = "mustache";
+const char *MustacheHTMLGenerator::Format = "mhtml";
 
 
 static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
@@ -343,7 +359,7 @@ static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator
 
 // This anchor is used to force the linker to link in the generated object
 // file and thus register the generator.
-volatile int HTMLGeneratorAnchorSource = 0;
+volatile int MHTMLGeneratorAnchorSource = 0;
 
 } // namespace doc
 } // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
index af4c60182ae52c..1d3407f8b52920 100644
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -3,7 +3,7 @@
     See https://llvm.org/LICENSE.txt for license information.
     SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     
-    This file defines the template
+    This file defines the template for generating Namespaces
 }}
 <!DOCTYPE html>
 <html lang="en-US">
@@ -11,13 +11,42 @@
         <meta charset="utf-8"/>
         <title>{{NamespaceTitle}}</title>
     </head>
+    <h1>{{NamespaceTitle}}</h1>
     {{#NamespaceComments}}
-    <p>Namespace Comment Present!</p>
+    <p>Namespace Comment</p>
     {{/NamespaceComments}}
     {{#Namespace}}
-    <p>Namespace Present!</p>
+    <h2 id="Namespace">Namespace</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Namespace}}
     {{#Record}}
-    <p>Record Present!</p>
+    <h2 id="Class">Class</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Record}}
+    {{#Function}}
+    <h2 id="Function">Function</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Function}}
+    {{#Enums}}
+    <h2 id="Enums">Enums</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Enums}}
 </html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index fc5a9529111b16..eee8dbf093cc53 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -103,6 +103,7 @@ enum OutputFormatTy {
   md,
   yaml,
   html,
+  mhtml
 };
 
 static llvm::cl::opt<OutputFormatTy>
@@ -112,7 +113,9 @@ static llvm::cl::opt<OutputFormatTy>
                                 clEnumValN(OutputFormatTy::md, "md",
                                            "Documentation in MD format."),
                                 clEnumValN(OutputFormatTy::html, "html",
-                                           "Documentation in HTML format.")),
+                                           "Documentation in HTML format."),
+                                clEnumValN(OutputFormatTy::mhtml, "mhtml",
+                                           "Documentation in mHTML format")),
                llvm::cl::init(OutputFormatTy::yaml),
                llvm::cl::cat(ClangDocCategory));
 
@@ -124,6 +127,8 @@ std::string getFormatString() {
     return "md";
   case OutputFormatTy::html:
     return "html";
+  case OutputFormatTy::mhtml:
+    return "mhtml";
   }
   llvm_unreachable("Unknown OutputFormatTy");
 }
@@ -227,6 +232,8 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
   llvm::sys::path::native(AssetsPath, MustacheTemplate);
   llvm::sys::path::append(MustacheTemplate, "template.mustache");
   CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+  
+  return llvm::Error::success();
 }
 
 /// Make the output of clang-doc deterministic by sorting the children of
diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
index e5c5d4c9e4412b..5354032f4d8323 100644
--- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
+++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
@@ -26,5 +26,3 @@ class Shape {
      */
     virtual double perimeter() const = 0;
 };
-
-

>From f713198d1c4dbc286fa180973ccf604f2656c287 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 02:08:00 -0400
Subject: [PATCH 28/57] [llvm] mustache address comments

---
 llvm/include/llvm/Support/Mustache.h |  67 ++++--
 llvm/lib/Support/Mustache.cpp        | 331 +++++++++++++++++----------
 2 files changed, 251 insertions(+), 147 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 073e3d0148dcc4..4cd66d08dd39fa 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -64,12 +64,13 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/JSON.h"
+#include "llvm/Support/StringSaver.h"
 #include <vector>
 
 namespace llvm {
 namespace mustache {
 
-using Accessor = SmallVector<SmallString<128>>;
+using Accessor = SmallVector<SmallString<0>>;
 using Lambda = std::function<llvm::json::Value()>;
 using SectionLambda = std::function<llvm::json::Value(StringRef)>;
 
@@ -100,13 +101,20 @@ class Token {
 
   Type getType() const { return TokenType; };
 
+  void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
+
+  size_t getIndentation() const { return Indentation; };
+
   static Type getTokenType(char Identifier);
 
 private:
+  size_t Indentation;
   Type TokenType;
+  // RawBody is the original string that was tokenized
   SmallString<128> RawBody;
   Accessor Accessor;
-  SmallString<128> TokenBody;
+  // TokenBody is the original string with the identifier removed
+  SmallString<0> TokenBody;
 };
 
 class ASTNode {
@@ -121,36 +129,55 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), LocalContext(nullptr) {};
+  ASTNode() : T(Type::Root), LocalContext(nullptr){};
 
   ASTNode(StringRef Body, ASTNode *Parent)
-      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr) {};
+      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr),
+        Indentation(0){};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        LocalContext(nullptr) {};
+        LocalContext(nullptr), Indentation(0){};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 
-  SmallString<128> getBody() const { return Body; };
-
   void setBody(StringRef NewBody) { Body = NewBody; };
 
   void setRawBody(StringRef NewBody) { RawBody = NewBody; };
 
-  SmallString<128> render(llvm::json::Value Data,
-                          llvm::BumpPtrAllocator &Allocator,
-                          DenseMap<StringRef, ASTNode *> &Partials,
-                          DenseMap<StringRef, Lambda> &Lambdas,
-                          DenseMap<StringRef, SectionLambda> &SectionLambdas,
-                          DenseMap<char, StringRef> &Escapes);
+  void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
+
+  void render(llvm::json::Value Data, SmallString<0> &Output);
+
+  void setUpNode(llvm::BumpPtrAllocator &Allocator,
+                 StringMap<ASTNode *> &Partials, StringMap<Lambda> &Lambdas,
+                 StringMap<SectionLambda> &SectionLambdas,
+                 DenseMap<char, StringRef> &Escapes);
 
 private:
+  void renderLambdas(llvm::json::Value &Contexts, SmallString<0> &Output,
+                     Lambda &L);
+
+  void renderSectionLambdas(llvm::json::Value &Contexts, SmallString<0> &Output,
+                            SectionLambda &L);
+
+  void renderPartial(llvm::json::Value &Contexts, SmallString<0> &Output,
+                     ASTNode *Partial);
+
+  void renderChild(llvm::json::Value &Context, SmallString<0> &Output);
+
   llvm::json::Value findContext();
+
+  llvm::BumpPtrAllocator *Allocator;
+  StringMap<ASTNode *> *Partials;
+  StringMap<Lambda> *Lambdas;
+  StringMap<SectionLambda> *SectionLambdas;
+  DenseMap<char, StringRef> *Escapes;
   Type T;
-  SmallString<128> RawBody;
-  SmallString<128> Body;
+  size_t Indentation;
+  SmallString<0> RawBody;
+  SmallString<0> Body;
   ASTNode *Parent;
   std::vector<ASTNode *> Children;
   const Accessor Accessor;
@@ -163,7 +190,7 @@ class Template {
 public:
   Template(StringRef TemplateStr);
 
-  SmallString<128> render(llvm::json::Value Data);
+  StringRef render(llvm::json::Value Data);
 
   void registerPartial(StringRef Name, StringRef Partial);
 
@@ -177,14 +204,14 @@ class Template {
   void registerEscape(DenseMap<char, StringRef> Escapes);
 
 private:
-  DenseMap<StringRef, ASTNode *> Partials;
-  DenseMap<StringRef, Lambda> Lambdas;
-  DenseMap<StringRef, SectionLambda> SectionLambdas;
+  SmallString<0> Output;
+  StringMap<ASTNode *> Partials;
+  StringMap<Lambda> Lambdas;
+  StringMap<SectionLambda> SectionLambdas;
   DenseMap<char, StringRef> Escapes;
   llvm::BumpPtrAllocator Allocator;
   ASTNode *Tree;
 };
-
 } // namespace mustache
 } // end namespace llvm
 #endif // LLVM_SUPPORT_MUSTACHE
\ No newline at end of file
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index dd6e5ebb19209c..76532161fd18b9 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -8,21 +8,23 @@
 
 #include "llvm/Support/Mustache.h"
 #include "llvm/Support/Error.h"
+#include <sstream>
 
 using namespace llvm;
 using namespace llvm::json;
 using namespace llvm::mustache;
 
-SmallString<128> escapeString(StringRef Input,
-                              DenseMap<char, StringRef> &Escape) {
-  SmallString<128> EscapedString("");
+SmallString<0> escapeString(StringRef Input,
+                            DenseMap<char, StringRef> &Escape) {
+
+  SmallString<0> Output;
   for (char C : Input) {
     if (Escape.find(C) != Escape.end())
-      EscapedString += Escape[C];
+      Output += Escape[C];
     else
-      EscapedString += C;
+      Output += C;
   }
-  return EscapedString;
+  return Output;
 }
 
 Accessor split(StringRef Str, char Delimiter) {
@@ -40,8 +42,19 @@ Accessor split(StringRef Str, char Delimiter) {
   return Tokens;
 }
 
+void addIndentation(llvm::SmallString<0> &PartialStr, size_t IndentationSize) {
+  std::string Indent(IndentationSize, ' ');
+  llvm::SmallString<0> Result;
+  for (size_t I = 0; I < PartialStr.size(); ++I) {
+    Result.push_back(PartialStr[I]);
+    if (PartialStr[I] == '\n' && I < PartialStr.size() - 1)
+      Result.append(Indent);
+  }
+  PartialStr = Result;
+}
+
 Token::Token(StringRef RawBody, StringRef InnerBody, char Identifier)
-    : RawBody(RawBody), TokenBody(InnerBody) {
+    : RawBody(RawBody), TokenBody(InnerBody), Indentation(0) {
   TokenType = getTokenType(Identifier);
   if (TokenType == Type::Comment)
     return;
@@ -53,7 +66,8 @@ Token::Token(StringRef RawBody, StringRef InnerBody, char Identifier)
 }
 
 Token::Token(StringRef Str)
-    : TokenType(Type::Text), RawBody(Str), Accessor({}), TokenBody(Str) {}
+    : TokenType(Type::Text), RawBody(Str), Accessor({}), TokenBody(Str),
+      Indentation(0) {}
 
 Token::Type Token::getTokenType(char Identifier) {
   switch (Identifier) {
@@ -80,8 +94,11 @@ bool noTextBehind(size_t Idx, const SmallVector<Token, 0> &Tokens) {
     return false;
   const Token &PrevToken = Tokens[Idx - 1];
   StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
-  return TokenBody.ends_with("\n") || TokenBody.ends_with("\r\n") ||
-         (TokenBody.empty() && Idx == 1);
+  // Check if the token body ends with a newline
+  // or if the previous token is empty and the current token is the first token
+  // eg. "  {{#section}}A{{#section}}" would be considered as no text behind
+  // and should be render as "A" instead of "  A"
+  return TokenBody.ends_with("\n") || (TokenBody.empty() && Idx == 1);
 }
 // Function to check if there's no meaningful text ahead
 bool noTextAhead(size_t Idx, const SmallVector<Token, 0> &Tokens) {
@@ -94,6 +111,13 @@ bool noTextAhead(size_t Idx, const SmallVector<Token, 0> &Tokens) {
   return TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n");
 }
 
+bool requiresCleanUp(Token::Type T) {
+  // We must clean up all the tokens that could contain child nodes
+  return T == Token::Type::SectionOpen || T == Token::Type::InvertSectionOpen ||
+         T == Token::Type::SectionClose || T == Token::Type::Comment ||
+         T == Token::Type::Partial;
+}
+
 // Simple tokenizer that splits the template into tokens
 // the mustache spec allows {{{ }}} to unescape variables
 // but we don't support that here unescape variable
@@ -102,8 +126,8 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
   SmallVector<Token, 0> Tokens;
   StringRef Open("{{");
   StringRef Close("}}");
-  std::size_t Start = 0;
-  std::size_t DelimiterStart = Template.find(Open);
+  size_t Start = 0;
+  size_t DelimiterStart = Template.find(Open);
   if (DelimiterStart == StringRef::npos) {
     Tokens.emplace_back(Template);
     return Tokens;
@@ -121,13 +145,9 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
     // Extract the Interpolated variable without {{ and }}
     size_t InterpolatedStart = DelimiterStart + Open.size();
     size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.size();
-    SmallString<128> Interpolated =
+    SmallString<0> Interpolated =
         Template.substr(InterpolatedStart, InterpolatedEnd);
-    SmallString<128> RawBody;
-    RawBody += Open;
-    RawBody += Interpolated;
-    RawBody += Close;
-
+    SmallString<0> RawBody({Open, Interpolated, Close});
     Tokens.emplace_back(RawBody, Interpolated, Interpolated[0]);
     Start = DelimiterEnd + Close.size();
     DelimiterStart = Template.find(Open, Start);
@@ -136,46 +156,66 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
   if (Start < Template.size())
     Tokens.emplace_back(Template.substr(Start));
 
-  // fix up white spaces for
-  // open sections/inverted sections/close section/comment
+  // Fix up white spaces for:
+  //  open sections/inverted sections/close section/comment
   // This loop attempts to find standalone tokens and tries to trim out
-  // the whitespace around them
-  // for example:
+  // the surrounding whitespace.
+  // For example:
   // if you have the template string
   //  "Line 1\n {{#section}} \n Line 2 \n {{/section}} \n Line 3"
   // The output would be
   //  "Line 1\n Line 2\n Line 3"
   size_t LastIdx = Tokens.size() - 1;
   for (size_t Idx = 0, End = Tokens.size(); Idx < End; ++Idx) {
-    Token::Type CurrentType = Tokens[Idx].getType();
+    Token &CurrentToken = Tokens[Idx];
+    Token::Type CurrentType = CurrentToken.getType();
     // Check if token type requires cleanup
-    bool RequiresCleanUp = (CurrentType == Token::Type::SectionOpen ||
-                            CurrentType == Token::Type::InvertSectionOpen ||
-                            CurrentType == Token::Type::SectionClose ||
-                            CurrentType == Token::Type::Comment ||
-                            CurrentType == Token::Type::Partial);
+    bool RequiresCleanUp = requiresCleanUp(CurrentType);
 
     if (!RequiresCleanUp)
       continue;
 
+    // We adjust the token body if there's no text behind or ahead a token is
+    // considered surrounded by no text if the right of the previous token
+    // is a newline followed by spaces or if the left of the next token
+    // is spaces followed by a newline
+    // eg.
+    //  "Line 1\n {{#section}} \n Line 2 \n {{/section}} \n Line 3"
+
     bool NoTextBehind = noTextBehind(Idx, Tokens);
     bool NoTextAhead = noTextAhead(Idx, Tokens);
 
-    // Adjust next token body if no text ahead
+    // Adjust next token body if there is no text ahead
+    // eg.
+    //  The template string
+    //  "{{! Comment }} \nLine 2"
+    // would be considered as no text ahead and should be render as
+    //  " Line 2"
     if ((NoTextBehind && NoTextAhead) || (NoTextAhead && Idx == 0)) {
       Token &NextToken = Tokens[Idx + 1];
       StringRef NextTokenBody = NextToken.getTokenBody();
-      if (NextTokenBody.starts_with("\r\n")) {
+      // cut off the leading newline which could be \n or \r\n
+      if (NextTokenBody.starts_with("\r\n"))
         NextToken.setTokenBody(NextTokenBody.substr(2));
-      } else if (NextTokenBody.starts_with("\n")) {
+      else if (NextTokenBody.starts_with("\n"))
         NextToken.setTokenBody(NextTokenBody.substr(1));
-      }
     }
-    // Adjust previous token body if no text behind
-    if ((NoTextBehind && NoTextAhead) || (NoTextBehind && Idx == LastIdx)) {
+    // Adjust previous token body if there no text behind
+    // eg.
+    //  The template string
+    //  " \t{{#section}}A{{/section}}"
+    // would be considered as no text ahead and should be render as
+    //  "A"
+    // The exception for this is partial tag which requires us to
+    // keep track of the indentation once it's rendered
+    if (((NoTextBehind && NoTextAhead) || (NoTextBehind && Idx == LastIdx))) {
       Token &PrevToken = Tokens[Idx - 1];
       StringRef PrevTokenBody = PrevToken.getTokenBody();
-      PrevToken.setTokenBody(PrevTokenBody.rtrim(" \t\v\t"));
+      StringRef Unindented = PrevTokenBody.rtrim(" \t\v");
+      size_t Indentation = PrevTokenBody.size() - Unindented.size();
+      if (CurrentType != Token::Type::Partial)
+        PrevToken.setTokenBody(Unindented);
+      CurrentToken.setIndentation(Indentation);
     }
   }
   return Tokens;
@@ -233,6 +273,7 @@ void Parser::parseMustache(ASTNode *Parent) {
     }
     case Token::Type::Partial: {
       CurrentNode = new (Node) ASTNode(ASTNode::Partial, A, Parent);
+      CurrentNode->setIndentation(CurrentToken.getIndentation());
       Parent->addChild(CurrentNode);
       break;
     }
@@ -241,12 +282,12 @@ void Parser::parseMustache(ASTNode *Parent) {
       size_t Start = CurrentPtr;
       parseMustache(CurrentNode);
       size_t End = CurrentPtr;
-      SmallString<128> RawBody;
+      SmallString<0> RawBody;
       if (Start + 1 < End - 1) {
         for (std::size_t I = Start + 1; I < End - 1; I++)
           RawBody += Tokens[I].getRawBody();
       } else if (Start + 1 == End - 1) {
-        RawBody = Tokens[Start].getRawBody();
+        RawBody = Tokens[Start + 1].getRawBody();
       }
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
@@ -257,12 +298,12 @@ void Parser::parseMustache(ASTNode *Parent) {
       size_t Start = CurrentPtr;
       parseMustache(CurrentNode);
       size_t End = CurrentPtr;
-      SmallString<128> RawBody;
+      SmallString<0> RawBody;
       if (Start + 1 < End - 1) {
         for (size_t Idx = Start + 1; Idx < End - 1; Idx++)
           RawBody += Tokens[Idx].getRawBody();
       } else if (Start + 1 == End - 1) {
-        RawBody = Tokens[Start].getRawBody();
+        RawBody = Tokens[Start + 1].getRawBody();
       }
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
@@ -276,16 +317,17 @@ void Parser::parseMustache(ASTNode *Parent) {
   }
 }
 
-SmallString<128> Template::render(Value Data) {
+StringRef Template::render(Value Data) {
   BumpPtrAllocator LocalAllocator;
-  return Tree->render(Data, LocalAllocator, Partials, Lambdas, SectionLambdas,
-                      Escapes);
+  Tree->setUpNode(LocalAllocator, Partials, Lambdas, SectionLambdas, Escapes);
+  Tree->render(Data, Output);
+  return Output.str();
 }
 
 void Template::registerPartial(StringRef Name, StringRef Partial) {
   Parser P = Parser(Partial, Allocator);
   ASTNode *PartialTree = P.parse();
-  Partials[Name] = PartialTree;
+  Partials.insert(std::make_pair(Name, PartialTree));
 }
 
 void Template::registerLambda(StringRef Name, Lambda L) { Lambdas[Name] = L; }
@@ -308,19 +350,23 @@ Template::Template(StringRef TemplateStr) {
   registerEscape(HtmlEntities);
 }
 
-SmallString<128> printJson(Value &Data) {
-
-  SmallString<128> Result;
+void toJsonString(Value &Data, SmallString<0> &Output) {
   if (Data.getAsNull())
-    return Result;
+    return;
   if (auto *Arr = Data.getAsArray())
     if (Arr->empty())
-      return Result;
+      return;
   if (Data.getAsString()) {
-    Result += Data.getAsString()->str();
-    return Result;
+    Output = Data.getAsString()->str();
+    return;
+  }
+  if (auto Num = Data.getAsNumber()) {
+    std::ostringstream Oss;
+    Oss << *Num;
+    Output = Oss.str();
+    return;
   }
-  return formatv("{0:2}", Data);
+  Output = formatv("{0:2}", Data);
 }
 
 bool isFalsey(Value &V) {
@@ -329,97 +375,70 @@ bool isFalsey(Value &V) {
          (V.getAsObject() && V.getAsObject()->empty());
 }
 
-SmallString<128>
-ASTNode::render(Value Data, BumpPtrAllocator &Allocator,
-                DenseMap<StringRef, ASTNode *> &Partials,
-                DenseMap<StringRef, Lambda> &Lambdas,
-                DenseMap<StringRef, SectionLambda> &SectionLambdas,
-                DenseMap<char, StringRef> &Escapes) {
+void ASTNode::render(Value Data, SmallString<0> &Output) {
   LocalContext = Data;
   Value Context = T == Root ? Data : findContext();
-  SmallString<128> Result;
   switch (T) {
-  case Root: {
-    for (ASTNode *Child : Children)
-      Result += Child->render(Context, Allocator, Partials, Lambdas,
-                              SectionLambdas, Escapes);
-    return Result;
-  }
+  case Root:
+    renderChild(Data, Output);
+    return;
   case Text:
-    return Body;
+    Output = Body;
+    return;
   case Partial: {
-    if (Partials.find(Accessor[0]) != Partials.end()) {
-      ASTNode *Partial = Partials[Accessor[0]];
-      Result += Partial->render(Data, Allocator, Partials, Lambdas,
-                                SectionLambdas, Escapes);
-      return Result;
-    }
-    return Result;
+    auto Partial = Partials->find(Accessor[0]);
+    if (Partial != Partials->end())
+      renderPartial(Context, Output, Partial->getValue());
+    return;
   }
   case Variable: {
-    if (Lambdas.find(Accessor[0]) != Lambdas.end()) {
-      Lambda &L = Lambdas[Accessor[0]];
-      Value LambdaResult = L();
-      StringRef LambdaStr = printJson(LambdaResult);
-      Parser P = Parser(LambdaStr, Allocator);
-      ASTNode *LambdaNode = P.parse();
-      SmallString<128> RenderStr = LambdaNode->render(
-          Data, Allocator, Partials, Lambdas, SectionLambdas, Escapes);
-      return escapeString(RenderStr, Escapes);
+    auto Lambda = Lambdas->find(Accessor[0]);
+    if (Lambda != Lambdas->end())
+      renderLambdas(Data, Output, Lambda->getValue());
+    else {
+      toJsonString(Context, Output);
+      Output = escapeString(Output, *Escapes);
     }
-    return escapeString(printJson(Context), Escapes);
+    return;
   }
   case UnescapeVariable: {
-    if (Lambdas.find(Accessor[0]) != Lambdas.end()) {
-      Lambda &L = Lambdas[Accessor[0]];
-      Value LambdaResult = L();
-      StringRef LambdaStr = printJson(LambdaResult);
-      Parser P = Parser(LambdaStr, Allocator);
-      ASTNode *LambdaNode = P.parse();
-      DenseMap<char, StringRef> EmptyEscapes;
-      return LambdaNode->render(Data, Allocator, Partials, Lambdas,
-                                SectionLambdas, EmptyEscapes);
-    }
-    return printJson(Context);
+    auto Lambda = Lambdas->find(Accessor[0]);
+    if (Lambda != Lambdas->end())
+      renderLambdas(Data, Output, Lambda->getValue());
+    else
+      toJsonString(Context, Output);
+    return;
   }
   case Section: {
     // Sections are not rendered if the context is falsey
-    bool IsLambda = SectionLambdas.find(Accessor[0]) != SectionLambdas.end();
+    auto SectionLambda = SectionLambdas->find(Accessor[0]);
+    bool IsLambda = SectionLambda != SectionLambdas->end();
     if (isFalsey(Context) && !IsLambda)
-      return Result;
+      return;
+
     if (IsLambda) {
-      SectionLambda &Lambda = SectionLambdas[Accessor[0]];
-      Value Return = Lambda(RawBody);
-      if (isFalsey(Return))
-        return Result;
-      StringRef LambdaStr = printJson(Return);
-      Parser P = Parser(LambdaStr.str(), Allocator);
-      ASTNode *LambdaNode = P.parse();
-      return LambdaNode->render(Data, Allocator, Partials, Lambdas,
-                                SectionLambdas, Escapes);
+      renderSectionLambdas(Data, Output, SectionLambda->getValue());
+      return;
     }
+
     if (Context.getAsArray()) {
+      SmallString<0> Result;
       json::Array *Arr = Context.getAsArray();
-      for (Value &V : *Arr) {
-        for (ASTNode *Child : Children)
-          Result += Child->render(V, Allocator, Partials, Lambdas,
-                                  SectionLambdas, Escapes);
-      }
-      return Result;
+      for (Value &V : *Arr)
+        renderChild(V, Result);
+      Output = Result;
+      return;
     }
-    for (ASTNode *Child : Children)
-      Result += Child->render(Context, Allocator, Partials, Lambdas,
-                              SectionLambdas, Escapes);
-    return Result;
+
+    renderChild(Context, Output);
   }
   case InvertSection: {
-    bool IsLambda = SectionLambdas.find(Accessor[0]) != SectionLambdas.end();
+    bool IsLambda = SectionLambdas->find(Accessor[0]) != SectionLambdas->end();
+
     if (!isFalsey(Context) || IsLambda)
-      return Result;
-    for (ASTNode *Child : Children)
-      Result += Child->render(Context, Allocator, Partials, Lambdas,
-                              SectionLambdas, Escapes);
-    return Result;
+      return;
+
+    renderChild(Context, Output);
   }
   }
   llvm_unreachable("Invalid ASTNode type");
@@ -427,10 +446,10 @@ ASTNode::render(Value Data, BumpPtrAllocator &Allocator,
 
 Value ASTNode::findContext() {
   // The mustache spec allows for dot notation to access nested values
-  // a single dot refers to the current context
-  // We attempt to find the JSON context in the current node if it is not found
-  // we traverse the parent nodes to find the context until we reach the root
-  // node or the context is found
+  // a single dot refers to the current context.
+  // We attempt to find the JSON context in the current node, if it is not
+  // found, then we traverse the parent nodes to find the context until we
+  // reach the root node or the context is found
   if (Accessor.empty())
     return nullptr;
   if (Accessor[0] == ".")
@@ -448,11 +467,11 @@ Value ASTNode::findContext() {
     return nullptr;
   }
   Value Context = nullptr;
-  for (auto E : enumerate(Accessor)) {
-    Value *CurrentValue = CurrentContext->get(E.value());
+  for (auto [Idx, Acc] : enumerate(Accessor)) {
+    Value *CurrentValue = CurrentContext->get(Acc);
     if (!CurrentValue)
       return nullptr;
-    if (E.index() < Accessor.size() - 1) {
+    if (Idx < Accessor.size() - 1) {
       CurrentContext = CurrentValue->getAsObject();
       if (!CurrentContext)
         return nullptr;
@@ -461,3 +480,61 @@ Value ASTNode::findContext() {
   }
   return Context;
 }
+
+void ASTNode::renderChild(Value &Context, SmallString<0> &Output) {
+  for (ASTNode *Child : Children) {
+    SmallString<0> ChildResult;
+    Child->render(Context, ChildResult);
+    Output += ChildResult;
+  }
+}
+
+void ASTNode::renderPartial(Value &Context, SmallString<0> &Output,
+                            ASTNode *Partial) {
+  Partial->render(Context, Output);
+  addIndentation(Output, Indentation);
+}
+
+void ASTNode::renderLambdas(Value &Context, SmallString<0> &Output, Lambda &L) {
+  Value LambdaResult = L();
+  SmallString<0> LambdaStr;
+  toJsonString(LambdaResult, LambdaStr);
+  Parser P = Parser(LambdaStr, *Allocator);
+  ASTNode *LambdaNode = P.parse();
+  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
+                        *Escapes);
+  LambdaNode->render(Context, Output);
+  if (T == Variable)
+    Output = escapeString(Output, *Escapes);
+  return;
+}
+
+void ASTNode::renderSectionLambdas(Value &Contexts, SmallString<0> &Output,
+                                   SectionLambda &L) {
+  Value Return = L(RawBody);
+  if (isFalsey(Return))
+    return;
+  SmallString<0> LambdaStr;
+  toJsonString(Return, LambdaStr);
+  Parser P = Parser(LambdaStr, *Allocator);
+  ASTNode *LambdaNode = P.parse();
+  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
+                        *Escapes);
+  LambdaNode->render(Contexts, Output);
+  return;
+}
+
+void ASTNode::setUpNode(BumpPtrAllocator &Alloc, StringMap<ASTNode *> &Par,
+                        StringMap<Lambda> &L, StringMap<SectionLambda> &SC,
+                        DenseMap<char, StringRef> &E) {
+
+  // Passed down datastructures needed for rendering to
+  // the children nodes
+  Allocator = &Alloc;
+  Partials = &Par;
+  Lambdas = &L;
+  SectionLambdas = &SC;
+  Escapes = &E;
+  for (ASTNode *Child : Children)
+    Child->setUpNode(Alloc, Par, L, SC, E);
+}

>From 9c5966efe2e45bc4118fba6944a8e68dfad09419 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 02:10:26 -0400
Subject: [PATCH 29/57] [llvm] add mustache verification tool

---
 llvm/tools/mustache/CMakeLists.txt |   3 +
 llvm/tools/mustache/mustache.cpp   | 102 +++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 llvm/tools/mustache/CMakeLists.txt
 create mode 100644 llvm/tools/mustache/mustache.cpp

diff --git a/llvm/tools/mustache/CMakeLists.txt b/llvm/tools/mustache/CMakeLists.txt
new file mode 100644
index 00000000000000..721b553741d05b
--- /dev/null
+++ b/llvm/tools/mustache/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+    add_llvm_tool(mustache mustache.cpp)
\ No newline at end of file
diff --git a/llvm/tools/mustache/mustache.cpp b/llvm/tools/mustache/mustache.cpp
new file mode 100644
index 00000000000000..07b7c0dc528696
--- /dev/null
+++ b/llvm/tools/mustache/mustache.cpp
@@ -0,0 +1,102 @@
+//===- mustache.cpp - The LLVM Modular Optimizer
+//-------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple drivers to test the mustache spec found here
+// https://github.com/mustache/
+// It is used to verify that the current implementation conforms to the spec
+// simply download the spec and pass the test files to the driver
+//
+// Currently Triple Mustache is not supported we expect the following spec
+// test to fail:
+//    Triple Mustache
+//    Triple Mustache Integer Interpolation
+//    Triple Mustache Decimal Interpolation
+//    Triple Mustache Null Interpolation
+//    Triple Mustache Context Miss Interpolation
+//    Dotted Names - Triple Mustache Interpolation
+//    Implicit Iterators - Triple Mustache
+//    Triple Mustache - Surrounding Whitespace
+//    Triple Mustache - Standalone
+//    Triple Mustache With Padding
+//    Standalone Indentation
+//    Implicit Iterator - Triple mustache
+//
+// Usage:
+//  mustache path/to/test/file/test.json path/to/test/file/test2.json ...
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+cl::list<std::string> InputFiles(cl::Positional, cl::desc("<input files>"),
+                                 cl::OneOrMore);
+
+void runThroughTest(StringRef InputFile) {
+  llvm::outs() << "Running Tests: " << InputFile << "\n";
+  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrError =
+      MemoryBuffer::getFile(InputFile);
+
+  if (auto EC = BufferOrError.getError()) {
+    return;
+  }
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+  llvm::StringRef FileContent = Buffer->getBuffer();
+  Expected<Value> Json = parse(FileContent);
+
+  if (auto E = Json.takeError()) {
+    errs() << "Parsing error: " << toString(std::move(E)) << "\n";
+    return;
+  }
+  // Get test
+  Array *Obj = (*Json).getAsObject()->getArray("tests");
+  size_t Total = 0;
+  size_t Success = 0;
+  for (Value V : *Obj) {
+    Object *TestCase = V.getAsObject();
+    StringRef TemplateStr = TestCase->getString("template").value();
+    StringRef ExpectedStr = TestCase->getString("expected").value();
+    StringRef Name = TestCase->getString("name").value();
+    Value *Data = TestCase->get("data");
+    Value *Partials = TestCase->get("partials");
+
+    if (!Data)
+      continue;
+
+    Template T = Template(TemplateStr);
+    if (Partials) {
+      for (auto PartialPairs : *Partials->getAsObject()) {
+        StringRef Partial = PartialPairs.getSecond().getAsString().value();
+        StringRef Str = llvm::StringRef(PartialPairs.getFirst());
+        T.registerPartial(Str, Partial);
+      }
+    }
+    StringRef ActualStr = T.render(*Data);
+    if (ExpectedStr == ActualStr) {
+      Success++;
+    } else {
+      llvm::outs() << "Test Failed: " << Name << "\n";
+    }
+    Total++;
+  }
+
+  llvm::outs() << "Result " << Success << "/" << Total << " succeeded\n";
+}
+int main(int argc, char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+  for (const auto &FileName : InputFiles) {
+    runThroughTest(FileName);
+  }
+  return 0;
+}
\ No newline at end of file

>From 6b4f5cd29a687974f346c46bc02425854a14589b Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 02:21:47 -0400
Subject: [PATCH 30/57] [llvm] clang-format

---
 llvm/include/llvm/Support/Mustache.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 4cd66d08dd39fa..21e233eb12d25c 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -129,16 +129,16 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), LocalContext(nullptr){};
+  ASTNode() : T(Type::Root), LocalContext(nullptr) {};
 
   ASTNode(StringRef Body, ASTNode *Parent)
       : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr),
-        Indentation(0){};
+        Indentation(0) {};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        LocalContext(nullptr), Indentation(0){};
+        LocalContext(nullptr), Indentation(0) {};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 

>From 1d5fa2ad5a9fcd8c14af3cecb48c6d0ac660c486 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 02:10:26 -0400
Subject: [PATCH 31/57] [llvm] add mustache verification tool

---
 llvm/tools/mustache/CMakeLists.txt |   3 +
 llvm/tools/mustache/mustache.cpp   | 102 +++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 llvm/tools/mustache/CMakeLists.txt
 create mode 100644 llvm/tools/mustache/mustache.cpp

diff --git a/llvm/tools/mustache/CMakeLists.txt b/llvm/tools/mustache/CMakeLists.txt
new file mode 100644
index 00000000000000..721b553741d05b
--- /dev/null
+++ b/llvm/tools/mustache/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+    add_llvm_tool(mustache mustache.cpp)
\ No newline at end of file
diff --git a/llvm/tools/mustache/mustache.cpp b/llvm/tools/mustache/mustache.cpp
new file mode 100644
index 00000000000000..07b7c0dc528696
--- /dev/null
+++ b/llvm/tools/mustache/mustache.cpp
@@ -0,0 +1,102 @@
+//===- mustache.cpp - The LLVM Modular Optimizer
+//-------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple drivers to test the mustache spec found here
+// https://github.com/mustache/
+// It is used to verify that the current implementation conforms to the spec
+// simply download the spec and pass the test files to the driver
+//
+// Currently Triple Mustache is not supported we expect the following spec
+// test to fail:
+//    Triple Mustache
+//    Triple Mustache Integer Interpolation
+//    Triple Mustache Decimal Interpolation
+//    Triple Mustache Null Interpolation
+//    Triple Mustache Context Miss Interpolation
+//    Dotted Names - Triple Mustache Interpolation
+//    Implicit Iterators - Triple Mustache
+//    Triple Mustache - Surrounding Whitespace
+//    Triple Mustache - Standalone
+//    Triple Mustache With Padding
+//    Standalone Indentation
+//    Implicit Iterator - Triple mustache
+//
+// Usage:
+//  mustache path/to/test/file/test.json path/to/test/file/test2.json ...
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+cl::list<std::string> InputFiles(cl::Positional, cl::desc("<input files>"),
+                                 cl::OneOrMore);
+
+void runThroughTest(StringRef InputFile) {
+  llvm::outs() << "Running Tests: " << InputFile << "\n";
+  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrError =
+      MemoryBuffer::getFile(InputFile);
+
+  if (auto EC = BufferOrError.getError()) {
+    return;
+  }
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+  llvm::StringRef FileContent = Buffer->getBuffer();
+  Expected<Value> Json = parse(FileContent);
+
+  if (auto E = Json.takeError()) {
+    errs() << "Parsing error: " << toString(std::move(E)) << "\n";
+    return;
+  }
+  // Get test
+  Array *Obj = (*Json).getAsObject()->getArray("tests");
+  size_t Total = 0;
+  size_t Success = 0;
+  for (Value V : *Obj) {
+    Object *TestCase = V.getAsObject();
+    StringRef TemplateStr = TestCase->getString("template").value();
+    StringRef ExpectedStr = TestCase->getString("expected").value();
+    StringRef Name = TestCase->getString("name").value();
+    Value *Data = TestCase->get("data");
+    Value *Partials = TestCase->get("partials");
+
+    if (!Data)
+      continue;
+
+    Template T = Template(TemplateStr);
+    if (Partials) {
+      for (auto PartialPairs : *Partials->getAsObject()) {
+        StringRef Partial = PartialPairs.getSecond().getAsString().value();
+        StringRef Str = llvm::StringRef(PartialPairs.getFirst());
+        T.registerPartial(Str, Partial);
+      }
+    }
+    StringRef ActualStr = T.render(*Data);
+    if (ExpectedStr == ActualStr) {
+      Success++;
+    } else {
+      llvm::outs() << "Test Failed: " << Name << "\n";
+    }
+    Total++;
+  }
+
+  llvm::outs() << "Result " << Success << "/" << Total << " succeeded\n";
+}
+int main(int argc, char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+  for (const auto &FileName : InputFiles) {
+    runThroughTest(FileName);
+  }
+  return 0;
+}
\ No newline at end of file

>From d400c29c76f05f29cc5a84c616b926876c9ed085 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 03:01:32 -0400
Subject: [PATCH 32/57] [llvm] fix errors

---
 llvm/lib/Support/Mustache.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 76532161fd18b9..d4d26245433175 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -287,7 +287,7 @@ void Parser::parseMustache(ASTNode *Parent) {
         for (std::size_t I = Start + 1; I < End - 1; I++)
           RawBody += Tokens[I].getRawBody();
       } else if (Start + 1 == End - 1) {
-        RawBody = Tokens[Start + 1].getRawBody();
+        RawBody = Tokens[Start].getRawBody();
       }
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
@@ -303,7 +303,7 @@ void Parser::parseMustache(ASTNode *Parent) {
         for (size_t Idx = Start + 1; Idx < End - 1; Idx++)
           RawBody += Tokens[Idx].getRawBody();
       } else if (Start + 1 == End - 1) {
-        RawBody = Tokens[Start + 1].getRawBody();
+        RawBody = Tokens[Start].getRawBody();
       }
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
@@ -388,7 +388,7 @@ void ASTNode::render(Value Data, SmallString<0> &Output) {
   case Partial: {
     auto Partial = Partials->find(Accessor[0]);
     if (Partial != Partials->end())
-      renderPartial(Context, Output, Partial->getValue());
+      renderPartial(Data, Output, Partial->getValue());
     return;
   }
   case Variable: {
@@ -439,6 +439,7 @@ void ASTNode::render(Value Data, SmallString<0> &Output) {
       return;
 
     renderChild(Context, Output);
+    return;
   }
   }
   llvm_unreachable("Invalid ASTNode type");
@@ -491,6 +492,8 @@ void ASTNode::renderChild(Value &Context, SmallString<0> &Output) {
 
 void ASTNode::renderPartial(Value &Context, SmallString<0> &Output,
                             ASTNode *Partial) {
+  Partial->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
+                     *Escapes);
   Partial->render(Context, Output);
   addIndentation(Output, Indentation);
 }

>From e92c17a28af56c36cdfb25cf10aabea05047d140 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 02:10:26 -0400
Subject: [PATCH 33/57] [llvm] add mustache verification tool

---
 llvm/tools/mustache/CMakeLists.txt |   3 +
 llvm/tools/mustache/mustache.cpp   | 102 +++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 llvm/tools/mustache/CMakeLists.txt
 create mode 100644 llvm/tools/mustache/mustache.cpp

diff --git a/llvm/tools/mustache/CMakeLists.txt b/llvm/tools/mustache/CMakeLists.txt
new file mode 100644
index 00000000000000..721b553741d05b
--- /dev/null
+++ b/llvm/tools/mustache/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+    add_llvm_tool(mustache mustache.cpp)
\ No newline at end of file
diff --git a/llvm/tools/mustache/mustache.cpp b/llvm/tools/mustache/mustache.cpp
new file mode 100644
index 00000000000000..07b7c0dc528696
--- /dev/null
+++ b/llvm/tools/mustache/mustache.cpp
@@ -0,0 +1,102 @@
+//===- mustache.cpp - The LLVM Modular Optimizer
+//-------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple drivers to test the mustache spec found here
+// https://github.com/mustache/
+// It is used to verify that the current implementation conforms to the spec
+// simply download the spec and pass the test files to the driver
+//
+// Currently Triple Mustache is not supported we expect the following spec
+// test to fail:
+//    Triple Mustache
+//    Triple Mustache Integer Interpolation
+//    Triple Mustache Decimal Interpolation
+//    Triple Mustache Null Interpolation
+//    Triple Mustache Context Miss Interpolation
+//    Dotted Names - Triple Mustache Interpolation
+//    Implicit Iterators - Triple Mustache
+//    Triple Mustache - Surrounding Whitespace
+//    Triple Mustache - Standalone
+//    Triple Mustache With Padding
+//    Standalone Indentation
+//    Implicit Iterator - Triple mustache
+//
+// Usage:
+//  mustache path/to/test/file/test.json path/to/test/file/test2.json ...
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+cl::list<std::string> InputFiles(cl::Positional, cl::desc("<input files>"),
+                                 cl::OneOrMore);
+
+void runThroughTest(StringRef InputFile) {
+  llvm::outs() << "Running Tests: " << InputFile << "\n";
+  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrError =
+      MemoryBuffer::getFile(InputFile);
+
+  if (auto EC = BufferOrError.getError()) {
+    return;
+  }
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+  llvm::StringRef FileContent = Buffer->getBuffer();
+  Expected<Value> Json = parse(FileContent);
+
+  if (auto E = Json.takeError()) {
+    errs() << "Parsing error: " << toString(std::move(E)) << "\n";
+    return;
+  }
+  // Get test
+  Array *Obj = (*Json).getAsObject()->getArray("tests");
+  size_t Total = 0;
+  size_t Success = 0;
+  for (Value V : *Obj) {
+    Object *TestCase = V.getAsObject();
+    StringRef TemplateStr = TestCase->getString("template").value();
+    StringRef ExpectedStr = TestCase->getString("expected").value();
+    StringRef Name = TestCase->getString("name").value();
+    Value *Data = TestCase->get("data");
+    Value *Partials = TestCase->get("partials");
+
+    if (!Data)
+      continue;
+
+    Template T = Template(TemplateStr);
+    if (Partials) {
+      for (auto PartialPairs : *Partials->getAsObject()) {
+        StringRef Partial = PartialPairs.getSecond().getAsString().value();
+        StringRef Str = llvm::StringRef(PartialPairs.getFirst());
+        T.registerPartial(Str, Partial);
+      }
+    }
+    StringRef ActualStr = T.render(*Data);
+    if (ExpectedStr == ActualStr) {
+      Success++;
+    } else {
+      llvm::outs() << "Test Failed: " << Name << "\n";
+    }
+    Total++;
+  }
+
+  llvm::outs() << "Result " << Success << "/" << Total << " succeeded\n";
+}
+int main(int argc, char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+  for (const auto &FileName : InputFiles) {
+    runThroughTest(FileName);
+  }
+  return 0;
+}
\ No newline at end of file

>From 8fa5fd78b0e870d128da0dfb0f235ae9cb62bf20 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 10:23:51 -0400
Subject: [PATCH 34/57] [llvm] fix more bugs

---
 llvm/lib/Support/Mustache.cpp | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index d4d26245433175..4bf31db15d634a 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -94,12 +94,14 @@ bool noTextBehind(size_t Idx, const SmallVector<Token, 0> &Tokens) {
     return false;
   const Token &PrevToken = Tokens[Idx - 1];
   StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
-  // Check if the token body ends with a newline
-  // or if the previous token is empty and the current token is the first token
-  // eg. "  {{#section}}A{{#section}}" would be considered as no text behind
-  // and should be render as "A" instead of "  A"
+  // We make a special exception for when previous token is empty 
+  // and the current token is the second token 
+  // ex.
+  //  " {{#section}}A{{/section}}"
+  // that's why we check if the token body is empty and the index is 1
   return TokenBody.ends_with("\n") || (TokenBody.empty() && Idx == 1);
 }
+
 // Function to check if there's no meaningful text ahead
 bool noTextAhead(size_t Idx, const SmallVector<Token, 0> &Tokens) {
   if (Idx >= Tokens.size() - 1 ||
@@ -431,6 +433,7 @@ void ASTNode::render(Value Data, SmallString<0> &Output) {
     }
 
     renderChild(Context, Output);
+    return;
   }
   case InvertSection: {
     bool IsLambda = SectionLambdas->find(Accessor[0]) != SectionLambdas->end();

>From fd7c106b30289ab5966799c4524535e6aa9393bb Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 14:40:28 -0400
Subject: [PATCH 35/57] [llvm] change mustache to pass by reference

---
 llvm/include/llvm/Support/Mustache.h |  32 ++++----
 llvm/lib/Support/Mustache.cpp        | 107 ++++++++++++++-------------
 2 files changed, 73 insertions(+), 66 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 21e233eb12d25c..433e2dfe4103b9 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -129,16 +129,16 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), LocalContext(nullptr) {};
+  ASTNode() : T(Type::Root), ParentContext(nullptr), LocalContext(nullptr){};
 
   ASTNode(StringRef Body, ASTNode *Parent)
-      : T(Type::Text), Body(Body), Parent(Parent), LocalContext(nullptr),
-        Indentation(0) {};
+      : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
+        LocalContext(nullptr), Indentation(0){};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        LocalContext(nullptr), Indentation(0) {};
+        ParentContext(nullptr), LocalContext(nullptr), Indentation(0){};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 
@@ -148,26 +148,27 @@ class ASTNode {
 
   void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
 
-  void render(llvm::json::Value Data, SmallString<0> &Output);
+  void render(const llvm::json::Value &Data, SmallString<0> &Output);
 
-  void setUpNode(llvm::BumpPtrAllocator &Allocator,
-                 StringMap<ASTNode *> &Partials, StringMap<Lambda> &Lambdas,
+  void setUpNode(StringMap<ASTNode *> &Partials, StringMap<Lambda> &Lambdas,
                  StringMap<SectionLambda> &SectionLambdas,
                  DenseMap<char, StringRef> &Escapes);
 
+  void setUpContext(llvm::BumpPtrAllocator *Alloc);
+
 private:
-  void renderLambdas(llvm::json::Value &Contexts, SmallString<0> &Output,
+  void renderLambdas(const llvm::json::Value &Contexts, SmallString<0> &Output,
                      Lambda &L);
 
-  void renderSectionLambdas(llvm::json::Value &Contexts, SmallString<0> &Output,
-                            SectionLambda &L);
+  void renderSectionLambdas(const llvm::json::Value &Contexts,
+                            SmallString<0> &Output, SectionLambda &L);
 
-  void renderPartial(llvm::json::Value &Contexts, SmallString<0> &Output,
+  void renderPartial(const llvm::json::Value &Contexts, SmallString<0> &Output,
                      ASTNode *Partial);
 
-  void renderChild(llvm::json::Value &Context, SmallString<0> &Output);
+  void renderChild(const llvm::json::Value &Context, SmallString<0> &Output);
 
-  llvm::json::Value findContext();
+  const llvm::json::Value *findContext();
 
   llvm::BumpPtrAllocator *Allocator;
   StringMap<ASTNode *> *Partials;
@@ -181,7 +182,8 @@ class ASTNode {
   ASTNode *Parent;
   std::vector<ASTNode *> Children;
   const Accessor Accessor;
-  llvm::json::Value LocalContext;
+  const llvm::json::Value *ParentContext;
+  const llvm::json::Value *LocalContext;
 };
 
 // A Template represents the container for the AST and the partials
@@ -190,7 +192,7 @@ class Template {
 public:
   Template(StringRef TemplateStr);
 
-  StringRef render(llvm::json::Value Data);
+  StringRef render(llvm::json::Value &Data);
 
   void registerPartial(StringRef Name, StringRef Partial);
 
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 4bf31db15d634a..87cded1ff0822b 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -94,8 +94,8 @@ bool noTextBehind(size_t Idx, const SmallVector<Token, 0> &Tokens) {
     return false;
   const Token &PrevToken = Tokens[Idx - 1];
   StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
-  // We make a special exception for when previous token is empty 
-  // and the current token is the second token 
+  // We make a special exception for when previous token is empty
+  // and the current token is the second token
   // ex.
   //  " {{#section}}A{{/section}}"
   // that's why we check if the token body is empty and the index is 1
@@ -144,7 +144,7 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
       break;
     }
 
-    // Extract the Interpolated variable without {{ and }}
+    // Extract the Interpolated variable without delimiters {{ and }}
     size_t InterpolatedStart = DelimiterStart + Open.size();
     size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.size();
     SmallString<0> Interpolated =
@@ -285,12 +285,8 @@ void Parser::parseMustache(ASTNode *Parent) {
       parseMustache(CurrentNode);
       size_t End = CurrentPtr;
       SmallString<0> RawBody;
-      if (Start + 1 < End - 1) {
-        for (std::size_t I = Start + 1; I < End - 1; I++)
-          RawBody += Tokens[I].getRawBody();
-      } else if (Start + 1 == End - 1) {
-        RawBody = Tokens[Start].getRawBody();
-      }
+      for (std::size_t I = Start; I < End - 1; I++)
+        RawBody += Tokens[I].getRawBody();
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
       break;
@@ -301,12 +297,8 @@ void Parser::parseMustache(ASTNode *Parent) {
       parseMustache(CurrentNode);
       size_t End = CurrentPtr;
       SmallString<0> RawBody;
-      if (Start + 1 < End - 1) {
-        for (size_t Idx = Start + 1; Idx < End - 1; Idx++)
-          RawBody += Tokens[Idx].getRawBody();
-      } else if (Start + 1 == End - 1) {
-        RawBody = Tokens[Start].getRawBody();
-      }
+      for (size_t Idx = Start; Idx < End - 1; Idx++)
+        RawBody += Tokens[Idx].getRawBody();
       CurrentNode->setRawBody(RawBody);
       Parent->addChild(CurrentNode);
       break;
@@ -319,9 +311,9 @@ void Parser::parseMustache(ASTNode *Parent) {
   }
 }
 
-StringRef Template::render(Value Data) {
+StringRef Template::render(Value &Data) {
   BumpPtrAllocator LocalAllocator;
-  Tree->setUpNode(LocalAllocator, Partials, Lambdas, SectionLambdas, Escapes);
+  Tree->setUpContext(&LocalAllocator);
   Tree->render(Data, Output);
   return Output.str();
 }
@@ -329,6 +321,7 @@ StringRef Template::render(Value Data) {
 void Template::registerPartial(StringRef Name, StringRef Partial) {
   Parser P = Parser(Partial, Allocator);
   ASTNode *PartialTree = P.parse();
+  PartialTree->setUpNode(Partials, Lambdas, SectionLambdas, Escapes);
   Partials.insert(std::make_pair(Name, PartialTree));
 }
 
@@ -350,9 +343,10 @@ Template::Template(StringRef TemplateStr) {
                                             {'"', """},
                                             {'\'', "'"}};
   registerEscape(HtmlEntities);
+  Tree->setUpNode(Partials, Lambdas, SectionLambdas, Escapes);
 }
 
-void toJsonString(Value &Data, SmallString<0> &Output) {
+void toJsonString(const Value &Data, SmallString<0> &Output) {
   if (Data.getAsNull())
     return;
   if (auto *Arr = Data.getAsArray())
@@ -371,15 +365,18 @@ void toJsonString(Value &Data, SmallString<0> &Output) {
   Output = formatv("{0:2}", Data);
 }
 
-bool isFalsey(Value &V) {
+bool isFalsey(const Value &V) {
   return V.getAsNull() || (V.getAsBoolean() && !V.getAsBoolean().value()) ||
          (V.getAsArray() && V.getAsArray()->empty()) ||
          (V.getAsObject() && V.getAsObject()->empty());
 }
 
-void ASTNode::render(Value Data, SmallString<0> &Output) {
-  LocalContext = Data;
-  Value Context = T == Root ? Data : findContext();
+void ASTNode::render(const Value &Data, SmallString<0> &Output) {
+
+  ParentContext = &Data;
+  const Value *ContextPtr = T == Root ? ParentContext : findContext();
+  const Value &Context = ContextPtr ? *ContextPtr : nullptr;
+
   switch (T) {
   case Root:
     renderChild(Data, Output);
@@ -425,8 +422,8 @@ void ASTNode::render(Value Data, SmallString<0> &Output) {
 
     if (Context.getAsArray()) {
       SmallString<0> Result;
-      json::Array *Arr = Context.getAsArray();
-      for (Value &V : *Arr)
+      const json::Array *Arr = Context.getAsArray();
+      for (const Value &V : *Arr)
         renderChild(V, Result);
       Output = Result;
       return;
@@ -448,7 +445,7 @@ void ASTNode::render(Value Data, SmallString<0> &Output) {
   llvm_unreachable("Invalid ASTNode type");
 }
 
-Value ASTNode::findContext() {
+const Value *ASTNode::findContext() {
   // The mustache spec allows for dot notation to access nested values
   // a single dot refers to the current context.
   // We attempt to find the JSON context in the current node, if it is not
@@ -457,22 +454,23 @@ Value ASTNode::findContext() {
   if (Accessor.empty())
     return nullptr;
   if (Accessor[0] == ".")
-    return LocalContext;
-  json::Object *CurrentContext = LocalContext.getAsObject();
+    return ParentContext;
+
+  const json::Object *CurrentContext = ParentContext->getAsObject();
   StringRef CurrentAccessor = Accessor[0];
   ASTNode *CurrentParent = Parent;
 
   while (!CurrentContext || !CurrentContext->get(CurrentAccessor)) {
     if (CurrentParent->T != Root) {
-      CurrentContext = CurrentParent->LocalContext.getAsObject();
+      CurrentContext = CurrentParent->ParentContext->getAsObject();
       CurrentParent = CurrentParent->Parent;
       continue;
     }
     return nullptr;
   }
-  Value Context = nullptr;
+  const Value *Context = nullptr;
   for (auto [Idx, Acc] : enumerate(Accessor)) {
-    Value *CurrentValue = CurrentContext->get(Acc);
+    const Value *CurrentValue = CurrentContext->get(Acc);
     if (!CurrentValue)
       return nullptr;
     if (Idx < Accessor.size() - 1) {
@@ -480,43 +478,43 @@ Value ASTNode::findContext() {
       if (!CurrentContext)
         return nullptr;
     } else
-      Context = *CurrentValue;
+      Context = CurrentValue;
   }
   return Context;
 }
 
-void ASTNode::renderChild(Value &Context, SmallString<0> &Output) {
+void ASTNode::renderChild(const Value &Contexts, SmallString<0> &Output) {
   for (ASTNode *Child : Children) {
     SmallString<0> ChildResult;
-    Child->render(Context, ChildResult);
+    Child->render(Contexts, ChildResult);
     Output += ChildResult;
   }
 }
 
-void ASTNode::renderPartial(Value &Context, SmallString<0> &Output,
+void ASTNode::renderPartial(const Value &Contexts, SmallString<0> &Output,
                             ASTNode *Partial) {
-  Partial->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
-                     *Escapes);
-  Partial->render(Context, Output);
+  Partial->setUpContext(Allocator);
+  Partial->render(Contexts, Output);
   addIndentation(Output, Indentation);
 }
 
-void ASTNode::renderLambdas(Value &Context, SmallString<0> &Output, Lambda &L) {
+void ASTNode::renderLambdas(const Value &Contexts, SmallString<0> &Output,
+                            Lambda &L) {
   Value LambdaResult = L();
   SmallString<0> LambdaStr;
   toJsonString(LambdaResult, LambdaStr);
   Parser P = Parser(LambdaStr, *Allocator);
   ASTNode *LambdaNode = P.parse();
-  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
-                        *Escapes);
-  LambdaNode->render(Context, Output);
+  LambdaNode->setUpNode(*Partials, *Lambdas, *SectionLambdas, *Escapes);
+  LambdaNode->setUpContext(Allocator);
+  LambdaNode->render(Contexts, Output);
   if (T == Variable)
     Output = escapeString(Output, *Escapes);
   return;
 }
 
-void ASTNode::renderSectionLambdas(Value &Contexts, SmallString<0> &Output,
-                                   SectionLambda &L) {
+void ASTNode::renderSectionLambdas(const Value &Contexts,
+                                   SmallString<0> &Output, SectionLambda &L) {
   Value Return = L(RawBody);
   if (isFalsey(Return))
     return;
@@ -524,23 +522,30 @@ void ASTNode::renderSectionLambdas(Value &Contexts, SmallString<0> &Output,
   toJsonString(Return, LambdaStr);
   Parser P = Parser(LambdaStr, *Allocator);
   ASTNode *LambdaNode = P.parse();
-  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
-                        *Escapes);
+  LambdaNode->setUpNode(*Partials, *Lambdas, *SectionLambdas, *Escapes);
+  LambdaNode->setUpContext(Allocator);
   LambdaNode->render(Contexts, Output);
   return;
 }
 
-void ASTNode::setUpNode(BumpPtrAllocator &Alloc, StringMap<ASTNode *> &Par,
-                        StringMap<Lambda> &L, StringMap<SectionLambda> &SC,
+void ASTNode::setUpNode(StringMap<ASTNode *> &Par, StringMap<Lambda> &L,
+                        StringMap<SectionLambda> &SC,
                         DenseMap<char, StringRef> &E) {
-
   // Passed down datastructures needed for rendering to
-  // the children nodes
-  Allocator = &Alloc;
+  // the children nodes. This must be called before rendering
   Partials = &Par;
   Lambdas = &L;
   SectionLambdas = &SC;
   Escapes = &E;
   for (ASTNode *Child : Children)
-    Child->setUpNode(Alloc, Par, L, SC, E);
+    Child->setUpNode(Par, L, SC, E);
+}
+
+void ASTNode::setUpContext(llvm::BumpPtrAllocator *Alloc) {
+  // Passed down the allocator to the children nodes.
+  // Each render call requires a allocator for generating
+  // Partial/Section nodes
+  Allocator = Alloc;
+  for (ASTNode *Child : Children)
+    Child->setUpContext(Alloc);
 }

>From 29bba68935ef7f8cc5dff0477853ac25b8cf65bc Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 14:58:04 -0400
Subject: [PATCH 36/57] [llvm] fix failing mustache regression test

---
 llvm/include/llvm/Support/Mustache.h | 6 +++---
 llvm/lib/Support/Mustache.cpp        | 5 +++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 433e2dfe4103b9..6d9cc8393a2f1e 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -129,16 +129,16 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), ParentContext(nullptr), LocalContext(nullptr){};
+  ASTNode() : T(Type::Root), ParentContext(nullptr), LocalContext(nullptr) {};
 
   ASTNode(StringRef Body, ASTNode *Parent)
       : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
-        LocalContext(nullptr), Indentation(0){};
+        LocalContext(nullptr), Indentation(0) {};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        ParentContext(nullptr), LocalContext(nullptr), Indentation(0){};
+        ParentContext(nullptr), LocalContext(nullptr), Indentation(0) {};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 87cded1ff0822b..422ab60a672e57 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -19,8 +19,9 @@ SmallString<0> escapeString(StringRef Input,
 
   SmallString<0> Output;
   for (char C : Input) {
-    if (Escape.find(C) != Escape.end())
-      Output += Escape[C];
+    auto It = Escape.find(C);
+    if (It != Escape.end())
+      Output += It->getSecond();
     else
       Output += C;
   }

>From 7eed82f343478e317b89dd9e48faeff2c9ce65f1 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 15:03:12 -0400
Subject: [PATCH 37/57] [llvm] format

---
 llvm/include/llvm/Support/Mustache.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 6d9cc8393a2f1e..1b6a8c76f5218a 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -55,6 +55,7 @@
 //   StringRef Rendered = Template.render(Data);
 //   // Rendered == "Hello, World!"
 // \endcode
+//
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_SUPPORT_MUSTACHE
@@ -157,6 +158,7 @@ class ASTNode {
   void setUpContext(llvm::BumpPtrAllocator *Alloc);
 
 private:
+  
   void renderLambdas(const llvm::json::Value &Contexts, SmallString<0> &Output,
                      Lambda &L);
 

>From e73454d198155a595efde5401ea0d344a8970765 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 15:05:24 -0400
Subject: [PATCH 38/57] [llvm] remove unused mustache member

---
 llvm/include/llvm/Support/Mustache.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 1b6a8c76f5218a..8b22fdfb74cf26 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -185,7 +185,6 @@ class ASTNode {
   std::vector<ASTNode *> Children;
   const Accessor Accessor;
   const llvm::json::Value *ParentContext;
-  const llvm::json::Value *LocalContext;
 };
 
 // A Template represents the container for the AST and the partials

>From b58fbcbbcbf93c077d63af64e67977e53f17cb9c Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 15:08:47 -0400
Subject: [PATCH 39/57] [llvm] remove unused mustache member

---
 llvm/include/llvm/Support/Mustache.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 8b22fdfb74cf26..50435d4a04cd0f 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -134,12 +134,12 @@ class ASTNode {
 
   ASTNode(StringRef Body, ASTNode *Parent)
       : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
-        LocalContext(nullptr), Indentation(0) {};
+        Indentation(0) {};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        ParentContext(nullptr), LocalContext(nullptr), Indentation(0) {};
+        ParentContext(nullptr), Indentation(0) {};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 

>From bb4ba4096446218b33e232a87d5309a174858092 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 16:03:11 -0400
Subject: [PATCH 40/57] [llvm] address more comments

---
 llvm/include/llvm/Support/Mustache.h |  15 +--
 llvm/lib/Support/Mustache.cpp        | 153 +++++++++++++++------------
 2 files changed, 95 insertions(+), 73 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 50435d4a04cd0f..62c15e05850e60 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -130,7 +130,7 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), ParentContext(nullptr), LocalContext(nullptr) {};
+  ASTNode() : T(Type::Root), ParentContext(nullptr) {};
 
   ASTNode(StringRef Body, ASTNode *Parent)
       : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
@@ -151,12 +151,12 @@ class ASTNode {
 
   void render(const llvm::json::Value &Data, SmallString<0> &Output);
 
-  void setUpNode(StringMap<ASTNode *> &Partials, StringMap<Lambda> &Lambdas,
+  void setUpNode(llvm::BumpPtrAllocator &Alloc,
+                 StringMap<ASTNode *> &Partials, 
+                 StringMap<Lambda> &Lambdas,
                  StringMap<SectionLambda> &SectionLambdas,
                  DenseMap<char, StringRef> &Escapes);
-
-  void setUpContext(llvm::BumpPtrAllocator *Alloc);
-
+  
 private:
   
   void renderLambdas(const llvm::json::Value &Contexts, SmallString<0> &Output,
@@ -212,9 +212,12 @@ class Template {
   StringMap<Lambda> Lambdas;
   StringMap<SectionLambda> SectionLambdas;
   DenseMap<char, StringRef> Escapes;
+  // The allocator for the ASTNode Tree
   llvm::BumpPtrAllocator Allocator;
+  // Allocator for each render call resets after each render
+  llvm::BumpPtrAllocator LocalAllocator;
   ASTNode *Tree;
 };
 } // namespace mustache
 } // end namespace llvm
-#endif // LLVM_SUPPORT_MUSTACHE
\ No newline at end of file
+#endif // LLVM_SUPPORT_MUSTACHE
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 422ab60a672e57..0fa88c0896f6d3 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -16,8 +16,8 @@ using namespace llvm::mustache;
 
 SmallString<0> escapeString(StringRef Input,
                             DenseMap<char, StringRef> &Escape) {
-
   SmallString<0> Output;
+  Output.reserve(Input.size());
   for (char C : Input) {
     auto It = Escape.find(C);
     if (It != Escape.end())
@@ -91,24 +91,33 @@ Token::Type Token::getTokenType(char Identifier) {
 
 // Function to check if there's no meaningful text behind
 bool noTextBehind(size_t Idx, const SmallVector<Token, 0> &Tokens) {
-  if (Idx == 0 || Tokens[Idx - 1].getType() != Token::Type::Text)
+  if(Idx == 0)
+    return false;
+  
+  int PrevIdx = Idx - 1;
+  if (Tokens[PrevIdx].getType() != Token::Type::Text)
     return false;
+  
   const Token &PrevToken = Tokens[Idx - 1];
   StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
-  // We make a special exception for when previous token is empty
+  // We make an exception for when previous token is empty
   // and the current token is the second token
   // ex.
   //  " {{#section}}A{{/section}}"
-  // that's why we check if the token body is empty and the index is 1
+  // the output of this is
+  //  "A"
   return TokenBody.ends_with("\n") || (TokenBody.empty() && Idx == 1);
 }
 
 // Function to check if there's no meaningful text ahead
 bool noTextAhead(size_t Idx, const SmallVector<Token, 0> &Tokens) {
-  if (Idx >= Tokens.size() - 1 ||
-      Tokens[Idx + 1].getType() != Token::Type::Text)
+  if (Idx >= Tokens.size() - 1)
     return false;
-
+  
+  int PrevIdx = Idx + 1;
+  if (Tokens[Idx + 1].getType() != Token::Type::Text)
+    return false;
+  
   const Token &NextToken = Tokens[Idx + 1];
   StringRef TokenBody = NextToken.getRawBody().ltrim(" ");
   return TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n");
@@ -121,10 +130,47 @@ bool requiresCleanUp(Token::Type T) {
          T == Token::Type::Partial;
 }
 
-// Simple tokenizer that splits the template into tokens
-// the mustache spec allows {{{ }}} to unescape variables
-// but we don't support that here unescape variable
-// is represented only by {{& variable}}
+// Adjust next token body if there is no text ahead
+// eg.
+//  The template string
+//  "{{! Comment }} \nLine 2"
+// would be considered as no text ahead and should be render as
+//  " Line 2"
+void stripTokenAhead(SmallVector<Token, 0>& Tokens, size_t Idx) {
+  Token &NextToken = Tokens[Idx + 1];
+  StringRef NextTokenBody = NextToken.getTokenBody();
+  // cut off the leading newline which could be \n or \r\n
+  if (NextTokenBody.starts_with("\r\n"))
+    NextToken.setTokenBody(NextTokenBody.substr(2));
+  else if (NextTokenBody.starts_with("\n"))
+    NextToken.setTokenBody(NextTokenBody.substr(1));
+}
+
+// Adjust previous token body if there no text behind
+// eg.
+//  The template string
+//  " \t{{#section}}A{{/section}}"
+// would be considered as no text ahead and should be render as
+//  "A"
+// The exception for this is partial tag which requires us to
+// keep track of the indentation once it's rendered
+void stripTokenBefore(SmallVector<Token, 0>& Tokens, 
+                      size_t Idx,
+                      Token& CurrentToken,
+                      Token::Type CurrentType) {
+  Token &PrevToken = Tokens[Idx - 1];
+  StringRef PrevTokenBody = PrevToken.getTokenBody();
+  StringRef Unindented = PrevTokenBody.rtrim(" \t\v");
+  size_t Indentation = PrevTokenBody.size() - Unindented.size();
+  if (CurrentType != Token::Type::Partial)
+    PrevToken.setTokenBody(Unindented);
+  CurrentToken.setIndentation(Indentation);
+}
+
+// Simple tokenizer that splits the template into tokens.
+// The mustache spec allows {{{ }}} to unescape variables
+// but we don't support that here. An unescape variable
+// is represented only by {{& variable}}.
 SmallVector<Token, 0> tokenize(StringRef Template) {
   SmallVector<Token, 0> Tokens;
   StringRef Open("{{");
@@ -160,7 +206,11 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
     Tokens.emplace_back(Template.substr(Start));
 
   // Fix up white spaces for:
-  //  open sections/inverted sections/close section/comment
+  //   - open sections
+  //   - inverted sections
+  //   - close sections
+  //   - comments
+  //
   // This loop attempts to find standalone tokens and tries to trim out
   // the surrounding whitespace.
   // For example:
@@ -178,47 +228,22 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
     if (!RequiresCleanUp)
       continue;
 
-    // We adjust the token body if there's no text behind or ahead a token is
-    // considered surrounded by no text if the right of the previous token
-    // is a newline followed by spaces or if the left of the next token
-    // is spaces followed by a newline
+    // We adjust the token body if there's no text behind or ahead. 
+    // A token is considered to have no text ahead if the right of the previous
+    // token is a newline followed by spaces.
+    // A token is considered to have no text behind if the left of the next 
+    // token is spaces followed by a newline.
     // eg.
     //  "Line 1\n {{#section}} \n Line 2 \n {{/section}} \n Line 3"
-
     bool NoTextBehind = noTextBehind(Idx, Tokens);
     bool NoTextAhead = noTextAhead(Idx, Tokens);
-
-    // Adjust next token body if there is no text ahead
-    // eg.
-    //  The template string
-    //  "{{! Comment }} \nLine 2"
-    // would be considered as no text ahead and should be render as
-    //  " Line 2"
+    
     if ((NoTextBehind && NoTextAhead) || (NoTextAhead && Idx == 0)) {
-      Token &NextToken = Tokens[Idx + 1];
-      StringRef NextTokenBody = NextToken.getTokenBody();
-      // cut off the leading newline which could be \n or \r\n
-      if (NextTokenBody.starts_with("\r\n"))
-        NextToken.setTokenBody(NextTokenBody.substr(2));
-      else if (NextTokenBody.starts_with("\n"))
-        NextToken.setTokenBody(NextTokenBody.substr(1));
+      stripTokenAhead(Tokens, Idx);
     }
-    // Adjust previous token body if there no text behind
-    // eg.
-    //  The template string
-    //  " \t{{#section}}A{{/section}}"
-    // would be considered as no text ahead and should be render as
-    //  "A"
-    // The exception for this is partial tag which requires us to
-    // keep track of the indentation once it's rendered
+    
     if (((NoTextBehind && NoTextAhead) || (NoTextBehind && Idx == LastIdx))) {
-      Token &PrevToken = Tokens[Idx - 1];
-      StringRef PrevTokenBody = PrevToken.getTokenBody();
-      StringRef Unindented = PrevTokenBody.rtrim(" \t\v");
-      size_t Indentation = PrevTokenBody.size() - Unindented.size();
-      if (CurrentType != Token::Type::Partial)
-        PrevToken.setTokenBody(Unindented);
-      CurrentToken.setIndentation(Indentation);
+      stripTokenBefore(Tokens, Idx, CurrentToken, CurrentType);
     }
   }
   return Tokens;
@@ -304,25 +329,25 @@ void Parser::parseMustache(ASTNode *Parent) {
       Parent->addChild(CurrentNode);
       break;
     }
+    case Token::Type::Comment:
+      break;
     case Token::Type::SectionClose:
       return;
-    default:
-      break;
     }
   }
 }
 
 StringRef Template::render(Value &Data) {
-  BumpPtrAllocator LocalAllocator;
-  Tree->setUpContext(&LocalAllocator);
   Tree->render(Data, Output);
+  LocalAllocator.Reset();
   return Output.str();
 }
 
 void Template::registerPartial(StringRef Name, StringRef Partial) {
   Parser P = Parser(Partial, Allocator);
   ASTNode *PartialTree = P.parse();
-  PartialTree->setUpNode(Partials, Lambdas, SectionLambdas, Escapes);
+  PartialTree->setUpNode(LocalAllocator, Partials, Lambdas, SectionLambdas, 
+                         Escapes);
   Partials.insert(std::make_pair(Name, PartialTree));
 }
 
@@ -344,7 +369,8 @@ Template::Template(StringRef TemplateStr) {
                                             {'"', """},
                                             {'\'', "'"}};
   registerEscape(HtmlEntities);
-  Tree->setUpNode(Partials, Lambdas, SectionLambdas, Escapes);
+  Tree->setUpNode(LocalAllocator,
+                  Partials, Lambdas, SectionLambdas, Escapes);
 }
 
 void toJsonString(const Value &Data, SmallString<0> &Output) {
@@ -494,7 +520,6 @@ void ASTNode::renderChild(const Value &Contexts, SmallString<0> &Output) {
 
 void ASTNode::renderPartial(const Value &Contexts, SmallString<0> &Output,
                             ASTNode *Partial) {
-  Partial->setUpContext(Allocator);
   Partial->render(Contexts, Output);
   addIndentation(Output, Indentation);
 }
@@ -506,8 +531,8 @@ void ASTNode::renderLambdas(const Value &Contexts, SmallString<0> &Output,
   toJsonString(LambdaResult, LambdaStr);
   Parser P = Parser(LambdaStr, *Allocator);
   ASTNode *LambdaNode = P.parse();
-  LambdaNode->setUpNode(*Partials, *Lambdas, *SectionLambdas, *Escapes);
-  LambdaNode->setUpContext(Allocator);
+  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas, 
+                        *Escapes);
   LambdaNode->render(Contexts, Output);
   if (T == Variable)
     Output = escapeString(Output, *Escapes);
@@ -523,30 +548,24 @@ void ASTNode::renderSectionLambdas(const Value &Contexts,
   toJsonString(Return, LambdaStr);
   Parser P = Parser(LambdaStr, *Allocator);
   ASTNode *LambdaNode = P.parse();
-  LambdaNode->setUpNode(*Partials, *Lambdas, *SectionLambdas, *Escapes);
-  LambdaNode->setUpContext(Allocator);
+  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas, 
+                        *Escapes);
   LambdaNode->render(Contexts, Output);
   return;
 }
 
-void ASTNode::setUpNode(StringMap<ASTNode *> &Par, StringMap<Lambda> &L,
+void ASTNode::setUpNode(llvm::BumpPtrAllocator &Alloc,
+                        StringMap<ASTNode *> &Par, StringMap<Lambda> &L,
                         StringMap<SectionLambda> &SC,
                         DenseMap<char, StringRef> &E) {
   // Passed down datastructures needed for rendering to
   // the children nodes. This must be called before rendering
+  Allocator = &Alloc;
   Partials = &Par;
   Lambdas = &L;
   SectionLambdas = &SC;
   Escapes = &E;
   for (ASTNode *Child : Children)
-    Child->setUpNode(Par, L, SC, E);
+    Child->setUpNode(Alloc, Par, L, SC, E);
 }
 
-void ASTNode::setUpContext(llvm::BumpPtrAllocator *Alloc) {
-  // Passed down the allocator to the children nodes.
-  // Each render call requires a allocator for generating
-  // Partial/Section nodes
-  Allocator = Alloc;
-  for (ASTNode *Child : Children)
-    Child->setUpContext(Alloc);
-}

>From b0ce196c46d0b488afd013861889f1eaf8cfffc6 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 16:16:49 -0400
Subject: [PATCH 41/57] [llvm] address comments

---
 llvm/include/llvm/Support/Mustache.h | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 62c15e05850e60..e475d05e108a75 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -96,7 +96,7 @@ class Token {
 
   StringRef getRawBody() const { return RawBody; };
 
-  void setTokenBody(SmallString<128> NewBody) { TokenBody = NewBody; };
+  void setTokenBody(StringRef NewBody) { TokenBody = NewBody.str(); };
 
   Accessor getAccessor() const { return Accessor; };
 
@@ -112,7 +112,7 @@ class Token {
   size_t Indentation;
   Type TokenType;
   // RawBody is the original string that was tokenized
-  SmallString<128> RawBody;
+  SmallString<0> RawBody;
   Accessor Accessor;
   // TokenBody is the original string with the identifier removed
   SmallString<0> TokenBody;
@@ -130,16 +130,16 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), ParentContext(nullptr) {};
+  ASTNode() : T(Type::Root), ParentContext(nullptr){};
 
   ASTNode(StringRef Body, ASTNode *Parent)
       : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
-        Indentation(0) {};
+        Indentation(0){};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        ParentContext(nullptr), Indentation(0) {};
+        ParentContext(nullptr), Indentation(0){};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 
@@ -151,14 +151,12 @@ class ASTNode {
 
   void render(const llvm::json::Value &Data, SmallString<0> &Output);
 
-  void setUpNode(llvm::BumpPtrAllocator &Alloc,
-                 StringMap<ASTNode *> &Partials, 
+  void setUpNode(llvm::BumpPtrAllocator &Alloc, StringMap<ASTNode *> &Partials,
                  StringMap<Lambda> &Lambdas,
                  StringMap<SectionLambda> &SectionLambdas,
                  DenseMap<char, StringRef> &Escapes);
-  
+
 private:
-  
   void renderLambdas(const llvm::json::Value &Contexts, SmallString<0> &Output,
                      Lambda &L);
 

>From 561c7eb095baf4648b0756d19fdd392f07a9586f Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 16:28:09 -0400
Subject: [PATCH 42/57] clang-format

---
 llvm/lib/Support/Mustache.cpp | 36 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 0fa88c0896f6d3..2af4307fae02a3 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -91,13 +91,13 @@ Token::Type Token::getTokenType(char Identifier) {
 
 // Function to check if there's no meaningful text behind
 bool noTextBehind(size_t Idx, const SmallVector<Token, 0> &Tokens) {
-  if(Idx == 0)
+  if (Idx == 0)
     return false;
-  
+
   int PrevIdx = Idx - 1;
   if (Tokens[PrevIdx].getType() != Token::Type::Text)
     return false;
-  
+
   const Token &PrevToken = Tokens[Idx - 1];
   StringRef TokenBody = PrevToken.getRawBody().rtrim(" \t\v\t");
   // We make an exception for when previous token is empty
@@ -113,11 +113,11 @@ bool noTextBehind(size_t Idx, const SmallVector<Token, 0> &Tokens) {
 bool noTextAhead(size_t Idx, const SmallVector<Token, 0> &Tokens) {
   if (Idx >= Tokens.size() - 1)
     return false;
-  
+
   int PrevIdx = Idx + 1;
   if (Tokens[Idx + 1].getType() != Token::Type::Text)
     return false;
-  
+
   const Token &NextToken = Tokens[Idx + 1];
   StringRef TokenBody = NextToken.getRawBody().ltrim(" ");
   return TokenBody.starts_with("\r\n") || TokenBody.starts_with("\n");
@@ -136,7 +136,7 @@ bool requiresCleanUp(Token::Type T) {
 //  "{{! Comment }} \nLine 2"
 // would be considered as no text ahead and should be render as
 //  " Line 2"
-void stripTokenAhead(SmallVector<Token, 0>& Tokens, size_t Idx) {
+void stripTokenAhead(SmallVector<Token, 0> &Tokens, size_t Idx) {
   Token &NextToken = Tokens[Idx + 1];
   StringRef NextTokenBody = NextToken.getTokenBody();
   // cut off the leading newline which could be \n or \r\n
@@ -154,10 +154,8 @@ void stripTokenAhead(SmallVector<Token, 0>& Tokens, size_t Idx) {
 //  "A"
 // The exception for this is partial tag which requires us to
 // keep track of the indentation once it's rendered
-void stripTokenBefore(SmallVector<Token, 0>& Tokens, 
-                      size_t Idx,
-                      Token& CurrentToken,
-                      Token::Type CurrentType) {
+void stripTokenBefore(SmallVector<Token, 0> &Tokens, size_t Idx,
+                      Token &CurrentToken, Token::Type CurrentType) {
   Token &PrevToken = Tokens[Idx - 1];
   StringRef PrevTokenBody = PrevToken.getTokenBody();
   StringRef Unindented = PrevTokenBody.rtrim(" \t\v");
@@ -228,20 +226,20 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
     if (!RequiresCleanUp)
       continue;
 
-    // We adjust the token body if there's no text behind or ahead. 
+    // We adjust the token body if there's no text behind or ahead.
     // A token is considered to have no text ahead if the right of the previous
     // token is a newline followed by spaces.
-    // A token is considered to have no text behind if the left of the next 
+    // A token is considered to have no text behind if the left of the next
     // token is spaces followed by a newline.
     // eg.
     //  "Line 1\n {{#section}} \n Line 2 \n {{/section}} \n Line 3"
     bool NoTextBehind = noTextBehind(Idx, Tokens);
     bool NoTextAhead = noTextAhead(Idx, Tokens);
-    
+
     if ((NoTextBehind && NoTextAhead) || (NoTextAhead && Idx == 0)) {
       stripTokenAhead(Tokens, Idx);
     }
-    
+
     if (((NoTextBehind && NoTextAhead) || (NoTextBehind && Idx == LastIdx))) {
       stripTokenBefore(Tokens, Idx, CurrentToken, CurrentType);
     }
@@ -346,7 +344,7 @@ StringRef Template::render(Value &Data) {
 void Template::registerPartial(StringRef Name, StringRef Partial) {
   Parser P = Parser(Partial, Allocator);
   ASTNode *PartialTree = P.parse();
-  PartialTree->setUpNode(LocalAllocator, Partials, Lambdas, SectionLambdas, 
+  PartialTree->setUpNode(LocalAllocator, Partials, Lambdas, SectionLambdas,
                          Escapes);
   Partials.insert(std::make_pair(Name, PartialTree));
 }
@@ -369,8 +367,7 @@ Template::Template(StringRef TemplateStr) {
                                             {'"', """},
                                             {'\'', "'"}};
   registerEscape(HtmlEntities);
-  Tree->setUpNode(LocalAllocator,
-                  Partials, Lambdas, SectionLambdas, Escapes);
+  Tree->setUpNode(LocalAllocator, Partials, Lambdas, SectionLambdas, Escapes);
 }
 
 void toJsonString(const Value &Data, SmallString<0> &Output) {
@@ -531,7 +528,7 @@ void ASTNode::renderLambdas(const Value &Contexts, SmallString<0> &Output,
   toJsonString(LambdaResult, LambdaStr);
   Parser P = Parser(LambdaStr, *Allocator);
   ASTNode *LambdaNode = P.parse();
-  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas, 
+  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
                         *Escapes);
   LambdaNode->render(Contexts, Output);
   if (T == Variable)
@@ -548,7 +545,7 @@ void ASTNode::renderSectionLambdas(const Value &Contexts,
   toJsonString(Return, LambdaStr);
   Parser P = Parser(LambdaStr, *Allocator);
   ASTNode *LambdaNode = P.parse();
-  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas, 
+  LambdaNode->setUpNode(*Allocator, *Partials, *Lambdas, *SectionLambdas,
                         *Escapes);
   LambdaNode->render(Contexts, Output);
   return;
@@ -568,4 +565,3 @@ void ASTNode::setUpNode(llvm::BumpPtrAllocator &Alloc,
   for (ASTNode *Child : Children)
     Child->setUpNode(Alloc, Par, L, SC, E);
 }
-

>From 96f69907c1be3418f617ecc10d192538e61633ec Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 16:28:56 -0400
Subject: [PATCH 43/57] clang-format

---
 llvm/include/llvm/Support/Mustache.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index e475d05e108a75..1130434a265e42 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -130,16 +130,16 @@ class ASTNode {
     InvertSection,
   };
 
-  ASTNode() : T(Type::Root), ParentContext(nullptr){};
+  ASTNode() : T(Type::Root), ParentContext(nullptr) {};
 
   ASTNode(StringRef Body, ASTNode *Parent)
       : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
-        Indentation(0){};
+        Indentation(0) {};
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable
   ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
       : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        ParentContext(nullptr), Indentation(0){};
+        ParentContext(nullptr), Indentation(0) {};
 
   void addChild(ASTNode *Child) { Children.emplace_back(Child); };
 

>From d68cc325116020cc27be7ae41d10e15f2d9c5b1f Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 02:10:26 -0400
Subject: [PATCH 44/57] [llvm] add mustache verification tool

---
 llvm/tools/mustache/CMakeLists.txt |   3 +
 llvm/tools/mustache/mustache.cpp   | 102 +++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 llvm/tools/mustache/CMakeLists.txt
 create mode 100644 llvm/tools/mustache/mustache.cpp

diff --git a/llvm/tools/mustache/CMakeLists.txt b/llvm/tools/mustache/CMakeLists.txt
new file mode 100644
index 00000000000000..721b553741d05b
--- /dev/null
+++ b/llvm/tools/mustache/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+    add_llvm_tool(mustache mustache.cpp)
\ No newline at end of file
diff --git a/llvm/tools/mustache/mustache.cpp b/llvm/tools/mustache/mustache.cpp
new file mode 100644
index 00000000000000..07b7c0dc528696
--- /dev/null
+++ b/llvm/tools/mustache/mustache.cpp
@@ -0,0 +1,102 @@
+//===- mustache.cpp - The LLVM Modular Optimizer
+//-------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple drivers to test the mustache spec found here
+// https://github.com/mustache/
+// It is used to verify that the current implementation conforms to the spec
+// simply download the spec and pass the test files to the driver
+//
+// Currently Triple Mustache is not supported we expect the following spec
+// test to fail:
+//    Triple Mustache
+//    Triple Mustache Integer Interpolation
+//    Triple Mustache Decimal Interpolation
+//    Triple Mustache Null Interpolation
+//    Triple Mustache Context Miss Interpolation
+//    Dotted Names - Triple Mustache Interpolation
+//    Implicit Iterators - Triple Mustache
+//    Triple Mustache - Surrounding Whitespace
+//    Triple Mustache - Standalone
+//    Triple Mustache With Padding
+//    Standalone Indentation
+//    Implicit Iterator - Triple mustache
+//
+// Usage:
+//  mustache path/to/test/file/test.json path/to/test/file/test2.json ...
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+cl::list<std::string> InputFiles(cl::Positional, cl::desc("<input files>"),
+                                 cl::OneOrMore);
+
+void runThroughTest(StringRef InputFile) {
+  llvm::outs() << "Running Tests: " << InputFile << "\n";
+  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrError =
+      MemoryBuffer::getFile(InputFile);
+
+  if (auto EC = BufferOrError.getError()) {
+    return;
+  }
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+  llvm::StringRef FileContent = Buffer->getBuffer();
+  Expected<Value> Json = parse(FileContent);
+
+  if (auto E = Json.takeError()) {
+    errs() << "Parsing error: " << toString(std::move(E)) << "\n";
+    return;
+  }
+  // Get test
+  Array *Obj = (*Json).getAsObject()->getArray("tests");
+  size_t Total = 0;
+  size_t Success = 0;
+  for (Value V : *Obj) {
+    Object *TestCase = V.getAsObject();
+    StringRef TemplateStr = TestCase->getString("template").value();
+    StringRef ExpectedStr = TestCase->getString("expected").value();
+    StringRef Name = TestCase->getString("name").value();
+    Value *Data = TestCase->get("data");
+    Value *Partials = TestCase->get("partials");
+
+    if (!Data)
+      continue;
+
+    Template T = Template(TemplateStr);
+    if (Partials) {
+      for (auto PartialPairs : *Partials->getAsObject()) {
+        StringRef Partial = PartialPairs.getSecond().getAsString().value();
+        StringRef Str = llvm::StringRef(PartialPairs.getFirst());
+        T.registerPartial(Str, Partial);
+      }
+    }
+    StringRef ActualStr = T.render(*Data);
+    if (ExpectedStr == ActualStr) {
+      Success++;
+    } else {
+      llvm::outs() << "Test Failed: " << Name << "\n";
+    }
+    Total++;
+  }
+
+  llvm::outs() << "Result " << Success << "/" << Total << " succeeded\n";
+}
+int main(int argc, char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+  for (const auto &FileName : InputFiles) {
+    runThroughTest(FileName);
+  }
+  return 0;
+}
\ No newline at end of file

>From 3c53b5a27d8ae5b8306aaa74e7da5248f025231c Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 02:26:22 -0400
Subject: [PATCH 45/57] [clang-doc] init mustache implementation

---
 clang-tools-extra/clang-doc/CMakeLists.txt    |   1 +
 clang-tools-extra/clang-doc/HTMLGenerator.cpp |   3 +-
 .../clang-doc/HTMLMustacheGenerator.cpp       | 349 ++++++++++++++++++
 clang-tools-extra/clang-doc/Representation.h  |   4 +-
 .../clang-doc/assets/template.mustache        |  23 ++
 .../clang-doc/tool/CMakeLists.txt             |   1 +
 .../clang-doc/tool/ClangDocMain.cpp           |  31 ++
 7 files changed, 410 insertions(+), 2 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
 create mode 100644 clang-tools-extra/clang-doc/assets/template.mustache

diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt
index 975ad8e242e490..82aded940222db 100644
--- a/clang-tools-extra/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -15,6 +15,7 @@ add_clang_library(clangDoc
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
+  HTMLMustacheGenerator.cpp
 
   DEPENDS
   omp_gen
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index e3532559a32fcc..ed65ac965114b5 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -1133,7 +1133,8 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-static llvm::Error copyFile(StringRef FilePath, StringRef OutDirectory) {
+static llvm::Error 
+copyFile(StringRef FilePath, StringRef OutDirectory) {
   llvm::SmallString<128> PathWrite;
   llvm::sys::path::native(OutDirectory, PathWrite);
   llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
new file mode 100644
index 00000000000000..63def07c5fa804
--- /dev/null
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -0,0 +1,349 @@
+//===-- HTMLMustacheGenerator.cpp - HTML Mustache Generator -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "Generators.h"
+#include "Representation.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Mustache.h"
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+namespace clang {
+namespace doc {
+
+
+class MustacheHTMLGenerator : public Generator {
+public:
+  static const char *Format;
+  llvm::Error generateDocs(StringRef RootDir,
+                           llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
+                           const ClangDocContext &CDCtx) override;
+  llvm::Error createResources(ClangDocContext &CDCtx) override;
+  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
+                                 const ClangDocContext &CDCtx) override;
+  
+};
+
+class MustacheTemplateFile : public Template {
+public:
+  static ErrorOr<std::unique_ptr<MustacheTemplateFile>> createMustacheFile
+      (StringRef FileName) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
+        MemoryBuffer::getFile(FileName);
+    
+    if (auto EC = BufferOrError.getError()) {
+      return EC;
+    }
+    std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+    llvm::StringRef FileContent = Buffer->getBuffer();
+    return std::make_unique<MustacheTemplateFile>(FileContent);
+  }
+  
+  Error registerPartialFile(StringRef Name, StringRef FileName) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
+        MemoryBuffer::getFile(FileName);
+    if (auto EC = BufferOrError.getError()) {
+      return llvm::createFileError("cannot open file", EC);
+    }
+    std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+    llvm::StringRef FileContent = Buffer->getBuffer();
+    registerPartial(Name, FileContent);
+  }
+
+  MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
+};
+
+static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
+
+static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
+
+
+llvm::Error 
+setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
+  auto TemplateFilePath = CDCtx.MustacheTemplates.lookup("template");
+  auto Template = MustacheTemplateFile::createMustacheFile(TemplateFilePath);
+  if (auto EC = Template.getError()) {
+    return llvm::createFileError("cannot open file", EC);
+  }
+  NamespaceTemplate = std::move(Template.get());
+}
+
+llvm::Error 
+MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir, 
+                                    llvm::StringMap<std::unique_ptr<doc::Info>> Infos, 
+                                    const clang::doc::ClangDocContext &CDCtx) {
+  if (auto Err = setupTemplateFiles(CDCtx)) {
+    return Err;
+  }
+  // Track which directories we already tried to create.
+  llvm::StringSet<> CreatedDirs;
+  // Collect all output by file name and create the necessary directories.
+  llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
+  for (const auto &Group : Infos) {
+    doc::Info *Info = Group.getValue().get();
+    
+    llvm::SmallString<128> Path;
+    llvm::sys::path::native(RootDir, Path);
+    llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
+    if (!CreatedDirs.contains(Path)) {
+      if (std::error_code Err = llvm::sys::fs::create_directories(Path);
+          Err != std::error_code()) {
+        return llvm::createStringError(Err, "Failed to create directory '%s'.",
+                                       Path.c_str());
+      }
+      CreatedDirs.insert(Path);
+    }
+
+    llvm::sys::path::append(Path, Info->getFileBaseName() + ".html");
+    FileToInfos[Path].push_back(Info);
+  }
+  
+  for (const auto &Group : FileToInfos) {
+    std::error_code FileErr;
+    llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
+                                llvm::sys::fs::OF_None);
+    if (FileErr) {
+      return llvm::createStringError(FileErr, "Error opening file '%s'",
+                                     Group.getKey().str().c_str());
+    }
+    for (const auto &Info : Group.getValue()) {
+      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
+        return Err;
+      }
+    }
+  }
+}
+
+Value extractValue(const Location &L, 
+                   std::optional<StringRef> RepositoryUrl = std::nullopt) {
+  Object Obj = Object();
+  if (!L.IsFileInRootDir || !RepositoryUrl) {
+    Obj.insert({"LineNumber", L.LineNumber});
+    Obj.insert({"Filename", L.Filename});
+  }
+  SmallString<128> FileURL(*RepositoryUrl);
+  llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
+  Obj.insert({"FileURL", FileURL});
+}
+
+Value extractValue(const Reference &I, StringRef CurrentDirectory) {
+  llvm::SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory);
+  llvm::sys::path::append(Path, I.getFileBaseName() + ".html");
+  llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
+  Object Obj = Object();
+  Obj.insert({"Link", Path});
+  Obj.insert({"Name", I.Name});
+  return Obj;
+}
+
+
+Value extractValue(const TypedefInfo &I) {
+  // Not Supported
+  return nullptr;
+}
+
+Value extractValue(const CommentInfo &I) {
+  Object Obj = Object();
+  Value Child = Object();
+  
+  if (I.Kind == "FullComment") {
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"FullComment", Child});
+  }
+  if (I.Kind == "ParagraphComment") {
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"ParagraphComment", Child});
+  }
+  if (I.Kind == "BlockCommandComment") {
+    Child.getAsObject()->insert({"Command", I.Name});
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"BlockCommandComment", Child});
+  }
+  if (I.Kind == "TextComment")
+    Obj.insert({"TextComment", I.Text});
+  
+  return Obj;
+}
+
+Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
+                   const ClangDocContext &CDCtx) {
+  Object Obj = Object();
+  Obj.insert({"Name", I.Name});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
+  Obj.insert({"Access", getAccessSpelling(I.Access).str()});
+  Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
+  
+  Value ParamArr = Array();
+  for (const auto &P : I.Params) {
+    ParamArr.getAsArray()->emplace_back(extractValue(P.Type, ParentInfoDir));
+  }
+  Obj.insert({"Params", ParamArr});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    Obj.insert({"FunctionComments", ArrDesc});
+  }
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
+    else
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
+  }
+  return Obj;
+}
+
+Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
+  Object Obj = Object();
+  std::string EnumType = I.Scoped ? "enum class " : "enum ";
+  EnumType += I.Name;
+  bool HasComment = std::any_of(
+      I.Members.begin(), I.Members.end(),
+      [](const EnumValueInfo &M) { return !M.Description.empty(); });
+  Obj.insert({"EnumName", EnumType});
+  Obj.insert({"HasComment", HasComment});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
+  
+  Value Arr = Array();
+  for (const EnumValueInfo& M: I.Members) {
+    Value EnumValue = Object();
+    EnumValue.getAsObject()->insert({"Name", M.Name});
+    if (!M.ValueExpr.empty())
+      EnumValue.getAsObject()->insert({"ValueExpr", M.ValueExpr});
+    else
+      EnumValue.getAsObject()->insert({"Value", M.Value});
+    
+    if (!M.Description.empty()) {
+      Value ArrDesc = Array();
+      for (const CommentInfo& Child : M.Description) 
+        ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+      EnumValue.getAsObject()->insert({"EnumValueComments", ArrDesc});
+    }
+    Arr.getAsArray()->emplace_back(EnumValue);
+  }
+  Obj.insert({"EnumValues", Arr});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    Obj.insert({"EnumComments", ArrDesc});
+  }
+  
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
+    else
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
+  }
+  
+  return Obj;
+}
+
+Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
+  Object NamespaceValue = Object();
+  std::string InfoTitle;
+  if (I.Name.str() == "")
+    InfoTitle = "Global Namespace";
+  else
+    InfoTitle = ("namespace " + I.Name).str();  
+  
+  StringRef BasePath = I.getRelativeFilePath("");
+  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
+  NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    NamespaceValue.insert({"NamespaceComments", ArrDesc });
+  }
+
+  Value ArrNamespace = Array();
+  for (const Reference& Child : I.Children.Namespaces)
+    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Namespace", ArrNamespace});
+  
+  Value ArrRecord = Array();
+  for (const Reference& Child : I.Children.Records)
+    ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Record", ArrRecord});
+  
+  Value ArrFunction = Array();
+  for (const FunctionInfo& Child : I.Children.Functions)
+    ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
+                                                        CDCtx));
+  NamespaceValue.insert({"Function", ArrRecord});
+  
+  Value ArrEnum = Array();
+  for (const EnumInfo& Child : I.Children.Enums)
+    ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
+  NamespaceValue.insert({"Enums", ArrEnum });
+  
+  Value ArrTypedefs = Array();
+  for (const TypedefInfo& Child : I.Children.Typedefs) 
+    ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
+  NamespaceValue.insert({"Typedefs", ArrTypedefs });
+  
+}
+
+
+
+llvm::Error
+MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
+                                          const ClangDocContext &CDCtx) {
+  switch (I->IT) {
+  case InfoType::IT_namespace: {
+    Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+    OS << NamespaceTemplate->render(V);
+    break;
+  }
+  case InfoType::IT_record:
+    break;
+  case InfoType::IT_enum:
+    break;
+  case InfoType::IT_function:
+    break;
+  case InfoType::IT_typedef:
+    break;
+  case InfoType::IT_default:
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "unexpected InfoType");
+  }
+  return llvm::Error::success();
+}
+
+llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
+  
+}
+
+const char *MustacheHTMLGenerator::Format = "mustache";
+
+
+static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
+                                                  "Generator for mustache HTML output.");
+
+// This anchor is used to force the linker to link in the generated object
+// file and thus register the generator.
+volatile int HTMLGeneratorAnchorSource = 0;
+
+} // namespace doc
+} // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index bb0c534af7b740..3175b8209e3be3 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -521,8 +521,10 @@ struct ClangDocContext {
   // Path of CSS stylesheets that will be copied to OutDirectory and used to
   // style all HTML files.
   std::vector<std::string> UserStylesheets;
-  // JavaScript files that will be imported in allHTML file.
+  // JavaScript files that will be imported in all HTML file.
   std::vector<std::string> JsScripts;
+  // Mustache Template files
+  llvm::StringMap<std::string> MustacheTemplates;
   Index Idx;
 };
 
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
new file mode 100644
index 00000000000000..af4c60182ae52c
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -0,0 +1,23 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+    <head>
+        <meta charset="utf-8"/>
+        <title>{{NamespaceTitle}}</title>
+    </head>
+    {{#NamespaceComments}}
+    <p>Namespace Comment Present!</p>
+    {{/NamespaceComments}}
+    {{#Namespace}}
+    <p>Namespace Present!</p>
+    {{/Namespace}}
+    {{#Record}}
+    <p>Record Present!</p>
+    {{/Record}}
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
index 601a0460d76b38..8eb067dbe6de87 100644
--- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -21,6 +21,7 @@ target_link_libraries(clang-doc
 
 set(assets
   index.js
+  template.mustache
   clang-doc-default-stylesheet.css
 )
 
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 04773fb8a6e721..fc5a9529111b16 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -205,6 +205,30 @@ llvm::Error getHtmlAssetFiles(const char *Argv0,
   return getDefaultAssetFiles(Argv0, CDCtx);
 }
 
+llvm::Error getMustacheHtmlFiles(const char *Argv0,
+                                 clang::doc::ClangDocContext &CDCtx) {
+  if (!UserAssetPath.empty() &&
+      !llvm::sys::fs::is_directory(std::string(UserAssetPath)))
+    llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath
+                 << " falling back to default\n";
+  if (llvm::sys::fs::is_directory(std::string(UserAssetPath)))
+    return getAssetFiles(CDCtx);
+  
+  void *MainAddr = (void *)(intptr_t)getExecutablePath;
+  std::string ClangDocPath = getExecutablePath(Argv0, MainAddr);
+  llvm::SmallString<128> NativeClangDocPath;
+  llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
+  
+  llvm::SmallString<128> AssetsPath;
+  AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
+  llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
+  
+  llvm::SmallString<128> MustacheTemplate;
+  llvm::sys::path::native(AssetsPath, MustacheTemplate);
+  llvm::sys::path::append(MustacheTemplate, "template.mustache");
+  CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+}
+
 /// Make the output of clang-doc deterministic by sorting the children of
 /// namespaces and records.
 void sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> &USRToInfo) {
@@ -277,6 +301,13 @@ Example usage for a project using a compile commands database:
       return 1;
     }
   }
+  
+  if (Format == "mhtml") {
+    if (auto Err = getMustacheHtmlFiles(argv[0], CDCtx)) {
+      llvm::errs() << toString(std::move(Err)) << "\n";
+      return 1;
+    }
+  }
 
   // Mapping phase
   llvm::outs() << "Mapping decls...\n";

>From 7067fab56f58ff565305ec03c5c8b5c23e748011 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 17:50:03 -0400
Subject: [PATCH 46/57] [clang-doc] add a mustache backend init implementation

---
 clang-tools-extra/clang-doc/Generators.cpp    |  4 +-
 .../clang-doc/HTMLMustacheGenerator.cpp       | 32 ++++++++++++----
 .../clang-doc/assets/template.mustache        | 37 +++++++++++++++++--
 .../clang-doc/tool/ClangDocMain.cpp           |  9 ++++-
 .../Inputs/basic-project/include/Shape.h      |  2 -
 5 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp
index a3986b66f3c742..ae5b556d17063b 100644
--- a/clang-tools-extra/clang-doc/Generators.cpp
+++ b/clang-tools-extra/clang-doc/Generators.cpp
@@ -100,12 +100,14 @@ void Generator::addInfoToIndex(Index &Idx, const doc::Info *Info) {
 extern volatile int YAMLGeneratorAnchorSource;
 extern volatile int MDGeneratorAnchorSource;
 extern volatile int HTMLGeneratorAnchorSource;
+extern volatile int MHTMLGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED YAMLGeneratorAnchorDest =
     YAMLGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED MDGeneratorAnchorDest =
     MDGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED HTMLGeneratorAnchorDest =
     HTMLGeneratorAnchorSource;
-
+static int LLVM_ATTRIBUTE_UNUSED MHTMLGeneratorAnchorDest =
+    MHTMLGeneratorAnchorSource;
 } // namespace doc
 } // namespace clang
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 63def07c5fa804..bfa563ebdc7b37 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -54,6 +54,7 @@ class MustacheTemplateFile : public Template {
     std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
     llvm::StringRef FileContent = Buffer->getBuffer();
     registerPartial(Name, FileContent);
+    return llvm::Error::success();
   }
 
   MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
@@ -72,6 +73,7 @@ setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
     return llvm::createFileError("cannot open file", EC);
   }
   NamespaceTemplate = std::move(Template.get());
+  return llvm::Error::success();
 }
 
 llvm::Error 
@@ -118,6 +120,7 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
       }
     }
   }
+  return llvm::Error::success();
 }
 
 Value extractValue(const Location &L, 
@@ -130,6 +133,8 @@ Value extractValue(const Location &L,
   SmallString<128> FileURL(*RepositoryUrl);
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
   Obj.insert({"FileURL", FileURL});
+  
+  return Obj;
 }
 
 Value extractValue(const Reference &I, StringRef CurrentDirectory) {
@@ -280,29 +285,39 @@ Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
   Value ArrNamespace = Array();
   for (const Reference& Child : I.Children.Namespaces)
     ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Namespace", ArrNamespace});
+  
+  if (!ArrNamespace.getAsArray()->empty())
+    NamespaceValue.insert({"Namespace", Object{{"Links", ArrNamespace}}});
   
   Value ArrRecord = Array();
   for (const Reference& Child : I.Children.Records)
     ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Record", ArrRecord});
+  
+  if (!ArrRecord.getAsArray()->empty())
+    NamespaceValue.insert({"Record", Object{{"Links", ArrRecord}}});
   
   Value ArrFunction = Array();
   for (const FunctionInfo& Child : I.Children.Functions)
     ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
                                                         CDCtx));
-  NamespaceValue.insert({"Function", ArrRecord});
+  if (!ArrFunction.getAsArray()->empty())
+    NamespaceValue.insert({"Function", Object{{"Obj", ArrFunction}}});
   
   Value ArrEnum = Array();
   for (const EnumInfo& Child : I.Children.Enums)
     ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
-  NamespaceValue.insert({"Enums", ArrEnum });
+  
+  if (!ArrEnum.getAsArray()->empty())
+    NamespaceValue.insert({"Enums", Object{{"Obj", ArrEnum }}});
   
   Value ArrTypedefs = Array();
   for (const TypedefInfo& Child : I.Children.Typedefs) 
     ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
-  NamespaceValue.insert({"Typedefs", ArrTypedefs });
   
+  if (!ArrTypedefs.getAsArray()->empty())
+    NamespaceValue.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+  
+  return NamespaceValue;
 }
 
 
@@ -313,6 +328,7 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+    llvm::outs() << V << "\n";
     OS << NamespaceTemplate->render(V);
     break;
   }
@@ -332,10 +348,10 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
 }
 
 llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
-  
+  return llvm::Error::success();
 }
 
-const char *MustacheHTMLGenerator::Format = "mustache";
+const char *MustacheHTMLGenerator::Format = "mhtml";
 
 
 static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
@@ -343,7 +359,7 @@ static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator
 
 // This anchor is used to force the linker to link in the generated object
 // file and thus register the generator.
-volatile int HTMLGeneratorAnchorSource = 0;
+volatile int MHTMLGeneratorAnchorSource = 0;
 
 } // namespace doc
 } // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
index af4c60182ae52c..1d3407f8b52920 100644
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -3,7 +3,7 @@
     See https://llvm.org/LICENSE.txt for license information.
     SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     
-    This file defines the template
+    This file defines the template for generating Namespaces
 }}
 <!DOCTYPE html>
 <html lang="en-US">
@@ -11,13 +11,42 @@
         <meta charset="utf-8"/>
         <title>{{NamespaceTitle}}</title>
     </head>
+    <h1>{{NamespaceTitle}}</h1>
     {{#NamespaceComments}}
-    <p>Namespace Comment Present!</p>
+    <p>Namespace Comment</p>
     {{/NamespaceComments}}
     {{#Namespace}}
-    <p>Namespace Present!</p>
+    <h2 id="Namespace">Namespace</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Namespace}}
     {{#Record}}
-    <p>Record Present!</p>
+    <h2 id="Class">Class</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Record}}
+    {{#Function}}
+    <h2 id="Function">Function</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Function}}
+    {{#Enums}}
+    <h2 id="Enums">Enums</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Enums}}
 </html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index fc5a9529111b16..eee8dbf093cc53 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -103,6 +103,7 @@ enum OutputFormatTy {
   md,
   yaml,
   html,
+  mhtml
 };
 
 static llvm::cl::opt<OutputFormatTy>
@@ -112,7 +113,9 @@ static llvm::cl::opt<OutputFormatTy>
                                 clEnumValN(OutputFormatTy::md, "md",
                                            "Documentation in MD format."),
                                 clEnumValN(OutputFormatTy::html, "html",
-                                           "Documentation in HTML format.")),
+                                           "Documentation in HTML format."),
+                                clEnumValN(OutputFormatTy::mhtml, "mhtml",
+                                           "Documentation in mHTML format")),
                llvm::cl::init(OutputFormatTy::yaml),
                llvm::cl::cat(ClangDocCategory));
 
@@ -124,6 +127,8 @@ std::string getFormatString() {
     return "md";
   case OutputFormatTy::html:
     return "html";
+  case OutputFormatTy::mhtml:
+    return "mhtml";
   }
   llvm_unreachable("Unknown OutputFormatTy");
 }
@@ -227,6 +232,8 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
   llvm::sys::path::native(AssetsPath, MustacheTemplate);
   llvm::sys::path::append(MustacheTemplate, "template.mustache");
   CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+  
+  return llvm::Error::success();
 }
 
 /// Make the output of clang-doc deterministic by sorting the children of
diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
index e5c5d4c9e4412b..5354032f4d8323 100644
--- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
+++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
@@ -26,5 +26,3 @@ class Shape {
      */
     virtual double perimeter() const = 0;
 };
-
-

>From 1cf2b18b4066407a722ce7b84736dc32f6c2fbcd Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 24 Sep 2024 16:48:29 -0400
Subject: [PATCH 47/57] [clang-doc] update

---
 .../clang-doc/HTMLMustacheGenerator.cpp       | 16 ++++++++---
 .../clang-doc/assets/comments.mustache        | 27 +++++++++++++++++++
 .../clang-doc/assets/template.mustache        |  7 +++--
 .../Inputs/basic-project/include/Shape.h      |  2 ++
 4 files changed, 46 insertions(+), 6 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/assets/comments.mustache

diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index bfa563ebdc7b37..96a685dbe2ae87 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -194,8 +194,12 @@ Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
   Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
   
   Value ParamArr = Array();
-  for (const auto &P : I.Params) {
-    ParamArr.getAsArray()->emplace_back(extractValue(P.Type, ParentInfoDir));
+  for (const auto Val : llvm::enumerate(I.Params)) {
+    Value V = Object();
+    V.getAsObject()->insert({"Name", Val.value().Name});
+    V.getAsObject()->insert({"Type", Val.value().Type.Name});
+    V.getAsObject()->insert({"End",  Val.index() + 1 == I.Params.size()});
+    ParamArr.getAsArray()->emplace_back(V);
   }
   Obj.insert({"Params", ParamArr});
   
@@ -328,17 +332,21 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
-    llvm::outs() << V << "\n";
-    OS << NamespaceTemplate->render(V);
+    llvm::raw_ostream &OS = llvm::outs();
+    llvm::json::OStream J(OS, /*IndentSize=*/2);
+    J.value(V);
     break;
   }
   case InfoType::IT_record:
     break;
   case InfoType::IT_enum:
+    llvm::outs() << "IT_enum\n";
     break;
   case InfoType::IT_function:
+    llvm::outs() << "IT_Function\n";
     break;
   case InfoType::IT_typedef:
+    llvm::outs() << "IT_typedef\n";
     break;
   case InfoType::IT_default:
     return createStringError(llvm::inconvertibleErrorCode(),
diff --git a/clang-tools-extra/clang-doc/assets/comments.mustache b/clang-tools-extra/clang-doc/assets/comments.mustache
new file mode 100644
index 00000000000000..1eac4de91836ab
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/comments.mustache
@@ -0,0 +1,27 @@
+{{!
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines templates for generating
+}}
+
+{{#FullComments}}
+    {{#Children}}
+    {{>Comment}}    
+    {{/Children}}
+{{/FullComments}}
+{{#ParagraphComment}}
+    {{#Children}}
+    {{>Comment}}
+    {{/Children}}
+{{/ParagraphComment}}
+{{#BlockCommandComment}}
+    <div>{{Command}}</div>
+    {{#Children}}
+    {{>Comment}}
+    {{/Children}}
+{{/BlockCommandComment}}
+{{#TextComment}}
+    <p>{{TextComment}}</p>
+{{/TextComment}}
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
index 1d3407f8b52920..3b77e0189f4e22 100644
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -3,7 +3,7 @@
     See https://llvm.org/LICENSE.txt for license information.
     SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     
-    This file defines the template for generating Namespaces
+    This file defines the template for generating namespaces
 }}
 <!DOCTYPE html>
 <html lang="en-US">
@@ -13,7 +13,9 @@
     </head>
     <h1>{{NamespaceTitle}}</h1>
     {{#NamespaceComments}}
-    <p>Namespace Comment</p>
+    <div>
+        {{>Comments}}
+    </div>
     {{/NamespaceComments}}
     {{#Namespace}}
     <h2 id="Namespace">Namespace</h2>
@@ -39,6 +41,7 @@
     <h2 id="Function">Function</h2>
     <div>
         {{#Obj}}
+            
         {{/Obj}}
     </div>
     {{/Function}}
diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
index 5354032f4d8323..e5c5d4c9e4412b 100644
--- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
+++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
@@ -26,3 +26,5 @@ class Shape {
      */
     virtual double perimeter() const = 0;
 };
+
+

>From f071bb77168252eb48fbfa05ab24ac6bd41c2e93 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Wed, 25 Sep 2024 05:08:40 -0400
Subject: [PATCH 48/57] [llvm] add mustache verification tool

---
 llvm/tools/mustache/CMakeLists.txt |   3 +
 llvm/tools/mustache/mustache.cpp   | 102 +++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 llvm/tools/mustache/CMakeLists.txt
 create mode 100644 llvm/tools/mustache/mustache.cpp

diff --git a/llvm/tools/mustache/CMakeLists.txt b/llvm/tools/mustache/CMakeLists.txt
new file mode 100644
index 00000000000000..721b553741d05b
--- /dev/null
+++ b/llvm/tools/mustache/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+    add_llvm_tool(mustache mustache.cpp)
\ No newline at end of file
diff --git a/llvm/tools/mustache/mustache.cpp b/llvm/tools/mustache/mustache.cpp
new file mode 100644
index 00000000000000..07b7c0dc528696
--- /dev/null
+++ b/llvm/tools/mustache/mustache.cpp
@@ -0,0 +1,102 @@
+//===- mustache.cpp - The LLVM Modular Optimizer
+//-------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple drivers to test the mustache spec found here
+// https://github.com/mustache/
+// It is used to verify that the current implementation conforms to the spec
+// simply download the spec and pass the test files to the driver
+//
+// Currently Triple Mustache is not supported we expect the following spec
+// test to fail:
+//    Triple Mustache
+//    Triple Mustache Integer Interpolation
+//    Triple Mustache Decimal Interpolation
+//    Triple Mustache Null Interpolation
+//    Triple Mustache Context Miss Interpolation
+//    Dotted Names - Triple Mustache Interpolation
+//    Implicit Iterators - Triple Mustache
+//    Triple Mustache - Surrounding Whitespace
+//    Triple Mustache - Standalone
+//    Triple Mustache With Padding
+//    Standalone Indentation
+//    Implicit Iterator - Triple mustache
+//
+// Usage:
+//  mustache path/to/test/file/test.json path/to/test/file/test2.json ...
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+cl::list<std::string> InputFiles(cl::Positional, cl::desc("<input files>"),
+                                 cl::OneOrMore);
+
+void runThroughTest(StringRef InputFile) {
+  llvm::outs() << "Running Tests: " << InputFile << "\n";
+  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrError =
+      MemoryBuffer::getFile(InputFile);
+
+  if (auto EC = BufferOrError.getError()) {
+    return;
+  }
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+  llvm::StringRef FileContent = Buffer->getBuffer();
+  Expected<Value> Json = parse(FileContent);
+
+  if (auto E = Json.takeError()) {
+    errs() << "Parsing error: " << toString(std::move(E)) << "\n";
+    return;
+  }
+  // Get test
+  Array *Obj = (*Json).getAsObject()->getArray("tests");
+  size_t Total = 0;
+  size_t Success = 0;
+  for (Value V : *Obj) {
+    Object *TestCase = V.getAsObject();
+    StringRef TemplateStr = TestCase->getString("template").value();
+    StringRef ExpectedStr = TestCase->getString("expected").value();
+    StringRef Name = TestCase->getString("name").value();
+    Value *Data = TestCase->get("data");
+    Value *Partials = TestCase->get("partials");
+
+    if (!Data)
+      continue;
+
+    Template T = Template(TemplateStr);
+    if (Partials) {
+      for (auto PartialPairs : *Partials->getAsObject()) {
+        StringRef Partial = PartialPairs.getSecond().getAsString().value();
+        StringRef Str = llvm::StringRef(PartialPairs.getFirst());
+        T.registerPartial(Str, Partial);
+      }
+    }
+    StringRef ActualStr = T.render(*Data);
+    if (ExpectedStr == ActualStr) {
+      Success++;
+    } else {
+      llvm::outs() << "Test Failed: " << Name << "\n";
+    }
+    Total++;
+  }
+
+  llvm::outs() << "Result " << Success << "/" << Total << " succeeded\n";
+}
+int main(int argc, char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+  for (const auto &FileName : InputFiles) {
+    runThroughTest(FileName);
+  }
+  return 0;
+}
\ No newline at end of file

>From ca1331529c9e751a4ffed9f32d421eec39839622 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 7 Oct 2024 15:07:41 -0400
Subject: [PATCH 49/57] [clang-doc] add more templates

---
 clang-tools-extra/clang-doc/CMakeLists.txt    |   5 +-
 .../clang-doc/FileHelpersClangDoc.cpp         |  75 +++
 .../clang-doc/FileHelpersClangDoc.h           |  26 +
 clang-tools-extra/clang-doc/HTMLGenerator.cpp |  59 +--
 .../clang-doc/HTMLMustacheGenerator.cpp       | 281 ++++++++---
 .../clang-doc/assets/clang-doc-mustache.css   | 476 ++++++++++++++++++
 .../clang-doc/assets/class-template.mustache  | 227 +++++++++
 .../assets/comments-template.mustache         |  34 ++
 .../clang-doc/assets/comments.mustache        |  27 -
 .../clang-doc/assets/enum-template.mustache   |  47 ++
 .../assets/function-template.mustache         |  23 +
 .../clang-doc/assets/mustache-index.js        |  33 ++
 .../assets/namespace-template.mustache        |  87 ++++
 .../clang-doc/assets/template.mustache        |  55 --
 .../clang-doc/tool/CMakeLists.txt             |   8 +-
 .../clang-doc/tool/ClangDocMain.cpp           |  53 +-
 16 files changed, 1296 insertions(+), 220 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
 create mode 100644 clang-tools-extra/clang-doc/FileHelpersClangDoc.h
 create mode 100644 clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
 create mode 100644 clang-tools-extra/clang-doc/assets/class-template.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/comments-template.mustache
 delete mode 100644 clang-tools-extra/clang-doc/assets/comments.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/enum-template.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/function-template.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/mustache-index.js
 create mode 100644 clang-tools-extra/clang-doc/assets/namespace-template.mustache
 delete mode 100644 clang-tools-extra/clang-doc/assets/template.mustache

diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt
index 82aded940222db..0793c343305184 100644
--- a/clang-tools-extra/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -8,15 +8,16 @@ add_clang_library(clangDoc
   BitcodeReader.cpp
   BitcodeWriter.cpp
   ClangDoc.cpp
+  FileHelpersClangDoc.cpp
   Generators.cpp
   HTMLGenerator.cpp
+  HTMLMustacheGenerator.cpp      
   Mapper.cpp
   MDGenerator.cpp
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
-  HTMLMustacheGenerator.cpp
-
+        
   DEPENDS
   omp_gen
   ClangDriverOptions
diff --git a/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp b/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
new file mode 100644
index 00000000000000..50209cfac1ca3d
--- /dev/null
+++ b/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
@@ -0,0 +1,75 @@
+//===-- FileHelpersClangDoc.cpp - File Helpers -------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "FileHelpersClangDoc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace doc {
+
+llvm::Error
+copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory) {
+  llvm::SmallString<128> PathWrite;
+  llvm::sys::path::native(OutDirectory, PathWrite);
+  llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
+  llvm::SmallString<128> PathRead;
+  llvm::sys::path::native(FilePath, PathRead);
+  std::error_code OK;
+  std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
+  if (FileErr != OK) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "error creating file " +
+                                       llvm::sys::path::filename(FilePath) +
+                                       ": " + FileErr.message() + "\n");
+  }
+  return llvm::Error::success();
+}
+
+
+llvm::SmallString<128> computeRelativePath(llvm::StringRef Destination,
+                                                  llvm::StringRef Origin) {
+  // If Origin is empty, the relative path to the Destination is its complete
+  // path.
+  if (Origin.empty())
+    return Destination;
+  
+  // The relative path is an empty path if both directories are the same.
+  if (Destination == Origin)
+    return {};
+
+  // These iterators iterate through each of their parent directories
+  llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
+  llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
+  llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
+  llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
+  // Advance both iterators until the paths differ. Example:
+  //    Destination = A/B/C/D
+  //    Origin      = A/B/E/F
+  // FileI will point to C and DirI to E. The directories behind them is the
+  // directory they share (A/B).
+  while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
+    ++FileI;
+    ++DirI;
+  }
+  llvm::SmallString<128> Result; // This will hold the resulting path.
+  // Result has to go up one directory for each of the remaining directories in
+  // Origin
+  while (DirI != DirE) {
+    llvm::sys::path::append(Result, "..");
+    ++DirI;
+  }
+  // Result has to append each of the remaining directories in Destination
+  while (FileI != FileE) {
+    llvm::sys::path::append(Result, *FileI);
+    ++FileI;
+  }
+  return Result;
+}
+
+} // namespace doc
+} // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/FileHelpersClangDoc.h b/clang-tools-extra/clang-doc/FileHelpersClangDoc.h
new file mode 100644
index 00000000000000..9072a7bd08a4f8
--- /dev/null
+++ b/clang-tools-extra/clang-doc/FileHelpersClangDoc.h
@@ -0,0 +1,26 @@
+//===-- FileHelpersClangDoc.h --- File Helpers -------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILEHELPER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILEHELPER_H
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace doc {
+
+llvm::Error 
+copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory);
+
+llvm::SmallString<128> 
+computeRelativePath(llvm::StringRef Destination,llvm::StringRef Origin);
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILEHELPER_H
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index ed65ac965114b5..aa76d17d9411d6 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -8,6 +8,7 @@
 
 #include "Generators.h"
 #include "Representation.h"
+#include "FileHelpersClangDoc.h"
 #include "clang/Basic/Version.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -251,46 +252,6 @@ static void appendVector(std::vector<Derived> &&New,
   std::move(New.begin(), New.end(), std::back_inserter(Original));
 }
 
-// Compute the relative path from an Origin directory to a Destination directory
-static SmallString<128> computeRelativePath(StringRef Destination,
-                                            StringRef Origin) {
-  // If Origin is empty, the relative path to the Destination is its complete
-  // path.
-  if (Origin.empty())
-    return Destination;
-
-  // The relative path is an empty path if both directories are the same.
-  if (Destination == Origin)
-    return {};
-
-  // These iterators iterate through each of their parent directories
-  llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
-  llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
-  llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
-  llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
-  // Advance both iterators until the paths differ. Example:
-  //    Destination = A/B/C/D
-  //    Origin      = A/B/E/F
-  // FileI will point to C and DirI to E. The directories behind them is the
-  // directory they share (A/B).
-  while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
-    ++FileI;
-    ++DirI;
-  }
-  SmallString<128> Result; // This will hold the resulting path.
-  // Result has to go up one directory for each of the remaining directories in
-  // Origin
-  while (DirI != DirE) {
-    llvm::sys::path::append(Result, "..");
-    ++DirI;
-  }
-  // Result has to append each of the remaining directories in Destination
-  while (FileI != FileE) {
-    llvm::sys::path::append(Result, *FileI);
-    ++FileI;
-  }
-  return Result;
-}
 
 // HTML generation
 
@@ -1133,24 +1094,6 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-static llvm::Error 
-copyFile(StringRef FilePath, StringRef OutDirectory) {
-  llvm::SmallString<128> PathWrite;
-  llvm::sys::path::native(OutDirectory, PathWrite);
-  llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
-  llvm::SmallString<128> PathRead;
-  llvm::sys::path::native(FilePath, PathRead);
-  std::error_code OK;
-  std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
-  if (FileErr != OK) {
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "error creating file " +
-                                       llvm::sys::path::filename(FilePath) +
-                                       ": " + FileErr.message() + "\n");
-  }
-  return llvm::Error::success();
-}
-
 llvm::Error HTMLGenerator::createResources(ClangDocContext &CDCtx) {
   auto Err = serializeIndex(CDCtx);
   if (Err)
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 96a685dbe2ae87..6be4c795a68654 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 #include "Generators.h"
 #include "Representation.h"
+#include "FileHelpersClangDoc.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Mustache.h"
 
@@ -48,9 +49,8 @@ class MustacheTemplateFile : public Template {
   Error registerPartialFile(StringRef Name, StringRef FileName) {
     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
         MemoryBuffer::getFile(FileName);
-    if (auto EC = BufferOrError.getError()) {
+    if (auto EC = BufferOrError.getError())
       return llvm::createFileError("cannot open file", EC);
-    }
     std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
     llvm::StringRef FileContent = Buffer->getBuffer();
     registerPartial(Name, FileContent);
@@ -65,24 +65,54 @@ static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
 static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
 
 
+llvm::Error setupTemplate(
+                   std::unique_ptr<MustacheTemplateFile> &Template,
+                   StringRef TemplatePath,
+                   std::vector<std::pair<StringRef, StringRef>> Partials) {
+  auto T = MustacheTemplateFile::createMustacheFile(TemplatePath);
+  if (auto EC = T.getError())
+     return llvm::createFileError("cannot open file", EC);
+  Template = std::move(T.get());
+  for (const auto &P : Partials) {
+    auto Err = Template->registerPartialFile(P.first, P.second);
+    if (Err)
+      return Err;
+  }
+  return llvm::Error::success();
+}
+
 llvm::Error 
 setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
-  auto TemplateFilePath = CDCtx.MustacheTemplates.lookup("template");
-  auto Template = MustacheTemplateFile::createMustacheFile(TemplateFilePath);
-  if (auto EC = Template.getError()) {
-    return llvm::createFileError("cannot open file", EC);
-  }
-  NamespaceTemplate = std::move(Template.get());
+  auto NamespaceFilePath = CDCtx.MustacheTemplates.lookup("namespace-template");
+  auto ClassFilePath = CDCtx.MustacheTemplates.lookup("class-template");
+  auto CommentFilePath = CDCtx.MustacheTemplates.lookup("comments-template");
+  auto FunctionFilePath = CDCtx.MustacheTemplates.lookup("function-template");
+  auto EnumFilePath = CDCtx.MustacheTemplates.lookup("enum-template");
+  std::vector<std::pair<StringRef, StringRef>> Partials = {
+    {"Comments", CommentFilePath},
+    {"FunctionPartial", FunctionFilePath},
+    {"EnumPartial", EnumFilePath}
+  };
+  
+  auto Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials);
+  if (Err)
+    return Err;
+  
+  Err = setupTemplate(RecordTemplate, ClassFilePath, Partials);
+  
+  if (Err)
+    return Err;
+  
   return llvm::Error::success();
 }
 
+
 llvm::Error 
 MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir, 
                                     llvm::StringMap<std::unique_ptr<doc::Info>> Infos, 
                                     const clang::doc::ClangDocContext &CDCtx) {
-  if (auto Err = setupTemplateFiles(CDCtx)) {
+  if (auto Err = setupTemplateFiles(CDCtx))
     return Err;
-  }
   // Track which directories we already tried to create.
   llvm::StringSet<> CreatedDirs;
   // Collect all output by file name and create the necessary directories.
@@ -95,10 +125,9 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
     if (!CreatedDirs.contains(Path)) {
       if (std::error_code Err = llvm::sys::fs::create_directories(Path);
-          Err != std::error_code()) {
+          Err != std::error_code())
         return llvm::createStringError(Err, "Failed to create directory '%s'.",
                                        Path.c_str());
-      }
       CreatedDirs.insert(Path);
     }
 
@@ -110,14 +139,13 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     std::error_code FileErr;
     llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
                                 llvm::sys::fs::OF_None);
-    if (FileErr) {
+    if (FileErr)
       return llvm::createStringError(FileErr, "Error opening file '%s'",
                                      Group.getKey().str().c_str());
-    }
+    
     for (const auto &Info : Group.getValue()) {
-      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
+      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx))
         return Err;
-      }
     }
   }
   return llvm::Error::success();
@@ -126,12 +154,15 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
 Value extractValue(const Location &L, 
                    std::optional<StringRef> RepositoryUrl = std::nullopt) {
   Object Obj = Object();
+  Obj.insert({"LineNumber", L.LineNumber});
+  Obj.insert({"Filename", L.Filename});
+  
   if (!L.IsFileInRootDir || !RepositoryUrl) {
-    Obj.insert({"LineNumber", L.LineNumber});
-    Obj.insert({"Filename", L.Filename});
+    return Obj;
   }
   SmallString<128> FileURL(*RepositoryUrl);
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
+  FileURL += "#" + std::to_string(L.LineNumber);
   Obj.insert({"FileURL", FileURL});
   
   return Obj;
@@ -144,6 +175,8 @@ Value extractValue(const Reference &I, StringRef CurrentDirectory) {
   Object Obj = Object();
   Obj.insert({"Link", Path});
   Obj.insert({"Name", I.Name});
+  Obj.insert({"QualName", I.QualName});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
   return Obj;
 }
 
@@ -209,12 +242,13 @@ Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
     Obj.insert({"FunctionComments", ArrDesc});
   }
-  if (I.DefLoc) {
-    if (!CDCtx.RepositoryUrl)
-      Obj.insert({"Location", extractValue(*I.DefLoc)});
+  if (I.DefLoc.has_value()) {
+    Location L = *I.DefLoc;
+    if (CDCtx.RepositoryUrl.has_value())
+      Obj.insert({"Location", extractValue(L,
+                                           StringRef{*CDCtx.RepositoryUrl})});
     else
-      Obj.insert({"Location", extractValue(*I.DefLoc, 
-                                           StringRef{*CDCtx.RepositoryUrl})});  
+      Obj.insert({"Location", extractValue(L)});  
   }
   return Obj;
 }
@@ -229,7 +263,6 @@ Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
   Obj.insert({"EnumName", EnumType});
   Obj.insert({"HasComment", HasComment});
   Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
-  
   Value Arr = Array();
   for (const EnumValueInfo& M: I.Members) {
     Value EnumValue = Object();
@@ -256,75 +289,175 @@ Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
     Obj.insert({"EnumComments", ArrDesc});
   }
   
-  if (I.DefLoc) {
-    if (!CDCtx.RepositoryUrl)
-      Obj.insert({"Location", extractValue(*I.DefLoc)});
+  if (I.DefLoc.has_value()) {
+    Location L = *I.DefLoc;
+    if (CDCtx.RepositoryUrl.has_value())
+      Obj.insert({"Location", extractValue(L,
+                                           StringRef{*CDCtx.RepositoryUrl})});
     else
-      Obj.insert({"Location", extractValue(*I.DefLoc, 
-                                           StringRef{*CDCtx.RepositoryUrl})});  
+      Obj.insert({"Location", extractValue(L)});  
   }
   
   return Obj;
 }
 
-Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
-  Object NamespaceValue = Object();
-  std::string InfoTitle;
-  if (I.Name.str() == "")
-    InfoTitle = "Global Namespace";
-  else
-    InfoTitle = ("namespace " + I.Name).str();  
-  
-  StringRef BasePath = I.getRelativeFilePath("");
-  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
-  NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
-  
-  if (!I.Description.empty()) {
-    Value ArrDesc = Array();
-    for (const CommentInfo& Child : I.Description) 
-      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
-    NamespaceValue.insert({"NamespaceComments", ArrDesc });
-  }
-
+void extractScopeChildren(const ScopeChildren &S, Object &Obj, 
+                          StringRef ParentInfoDir,
+                          const ClangDocContext &CDCtx) {
   Value ArrNamespace = Array();
-  for (const Reference& Child : I.Children.Namespaces)
-    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  for (const Reference& Child : S.Namespaces)
+    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
   
   if (!ArrNamespace.getAsArray()->empty())
-    NamespaceValue.insert({"Namespace", Object{{"Links", ArrNamespace}}});
+    Obj.insert({"Namespace", Object{{"Links", ArrNamespace}}});
   
   Value ArrRecord = Array();
-  for (const Reference& Child : I.Children.Records)
-    ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  for (const Reference& Child : S.Records)
+    ArrRecord.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
   
   if (!ArrRecord.getAsArray()->empty())
-    NamespaceValue.insert({"Record", Object{{"Links", ArrRecord}}});
+    Obj.insert({"Record", Object{{"Links", ArrRecord}}});
   
   Value ArrFunction = Array();
-  for (const FunctionInfo& Child : I.Children.Functions)
-    ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
-                                                        CDCtx));
+  Value PublicFunction = Array();
+  Value ProtectedFunction = Array();
+  Value PrivateFunction = Array();
+  
+  for (const FunctionInfo& Child : S.Functions) {
+    Value F = extractValue(Child, ParentInfoDir, CDCtx);
+    AccessSpecifier Access = Child.Access;
+    if (Access == AccessSpecifier::AS_public)
+      PublicFunction.getAsArray()->emplace_back(F);
+    else if (Access == AccessSpecifier::AS_protected)
+      ProtectedFunction.getAsArray()->emplace_back(F);
+    else
+      ArrFunction.getAsArray()->emplace_back(F);
+  }  
   if (!ArrFunction.getAsArray()->empty())
-    NamespaceValue.insert({"Function", Object{{"Obj", ArrFunction}}});
+    Obj.insert({"Function", Object{{"Obj", ArrFunction}}});
+  
+  if (!PublicFunction.getAsArray()->empty())
+    Obj.insert({"PublicFunction", Object{{"Obj", PublicFunction}}});
+  
+  if (!ProtectedFunction.getAsArray()->empty())
+    Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunction}}});
+  
   
   Value ArrEnum = Array();
-  for (const EnumInfo& Child : I.Children.Enums)
+  for (const EnumInfo& Child : S.Enums)
     ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
   
   if (!ArrEnum.getAsArray()->empty())
-    NamespaceValue.insert({"Enums", Object{{"Obj", ArrEnum }}});
+    Obj.insert({"Enums", Object{{"Obj", ArrEnum }}});
   
   Value ArrTypedefs = Array();
-  for (const TypedefInfo& Child : I.Children.Typedefs) 
+  for (const TypedefInfo& Child : S.Typedefs) 
     ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
   
   if (!ArrTypedefs.getAsArray()->empty())
-    NamespaceValue.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+    Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+}
+
+Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
+  Object NamespaceValue = Object();
+  std::string InfoTitle;
+  if (I.Name.str() == "")
+    InfoTitle = "Global Namespace";
+  else
+    InfoTitle = ("namespace " + I.Name).str();  
+  
+  StringRef BasePath = I.getRelativeFilePath("");
+  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
+  NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
   
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    NamespaceValue.insert({"NamespaceComments", ArrDesc });
+  }
+  extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx);
   return NamespaceValue;
 }
 
+Value extractValue(const RecordInfo &I, const ClangDocContext &CDCtx) {
+  Object RecordValue = Object();
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    RecordValue.insert({"RecordComments", ArrDesc });
+  }
+  RecordValue.insert({"Name", I.Name});
+  RecordValue.insert({"FullName", I.FullName});
+  RecordValue.insert({"RecordType", getTagType(I.TagType)});
+  
+  if (I.DefLoc.has_value()) {
+    Location L = *I.DefLoc;
+    if (CDCtx.RepositoryUrl.has_value())
+      RecordValue.insert({"Location", extractValue(L,
+                                           StringRef{*CDCtx.RepositoryUrl})});
+    else
+      RecordValue.insert({"Location", extractValue(L)});  
+  }
+  
+  StringRef BasePath = I.getRelativeFilePath("");
+  extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
+  Value PublicMembers = Array();
+  Value ProtectedMembers = Array();
+  Value PrivateMembers = Array();
+  for (const MemberTypeInfo &Member : I.Members ) {
+    Value MemberValue = Object();
+    MemberValue.getAsObject()->insert({"Name", Member.Name});
+    MemberValue.getAsObject()->insert({"Type", Member.Type.Name});
+    if (!Member.Description.empty()) {
+      Value ArrDesc = Array();
+      for (const CommentInfo& Child : Member.Description) 
+            ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+      MemberValue.getAsObject()->insert({"MemberComments", ArrDesc });
+    }
+    
+    if (Member.Access == AccessSpecifier::AS_public)
+      PublicMembers.getAsArray()->emplace_back(MemberValue);
+    else if (Member.Access == AccessSpecifier::AS_protected)
+      ProtectedMembers.getAsArray()->emplace_back(MemberValue);
+    else if (Member.Access == AccessSpecifier::AS_private)
+      PrivateMembers.getAsArray()->emplace_back(MemberValue);
+  }
+  if (!PublicMembers.getAsArray()->empty())
+    RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}});
+  if (!ProtectedMembers.getAsArray()->empty())
+    RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
+  if (!PrivateMembers.getAsArray()->empty())
+    RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
+  
+  return RecordValue;
+}
 
+void setupTemplateValue(const ClangDocContext &CDCtx, Value &V, Info *I) {
+  V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName});
+  Value StylesheetArr = Array();
+  auto InfoPath = I->getRelativeFilePath("");
+  SmallString<128> RelativePath = computeRelativePath("", InfoPath);
+  for (const auto &FilePath  : CDCtx.UserStylesheets) {
+    SmallString<128> StylesheetPath = RelativePath;
+    llvm::sys::path::append(StylesheetPath,
+                            llvm::sys::path::filename(FilePath));
+    llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
+    StylesheetArr.getAsArray()->emplace_back(StylesheetPath);
+  }
+  V.getAsObject()->insert({"Stylesheets", StylesheetArr});
+  
+  Value ScriptArr = Array();
+  for (auto Script : CDCtx.JsScripts) {
+    SmallString<128> JsPath = RelativePath;
+    llvm::sys::path::append(JsPath, llvm::sys::path::filename(Script));
+    ScriptArr.getAsArray()->emplace_back(JsPath);
+  }
+  V.getAsObject()->insert({"Scripts", ScriptArr});
+}
+ 
 
 llvm::Error
 MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
@@ -332,13 +465,18 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
-    llvm::raw_ostream &OS = llvm::outs();
-    llvm::json::OStream J(OS, /*IndentSize=*/2);
-    J.value(V);
+    setupTemplateValue(CDCtx, V, I);
+    OS << NamespaceTemplate->render(V);
     break;
   }
-  case InfoType::IT_record:
+  case InfoType::IT_record: {
+    Value V = extractValue(*static_cast<clang::doc::RecordInfo *>(I), CDCtx);
+    setupTemplateValue(CDCtx, V, I);
+    // Serialize the JSON value to the output stream in a readable format.
+    llvm::outs() << llvm::formatv("{0:2}", V);
+    OS << RecordTemplate->render(V);
     break;
+  }  
   case InfoType::IT_enum:
     llvm::outs() << "IT_enum\n";
     break;
@@ -356,6 +494,17 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
 }
 
 llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
+  llvm::Error Err = llvm::Error::success();
+  for (const auto &FilePath : CDCtx.UserStylesheets) {
+    Err = copyFile(FilePath, CDCtx.OutDirectory);
+    if (Err)
+      return Err;
+  }
+  for (const auto &FilePath : CDCtx.JsScripts) {
+    Err = copyFile(FilePath, CDCtx.OutDirectory);
+    if (Err)
+      return Err;
+  }
   return llvm::Error::success();
 }
 
diff --git a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
new file mode 100644
index 00000000000000..2f07baa7ca0a1a
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
@@ -0,0 +1,476 @@
+ at import "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap";
+
+*,*::before *::after {
+    box-sizing:border-box
+}
+* {
+    margin:0;
+    padding:0
+}
+ol,
+ul {
+    list-style:none
+}
+img,
+picture,
+svg,
+video {
+    display:block;
+    max-width:100%
+}
+* {
+    --brand-light:#ce6300;
+    --text1-light:#000000;
+    --text2-light:#333333;
+    --surface1-light:#ffffff;
+    --surface2-light:#f5f5f5;
+    --brand-dark:#de9853;
+    --text1-dark:#ffffff;
+    --text2-dark:#cccccc;
+    --surface1-dark:#161212;
+    --surface2-dark:#272424
+}
+:root {
+    color-scheme:light;
+    --brand:var(--brand-light);
+    --text1:var(--text1-light);
+    --text2:var(--text2-light);
+    --text1-inverse:var(--text1-dark);
+    --text2-inverse:var(--text2-dark);
+    --surface1:var(--surface1-light);
+    --surface2:var(--surface2-light)
+}
+ at media(prefers-color-scheme:dark) {
+    :root {
+        color-scheme:dark;
+        --brand:var(--brand-dark);
+        --text1:var(--text1-dark);
+        --text2:var(--text2-dark);
+        --text1-inverse:var(--text1-light);
+        --text2-inverse:var(--text2-light);
+        --surface1:var(--surface1-dark);
+        --surface2:var(--surface2-dark)
+    }
+}
+[color-scheme=light] {
+    color-scheme:light;
+    --brand:var(--brand-light);
+    --text1:var(--text1-light);
+    --text2:var(--text2-light);
+    --text1-inverse:var(--text1-dark);
+    --text2-inverse:var(--text2-dark);
+    --surface1:var(--surface1-light);
+    --surface2:var(--surface2-light)
+}
+[color-scheme=dark] {
+    color-scheme:dark;
+    --brand:var(--brand-dark);
+    --text1:var(--text1-dark);
+    --text2:var(--text2-dark);
+    --text1-inverse:var(--text1-light);
+    --text2-inverse:var(--text2-light);
+    --surface1:var(--surface1-dark);
+    --surface2:var(--surface2-dark)
+}
+html {
+    background-color:var(--surface1)
+}
+
+html, body {
+    min-height: 100vh;
+    margin: 0;
+    padding: 0;
+    width: 100%;
+}
+
+.container {
+    display: flex;
+    margin-top: 60px;
+    height: calc(100% - 60px);
+    box-sizing: border-box;
+}
+
+body, html {
+    font-family:Inter,sans-serif;
+    margin: 0;
+    padding: 0;
+    height: 100%;
+}
+
+/* Navbar Styles */
+.navbar {
+    background-color: var(--surface2);
+    border-bottom: 1px solid var(--text2);
+    position: fixed;
+    width: 100%;
+    top: 0;
+    left: 0;
+    height: 60px; /* Adjust as needed */
+    color: white;
+    display: flex;
+    align-items: center;
+    padding: 0 20px;
+    box-sizing: border-box;
+    z-index: 1000;
+}
+
+
+.navbar__container {
+    display:flex;
+    justify-content:space-between;
+    align-items:center;
+    padding:1rem;
+    color:var(--text1);
+    max-width:2048px;
+    margin:auto
+}
+.navbar__logo {
+    display:flex;
+    align-items:center;
+    height:40px
+}
+.navbar__logo a {
+    display:flex;
+    align-items:center;
+    text-decoration:none;
+    height:100%
+}
+.navbar__logo img {
+    height:100%;
+    width:auto
+}
+.navbar__toggle {
+    background:0 0;
+    color:var(--text2);
+    border:none;
+    cursor:pointer;
+    font-size:1.5rem;
+    width:2.5rem;
+    height:2.5rem;
+    margin-left:auto
+}
+.navbar__toggle:hover {
+    color:var(--text1)
+}
+ at media(min-width:769px) {
+    .navbar__toggle {
+        display:none
+    }
+}
+.navbar__menu {
+    display:flex;
+    justify-content:space-between;
+    align-items:center;
+    list-style:none;
+    margin:0;
+    padding:0;
+    gap:.25rem;
+    margin-left:auto
+}
+
+ at media(max-width:768px) {
+    .navbar__menu {
+        flex-direction:column;
+        justify-content:flex-start;
+        width:100%;
+        background-color:var(--surface2);
+        position:fixed;
+        top:0;
+        left:0;
+        right:0;
+        bottom:0;
+        padding:1.5rem;
+        transform:translateX(100%);
+        transition:transform .5s ease-in-out
+    }
+}
+ at media(max-width:768px) {
+    .navbar__menu.active {
+        transform:translateX(0)
+    }
+}
+.navbar__close {
+    background:0 0;
+    border:none;
+    cursor:pointer;
+    font-size:1.5rem;
+    color:var(--text2);
+    margin-left:auto
+}
+.navbar__close:hover {
+    color:var(--text1)
+}
+ at media(min-width:769px) {
+    .navbar__close {
+        display:none
+    }
+}
+.navbar__links {
+    display:flex;
+    gap:1rem;
+    align-items:center;
+    margin:0;
+    padding:0
+}
+ at media(max-width:768px) {
+    .navbar__links {
+        flex-direction:column
+    }
+}
+.navbar__item {
+    list-style-type:none
+}
+.navbar__link {
+    color:var(--text2);
+    text-decoration:none;
+    padding:.5rem
+}
+.navbar__link:hover {
+    color:var(--text1)
+}
+.navbar__theme-toggle-button {
+    background:0 0;
+    color:var(--text2);
+    border:none;
+    cursor:pointer;
+    font-size:1.5rem;
+    width:2.5rem;
+    height:2.5rem
+}
+.navbar__theme-toggle-button:hover {
+    color:var(--text1)
+}
+
+.hero__container {
+    margin-top:1rem;
+    display:flex;
+    justify-content:center;
+    align-items:center;
+    gap:2rem
+}
+.hero__title {
+    font-size:2.5rem;
+    margin-bottom:.5rem
+}
+.hero__title-large {
+    font-size:3rem
+}
+ at media(max-width:768px) {
+    .hero__title-large {
+        font-size:2.5rem
+    }
+}
+ at media(max-width:480px) {
+    .hero__title-large {
+        font-size:2rem
+    }
+}
+ at media(max-width:768px) {
+    .hero__title {
+        font-size:2rem
+    }
+}
+ at media(max-width:480px) {
+    .hero__title {
+        font-size:1.75rem
+    }
+}
+.hero__subtitle {
+    font-size:1.25rem;
+    font-weight:500
+}
+ at media(max-width:768px) {
+    .hero__subtitle {
+        font-size:1rem
+    }
+}
+ at media(max-width:480px) {
+    .hero__subtitle {
+        font-size:.875rem
+    }
+}
+
+.section-container {
+    max-width: 2048px;
+    margin-left:auto;
+    margin-right:auto;
+    margin-top:0;
+    margin-bottom: 1rem;
+    padding:1rem 2rem
+}
+
+
+ at media(max-width:768px) {
+    .section-container {
+        padding:1rem
+    }
+}
+.section-container h2 {
+    font-size:1.5rem;
+    margin-bottom:1rem;
+    color:var(--brand);
+    border-bottom: 1px solid var(--text2);
+}
+ at media(max-width:768px) {
+    .section-container h2 {
+        font-size:1.25rem
+    }
+}
+.section-container p {
+    font-size:1rem;
+    line-height:1.5
+}
+ at media(max-width:768px) {
+    .section-container p {
+        font-size:.875rem
+    }
+}
+.home__row {
+    display:grid;
+    grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
+    gap:2rem
+}
+
+
+.links-wrapper {
+    display:grid;
+    gap:1rem;
+    grid-template-columns:1fr 1fr 1fr 1fr
+}
+ at media(max-width:768px) {
+    .links-wrapper {
+        grid-template-columns:1fr 1fr
+    }
+}
+ at media(max-width:480px) {
+    .links-wrapper {
+        grid-template-columns:1fr
+    }
+}
+.links-wrapper .link {
+    display:flex;
+    flex-direction:column;
+    align-items:center;
+    padding:1rem;
+    border:1px solid var(--text1);
+    border-radius:.25rem
+}
+.links-wrapper .link__icon {
+    font-size:2rem
+}
+.links-wrapper .link__title {
+    font-size:1rem
+}
+
+.table-wrapper {
+    display:flex;
+    flex-direction:column;
+    padding:1rem;
+    border-collapse: collapse; /* Ensures there are no gaps between cells */
+}
+
+.table-wrapper th, .table-wrapper td {
+    padding: 0.5rem 1rem; /* Adds padding inside the cells */
+    border:1px solid var(--text1);
+    text-align: left;
+}
+
+
+.block-command-command {
+    font-weight: bold;
+}
+
+.code-clang-doc {
+    font-size: 1.1rem;
+}
+
+.delimiter-container {
+    padding: 0.5rem 1rem;
+    margin-bottom:1rem; 
+}
+
+.resizer {
+    width: 5px;
+    cursor: col-resize;
+    background-color: var(--text2);
+}
+
+.resizer:hover {
+    background-color: var(--text2-inverse);
+}
+
+.sidebar {
+    width: 250px;
+    top: 0;
+    left: 0;
+    height: 100%;
+    position: fixed;
+    background-color: var(--surface1);
+    display: flex;
+    border-left: 1px solid var(--text2);
+    flex-direction: column;
+    overflow-y: auto;
+    scrollbar-width: thin;
+}
+
+.sidebar h2 {
+    margin-top: 0;
+    margin-bottom: 20px;
+    padding: 10px;
+}
+
+.sidebar ul {
+    width: 100%;
+    padding: 0;
+    list-style-type: none;
+}
+
+.sidebar ul li {
+    padding-right: 1rem;
+    padding-left: 2rem;
+    padding-top: 0.25rem;
+    padding-bottom: 0.25rem;
+}
+
+.sidebar-section {
+    font-size:1.5rem;
+    font-weight: bold;
+    margin-bottom: 1rem;
+    padding: 3rem;
+}
+.sidebar-section a {
+    color: var(--brand)
+}
+
+
+/* Content */
+.content {
+    background-color: var(--text1-inverse);
+    padding: 20px;
+    left: 250px;
+    position: relative;
+    width: calc(100% - 250px);
+    height: 100vh;
+}
+.sidebar-item {
+    color: var(--text1);
+}
+
+.sidebar-item-container:hover {
+    width: 100%;
+    background-color: grey;
+}
+
+.sidebar-item-container:hover a {
+    width: 100%;
+    color: var(--text1-inverse);
+}
+
+.class-container {
+    padding: 0.5rem 1rem;
+}
+
+a, a:visited, a:hover, a:active {
+    text-decoration: none;
+    color: inherit;
+}
diff --git a/clang-tools-extra/clang-doc/assets/class-template.mustache b/clang-tools-extra/clang-doc/assets/class-template.mustache
new file mode 100644
index 00000000000000..7ce51c6e162110
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/class-template.mustache
@@ -0,0 +1,227 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for classes/struct
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+    <meta charset="utf-8"/>
+    <title>{{Name}}</title>
+    {{#Stylesheets}}
+        <link rel="stylesheet" type="text/css" href="{{.}}"/>
+    {{/Stylesheets}}
+    {{#Scripts}}
+        <script src="{{.}}"></script>
+    {{/Scripts}}
+    {{! Highlight.js dependency for syntax highlighting }}
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script>
+</head>
+<body>
+<nav class="navbar">
+    <div class="navbar__container">
+        {{#ProjectName}}
+            <div class="navbar__logo">
+                {{ProjectName}}
+            </div>
+        {{/ProjectName}}
+        <div class="navbar__menu">
+            <ul class="navbar__links">
+                <li class="navbar__item">
+                    <a href="/" class="navbar__link">Namespace</a>
+                </li>
+                <li class="navbar__item">
+                    <a href="/" class="navbar__link">Class</a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</nav>
+<main>
+    <div class="container">
+        <div class="sidebar">
+            <h2>{{RecordType}} {{Name}}</h2>
+            <ul>
+                {{#PublicMembers}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#PublicMethods">Public Members</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{Name}}">{{Name}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/PublicMembers}}
+                {{#ProtectedMembers}}
+                    <li class="sidebar-section">
+                        <a class="sidebar-item" href="#PublicMethods">Protected Members</a>
+                    </li>
+                    <ul>
+                        {{#Obj}}
+                            <li class="sidebar-item-container">
+                                <a class="sidebar-item" href="#{{Name}}">{{Name}}</a>
+                            </li>
+                        {{/Obj}}
+                    </ul>
+                {{/ProtectedMembers}}
+                {{#PublicFunction}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#PublicMethods">Public Method</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{Name}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/PublicFunction}}
+                {{#ProtectedFunction}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#ProtectedFunction">Protected Method</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{Name}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/ProtectedFunction}}
+                {{#Enums}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#Enums">Enums</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{EnumName}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/Enums}}
+                {{#Typedef}}
+                <li class="sidebar-section">Typedef</li>
+                {{/Typedef}}
+                {{#Record}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#Classes">Inner Classes</a>
+                </li>
+                <ul>
+                    {{#Links}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{Name}}</a>
+                    </li>
+                    {{/Links}}
+                </ul>
+                {{/Record}}
+            </ul>
+        </div>
+        <div class="resizer" id="resizer"></div>
+        <div class="content">
+            <section class="hero section-container">
+                <div class="hero__title">
+                    <h1 class="hero__title-large">{{RecordType}} {{Name}}</h1>
+                    {{#RecordComments}}
+                    <div class="hero__subtitle">
+                        {{>Comments}}
+                    </div>
+                    {{/RecordComments}}
+                </div>
+            </section>
+            {{#PublicMembers}}
+            <section id="PublicMembers" class="section-container">
+                <h2>Public Members</h2>
+                <div>
+                    {{#Obj}}
+                    <div id="{{Name}}" class="delimiter-container">
+                        <pre>
+<code class="language-cpp code-clang-doc" >{{Type}} {{Name}}</code>
+                        </pre>
+                        {{#MemberComments}}
+                        <div>
+                            {{>Comments}}
+                        </div>
+                        {{/MemberComments}}
+                    </div>
+                    {{/Obj}}
+                </div>
+            </section>    
+            {{/PublicMembers}}
+            {{#ProtectedMembers}}
+            <section id="ProtectedMembers" class="section-container">
+                <h2>Protected Members</h2>
+                <div>
+                    {{#Obj}}
+                    <div id="{{Name}}" class="delimiter-container">
+                        <pre>
+<code class="language-cpp code-clang-doc" >{{Type}} {{Name}}</code>
+                        </pre>
+                        {{#MemberComments}}
+                        <div>
+                            {{>Comments}}
+                        </div>
+                        {{/MemberComments}}
+                    </div>
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/ProtectedMembers}}
+            {{#PublicFunction}}
+            <section id="PublicMethods" class="section-container">
+                <h2>Public Methods</h2>
+                <div>
+                    {{#Obj}}
+{{>FunctionPartial}}
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/PublicFunction}}
+            {{#ProtectedFunction}}
+            <section id="ProtectedFunction" class="section-container">
+                <h2>Protected Methods</h2>
+                <div>
+                    {{#Obj}}
+{{>FunctionPartial}}
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/ProtectedFunction}}
+            {{#Enums}}
+            <section id="Enums" class="section-container">
+                <h2>Enumerations</h2>
+                <div>
+                    {{#Obj}}
+{{>EnumPartial}}
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/Enums}}
+            {{#Record}}
+            <section id="Classes" class="section-container">
+                <h2>Inner Classes</h2>
+                <ul class="class-container">
+                    {{#Links}}
+                    <li id="{{ID}}" style="max-height: 40px;">
+<a href="{{Link}}"><pre><code class="language-cpp code-clang-doc" >class {{Name}}</code></pre></a>
+                    </li>
+                    {{/Links}}
+                </ul>
+            </section>
+            {{/Record}}
+            {{#Typedef}}
+            <section class="section-container">
+                <h2 id="Enums">Enums</h2>
+            </section>
+            {{/Typedef}}
+        </div>
+    </div>
+</main>
+</body>
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/comments-template.mustache b/clang-tools-extra/clang-doc/assets/comments-template.mustache
new file mode 100644
index 00000000000000..f6b62b4407b9c4
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/comments-template.mustache
@@ -0,0 +1,34 @@
+{{!
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines templates for generating comments
+}}
+{{#FullComment}}
+    {{#Children}}
+    {{>Comments}}    
+    {{/Children}}
+{{/FullComment}}
+{{#ParagraphComment}}
+    {{#Children}}
+    {{>Comments}}
+    {{/Children}}
+{{/ParagraphComment}}
+{{#BlockCommandComment}}
+    <div class="block-command-comment__command">
+        <div class="block-command-command">
+            {{Command}}
+        </div>
+        <div>
+            {{#Children}}
+                {{>Comments}}
+            {{/Children}}
+        </div>
+    </div>
+{{/BlockCommandComment}}
+{{#TextComment}}
+    <div>
+        <p>{{TextComment}}</p>
+    </div>
+{{/TextComment}}
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/comments.mustache b/clang-tools-extra/clang-doc/assets/comments.mustache
deleted file mode 100644
index 1eac4de91836ab..00000000000000
--- a/clang-tools-extra/clang-doc/assets/comments.mustache
+++ /dev/null
@@ -1,27 +0,0 @@
-{{!
-    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-    See https://llvm.org/LICENSE.txt for license information.
-    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-    
-    This file defines templates for generating
-}}
-
-{{#FullComments}}
-    {{#Children}}
-    {{>Comment}}    
-    {{/Children}}
-{{/FullComments}}
-{{#ParagraphComment}}
-    {{#Children}}
-    {{>Comment}}
-    {{/Children}}
-{{/ParagraphComment}}
-{{#BlockCommandComment}}
-    <div>{{Command}}</div>
-    {{#Children}}
-    {{>Comment}}
-    {{/Children}}
-{{/BlockCommandComment}}
-{{#TextComment}}
-    <p>{{TextComment}}</p>
-{{/TextComment}}
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/enum-template.mustache b/clang-tools-extra/clang-doc/assets/enum-template.mustache
new file mode 100644
index 00000000000000..d63bf258f8f0fb
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/enum-template.mustache
@@ -0,0 +1,47 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for enums
+}}
+<div id="{{ID}}" class="delimiter-container">
+    <div>
+        <pre>
+            <code class="language-cpp code-clang-doc">
+{{EnumName}}
+            </code>
+        </pre>
+    </div>
+    {{! Enum Values }}
+    <table class="table-wrapper">
+        <tbody>
+        <tr>
+            <th>Name</th>
+            <th>Value</th>
+            {{#HasComment}}
+                <th>Comment</th>
+            {{/HasComment}}
+        </tr>
+        {{#EnumValues}}
+            <tr>
+                <td>{{Name}}</td>
+                <td>{{Value}}</td>
+                {{#EnumValueComments}}
+                    <td>{{>Comments}}</td>
+                {{/EnumValueComments}}
+            </tr>
+        {{/EnumValues}}
+        </tbody>
+    </table>
+    {{#EnumComments}}
+    <div>
+        {{>Comments}}
+    </div>
+    {{/EnumComments}}
+    {{#Location}}
+    <div>
+        Defined at line {{LineNumber}} of file {{Filename}}
+    </div>
+    {{/Location}}
+</div>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/function-template.mustache b/clang-tools-extra/clang-doc/assets/function-template.mustache
new file mode 100644
index 00000000000000..0564647467aa60
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/function-template.mustache
@@ -0,0 +1,23 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for functions/methods
+}}
+<div class="delimiter-container">
+    <div id="{{ID}}">
+        {{! Function Prototype }}
+        <pre>
+            <code class="language-cpp code-clang-doc">
+{{ReturnType.Name}} {{Name}} ({{#Params}}{{^End}}{{Type}} {{Name}}, {{/End}}{{#End}}{{Type}} {{Name}}{{/End}}{{/Params}})
+            </code>
+        </pre>
+        {{! Function Comments }}
+        {{#FunctionComments}}
+        <div>
+            {{>Comments}}
+        </div>
+        {{/FunctionComments}}
+    </div>
+</div>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/mustache-index.js b/clang-tools-extra/clang-doc/assets/mustache-index.js
new file mode 100644
index 00000000000000..db320cd8ae403c
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/mustache-index.js
@@ -0,0 +1,33 @@
+document.addEventListener("DOMContentLoaded", function() {
+    const resizer = document.getElementById('resizer');
+    const sidebar = document.querySelector('.sidebar');
+    
+    let isResizing = false;
+    resizer.addEventListener('mousedown', (e) => {
+        isResizing = true;
+    });
+
+    document.addEventListener('mousemove', (e) => {
+        if (!isResizing) return;
+        const newWidth = e.clientX;
+        if (newWidth > 100 && newWidth < window.innerWidth - 100) {
+            sidebar.style.width = `${newWidth}px`;
+        }
+    });
+
+    document.addEventListener('mouseup', () => {
+        isResizing = false;
+    });
+
+    document.querySelectorAll('pre code').forEach((el) => {
+        hljs.highlightElement(el);
+        el.classList.remove("hljs");
+    });
+
+    document.querySelectorAll('.sidebar-item-container').forEach(item => {
+        item.addEventListener('click', function() {
+            const anchor = item.getElementsByTagName("a");
+            window.location.hash = anchor[0].getAttribute('href');
+        });
+    });
+})
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/namespace-template.mustache b/clang-tools-extra/clang-doc/assets/namespace-template.mustache
new file mode 100644
index 00000000000000..4061fd026886e4
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/namespace-template.mustache
@@ -0,0 +1,87 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for generating namespaces
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+    <head>
+        <meta charset="utf-8"/>
+        <title>{{NamespaceTitle}}</title>
+        {{#Stylesheets}}
+        <link rel="stylesheet" type="text/css" href="{{.}}"/>
+        {{/Stylesheets}}
+        {{#Scripts}}
+        <script src="{{.}}"></script>
+        {{/Scripts}}
+        {{! Highlight.js dependency for syntax highlighting }}
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script>
+    </head>
+    <body>
+        <nav class="navbar">
+            Navbar
+        </nav>
+        <main>
+            <div class="container">
+                <div class="sidebar">
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
+                        sed do eiusmod tempor incididunt ut labore et dolore magna 
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco 
+                        laboris nisi ut aliquip ex ea commodo consequat. 
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse 
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat 
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit 
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                </div>
+                <div class="resizer" id="resizer"></div>
+                <div class="content">
+                    Content
+                </div>
+            </div>
+        </main>
+    </body>
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
deleted file mode 100644
index 3b77e0189f4e22..00000000000000
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ /dev/null
@@ -1,55 +0,0 @@
-{{! 
-    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-    See https://llvm.org/LICENSE.txt for license information.
-    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-    
-    This file defines the template for generating namespaces
-}}
-<!DOCTYPE html>
-<html lang="en-US">
-    <head>
-        <meta charset="utf-8"/>
-        <title>{{NamespaceTitle}}</title>
-    </head>
-    <h1>{{NamespaceTitle}}</h1>
-    {{#NamespaceComments}}
-    <div>
-        {{>Comments}}
-    </div>
-    {{/NamespaceComments}}
-    {{#Namespace}}
-    <h2 id="Namespace">Namespace</h2>
-    <ul>
-        {{#Links}}
-        <li>
-            <a href="{{Link}}">{{Name}}</a>
-        </li>
-        {{/Links}}
-    </ul>
-    {{/Namespace}}
-    {{#Record}}
-    <h2 id="Class">Class</h2>
-    <ul>
-        {{#Links}}
-        <li>
-            <a href="{{Link}}">{{Name}}</a>
-        </li>
-        {{/Links}}
-    </ul>
-    {{/Record}}
-    {{#Function}}
-    <h2 id="Function">Function</h2>
-    <div>
-        {{#Obj}}
-            
-        {{/Obj}}
-    </div>
-    {{/Function}}
-    {{#Enums}}
-    <h2 id="Enums">Enums</h2>
-    <div>
-        {{#Obj}}
-        {{/Obj}}
-    </div>
-    {{/Enums}}
-</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
index 8eb067dbe6de87..eccbc99a7ecc4b 100644
--- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -21,7 +21,13 @@ target_link_libraries(clang-doc
 
 set(assets
   index.js
-  template.mustache
+  mustache-index.js
+  class-template.mustache
+  comments-template.mustache
+  enum-template.mustache      
+  function-template.mustache
+  namespace-template.mustache      
+  clang-doc-mustache.css
   clang-doc-default-stylesheet.css
 )
 
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index eee8dbf093cc53..256e29c3c9f894 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -163,6 +163,15 @@ llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
+llvm::SmallString<128> appendPathNative(llvm::SmallString<128> Path, 
+                                    llvm::StringRef Asset) {
+  llvm::SmallString<128> Default;
+  llvm::sys::path::native(Path, Default);
+  llvm::sys::path::append(Default, Asset);
+  return Default;
+}
+
+
 llvm::Error getDefaultAssetFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   void *MainAddr = (void *)(intptr_t)getExecutablePath;
@@ -173,13 +182,10 @@ llvm::Error getDefaultAssetFiles(const char *Argv0,
   llvm::SmallString<128> AssetsPath;
   AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
   llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
-  llvm::SmallString<128> DefaultStylesheet;
-  llvm::sys::path::native(AssetsPath, DefaultStylesheet);
-  llvm::sys::path::append(DefaultStylesheet,
-                          "clang-doc-default-stylesheet.css");
-  llvm::SmallString<128> IndexJS;
-  llvm::sys::path::native(AssetsPath, IndexJS);
-  llvm::sys::path::append(IndexJS, "index.js");
+  llvm::SmallString<128> DefaultStylesheet =
+      appendPathNative(AssetsPath, "clang-doc-default-stylesheet.css");
+  llvm::SmallString<128> IndexJS =
+      appendPathNative(AssetsPath, "index.js");
 
   if (!llvm::sys::fs::is_regular_file(IndexJS))
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -210,6 +216,7 @@ llvm::Error getHtmlAssetFiles(const char *Argv0,
   return getDefaultAssetFiles(Argv0, CDCtx);
 }
 
+
 llvm::Error getMustacheHtmlFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   if (!UserAssetPath.empty() &&
@@ -228,10 +235,34 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
   AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
   llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
   
-  llvm::SmallString<128> MustacheTemplate;
-  llvm::sys::path::native(AssetsPath, MustacheTemplate);
-  llvm::sys::path::append(MustacheTemplate, "template.mustache");
-  CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+  llvm::SmallString<128> DefaultStylesheet
+      = appendPathNative(AssetsPath, "clang-doc-mustache.css");
+  llvm::SmallString<128> NamespaceTemplate 
+      = appendPathNative(AssetsPath, "namespace-template.mustache");
+  llvm::SmallString<128> ClassTemplate
+      = appendPathNative(AssetsPath, "class-template.mustache");
+  llvm::SmallString<128> EnumTemplate
+      = appendPathNative(AssetsPath, "enum-template.mustache");
+  llvm::SmallString<128> FunctionTemplate
+      = appendPathNative(AssetsPath, "function-template.mustache");
+  llvm::SmallString<128> CommentTemplate
+      = appendPathNative(AssetsPath, "comments-template.mustache");
+  llvm::SmallString<128> IndexJS
+      = appendPathNative(AssetsPath, "mustache-index.js");
+  
+  CDCtx.JsScripts.insert(CDCtx.JsScripts.begin(), IndexJS.c_str());
+  CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
+                               std::string(DefaultStylesheet));
+  CDCtx.MustacheTemplates.insert({"namespace-template", 
+                                  NamespaceTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"class-template",
+                                  ClassTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"enum-template",
+                                  EnumTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"function-template",
+                                  FunctionTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"comments-template", 
+                                  CommentTemplate.c_str()});
   
   return llvm::Error::success();
 }

>From a247423a1be655c5fb432f56929361149ddbea66 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Thu, 10 Oct 2024 13:02:53 -0400
Subject: [PATCH 50/57] [llvm] factor out internal classes

---
 llvm/include/llvm/Support/Mustache.h | 110 +------------------------
 llvm/lib/Support/Mustache.cpp        | 116 ++++++++++++++++++++++++++-
 2 files changed, 116 insertions(+), 110 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h
index 1130434a265e42..ab8c02fa732ab8 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -75,115 +75,7 @@ using Accessor = SmallVector<SmallString<0>>;
 using Lambda = std::function<llvm::json::Value()>;
 using SectionLambda = std::function<llvm::json::Value(StringRef)>;
 
-class Token {
-public:
-  enum class Type {
-    Text,
-    Variable,
-    Partial,
-    SectionOpen,
-    SectionClose,
-    InvertSectionOpen,
-    UnescapeVariable,
-    Comment,
-  };
-
-  Token(StringRef Str);
-
-  Token(StringRef RawBody, StringRef Str, char Identifier);
-
-  StringRef getTokenBody() const { return TokenBody; };
-
-  StringRef getRawBody() const { return RawBody; };
-
-  void setTokenBody(StringRef NewBody) { TokenBody = NewBody.str(); };
-
-  Accessor getAccessor() const { return Accessor; };
-
-  Type getType() const { return TokenType; };
-
-  void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
-
-  size_t getIndentation() const { return Indentation; };
-
-  static Type getTokenType(char Identifier);
-
-private:
-  size_t Indentation;
-  Type TokenType;
-  // RawBody is the original string that was tokenized
-  SmallString<0> RawBody;
-  Accessor Accessor;
-  // TokenBody is the original string with the identifier removed
-  SmallString<0> TokenBody;
-};
-
-class ASTNode {
-public:
-  enum Type {
-    Root,
-    Text,
-    Partial,
-    Variable,
-    UnescapeVariable,
-    Section,
-    InvertSection,
-  };
-
-  ASTNode() : T(Type::Root), ParentContext(nullptr) {};
-
-  ASTNode(StringRef Body, ASTNode *Parent)
-      : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
-        Indentation(0) {};
-
-  // Constructor for Section/InvertSection/Variable/UnescapeVariable
-  ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
-      : T(T), Parent(Parent), Children({}), Accessor(Accessor),
-        ParentContext(nullptr), Indentation(0) {};
-
-  void addChild(ASTNode *Child) { Children.emplace_back(Child); };
-
-  void setBody(StringRef NewBody) { Body = NewBody; };
-
-  void setRawBody(StringRef NewBody) { RawBody = NewBody; };
-
-  void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
-
-  void render(const llvm::json::Value &Data, SmallString<0> &Output);
-
-  void setUpNode(llvm::BumpPtrAllocator &Alloc, StringMap<ASTNode *> &Partials,
-                 StringMap<Lambda> &Lambdas,
-                 StringMap<SectionLambda> &SectionLambdas,
-                 DenseMap<char, StringRef> &Escapes);
-
-private:
-  void renderLambdas(const llvm::json::Value &Contexts, SmallString<0> &Output,
-                     Lambda &L);
-
-  void renderSectionLambdas(const llvm::json::Value &Contexts,
-                            SmallString<0> &Output, SectionLambda &L);
-
-  void renderPartial(const llvm::json::Value &Contexts, SmallString<0> &Output,
-                     ASTNode *Partial);
-
-  void renderChild(const llvm::json::Value &Context, SmallString<0> &Output);
-
-  const llvm::json::Value *findContext();
-
-  llvm::BumpPtrAllocator *Allocator;
-  StringMap<ASTNode *> *Partials;
-  StringMap<Lambda> *Lambdas;
-  StringMap<SectionLambda> *SectionLambdas;
-  DenseMap<char, StringRef> *Escapes;
-  Type T;
-  size_t Indentation;
-  SmallString<0> RawBody;
-  SmallString<0> Body;
-  ASTNode *Parent;
-  std::vector<ASTNode *> Children;
-  const Accessor Accessor;
-  const llvm::json::Value *ParentContext;
-};
+class ASTNode;
 
 // A Template represents the container for the AST and the partials
 // and Lambdas that are registered with it.
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 2af4307fae02a3..031481955feabb 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -12,7 +12,119 @@
 
 using namespace llvm;
 using namespace llvm::json;
-using namespace llvm::mustache;
+
+namespace llvm {
+namespace mustache {
+
+class Token {
+public:
+  enum class Type {
+    Text,
+    Variable,
+    Partial,
+    SectionOpen,
+    SectionClose,
+    InvertSectionOpen,
+    UnescapeVariable,
+    Comment,
+  };
+  
+  Token(StringRef Str);
+
+  Token(StringRef RawBody, StringRef Str, char Identifier);
+
+  StringRef getTokenBody() const { return TokenBody; };
+
+  StringRef getRawBody() const { return RawBody; };
+
+  void setTokenBody(StringRef NewBody) { TokenBody = NewBody.str(); };
+
+  Accessor getAccessor() const { return Accessor; };
+
+  Type getType() const { return TokenType; };
+
+  void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
+
+  size_t getIndentation() const { return Indentation; };
+
+  static Type getTokenType(char Identifier);
+
+private:
+  size_t Indentation;
+  Type TokenType;
+  // RawBody is the original string that was tokenized
+  SmallString<0> RawBody;
+  Accessor Accessor;
+  // TokenBody is the original string with the identifier removed
+  SmallString<0> TokenBody;
+};
+
+class ASTNode {
+public:
+  enum Type {
+    Root,
+    Text,
+    Partial,
+    Variable,
+    UnescapeVariable,
+    Section,
+    InvertSection,
+  };
+
+  ASTNode() : T(Type::Root), ParentContext(nullptr) {};
+
+  ASTNode(StringRef Body, ASTNode *Parent)
+      : T(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr),
+        Indentation(0) {};
+
+  // Constructor for Section/InvertSection/Variable/UnescapeVariable
+  ASTNode(Type T, Accessor Accessor, ASTNode *Parent)
+      : T(T), Parent(Parent), Children({}), Accessor(Accessor),
+        ParentContext(nullptr), Indentation(0) {};
+
+  void addChild(ASTNode *Child) { Children.emplace_back(Child); };
+
+  void setBody(StringRef NewBody) { Body = NewBody; };
+
+  void setRawBody(StringRef NewBody) { RawBody = NewBody; };
+
+  void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
+
+  void render(const llvm::json::Value &Data, SmallString<0> &Output);
+
+  void setUpNode(llvm::BumpPtrAllocator &Alloc, StringMap<ASTNode *> &Partials,
+                 StringMap<Lambda> &Lambdas,
+                 StringMap<SectionLambda> &SectionLambdas,
+                 DenseMap<char, StringRef> &Escapes);
+
+private:
+  void renderLambdas(const llvm::json::Value &Contexts, SmallString<0> &Output,
+                     Lambda &L);
+
+  void renderSectionLambdas(const llvm::json::Value &Contexts,
+                            SmallString<0> &Output, SectionLambda &L);
+
+  void renderPartial(const llvm::json::Value &Contexts, SmallString<0> &Output,
+                     ASTNode *Partial);
+
+  void renderChild(const llvm::json::Value &Context, SmallString<0> &Output);
+
+  const llvm::json::Value *findContext();
+
+  llvm::BumpPtrAllocator *Allocator;
+  StringMap<ASTNode *> *Partials;
+  StringMap<Lambda> *Lambdas;
+  StringMap<SectionLambda> *SectionLambdas;
+  DenseMap<char, StringRef> *Escapes;
+  Type T;
+  size_t Indentation;
+  SmallString<0> RawBody;
+  SmallString<0> Body;
+  ASTNode *Parent;
+  std::vector<ASTNode *> Children;
+  const Accessor Accessor;
+  const llvm::json::Value *ParentContext;
+};
 
 SmallString<0> escapeString(StringRef Input,
                             DenseMap<char, StringRef> &Escape) {
@@ -565,3 +677,5 @@ void ASTNode::setUpNode(llvm::BumpPtrAllocator &Alloc,
   for (ASTNode *Child : Children)
     Child->setUpNode(Alloc, Par, L, SC, E);
 }
+} // namespace mustache
+} // namespace llvm

>From 5c5a84fd1aaa2a9f375b133be782da6bc4c60245 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 8 Oct 2024 02:10:26 -0400
Subject: [PATCH 51/57] [llvm] add mustache verification tool

---
 llvm/tools/mustache/CMakeLists.txt |   3 +
 llvm/tools/mustache/mustache.cpp   | 102 +++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 llvm/tools/mustache/CMakeLists.txt
 create mode 100644 llvm/tools/mustache/mustache.cpp

diff --git a/llvm/tools/mustache/CMakeLists.txt b/llvm/tools/mustache/CMakeLists.txt
new file mode 100644
index 00000000000000..721b553741d05b
--- /dev/null
+++ b/llvm/tools/mustache/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+    add_llvm_tool(mustache mustache.cpp)
\ No newline at end of file
diff --git a/llvm/tools/mustache/mustache.cpp b/llvm/tools/mustache/mustache.cpp
new file mode 100644
index 00000000000000..07b7c0dc528696
--- /dev/null
+++ b/llvm/tools/mustache/mustache.cpp
@@ -0,0 +1,102 @@
+//===- mustache.cpp - The LLVM Modular Optimizer
+//-------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple drivers to test the mustache spec found here
+// https://github.com/mustache/
+// It is used to verify that the current implementation conforms to the spec
+// simply download the spec and pass the test files to the driver
+//
+// Currently Triple Mustache is not supported we expect the following spec
+// test to fail:
+//    Triple Mustache
+//    Triple Mustache Integer Interpolation
+//    Triple Mustache Decimal Interpolation
+//    Triple Mustache Null Interpolation
+//    Triple Mustache Context Miss Interpolation
+//    Dotted Names - Triple Mustache Interpolation
+//    Implicit Iterators - Triple Mustache
+//    Triple Mustache - Surrounding Whitespace
+//    Triple Mustache - Standalone
+//    Triple Mustache With Padding
+//    Standalone Indentation
+//    Implicit Iterator - Triple mustache
+//
+// Usage:
+//  mustache path/to/test/file/test.json path/to/test/file/test2.json ...
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Mustache.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+cl::list<std::string> InputFiles(cl::Positional, cl::desc("<input files>"),
+                                 cl::OneOrMore);
+
+void runThroughTest(StringRef InputFile) {
+  llvm::outs() << "Running Tests: " << InputFile << "\n";
+  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrError =
+      MemoryBuffer::getFile(InputFile);
+
+  if (auto EC = BufferOrError.getError()) {
+    return;
+  }
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+  llvm::StringRef FileContent = Buffer->getBuffer();
+  Expected<Value> Json = parse(FileContent);
+
+  if (auto E = Json.takeError()) {
+    errs() << "Parsing error: " << toString(std::move(E)) << "\n";
+    return;
+  }
+  // Get test
+  Array *Obj = (*Json).getAsObject()->getArray("tests");
+  size_t Total = 0;
+  size_t Success = 0;
+  for (Value V : *Obj) {
+    Object *TestCase = V.getAsObject();
+    StringRef TemplateStr = TestCase->getString("template").value();
+    StringRef ExpectedStr = TestCase->getString("expected").value();
+    StringRef Name = TestCase->getString("name").value();
+    Value *Data = TestCase->get("data");
+    Value *Partials = TestCase->get("partials");
+
+    if (!Data)
+      continue;
+
+    Template T = Template(TemplateStr);
+    if (Partials) {
+      for (auto PartialPairs : *Partials->getAsObject()) {
+        StringRef Partial = PartialPairs.getSecond().getAsString().value();
+        StringRef Str = llvm::StringRef(PartialPairs.getFirst());
+        T.registerPartial(Str, Partial);
+      }
+    }
+    StringRef ActualStr = T.render(*Data);
+    if (ExpectedStr == ActualStr) {
+      Success++;
+    } else {
+      llvm::outs() << "Test Failed: " << Name << "\n";
+    }
+    Total++;
+  }
+
+  llvm::outs() << "Result " << Success << "/" << Total << " succeeded\n";
+}
+int main(int argc, char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+  for (const auto &FileName : InputFiles) {
+    runThroughTest(FileName);
+  }
+  return 0;
+}
\ No newline at end of file

>From 58b915b1c49c854bf06ce6c862354e061fcc7895 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 02:26:22 -0400
Subject: [PATCH 52/57] [clang-doc] init mustache implementation

---
 clang-tools-extra/clang-doc/CMakeLists.txt    |   1 +
 clang-tools-extra/clang-doc/HTMLGenerator.cpp |   3 +-
 .../clang-doc/HTMLMustacheGenerator.cpp       | 349 ++++++++++++++++++
 clang-tools-extra/clang-doc/Representation.h  |   4 +-
 .../clang-doc/assets/template.mustache        |  23 ++
 .../clang-doc/tool/CMakeLists.txt             |   1 +
 .../clang-doc/tool/ClangDocMain.cpp           |  31 ++
 7 files changed, 410 insertions(+), 2 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
 create mode 100644 clang-tools-extra/clang-doc/assets/template.mustache

diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt
index 975ad8e242e490..82aded940222db 100644
--- a/clang-tools-extra/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -15,6 +15,7 @@ add_clang_library(clangDoc
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
+  HTMLMustacheGenerator.cpp
 
   DEPENDS
   omp_gen
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index e3532559a32fcc..ed65ac965114b5 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -1133,7 +1133,8 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-static llvm::Error copyFile(StringRef FilePath, StringRef OutDirectory) {
+static llvm::Error 
+copyFile(StringRef FilePath, StringRef OutDirectory) {
   llvm::SmallString<128> PathWrite;
   llvm::sys::path::native(OutDirectory, PathWrite);
   llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
new file mode 100644
index 00000000000000..63def07c5fa804
--- /dev/null
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -0,0 +1,349 @@
+//===-- HTMLMustacheGenerator.cpp - HTML Mustache Generator -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "Generators.h"
+#include "Representation.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Mustache.h"
+
+using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
+
+namespace clang {
+namespace doc {
+
+
+class MustacheHTMLGenerator : public Generator {
+public:
+  static const char *Format;
+  llvm::Error generateDocs(StringRef RootDir,
+                           llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
+                           const ClangDocContext &CDCtx) override;
+  llvm::Error createResources(ClangDocContext &CDCtx) override;
+  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
+                                 const ClangDocContext &CDCtx) override;
+  
+};
+
+class MustacheTemplateFile : public Template {
+public:
+  static ErrorOr<std::unique_ptr<MustacheTemplateFile>> createMustacheFile
+      (StringRef FileName) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
+        MemoryBuffer::getFile(FileName);
+    
+    if (auto EC = BufferOrError.getError()) {
+      return EC;
+    }
+    std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+    llvm::StringRef FileContent = Buffer->getBuffer();
+    return std::make_unique<MustacheTemplateFile>(FileContent);
+  }
+  
+  Error registerPartialFile(StringRef Name, StringRef FileName) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
+        MemoryBuffer::getFile(FileName);
+    if (auto EC = BufferOrError.getError()) {
+      return llvm::createFileError("cannot open file", EC);
+    }
+    std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
+    llvm::StringRef FileContent = Buffer->getBuffer();
+    registerPartial(Name, FileContent);
+  }
+
+  MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
+};
+
+static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
+
+static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
+
+
+llvm::Error 
+setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
+  auto TemplateFilePath = CDCtx.MustacheTemplates.lookup("template");
+  auto Template = MustacheTemplateFile::createMustacheFile(TemplateFilePath);
+  if (auto EC = Template.getError()) {
+    return llvm::createFileError("cannot open file", EC);
+  }
+  NamespaceTemplate = std::move(Template.get());
+}
+
+llvm::Error 
+MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir, 
+                                    llvm::StringMap<std::unique_ptr<doc::Info>> Infos, 
+                                    const clang::doc::ClangDocContext &CDCtx) {
+  if (auto Err = setupTemplateFiles(CDCtx)) {
+    return Err;
+  }
+  // Track which directories we already tried to create.
+  llvm::StringSet<> CreatedDirs;
+  // Collect all output by file name and create the necessary directories.
+  llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
+  for (const auto &Group : Infos) {
+    doc::Info *Info = Group.getValue().get();
+    
+    llvm::SmallString<128> Path;
+    llvm::sys::path::native(RootDir, Path);
+    llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
+    if (!CreatedDirs.contains(Path)) {
+      if (std::error_code Err = llvm::sys::fs::create_directories(Path);
+          Err != std::error_code()) {
+        return llvm::createStringError(Err, "Failed to create directory '%s'.",
+                                       Path.c_str());
+      }
+      CreatedDirs.insert(Path);
+    }
+
+    llvm::sys::path::append(Path, Info->getFileBaseName() + ".html");
+    FileToInfos[Path].push_back(Info);
+  }
+  
+  for (const auto &Group : FileToInfos) {
+    std::error_code FileErr;
+    llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
+                                llvm::sys::fs::OF_None);
+    if (FileErr) {
+      return llvm::createStringError(FileErr, "Error opening file '%s'",
+                                     Group.getKey().str().c_str());
+    }
+    for (const auto &Info : Group.getValue()) {
+      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
+        return Err;
+      }
+    }
+  }
+}
+
+Value extractValue(const Location &L, 
+                   std::optional<StringRef> RepositoryUrl = std::nullopt) {
+  Object Obj = Object();
+  if (!L.IsFileInRootDir || !RepositoryUrl) {
+    Obj.insert({"LineNumber", L.LineNumber});
+    Obj.insert({"Filename", L.Filename});
+  }
+  SmallString<128> FileURL(*RepositoryUrl);
+  llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
+  Obj.insert({"FileURL", FileURL});
+}
+
+Value extractValue(const Reference &I, StringRef CurrentDirectory) {
+  llvm::SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory);
+  llvm::sys::path::append(Path, I.getFileBaseName() + ".html");
+  llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
+  Object Obj = Object();
+  Obj.insert({"Link", Path});
+  Obj.insert({"Name", I.Name});
+  return Obj;
+}
+
+
+Value extractValue(const TypedefInfo &I) {
+  // Not Supported
+  return nullptr;
+}
+
+Value extractValue(const CommentInfo &I) {
+  Object Obj = Object();
+  Value Child = Object();
+  
+  if (I.Kind == "FullComment") {
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"FullComment", Child});
+  }
+  if (I.Kind == "ParagraphComment") {
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"ParagraphComment", Child});
+  }
+  if (I.Kind == "BlockCommandComment") {
+    Child.getAsObject()->insert({"Command", I.Name});
+    Value ChildArr = Array();
+    for (const auto& C: I.Children)
+      ChildArr.getAsArray()->emplace_back(extractValue(*C));
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({"BlockCommandComment", Child});
+  }
+  if (I.Kind == "TextComment")
+    Obj.insert({"TextComment", I.Text});
+  
+  return Obj;
+}
+
+Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
+                   const ClangDocContext &CDCtx) {
+  Object Obj = Object();
+  Obj.insert({"Name", I.Name});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
+  Obj.insert({"Access", getAccessSpelling(I.Access).str()});
+  Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
+  
+  Value ParamArr = Array();
+  for (const auto &P : I.Params) {
+    ParamArr.getAsArray()->emplace_back(extractValue(P.Type, ParentInfoDir));
+  }
+  Obj.insert({"Params", ParamArr});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    Obj.insert({"FunctionComments", ArrDesc});
+  }
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
+    else
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
+  }
+  return Obj;
+}
+
+Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
+  Object Obj = Object();
+  std::string EnumType = I.Scoped ? "enum class " : "enum ";
+  EnumType += I.Name;
+  bool HasComment = std::any_of(
+      I.Members.begin(), I.Members.end(),
+      [](const EnumValueInfo &M) { return !M.Description.empty(); });
+  Obj.insert({"EnumName", EnumType});
+  Obj.insert({"HasComment", HasComment});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
+  
+  Value Arr = Array();
+  for (const EnumValueInfo& M: I.Members) {
+    Value EnumValue = Object();
+    EnumValue.getAsObject()->insert({"Name", M.Name});
+    if (!M.ValueExpr.empty())
+      EnumValue.getAsObject()->insert({"ValueExpr", M.ValueExpr});
+    else
+      EnumValue.getAsObject()->insert({"Value", M.Value});
+    
+    if (!M.Description.empty()) {
+      Value ArrDesc = Array();
+      for (const CommentInfo& Child : M.Description) 
+        ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+      EnumValue.getAsObject()->insert({"EnumValueComments", ArrDesc});
+    }
+    Arr.getAsArray()->emplace_back(EnumValue);
+  }
+  Obj.insert({"EnumValues", Arr});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    Obj.insert({"EnumComments", ArrDesc});
+  }
+  
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
+    else
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
+  }
+  
+  return Obj;
+}
+
+Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
+  Object NamespaceValue = Object();
+  std::string InfoTitle;
+  if (I.Name.str() == "")
+    InfoTitle = "Global Namespace";
+  else
+    InfoTitle = ("namespace " + I.Name).str();  
+  
+  StringRef BasePath = I.getRelativeFilePath("");
+  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
+  NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    NamespaceValue.insert({"NamespaceComments", ArrDesc });
+  }
+
+  Value ArrNamespace = Array();
+  for (const Reference& Child : I.Children.Namespaces)
+    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Namespace", ArrNamespace});
+  
+  Value ArrRecord = Array();
+  for (const Reference& Child : I.Children.Records)
+    ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Record", ArrRecord});
+  
+  Value ArrFunction = Array();
+  for (const FunctionInfo& Child : I.Children.Functions)
+    ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
+                                                        CDCtx));
+  NamespaceValue.insert({"Function", ArrRecord});
+  
+  Value ArrEnum = Array();
+  for (const EnumInfo& Child : I.Children.Enums)
+    ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
+  NamespaceValue.insert({"Enums", ArrEnum });
+  
+  Value ArrTypedefs = Array();
+  for (const TypedefInfo& Child : I.Children.Typedefs) 
+    ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
+  NamespaceValue.insert({"Typedefs", ArrTypedefs });
+  
+}
+
+
+
+llvm::Error
+MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
+                                          const ClangDocContext &CDCtx) {
+  switch (I->IT) {
+  case InfoType::IT_namespace: {
+    Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+    OS << NamespaceTemplate->render(V);
+    break;
+  }
+  case InfoType::IT_record:
+    break;
+  case InfoType::IT_enum:
+    break;
+  case InfoType::IT_function:
+    break;
+  case InfoType::IT_typedef:
+    break;
+  case InfoType::IT_default:
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "unexpected InfoType");
+  }
+  return llvm::Error::success();
+}
+
+llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
+  
+}
+
+const char *MustacheHTMLGenerator::Format = "mustache";
+
+
+static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
+                                                  "Generator for mustache HTML output.");
+
+// This anchor is used to force the linker to link in the generated object
+// file and thus register the generator.
+volatile int HTMLGeneratorAnchorSource = 0;
+
+} // namespace doc
+} // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index bb0c534af7b740..3175b8209e3be3 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -521,8 +521,10 @@ struct ClangDocContext {
   // Path of CSS stylesheets that will be copied to OutDirectory and used to
   // style all HTML files.
   std::vector<std::string> UserStylesheets;
-  // JavaScript files that will be imported in allHTML file.
+  // JavaScript files that will be imported in all HTML file.
   std::vector<std::string> JsScripts;
+  // Mustache Template files
+  llvm::StringMap<std::string> MustacheTemplates;
   Index Idx;
 };
 
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
new file mode 100644
index 00000000000000..af4c60182ae52c
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -0,0 +1,23 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+    <head>
+        <meta charset="utf-8"/>
+        <title>{{NamespaceTitle}}</title>
+    </head>
+    {{#NamespaceComments}}
+    <p>Namespace Comment Present!</p>
+    {{/NamespaceComments}}
+    {{#Namespace}}
+    <p>Namespace Present!</p>
+    {{/Namespace}}
+    {{#Record}}
+    <p>Record Present!</p>
+    {{/Record}}
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
index 601a0460d76b38..8eb067dbe6de87 100644
--- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -21,6 +21,7 @@ target_link_libraries(clang-doc
 
 set(assets
   index.js
+  template.mustache
   clang-doc-default-stylesheet.css
 )
 
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 04773fb8a6e721..fc5a9529111b16 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -205,6 +205,30 @@ llvm::Error getHtmlAssetFiles(const char *Argv0,
   return getDefaultAssetFiles(Argv0, CDCtx);
 }
 
+llvm::Error getMustacheHtmlFiles(const char *Argv0,
+                                 clang::doc::ClangDocContext &CDCtx) {
+  if (!UserAssetPath.empty() &&
+      !llvm::sys::fs::is_directory(std::string(UserAssetPath)))
+    llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath
+                 << " falling back to default\n";
+  if (llvm::sys::fs::is_directory(std::string(UserAssetPath)))
+    return getAssetFiles(CDCtx);
+  
+  void *MainAddr = (void *)(intptr_t)getExecutablePath;
+  std::string ClangDocPath = getExecutablePath(Argv0, MainAddr);
+  llvm::SmallString<128> NativeClangDocPath;
+  llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
+  
+  llvm::SmallString<128> AssetsPath;
+  AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
+  llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
+  
+  llvm::SmallString<128> MustacheTemplate;
+  llvm::sys::path::native(AssetsPath, MustacheTemplate);
+  llvm::sys::path::append(MustacheTemplate, "template.mustache");
+  CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+}
+
 /// Make the output of clang-doc deterministic by sorting the children of
 /// namespaces and records.
 void sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> &USRToInfo) {
@@ -277,6 +301,13 @@ Example usage for a project using a compile commands database:
       return 1;
     }
   }
+  
+  if (Format == "mhtml") {
+    if (auto Err = getMustacheHtmlFiles(argv[0], CDCtx)) {
+      llvm::errs() << toString(std::move(Err)) << "\n";
+      return 1;
+    }
+  }
 
   // Mapping phase
   llvm::outs() << "Mapping decls...\n";

>From 054b99638fa1000a9a7148120030c40b3e0cbc3d Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 17:50:03 -0400
Subject: [PATCH 53/57] [clang-doc] add a mustache backend init implementation

---
 clang-tools-extra/clang-doc/Generators.cpp    |  4 +-
 .../clang-doc/HTMLMustacheGenerator.cpp       | 32 ++++++++++++----
 .../clang-doc/assets/template.mustache        | 37 +++++++++++++++++--
 .../clang-doc/tool/ClangDocMain.cpp           |  9 ++++-
 .../Inputs/basic-project/include/Shape.h      |  2 -
 5 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp
index a3986b66f3c742..ae5b556d17063b 100644
--- a/clang-tools-extra/clang-doc/Generators.cpp
+++ b/clang-tools-extra/clang-doc/Generators.cpp
@@ -100,12 +100,14 @@ void Generator::addInfoToIndex(Index &Idx, const doc::Info *Info) {
 extern volatile int YAMLGeneratorAnchorSource;
 extern volatile int MDGeneratorAnchorSource;
 extern volatile int HTMLGeneratorAnchorSource;
+extern volatile int MHTMLGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED YAMLGeneratorAnchorDest =
     YAMLGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED MDGeneratorAnchorDest =
     MDGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED HTMLGeneratorAnchorDest =
     HTMLGeneratorAnchorSource;
-
+static int LLVM_ATTRIBUTE_UNUSED MHTMLGeneratorAnchorDest =
+    MHTMLGeneratorAnchorSource;
 } // namespace doc
 } // namespace clang
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 63def07c5fa804..bfa563ebdc7b37 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -54,6 +54,7 @@ class MustacheTemplateFile : public Template {
     std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
     llvm::StringRef FileContent = Buffer->getBuffer();
     registerPartial(Name, FileContent);
+    return llvm::Error::success();
   }
 
   MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
@@ -72,6 +73,7 @@ setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
     return llvm::createFileError("cannot open file", EC);
   }
   NamespaceTemplate = std::move(Template.get());
+  return llvm::Error::success();
 }
 
 llvm::Error 
@@ -118,6 +120,7 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
       }
     }
   }
+  return llvm::Error::success();
 }
 
 Value extractValue(const Location &L, 
@@ -130,6 +133,8 @@ Value extractValue(const Location &L,
   SmallString<128> FileURL(*RepositoryUrl);
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
   Obj.insert({"FileURL", FileURL});
+  
+  return Obj;
 }
 
 Value extractValue(const Reference &I, StringRef CurrentDirectory) {
@@ -280,29 +285,39 @@ Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
   Value ArrNamespace = Array();
   for (const Reference& Child : I.Children.Namespaces)
     ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Namespace", ArrNamespace});
+  
+  if (!ArrNamespace.getAsArray()->empty())
+    NamespaceValue.insert({"Namespace", Object{{"Links", ArrNamespace}}});
   
   Value ArrRecord = Array();
   for (const Reference& Child : I.Children.Records)
     ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Record", ArrRecord});
+  
+  if (!ArrRecord.getAsArray()->empty())
+    NamespaceValue.insert({"Record", Object{{"Links", ArrRecord}}});
   
   Value ArrFunction = Array();
   for (const FunctionInfo& Child : I.Children.Functions)
     ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
                                                         CDCtx));
-  NamespaceValue.insert({"Function", ArrRecord});
+  if (!ArrFunction.getAsArray()->empty())
+    NamespaceValue.insert({"Function", Object{{"Obj", ArrFunction}}});
   
   Value ArrEnum = Array();
   for (const EnumInfo& Child : I.Children.Enums)
     ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
-  NamespaceValue.insert({"Enums", ArrEnum });
+  
+  if (!ArrEnum.getAsArray()->empty())
+    NamespaceValue.insert({"Enums", Object{{"Obj", ArrEnum }}});
   
   Value ArrTypedefs = Array();
   for (const TypedefInfo& Child : I.Children.Typedefs) 
     ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
-  NamespaceValue.insert({"Typedefs", ArrTypedefs });
   
+  if (!ArrTypedefs.getAsArray()->empty())
+    NamespaceValue.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+  
+  return NamespaceValue;
 }
 
 
@@ -313,6 +328,7 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+    llvm::outs() << V << "\n";
     OS << NamespaceTemplate->render(V);
     break;
   }
@@ -332,10 +348,10 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
 }
 
 llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
-  
+  return llvm::Error::success();
 }
 
-const char *MustacheHTMLGenerator::Format = "mustache";
+const char *MustacheHTMLGenerator::Format = "mhtml";
 
 
 static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
@@ -343,7 +359,7 @@ static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator
 
 // This anchor is used to force the linker to link in the generated object
 // file and thus register the generator.
-volatile int HTMLGeneratorAnchorSource = 0;
+volatile int MHTMLGeneratorAnchorSource = 0;
 
 } // namespace doc
 } // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
index af4c60182ae52c..1d3407f8b52920 100644
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -3,7 +3,7 @@
     See https://llvm.org/LICENSE.txt for license information.
     SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     
-    This file defines the template
+    This file defines the template for generating Namespaces
 }}
 <!DOCTYPE html>
 <html lang="en-US">
@@ -11,13 +11,42 @@
         <meta charset="utf-8"/>
         <title>{{NamespaceTitle}}</title>
     </head>
+    <h1>{{NamespaceTitle}}</h1>
     {{#NamespaceComments}}
-    <p>Namespace Comment Present!</p>
+    <p>Namespace Comment</p>
     {{/NamespaceComments}}
     {{#Namespace}}
-    <p>Namespace Present!</p>
+    <h2 id="Namespace">Namespace</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Namespace}}
     {{#Record}}
-    <p>Record Present!</p>
+    <h2 id="Class">Class</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Record}}
+    {{#Function}}
+    <h2 id="Function">Function</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Function}}
+    {{#Enums}}
+    <h2 id="Enums">Enums</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Enums}}
 </html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index fc5a9529111b16..eee8dbf093cc53 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -103,6 +103,7 @@ enum OutputFormatTy {
   md,
   yaml,
   html,
+  mhtml
 };
 
 static llvm::cl::opt<OutputFormatTy>
@@ -112,7 +113,9 @@ static llvm::cl::opt<OutputFormatTy>
                                 clEnumValN(OutputFormatTy::md, "md",
                                            "Documentation in MD format."),
                                 clEnumValN(OutputFormatTy::html, "html",
-                                           "Documentation in HTML format.")),
+                                           "Documentation in HTML format."),
+                                clEnumValN(OutputFormatTy::mhtml, "mhtml",
+                                           "Documentation in mHTML format")),
                llvm::cl::init(OutputFormatTy::yaml),
                llvm::cl::cat(ClangDocCategory));
 
@@ -124,6 +127,8 @@ std::string getFormatString() {
     return "md";
   case OutputFormatTy::html:
     return "html";
+  case OutputFormatTy::mhtml:
+    return "mhtml";
   }
   llvm_unreachable("Unknown OutputFormatTy");
 }
@@ -227,6 +232,8 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
   llvm::sys::path::native(AssetsPath, MustacheTemplate);
   llvm::sys::path::append(MustacheTemplate, "template.mustache");
   CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+  
+  return llvm::Error::success();
 }
 
 /// Make the output of clang-doc deterministic by sorting the children of
diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
index e5c5d4c9e4412b..5354032f4d8323 100644
--- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
+++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
@@ -26,5 +26,3 @@ class Shape {
      */
     virtual double perimeter() const = 0;
 };
-
-

>From 814c86c6489681c6a53e0bdbf6464fde5a8f8a89 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 24 Sep 2024 16:48:29 -0400
Subject: [PATCH 54/57] [clang-doc] update

---
 .../clang-doc/HTMLMustacheGenerator.cpp       | 16 ++++++++---
 .../clang-doc/assets/comments.mustache        | 27 +++++++++++++++++++
 .../clang-doc/assets/template.mustache        |  7 +++--
 .../Inputs/basic-project/include/Shape.h      |  2 ++
 4 files changed, 46 insertions(+), 6 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/assets/comments.mustache

diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index bfa563ebdc7b37..96a685dbe2ae87 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -194,8 +194,12 @@ Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
   Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
   
   Value ParamArr = Array();
-  for (const auto &P : I.Params) {
-    ParamArr.getAsArray()->emplace_back(extractValue(P.Type, ParentInfoDir));
+  for (const auto Val : llvm::enumerate(I.Params)) {
+    Value V = Object();
+    V.getAsObject()->insert({"Name", Val.value().Name});
+    V.getAsObject()->insert({"Type", Val.value().Type.Name});
+    V.getAsObject()->insert({"End",  Val.index() + 1 == I.Params.size()});
+    ParamArr.getAsArray()->emplace_back(V);
   }
   Obj.insert({"Params", ParamArr});
   
@@ -328,17 +332,21 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
-    llvm::outs() << V << "\n";
-    OS << NamespaceTemplate->render(V);
+    llvm::raw_ostream &OS = llvm::outs();
+    llvm::json::OStream J(OS, /*IndentSize=*/2);
+    J.value(V);
     break;
   }
   case InfoType::IT_record:
     break;
   case InfoType::IT_enum:
+    llvm::outs() << "IT_enum\n";
     break;
   case InfoType::IT_function:
+    llvm::outs() << "IT_Function\n";
     break;
   case InfoType::IT_typedef:
+    llvm::outs() << "IT_typedef\n";
     break;
   case InfoType::IT_default:
     return createStringError(llvm::inconvertibleErrorCode(),
diff --git a/clang-tools-extra/clang-doc/assets/comments.mustache b/clang-tools-extra/clang-doc/assets/comments.mustache
new file mode 100644
index 00000000000000..1eac4de91836ab
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/comments.mustache
@@ -0,0 +1,27 @@
+{{!
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines templates for generating
+}}
+
+{{#FullComments}}
+    {{#Children}}
+    {{>Comment}}    
+    {{/Children}}
+{{/FullComments}}
+{{#ParagraphComment}}
+    {{#Children}}
+    {{>Comment}}
+    {{/Children}}
+{{/ParagraphComment}}
+{{#BlockCommandComment}}
+    <div>{{Command}}</div>
+    {{#Children}}
+    {{>Comment}}
+    {{/Children}}
+{{/BlockCommandComment}}
+{{#TextComment}}
+    <p>{{TextComment}}</p>
+{{/TextComment}}
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
index 1d3407f8b52920..3b77e0189f4e22 100644
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -3,7 +3,7 @@
     See https://llvm.org/LICENSE.txt for license information.
     SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     
-    This file defines the template for generating Namespaces
+    This file defines the template for generating namespaces
 }}
 <!DOCTYPE html>
 <html lang="en-US">
@@ -13,7 +13,9 @@
     </head>
     <h1>{{NamespaceTitle}}</h1>
     {{#NamespaceComments}}
-    <p>Namespace Comment</p>
+    <div>
+        {{>Comments}}
+    </div>
     {{/NamespaceComments}}
     {{#Namespace}}
     <h2 id="Namespace">Namespace</h2>
@@ -39,6 +41,7 @@
     <h2 id="Function">Function</h2>
     <div>
         {{#Obj}}
+            
         {{/Obj}}
     </div>
     {{/Function}}
diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
index 5354032f4d8323..e5c5d4c9e4412b 100644
--- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
+++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
@@ -26,3 +26,5 @@ class Shape {
      */
     virtual double perimeter() const = 0;
 };
+
+

>From 0f8afafa35b4dda5d73f439af9af30cf42c7c766 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 7 Oct 2024 15:07:41 -0400
Subject: [PATCH 55/57] [clang-doc] add more templates

---
 clang-tools-extra/clang-doc/CMakeLists.txt    |   5 +-
 .../clang-doc/FileHelpersClangDoc.cpp         |  75 +++
 .../clang-doc/FileHelpersClangDoc.h           |  26 +
 clang-tools-extra/clang-doc/HTMLGenerator.cpp |  59 +--
 .../clang-doc/HTMLMustacheGenerator.cpp       | 281 ++++++++---
 .../clang-doc/assets/clang-doc-mustache.css   | 476 ++++++++++++++++++
 .../clang-doc/assets/class-template.mustache  | 227 +++++++++
 .../assets/comments-template.mustache         |  34 ++
 .../clang-doc/assets/comments.mustache        |  27 -
 .../clang-doc/assets/enum-template.mustache   |  47 ++
 .../assets/function-template.mustache         |  23 +
 .../clang-doc/assets/mustache-index.js        |  33 ++
 .../assets/namespace-template.mustache        |  87 ++++
 .../clang-doc/assets/template.mustache        |  55 --
 .../clang-doc/tool/CMakeLists.txt             |   8 +-
 .../clang-doc/tool/ClangDocMain.cpp           |  53 +-
 16 files changed, 1296 insertions(+), 220 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
 create mode 100644 clang-tools-extra/clang-doc/FileHelpersClangDoc.h
 create mode 100644 clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
 create mode 100644 clang-tools-extra/clang-doc/assets/class-template.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/comments-template.mustache
 delete mode 100644 clang-tools-extra/clang-doc/assets/comments.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/enum-template.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/function-template.mustache
 create mode 100644 clang-tools-extra/clang-doc/assets/mustache-index.js
 create mode 100644 clang-tools-extra/clang-doc/assets/namespace-template.mustache
 delete mode 100644 clang-tools-extra/clang-doc/assets/template.mustache

diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt
index 82aded940222db..0793c343305184 100644
--- a/clang-tools-extra/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -8,15 +8,16 @@ add_clang_library(clangDoc
   BitcodeReader.cpp
   BitcodeWriter.cpp
   ClangDoc.cpp
+  FileHelpersClangDoc.cpp
   Generators.cpp
   HTMLGenerator.cpp
+  HTMLMustacheGenerator.cpp      
   Mapper.cpp
   MDGenerator.cpp
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
-  HTMLMustacheGenerator.cpp
-
+        
   DEPENDS
   omp_gen
   ClangDriverOptions
diff --git a/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp b/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
new file mode 100644
index 00000000000000..50209cfac1ca3d
--- /dev/null
+++ b/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
@@ -0,0 +1,75 @@
+//===-- FileHelpersClangDoc.cpp - File Helpers -------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "FileHelpersClangDoc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace doc {
+
+llvm::Error
+copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory) {
+  llvm::SmallString<128> PathWrite;
+  llvm::sys::path::native(OutDirectory, PathWrite);
+  llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
+  llvm::SmallString<128> PathRead;
+  llvm::sys::path::native(FilePath, PathRead);
+  std::error_code OK;
+  std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
+  if (FileErr != OK) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "error creating file " +
+                                       llvm::sys::path::filename(FilePath) +
+                                       ": " + FileErr.message() + "\n");
+  }
+  return llvm::Error::success();
+}
+
+
+llvm::SmallString<128> computeRelativePath(llvm::StringRef Destination,
+                                                  llvm::StringRef Origin) {
+  // If Origin is empty, the relative path to the Destination is its complete
+  // path.
+  if (Origin.empty())
+    return Destination;
+  
+  // The relative path is an empty path if both directories are the same.
+  if (Destination == Origin)
+    return {};
+
+  // These iterators iterate through each of their parent directories
+  llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
+  llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
+  llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
+  llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
+  // Advance both iterators until the paths differ. Example:
+  //    Destination = A/B/C/D
+  //    Origin      = A/B/E/F
+  // FileI will point to C and DirI to E. The directories behind them is the
+  // directory they share (A/B).
+  while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
+    ++FileI;
+    ++DirI;
+  }
+  llvm::SmallString<128> Result; // This will hold the resulting path.
+  // Result has to go up one directory for each of the remaining directories in
+  // Origin
+  while (DirI != DirE) {
+    llvm::sys::path::append(Result, "..");
+    ++DirI;
+  }
+  // Result has to append each of the remaining directories in Destination
+  while (FileI != FileE) {
+    llvm::sys::path::append(Result, *FileI);
+    ++FileI;
+  }
+  return Result;
+}
+
+} // namespace doc
+} // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/FileHelpersClangDoc.h b/clang-tools-extra/clang-doc/FileHelpersClangDoc.h
new file mode 100644
index 00000000000000..9072a7bd08a4f8
--- /dev/null
+++ b/clang-tools-extra/clang-doc/FileHelpersClangDoc.h
@@ -0,0 +1,26 @@
+//===-- FileHelpersClangDoc.h --- File Helpers -------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILEHELPER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILEHELPER_H
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace doc {
+
+llvm::Error 
+copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory);
+
+llvm::SmallString<128> 
+computeRelativePath(llvm::StringRef Destination,llvm::StringRef Origin);
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILEHELPER_H
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index ed65ac965114b5..aa76d17d9411d6 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -8,6 +8,7 @@
 
 #include "Generators.h"
 #include "Representation.h"
+#include "FileHelpersClangDoc.h"
 #include "clang/Basic/Version.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -251,46 +252,6 @@ static void appendVector(std::vector<Derived> &&New,
   std::move(New.begin(), New.end(), std::back_inserter(Original));
 }
 
-// Compute the relative path from an Origin directory to a Destination directory
-static SmallString<128> computeRelativePath(StringRef Destination,
-                                            StringRef Origin) {
-  // If Origin is empty, the relative path to the Destination is its complete
-  // path.
-  if (Origin.empty())
-    return Destination;
-
-  // The relative path is an empty path if both directories are the same.
-  if (Destination == Origin)
-    return {};
-
-  // These iterators iterate through each of their parent directories
-  llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
-  llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
-  llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
-  llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
-  // Advance both iterators until the paths differ. Example:
-  //    Destination = A/B/C/D
-  //    Origin      = A/B/E/F
-  // FileI will point to C and DirI to E. The directories behind them is the
-  // directory they share (A/B).
-  while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
-    ++FileI;
-    ++DirI;
-  }
-  SmallString<128> Result; // This will hold the resulting path.
-  // Result has to go up one directory for each of the remaining directories in
-  // Origin
-  while (DirI != DirE) {
-    llvm::sys::path::append(Result, "..");
-    ++DirI;
-  }
-  // Result has to append each of the remaining directories in Destination
-  while (FileI != FileE) {
-    llvm::sys::path::append(Result, *FileI);
-    ++FileI;
-  }
-  return Result;
-}
 
 // HTML generation
 
@@ -1133,24 +1094,6 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-static llvm::Error 
-copyFile(StringRef FilePath, StringRef OutDirectory) {
-  llvm::SmallString<128> PathWrite;
-  llvm::sys::path::native(OutDirectory, PathWrite);
-  llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
-  llvm::SmallString<128> PathRead;
-  llvm::sys::path::native(FilePath, PathRead);
-  std::error_code OK;
-  std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
-  if (FileErr != OK) {
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "error creating file " +
-                                       llvm::sys::path::filename(FilePath) +
-                                       ": " + FileErr.message() + "\n");
-  }
-  return llvm::Error::success();
-}
-
 llvm::Error HTMLGenerator::createResources(ClangDocContext &CDCtx) {
   auto Err = serializeIndex(CDCtx);
   if (Err)
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 96a685dbe2ae87..6be4c795a68654 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 #include "Generators.h"
 #include "Representation.h"
+#include "FileHelpersClangDoc.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Mustache.h"
 
@@ -48,9 +49,8 @@ class MustacheTemplateFile : public Template {
   Error registerPartialFile(StringRef Name, StringRef FileName) {
     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
         MemoryBuffer::getFile(FileName);
-    if (auto EC = BufferOrError.getError()) {
+    if (auto EC = BufferOrError.getError())
       return llvm::createFileError("cannot open file", EC);
-    }
     std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
     llvm::StringRef FileContent = Buffer->getBuffer();
     registerPartial(Name, FileContent);
@@ -65,24 +65,54 @@ static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
 static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
 
 
+llvm::Error setupTemplate(
+                   std::unique_ptr<MustacheTemplateFile> &Template,
+                   StringRef TemplatePath,
+                   std::vector<std::pair<StringRef, StringRef>> Partials) {
+  auto T = MustacheTemplateFile::createMustacheFile(TemplatePath);
+  if (auto EC = T.getError())
+     return llvm::createFileError("cannot open file", EC);
+  Template = std::move(T.get());
+  for (const auto &P : Partials) {
+    auto Err = Template->registerPartialFile(P.first, P.second);
+    if (Err)
+      return Err;
+  }
+  return llvm::Error::success();
+}
+
 llvm::Error 
 setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
-  auto TemplateFilePath = CDCtx.MustacheTemplates.lookup("template");
-  auto Template = MustacheTemplateFile::createMustacheFile(TemplateFilePath);
-  if (auto EC = Template.getError()) {
-    return llvm::createFileError("cannot open file", EC);
-  }
-  NamespaceTemplate = std::move(Template.get());
+  auto NamespaceFilePath = CDCtx.MustacheTemplates.lookup("namespace-template");
+  auto ClassFilePath = CDCtx.MustacheTemplates.lookup("class-template");
+  auto CommentFilePath = CDCtx.MustacheTemplates.lookup("comments-template");
+  auto FunctionFilePath = CDCtx.MustacheTemplates.lookup("function-template");
+  auto EnumFilePath = CDCtx.MustacheTemplates.lookup("enum-template");
+  std::vector<std::pair<StringRef, StringRef>> Partials = {
+    {"Comments", CommentFilePath},
+    {"FunctionPartial", FunctionFilePath},
+    {"EnumPartial", EnumFilePath}
+  };
+  
+  auto Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials);
+  if (Err)
+    return Err;
+  
+  Err = setupTemplate(RecordTemplate, ClassFilePath, Partials);
+  
+  if (Err)
+    return Err;
+  
   return llvm::Error::success();
 }
 
+
 llvm::Error 
 MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir, 
                                     llvm::StringMap<std::unique_ptr<doc::Info>> Infos, 
                                     const clang::doc::ClangDocContext &CDCtx) {
-  if (auto Err = setupTemplateFiles(CDCtx)) {
+  if (auto Err = setupTemplateFiles(CDCtx))
     return Err;
-  }
   // Track which directories we already tried to create.
   llvm::StringSet<> CreatedDirs;
   // Collect all output by file name and create the necessary directories.
@@ -95,10 +125,9 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
     if (!CreatedDirs.contains(Path)) {
       if (std::error_code Err = llvm::sys::fs::create_directories(Path);
-          Err != std::error_code()) {
+          Err != std::error_code())
         return llvm::createStringError(Err, "Failed to create directory '%s'.",
                                        Path.c_str());
-      }
       CreatedDirs.insert(Path);
     }
 
@@ -110,14 +139,13 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     std::error_code FileErr;
     llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
                                 llvm::sys::fs::OF_None);
-    if (FileErr) {
+    if (FileErr)
       return llvm::createStringError(FileErr, "Error opening file '%s'",
                                      Group.getKey().str().c_str());
-    }
+    
     for (const auto &Info : Group.getValue()) {
-      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
+      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx))
         return Err;
-      }
     }
   }
   return llvm::Error::success();
@@ -126,12 +154,15 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
 Value extractValue(const Location &L, 
                    std::optional<StringRef> RepositoryUrl = std::nullopt) {
   Object Obj = Object();
+  Obj.insert({"LineNumber", L.LineNumber});
+  Obj.insert({"Filename", L.Filename});
+  
   if (!L.IsFileInRootDir || !RepositoryUrl) {
-    Obj.insert({"LineNumber", L.LineNumber});
-    Obj.insert({"Filename", L.Filename});
+    return Obj;
   }
   SmallString<128> FileURL(*RepositoryUrl);
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
+  FileURL += "#" + std::to_string(L.LineNumber);
   Obj.insert({"FileURL", FileURL});
   
   return Obj;
@@ -144,6 +175,8 @@ Value extractValue(const Reference &I, StringRef CurrentDirectory) {
   Object Obj = Object();
   Obj.insert({"Link", Path});
   Obj.insert({"Name", I.Name});
+  Obj.insert({"QualName", I.QualName});
+  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
   return Obj;
 }
 
@@ -209,12 +242,13 @@ Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
     Obj.insert({"FunctionComments", ArrDesc});
   }
-  if (I.DefLoc) {
-    if (!CDCtx.RepositoryUrl)
-      Obj.insert({"Location", extractValue(*I.DefLoc)});
+  if (I.DefLoc.has_value()) {
+    Location L = *I.DefLoc;
+    if (CDCtx.RepositoryUrl.has_value())
+      Obj.insert({"Location", extractValue(L,
+                                           StringRef{*CDCtx.RepositoryUrl})});
     else
-      Obj.insert({"Location", extractValue(*I.DefLoc, 
-                                           StringRef{*CDCtx.RepositoryUrl})});  
+      Obj.insert({"Location", extractValue(L)});  
   }
   return Obj;
 }
@@ -229,7 +263,6 @@ Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
   Obj.insert({"EnumName", EnumType});
   Obj.insert({"HasComment", HasComment});
   Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
-  
   Value Arr = Array();
   for (const EnumValueInfo& M: I.Members) {
     Value EnumValue = Object();
@@ -256,75 +289,175 @@ Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
     Obj.insert({"EnumComments", ArrDesc});
   }
   
-  if (I.DefLoc) {
-    if (!CDCtx.RepositoryUrl)
-      Obj.insert({"Location", extractValue(*I.DefLoc)});
+  if (I.DefLoc.has_value()) {
+    Location L = *I.DefLoc;
+    if (CDCtx.RepositoryUrl.has_value())
+      Obj.insert({"Location", extractValue(L,
+                                           StringRef{*CDCtx.RepositoryUrl})});
     else
-      Obj.insert({"Location", extractValue(*I.DefLoc, 
-                                           StringRef{*CDCtx.RepositoryUrl})});  
+      Obj.insert({"Location", extractValue(L)});  
   }
   
   return Obj;
 }
 
-Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
-  Object NamespaceValue = Object();
-  std::string InfoTitle;
-  if (I.Name.str() == "")
-    InfoTitle = "Global Namespace";
-  else
-    InfoTitle = ("namespace " + I.Name).str();  
-  
-  StringRef BasePath = I.getRelativeFilePath("");
-  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
-  NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
-  
-  if (!I.Description.empty()) {
-    Value ArrDesc = Array();
-    for (const CommentInfo& Child : I.Description) 
-      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
-    NamespaceValue.insert({"NamespaceComments", ArrDesc });
-  }
-
+void extractScopeChildren(const ScopeChildren &S, Object &Obj, 
+                          StringRef ParentInfoDir,
+                          const ClangDocContext &CDCtx) {
   Value ArrNamespace = Array();
-  for (const Reference& Child : I.Children.Namespaces)
-    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  for (const Reference& Child : S.Namespaces)
+    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
   
   if (!ArrNamespace.getAsArray()->empty())
-    NamespaceValue.insert({"Namespace", Object{{"Links", ArrNamespace}}});
+    Obj.insert({"Namespace", Object{{"Links", ArrNamespace}}});
   
   Value ArrRecord = Array();
-  for (const Reference& Child : I.Children.Records)
-    ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  for (const Reference& Child : S.Records)
+    ArrRecord.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
   
   if (!ArrRecord.getAsArray()->empty())
-    NamespaceValue.insert({"Record", Object{{"Links", ArrRecord}}});
+    Obj.insert({"Record", Object{{"Links", ArrRecord}}});
   
   Value ArrFunction = Array();
-  for (const FunctionInfo& Child : I.Children.Functions)
-    ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
-                                                        CDCtx));
+  Value PublicFunction = Array();
+  Value ProtectedFunction = Array();
+  Value PrivateFunction = Array();
+  
+  for (const FunctionInfo& Child : S.Functions) {
+    Value F = extractValue(Child, ParentInfoDir, CDCtx);
+    AccessSpecifier Access = Child.Access;
+    if (Access == AccessSpecifier::AS_public)
+      PublicFunction.getAsArray()->emplace_back(F);
+    else if (Access == AccessSpecifier::AS_protected)
+      ProtectedFunction.getAsArray()->emplace_back(F);
+    else
+      ArrFunction.getAsArray()->emplace_back(F);
+  }  
   if (!ArrFunction.getAsArray()->empty())
-    NamespaceValue.insert({"Function", Object{{"Obj", ArrFunction}}});
+    Obj.insert({"Function", Object{{"Obj", ArrFunction}}});
+  
+  if (!PublicFunction.getAsArray()->empty())
+    Obj.insert({"PublicFunction", Object{{"Obj", PublicFunction}}});
+  
+  if (!ProtectedFunction.getAsArray()->empty())
+    Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunction}}});
+  
   
   Value ArrEnum = Array();
-  for (const EnumInfo& Child : I.Children.Enums)
+  for (const EnumInfo& Child : S.Enums)
     ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
   
   if (!ArrEnum.getAsArray()->empty())
-    NamespaceValue.insert({"Enums", Object{{"Obj", ArrEnum }}});
+    Obj.insert({"Enums", Object{{"Obj", ArrEnum }}});
   
   Value ArrTypedefs = Array();
-  for (const TypedefInfo& Child : I.Children.Typedefs) 
+  for (const TypedefInfo& Child : S.Typedefs) 
     ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
   
   if (!ArrTypedefs.getAsArray()->empty())
-    NamespaceValue.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+    Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+}
+
+Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
+  Object NamespaceValue = Object();
+  std::string InfoTitle;
+  if (I.Name.str() == "")
+    InfoTitle = "Global Namespace";
+  else
+    InfoTitle = ("namespace " + I.Name).str();  
+  
+  StringRef BasePath = I.getRelativeFilePath("");
+  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
+  NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
   
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    NamespaceValue.insert({"NamespaceComments", ArrDesc });
+  }
+  extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx);
   return NamespaceValue;
 }
 
+Value extractValue(const RecordInfo &I, const ClangDocContext &CDCtx) {
+  Object RecordValue = Object();
+  
+  if (!I.Description.empty()) {
+    Value ArrDesc = Array();
+    for (const CommentInfo& Child : I.Description) 
+      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+    RecordValue.insert({"RecordComments", ArrDesc });
+  }
+  RecordValue.insert({"Name", I.Name});
+  RecordValue.insert({"FullName", I.FullName});
+  RecordValue.insert({"RecordType", getTagType(I.TagType)});
+  
+  if (I.DefLoc.has_value()) {
+    Location L = *I.DefLoc;
+    if (CDCtx.RepositoryUrl.has_value())
+      RecordValue.insert({"Location", extractValue(L,
+                                           StringRef{*CDCtx.RepositoryUrl})});
+    else
+      RecordValue.insert({"Location", extractValue(L)});  
+  }
+  
+  StringRef BasePath = I.getRelativeFilePath("");
+  extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
+  Value PublicMembers = Array();
+  Value ProtectedMembers = Array();
+  Value PrivateMembers = Array();
+  for (const MemberTypeInfo &Member : I.Members ) {
+    Value MemberValue = Object();
+    MemberValue.getAsObject()->insert({"Name", Member.Name});
+    MemberValue.getAsObject()->insert({"Type", Member.Type.Name});
+    if (!Member.Description.empty()) {
+      Value ArrDesc = Array();
+      for (const CommentInfo& Child : Member.Description) 
+            ArrDesc.getAsArray()->emplace_back(extractValue(Child));
+      MemberValue.getAsObject()->insert({"MemberComments", ArrDesc });
+    }
+    
+    if (Member.Access == AccessSpecifier::AS_public)
+      PublicMembers.getAsArray()->emplace_back(MemberValue);
+    else if (Member.Access == AccessSpecifier::AS_protected)
+      ProtectedMembers.getAsArray()->emplace_back(MemberValue);
+    else if (Member.Access == AccessSpecifier::AS_private)
+      PrivateMembers.getAsArray()->emplace_back(MemberValue);
+  }
+  if (!PublicMembers.getAsArray()->empty())
+    RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}});
+  if (!ProtectedMembers.getAsArray()->empty())
+    RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
+  if (!PrivateMembers.getAsArray()->empty())
+    RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
+  
+  return RecordValue;
+}
 
+void setupTemplateValue(const ClangDocContext &CDCtx, Value &V, Info *I) {
+  V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName});
+  Value StylesheetArr = Array();
+  auto InfoPath = I->getRelativeFilePath("");
+  SmallString<128> RelativePath = computeRelativePath("", InfoPath);
+  for (const auto &FilePath  : CDCtx.UserStylesheets) {
+    SmallString<128> StylesheetPath = RelativePath;
+    llvm::sys::path::append(StylesheetPath,
+                            llvm::sys::path::filename(FilePath));
+    llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
+    StylesheetArr.getAsArray()->emplace_back(StylesheetPath);
+  }
+  V.getAsObject()->insert({"Stylesheets", StylesheetArr});
+  
+  Value ScriptArr = Array();
+  for (auto Script : CDCtx.JsScripts) {
+    SmallString<128> JsPath = RelativePath;
+    llvm::sys::path::append(JsPath, llvm::sys::path::filename(Script));
+    ScriptArr.getAsArray()->emplace_back(JsPath);
+  }
+  V.getAsObject()->insert({"Scripts", ScriptArr});
+}
+ 
 
 llvm::Error
 MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
@@ -332,13 +465,18 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
-    llvm::raw_ostream &OS = llvm::outs();
-    llvm::json::OStream J(OS, /*IndentSize=*/2);
-    J.value(V);
+    setupTemplateValue(CDCtx, V, I);
+    OS << NamespaceTemplate->render(V);
     break;
   }
-  case InfoType::IT_record:
+  case InfoType::IT_record: {
+    Value V = extractValue(*static_cast<clang::doc::RecordInfo *>(I), CDCtx);
+    setupTemplateValue(CDCtx, V, I);
+    // Serialize the JSON value to the output stream in a readable format.
+    llvm::outs() << llvm::formatv("{0:2}", V);
+    OS << RecordTemplate->render(V);
     break;
+  }  
   case InfoType::IT_enum:
     llvm::outs() << "IT_enum\n";
     break;
@@ -356,6 +494,17 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
 }
 
 llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
+  llvm::Error Err = llvm::Error::success();
+  for (const auto &FilePath : CDCtx.UserStylesheets) {
+    Err = copyFile(FilePath, CDCtx.OutDirectory);
+    if (Err)
+      return Err;
+  }
+  for (const auto &FilePath : CDCtx.JsScripts) {
+    Err = copyFile(FilePath, CDCtx.OutDirectory);
+    if (Err)
+      return Err;
+  }
   return llvm::Error::success();
 }
 
diff --git a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
new file mode 100644
index 00000000000000..2f07baa7ca0a1a
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
@@ -0,0 +1,476 @@
+ at import "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap";
+
+*,*::before *::after {
+    box-sizing:border-box
+}
+* {
+    margin:0;
+    padding:0
+}
+ol,
+ul {
+    list-style:none
+}
+img,
+picture,
+svg,
+video {
+    display:block;
+    max-width:100%
+}
+* {
+    --brand-light:#ce6300;
+    --text1-light:#000000;
+    --text2-light:#333333;
+    --surface1-light:#ffffff;
+    --surface2-light:#f5f5f5;
+    --brand-dark:#de9853;
+    --text1-dark:#ffffff;
+    --text2-dark:#cccccc;
+    --surface1-dark:#161212;
+    --surface2-dark:#272424
+}
+:root {
+    color-scheme:light;
+    --brand:var(--brand-light);
+    --text1:var(--text1-light);
+    --text2:var(--text2-light);
+    --text1-inverse:var(--text1-dark);
+    --text2-inverse:var(--text2-dark);
+    --surface1:var(--surface1-light);
+    --surface2:var(--surface2-light)
+}
+ at media(prefers-color-scheme:dark) {
+    :root {
+        color-scheme:dark;
+        --brand:var(--brand-dark);
+        --text1:var(--text1-dark);
+        --text2:var(--text2-dark);
+        --text1-inverse:var(--text1-light);
+        --text2-inverse:var(--text2-light);
+        --surface1:var(--surface1-dark);
+        --surface2:var(--surface2-dark)
+    }
+}
+[color-scheme=light] {
+    color-scheme:light;
+    --brand:var(--brand-light);
+    --text1:var(--text1-light);
+    --text2:var(--text2-light);
+    --text1-inverse:var(--text1-dark);
+    --text2-inverse:var(--text2-dark);
+    --surface1:var(--surface1-light);
+    --surface2:var(--surface2-light)
+}
+[color-scheme=dark] {
+    color-scheme:dark;
+    --brand:var(--brand-dark);
+    --text1:var(--text1-dark);
+    --text2:var(--text2-dark);
+    --text1-inverse:var(--text1-light);
+    --text2-inverse:var(--text2-light);
+    --surface1:var(--surface1-dark);
+    --surface2:var(--surface2-dark)
+}
+html {
+    background-color:var(--surface1)
+}
+
+html, body {
+    min-height: 100vh;
+    margin: 0;
+    padding: 0;
+    width: 100%;
+}
+
+.container {
+    display: flex;
+    margin-top: 60px;
+    height: calc(100% - 60px);
+    box-sizing: border-box;
+}
+
+body, html {
+    font-family:Inter,sans-serif;
+    margin: 0;
+    padding: 0;
+    height: 100%;
+}
+
+/* Navbar Styles */
+.navbar {
+    background-color: var(--surface2);
+    border-bottom: 1px solid var(--text2);
+    position: fixed;
+    width: 100%;
+    top: 0;
+    left: 0;
+    height: 60px; /* Adjust as needed */
+    color: white;
+    display: flex;
+    align-items: center;
+    padding: 0 20px;
+    box-sizing: border-box;
+    z-index: 1000;
+}
+
+
+.navbar__container {
+    display:flex;
+    justify-content:space-between;
+    align-items:center;
+    padding:1rem;
+    color:var(--text1);
+    max-width:2048px;
+    margin:auto
+}
+.navbar__logo {
+    display:flex;
+    align-items:center;
+    height:40px
+}
+.navbar__logo a {
+    display:flex;
+    align-items:center;
+    text-decoration:none;
+    height:100%
+}
+.navbar__logo img {
+    height:100%;
+    width:auto
+}
+.navbar__toggle {
+    background:0 0;
+    color:var(--text2);
+    border:none;
+    cursor:pointer;
+    font-size:1.5rem;
+    width:2.5rem;
+    height:2.5rem;
+    margin-left:auto
+}
+.navbar__toggle:hover {
+    color:var(--text1)
+}
+ at media(min-width:769px) {
+    .navbar__toggle {
+        display:none
+    }
+}
+.navbar__menu {
+    display:flex;
+    justify-content:space-between;
+    align-items:center;
+    list-style:none;
+    margin:0;
+    padding:0;
+    gap:.25rem;
+    margin-left:auto
+}
+
+ at media(max-width:768px) {
+    .navbar__menu {
+        flex-direction:column;
+        justify-content:flex-start;
+        width:100%;
+        background-color:var(--surface2);
+        position:fixed;
+        top:0;
+        left:0;
+        right:0;
+        bottom:0;
+        padding:1.5rem;
+        transform:translateX(100%);
+        transition:transform .5s ease-in-out
+    }
+}
+ at media(max-width:768px) {
+    .navbar__menu.active {
+        transform:translateX(0)
+    }
+}
+.navbar__close {
+    background:0 0;
+    border:none;
+    cursor:pointer;
+    font-size:1.5rem;
+    color:var(--text2);
+    margin-left:auto
+}
+.navbar__close:hover {
+    color:var(--text1)
+}
+ at media(min-width:769px) {
+    .navbar__close {
+        display:none
+    }
+}
+.navbar__links {
+    display:flex;
+    gap:1rem;
+    align-items:center;
+    margin:0;
+    padding:0
+}
+ at media(max-width:768px) {
+    .navbar__links {
+        flex-direction:column
+    }
+}
+.navbar__item {
+    list-style-type:none
+}
+.navbar__link {
+    color:var(--text2);
+    text-decoration:none;
+    padding:.5rem
+}
+.navbar__link:hover {
+    color:var(--text1)
+}
+.navbar__theme-toggle-button {
+    background:0 0;
+    color:var(--text2);
+    border:none;
+    cursor:pointer;
+    font-size:1.5rem;
+    width:2.5rem;
+    height:2.5rem
+}
+.navbar__theme-toggle-button:hover {
+    color:var(--text1)
+}
+
+.hero__container {
+    margin-top:1rem;
+    display:flex;
+    justify-content:center;
+    align-items:center;
+    gap:2rem
+}
+.hero__title {
+    font-size:2.5rem;
+    margin-bottom:.5rem
+}
+.hero__title-large {
+    font-size:3rem
+}
+ at media(max-width:768px) {
+    .hero__title-large {
+        font-size:2.5rem
+    }
+}
+ at media(max-width:480px) {
+    .hero__title-large {
+        font-size:2rem
+    }
+}
+ at media(max-width:768px) {
+    .hero__title {
+        font-size:2rem
+    }
+}
+ at media(max-width:480px) {
+    .hero__title {
+        font-size:1.75rem
+    }
+}
+.hero__subtitle {
+    font-size:1.25rem;
+    font-weight:500
+}
+ at media(max-width:768px) {
+    .hero__subtitle {
+        font-size:1rem
+    }
+}
+ at media(max-width:480px) {
+    .hero__subtitle {
+        font-size:.875rem
+    }
+}
+
+.section-container {
+    max-width: 2048px;
+    margin-left:auto;
+    margin-right:auto;
+    margin-top:0;
+    margin-bottom: 1rem;
+    padding:1rem 2rem
+}
+
+
+ at media(max-width:768px) {
+    .section-container {
+        padding:1rem
+    }
+}
+.section-container h2 {
+    font-size:1.5rem;
+    margin-bottom:1rem;
+    color:var(--brand);
+    border-bottom: 1px solid var(--text2);
+}
+ at media(max-width:768px) {
+    .section-container h2 {
+        font-size:1.25rem
+    }
+}
+.section-container p {
+    font-size:1rem;
+    line-height:1.5
+}
+ at media(max-width:768px) {
+    .section-container p {
+        font-size:.875rem
+    }
+}
+.home__row {
+    display:grid;
+    grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
+    gap:2rem
+}
+
+
+.links-wrapper {
+    display:grid;
+    gap:1rem;
+    grid-template-columns:1fr 1fr 1fr 1fr
+}
+ at media(max-width:768px) {
+    .links-wrapper {
+        grid-template-columns:1fr 1fr
+    }
+}
+ at media(max-width:480px) {
+    .links-wrapper {
+        grid-template-columns:1fr
+    }
+}
+.links-wrapper .link {
+    display:flex;
+    flex-direction:column;
+    align-items:center;
+    padding:1rem;
+    border:1px solid var(--text1);
+    border-radius:.25rem
+}
+.links-wrapper .link__icon {
+    font-size:2rem
+}
+.links-wrapper .link__title {
+    font-size:1rem
+}
+
+.table-wrapper {
+    display:flex;
+    flex-direction:column;
+    padding:1rem;
+    border-collapse: collapse; /* Ensures there are no gaps between cells */
+}
+
+.table-wrapper th, .table-wrapper td {
+    padding: 0.5rem 1rem; /* Adds padding inside the cells */
+    border:1px solid var(--text1);
+    text-align: left;
+}
+
+
+.block-command-command {
+    font-weight: bold;
+}
+
+.code-clang-doc {
+    font-size: 1.1rem;
+}
+
+.delimiter-container {
+    padding: 0.5rem 1rem;
+    margin-bottom:1rem; 
+}
+
+.resizer {
+    width: 5px;
+    cursor: col-resize;
+    background-color: var(--text2);
+}
+
+.resizer:hover {
+    background-color: var(--text2-inverse);
+}
+
+.sidebar {
+    width: 250px;
+    top: 0;
+    left: 0;
+    height: 100%;
+    position: fixed;
+    background-color: var(--surface1);
+    display: flex;
+    border-left: 1px solid var(--text2);
+    flex-direction: column;
+    overflow-y: auto;
+    scrollbar-width: thin;
+}
+
+.sidebar h2 {
+    margin-top: 0;
+    margin-bottom: 20px;
+    padding: 10px;
+}
+
+.sidebar ul {
+    width: 100%;
+    padding: 0;
+    list-style-type: none;
+}
+
+.sidebar ul li {
+    padding-right: 1rem;
+    padding-left: 2rem;
+    padding-top: 0.25rem;
+    padding-bottom: 0.25rem;
+}
+
+.sidebar-section {
+    font-size:1.5rem;
+    font-weight: bold;
+    margin-bottom: 1rem;
+    padding: 3rem;
+}
+.sidebar-section a {
+    color: var(--brand)
+}
+
+
+/* Content */
+.content {
+    background-color: var(--text1-inverse);
+    padding: 20px;
+    left: 250px;
+    position: relative;
+    width: calc(100% - 250px);
+    height: 100vh;
+}
+.sidebar-item {
+    color: var(--text1);
+}
+
+.sidebar-item-container:hover {
+    width: 100%;
+    background-color: grey;
+}
+
+.sidebar-item-container:hover a {
+    width: 100%;
+    color: var(--text1-inverse);
+}
+
+.class-container {
+    padding: 0.5rem 1rem;
+}
+
+a, a:visited, a:hover, a:active {
+    text-decoration: none;
+    color: inherit;
+}
diff --git a/clang-tools-extra/clang-doc/assets/class-template.mustache b/clang-tools-extra/clang-doc/assets/class-template.mustache
new file mode 100644
index 00000000000000..7ce51c6e162110
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/class-template.mustache
@@ -0,0 +1,227 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for classes/struct
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+    <meta charset="utf-8"/>
+    <title>{{Name}}</title>
+    {{#Stylesheets}}
+        <link rel="stylesheet" type="text/css" href="{{.}}"/>
+    {{/Stylesheets}}
+    {{#Scripts}}
+        <script src="{{.}}"></script>
+    {{/Scripts}}
+    {{! Highlight.js dependency for syntax highlighting }}
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script>
+</head>
+<body>
+<nav class="navbar">
+    <div class="navbar__container">
+        {{#ProjectName}}
+            <div class="navbar__logo">
+                {{ProjectName}}
+            </div>
+        {{/ProjectName}}
+        <div class="navbar__menu">
+            <ul class="navbar__links">
+                <li class="navbar__item">
+                    <a href="/" class="navbar__link">Namespace</a>
+                </li>
+                <li class="navbar__item">
+                    <a href="/" class="navbar__link">Class</a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</nav>
+<main>
+    <div class="container">
+        <div class="sidebar">
+            <h2>{{RecordType}} {{Name}}</h2>
+            <ul>
+                {{#PublicMembers}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#PublicMethods">Public Members</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{Name}}">{{Name}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/PublicMembers}}
+                {{#ProtectedMembers}}
+                    <li class="sidebar-section">
+                        <a class="sidebar-item" href="#PublicMethods">Protected Members</a>
+                    </li>
+                    <ul>
+                        {{#Obj}}
+                            <li class="sidebar-item-container">
+                                <a class="sidebar-item" href="#{{Name}}">{{Name}}</a>
+                            </li>
+                        {{/Obj}}
+                    </ul>
+                {{/ProtectedMembers}}
+                {{#PublicFunction}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#PublicMethods">Public Method</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{Name}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/PublicFunction}}
+                {{#ProtectedFunction}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#ProtectedFunction">Protected Method</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{Name}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/ProtectedFunction}}
+                {{#Enums}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#Enums">Enums</a>
+                </li>
+                <ul>
+                    {{#Obj}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{EnumName}}</a>
+                    </li>
+                    {{/Obj}}
+                </ul>
+                {{/Enums}}
+                {{#Typedef}}
+                <li class="sidebar-section">Typedef</li>
+                {{/Typedef}}
+                {{#Record}}
+                <li class="sidebar-section">
+                    <a class="sidebar-item" href="#Classes">Inner Classes</a>
+                </li>
+                <ul>
+                    {{#Links}}
+                    <li class="sidebar-item-container">
+                        <a class="sidebar-item" href="#{{ID}}">{{Name}}</a>
+                    </li>
+                    {{/Links}}
+                </ul>
+                {{/Record}}
+            </ul>
+        </div>
+        <div class="resizer" id="resizer"></div>
+        <div class="content">
+            <section class="hero section-container">
+                <div class="hero__title">
+                    <h1 class="hero__title-large">{{RecordType}} {{Name}}</h1>
+                    {{#RecordComments}}
+                    <div class="hero__subtitle">
+                        {{>Comments}}
+                    </div>
+                    {{/RecordComments}}
+                </div>
+            </section>
+            {{#PublicMembers}}
+            <section id="PublicMembers" class="section-container">
+                <h2>Public Members</h2>
+                <div>
+                    {{#Obj}}
+                    <div id="{{Name}}" class="delimiter-container">
+                        <pre>
+<code class="language-cpp code-clang-doc" >{{Type}} {{Name}}</code>
+                        </pre>
+                        {{#MemberComments}}
+                        <div>
+                            {{>Comments}}
+                        </div>
+                        {{/MemberComments}}
+                    </div>
+                    {{/Obj}}
+                </div>
+            </section>    
+            {{/PublicMembers}}
+            {{#ProtectedMembers}}
+            <section id="ProtectedMembers" class="section-container">
+                <h2>Protected Members</h2>
+                <div>
+                    {{#Obj}}
+                    <div id="{{Name}}" class="delimiter-container">
+                        <pre>
+<code class="language-cpp code-clang-doc" >{{Type}} {{Name}}</code>
+                        </pre>
+                        {{#MemberComments}}
+                        <div>
+                            {{>Comments}}
+                        </div>
+                        {{/MemberComments}}
+                    </div>
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/ProtectedMembers}}
+            {{#PublicFunction}}
+            <section id="PublicMethods" class="section-container">
+                <h2>Public Methods</h2>
+                <div>
+                    {{#Obj}}
+{{>FunctionPartial}}
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/PublicFunction}}
+            {{#ProtectedFunction}}
+            <section id="ProtectedFunction" class="section-container">
+                <h2>Protected Methods</h2>
+                <div>
+                    {{#Obj}}
+{{>FunctionPartial}}
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/ProtectedFunction}}
+            {{#Enums}}
+            <section id="Enums" class="section-container">
+                <h2>Enumerations</h2>
+                <div>
+                    {{#Obj}}
+{{>EnumPartial}}
+                    {{/Obj}}
+                </div>
+            </section>
+            {{/Enums}}
+            {{#Record}}
+            <section id="Classes" class="section-container">
+                <h2>Inner Classes</h2>
+                <ul class="class-container">
+                    {{#Links}}
+                    <li id="{{ID}}" style="max-height: 40px;">
+<a href="{{Link}}"><pre><code class="language-cpp code-clang-doc" >class {{Name}}</code></pre></a>
+                    </li>
+                    {{/Links}}
+                </ul>
+            </section>
+            {{/Record}}
+            {{#Typedef}}
+            <section class="section-container">
+                <h2 id="Enums">Enums</h2>
+            </section>
+            {{/Typedef}}
+        </div>
+    </div>
+</main>
+</body>
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/comments-template.mustache b/clang-tools-extra/clang-doc/assets/comments-template.mustache
new file mode 100644
index 00000000000000..f6b62b4407b9c4
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/comments-template.mustache
@@ -0,0 +1,34 @@
+{{!
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines templates for generating comments
+}}
+{{#FullComment}}
+    {{#Children}}
+    {{>Comments}}    
+    {{/Children}}
+{{/FullComment}}
+{{#ParagraphComment}}
+    {{#Children}}
+    {{>Comments}}
+    {{/Children}}
+{{/ParagraphComment}}
+{{#BlockCommandComment}}
+    <div class="block-command-comment__command">
+        <div class="block-command-command">
+            {{Command}}
+        </div>
+        <div>
+            {{#Children}}
+                {{>Comments}}
+            {{/Children}}
+        </div>
+    </div>
+{{/BlockCommandComment}}
+{{#TextComment}}
+    <div>
+        <p>{{TextComment}}</p>
+    </div>
+{{/TextComment}}
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/comments.mustache b/clang-tools-extra/clang-doc/assets/comments.mustache
deleted file mode 100644
index 1eac4de91836ab..00000000000000
--- a/clang-tools-extra/clang-doc/assets/comments.mustache
+++ /dev/null
@@ -1,27 +0,0 @@
-{{!
-    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-    See https://llvm.org/LICENSE.txt for license information.
-    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-    
-    This file defines templates for generating
-}}
-
-{{#FullComments}}
-    {{#Children}}
-    {{>Comment}}    
-    {{/Children}}
-{{/FullComments}}
-{{#ParagraphComment}}
-    {{#Children}}
-    {{>Comment}}
-    {{/Children}}
-{{/ParagraphComment}}
-{{#BlockCommandComment}}
-    <div>{{Command}}</div>
-    {{#Children}}
-    {{>Comment}}
-    {{/Children}}
-{{/BlockCommandComment}}
-{{#TextComment}}
-    <p>{{TextComment}}</p>
-{{/TextComment}}
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/enum-template.mustache b/clang-tools-extra/clang-doc/assets/enum-template.mustache
new file mode 100644
index 00000000000000..d63bf258f8f0fb
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/enum-template.mustache
@@ -0,0 +1,47 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for enums
+}}
+<div id="{{ID}}" class="delimiter-container">
+    <div>
+        <pre>
+            <code class="language-cpp code-clang-doc">
+{{EnumName}}
+            </code>
+        </pre>
+    </div>
+    {{! Enum Values }}
+    <table class="table-wrapper">
+        <tbody>
+        <tr>
+            <th>Name</th>
+            <th>Value</th>
+            {{#HasComment}}
+                <th>Comment</th>
+            {{/HasComment}}
+        </tr>
+        {{#EnumValues}}
+            <tr>
+                <td>{{Name}}</td>
+                <td>{{Value}}</td>
+                {{#EnumValueComments}}
+                    <td>{{>Comments}}</td>
+                {{/EnumValueComments}}
+            </tr>
+        {{/EnumValues}}
+        </tbody>
+    </table>
+    {{#EnumComments}}
+    <div>
+        {{>Comments}}
+    </div>
+    {{/EnumComments}}
+    {{#Location}}
+    <div>
+        Defined at line {{LineNumber}} of file {{Filename}}
+    </div>
+    {{/Location}}
+</div>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/function-template.mustache b/clang-tools-extra/clang-doc/assets/function-template.mustache
new file mode 100644
index 00000000000000..0564647467aa60
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/function-template.mustache
@@ -0,0 +1,23 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for functions/methods
+}}
+<div class="delimiter-container">
+    <div id="{{ID}}">
+        {{! Function Prototype }}
+        <pre>
+            <code class="language-cpp code-clang-doc">
+{{ReturnType.Name}} {{Name}} ({{#Params}}{{^End}}{{Type}} {{Name}}, {{/End}}{{#End}}{{Type}} {{Name}}{{/End}}{{/Params}})
+            </code>
+        </pre>
+        {{! Function Comments }}
+        {{#FunctionComments}}
+        <div>
+            {{>Comments}}
+        </div>
+        {{/FunctionComments}}
+    </div>
+</div>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/mustache-index.js b/clang-tools-extra/clang-doc/assets/mustache-index.js
new file mode 100644
index 00000000000000..db320cd8ae403c
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/mustache-index.js
@@ -0,0 +1,33 @@
+document.addEventListener("DOMContentLoaded", function() {
+    const resizer = document.getElementById('resizer');
+    const sidebar = document.querySelector('.sidebar');
+    
+    let isResizing = false;
+    resizer.addEventListener('mousedown', (e) => {
+        isResizing = true;
+    });
+
+    document.addEventListener('mousemove', (e) => {
+        if (!isResizing) return;
+        const newWidth = e.clientX;
+        if (newWidth > 100 && newWidth < window.innerWidth - 100) {
+            sidebar.style.width = `${newWidth}px`;
+        }
+    });
+
+    document.addEventListener('mouseup', () => {
+        isResizing = false;
+    });
+
+    document.querySelectorAll('pre code').forEach((el) => {
+        hljs.highlightElement(el);
+        el.classList.remove("hljs");
+    });
+
+    document.querySelectorAll('.sidebar-item-container').forEach(item => {
+        item.addEventListener('click', function() {
+            const anchor = item.getElementsByTagName("a");
+            window.location.hash = anchor[0].getAttribute('href');
+        });
+    });
+})
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/namespace-template.mustache b/clang-tools-extra/clang-doc/assets/namespace-template.mustache
new file mode 100644
index 00000000000000..4061fd026886e4
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/namespace-template.mustache
@@ -0,0 +1,87 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template for generating namespaces
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+    <head>
+        <meta charset="utf-8"/>
+        <title>{{NamespaceTitle}}</title>
+        {{#Stylesheets}}
+        <link rel="stylesheet" type="text/css" href="{{.}}"/>
+        {{/Stylesheets}}
+        {{#Scripts}}
+        <script src="{{.}}"></script>
+        {{/Scripts}}
+        {{! Highlight.js dependency for syntax highlighting }}
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script>
+    </head>
+    <body>
+        <nav class="navbar">
+            Navbar
+        </nav>
+        <main>
+            <div class="container">
+                <div class="sidebar">
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
+                        sed do eiusmod tempor incididunt ut labore et dolore magna 
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco 
+                        laboris nisi ut aliquip ex ea commodo consequat. 
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse 
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat 
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit 
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+                        sed do eiusmod tempor incididunt ut labore et dolore magna
+                        aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+                        laboris nisi ut aliquip ex ea commodo consequat.
+                        Duis aute irure dolor in reprehenderit in voluptate velit esse
+                        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+                        cupidatat non proident, sunt in culpa qui officia deserunt mollit
+                        anim id est laborum.
+                </div>
+                <div class="resizer" id="resizer"></div>
+                <div class="content">
+                    Content
+                </div>
+            </div>
+        </main>
+    </body>
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
deleted file mode 100644
index 3b77e0189f4e22..00000000000000
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ /dev/null
@@ -1,55 +0,0 @@
-{{! 
-    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-    See https://llvm.org/LICENSE.txt for license information.
-    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-    
-    This file defines the template for generating namespaces
-}}
-<!DOCTYPE html>
-<html lang="en-US">
-    <head>
-        <meta charset="utf-8"/>
-        <title>{{NamespaceTitle}}</title>
-    </head>
-    <h1>{{NamespaceTitle}}</h1>
-    {{#NamespaceComments}}
-    <div>
-        {{>Comments}}
-    </div>
-    {{/NamespaceComments}}
-    {{#Namespace}}
-    <h2 id="Namespace">Namespace</h2>
-    <ul>
-        {{#Links}}
-        <li>
-            <a href="{{Link}}">{{Name}}</a>
-        </li>
-        {{/Links}}
-    </ul>
-    {{/Namespace}}
-    {{#Record}}
-    <h2 id="Class">Class</h2>
-    <ul>
-        {{#Links}}
-        <li>
-            <a href="{{Link}}">{{Name}}</a>
-        </li>
-        {{/Links}}
-    </ul>
-    {{/Record}}
-    {{#Function}}
-    <h2 id="Function">Function</h2>
-    <div>
-        {{#Obj}}
-            
-        {{/Obj}}
-    </div>
-    {{/Function}}
-    {{#Enums}}
-    <h2 id="Enums">Enums</h2>
-    <div>
-        {{#Obj}}
-        {{/Obj}}
-    </div>
-    {{/Enums}}
-</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
index 8eb067dbe6de87..eccbc99a7ecc4b 100644
--- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -21,7 +21,13 @@ target_link_libraries(clang-doc
 
 set(assets
   index.js
-  template.mustache
+  mustache-index.js
+  class-template.mustache
+  comments-template.mustache
+  enum-template.mustache      
+  function-template.mustache
+  namespace-template.mustache      
+  clang-doc-mustache.css
   clang-doc-default-stylesheet.css
 )
 
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index eee8dbf093cc53..256e29c3c9f894 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -163,6 +163,15 @@ llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
+llvm::SmallString<128> appendPathNative(llvm::SmallString<128> Path, 
+                                    llvm::StringRef Asset) {
+  llvm::SmallString<128> Default;
+  llvm::sys::path::native(Path, Default);
+  llvm::sys::path::append(Default, Asset);
+  return Default;
+}
+
+
 llvm::Error getDefaultAssetFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   void *MainAddr = (void *)(intptr_t)getExecutablePath;
@@ -173,13 +182,10 @@ llvm::Error getDefaultAssetFiles(const char *Argv0,
   llvm::SmallString<128> AssetsPath;
   AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
   llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
-  llvm::SmallString<128> DefaultStylesheet;
-  llvm::sys::path::native(AssetsPath, DefaultStylesheet);
-  llvm::sys::path::append(DefaultStylesheet,
-                          "clang-doc-default-stylesheet.css");
-  llvm::SmallString<128> IndexJS;
-  llvm::sys::path::native(AssetsPath, IndexJS);
-  llvm::sys::path::append(IndexJS, "index.js");
+  llvm::SmallString<128> DefaultStylesheet =
+      appendPathNative(AssetsPath, "clang-doc-default-stylesheet.css");
+  llvm::SmallString<128> IndexJS =
+      appendPathNative(AssetsPath, "index.js");
 
   if (!llvm::sys::fs::is_regular_file(IndexJS))
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -210,6 +216,7 @@ llvm::Error getHtmlAssetFiles(const char *Argv0,
   return getDefaultAssetFiles(Argv0, CDCtx);
 }
 
+
 llvm::Error getMustacheHtmlFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   if (!UserAssetPath.empty() &&
@@ -228,10 +235,34 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
   AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
   llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
   
-  llvm::SmallString<128> MustacheTemplate;
-  llvm::sys::path::native(AssetsPath, MustacheTemplate);
-  llvm::sys::path::append(MustacheTemplate, "template.mustache");
-  CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+  llvm::SmallString<128> DefaultStylesheet
+      = appendPathNative(AssetsPath, "clang-doc-mustache.css");
+  llvm::SmallString<128> NamespaceTemplate 
+      = appendPathNative(AssetsPath, "namespace-template.mustache");
+  llvm::SmallString<128> ClassTemplate
+      = appendPathNative(AssetsPath, "class-template.mustache");
+  llvm::SmallString<128> EnumTemplate
+      = appendPathNative(AssetsPath, "enum-template.mustache");
+  llvm::SmallString<128> FunctionTemplate
+      = appendPathNative(AssetsPath, "function-template.mustache");
+  llvm::SmallString<128> CommentTemplate
+      = appendPathNative(AssetsPath, "comments-template.mustache");
+  llvm::SmallString<128> IndexJS
+      = appendPathNative(AssetsPath, "mustache-index.js");
+  
+  CDCtx.JsScripts.insert(CDCtx.JsScripts.begin(), IndexJS.c_str());
+  CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
+                               std::string(DefaultStylesheet));
+  CDCtx.MustacheTemplates.insert({"namespace-template", 
+                                  NamespaceTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"class-template",
+                                  ClassTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"enum-template",
+                                  EnumTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"function-template",
+                                  FunctionTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"comments-template", 
+                                  CommentTemplate.c_str()});
   
   return llvm::Error::success();
 }

>From 644b6d4b3835cd26474ebaecd680a0c4a49cd2f9 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 02:26:22 -0400
Subject: [PATCH 56/57] [clang-doc] init mustache implementation

---
 clang-tools-extra/clang-doc/CMakeLists.txt    |   5 +-
 clang-tools-extra/clang-doc/HTMLGenerator.cpp |  59 +++-
 .../clang-doc/HTMLMustacheGenerator.cpp       | 289 ++++--------------
 .../clang-doc/assets/template.mustache        |  23 ++
 .../clang-doc/tool/CMakeLists.txt             |   8 +-
 .../clang-doc/tool/ClangDocMain.cpp           |  62 +---
 6 files changed, 154 insertions(+), 292 deletions(-)
 create mode 100644 clang-tools-extra/clang-doc/assets/template.mustache

diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt
index 0793c343305184..82aded940222db 100644
--- a/clang-tools-extra/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -8,16 +8,15 @@ add_clang_library(clangDoc
   BitcodeReader.cpp
   BitcodeWriter.cpp
   ClangDoc.cpp
-  FileHelpersClangDoc.cpp
   Generators.cpp
   HTMLGenerator.cpp
-  HTMLMustacheGenerator.cpp      
   Mapper.cpp
   MDGenerator.cpp
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
-        
+  HTMLMustacheGenerator.cpp
+
   DEPENDS
   omp_gen
   ClangDriverOptions
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index aa76d17d9411d6..ed65ac965114b5 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -8,7 +8,6 @@
 
 #include "Generators.h"
 #include "Representation.h"
-#include "FileHelpersClangDoc.h"
 #include "clang/Basic/Version.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -252,6 +251,46 @@ static void appendVector(std::vector<Derived> &&New,
   std::move(New.begin(), New.end(), std::back_inserter(Original));
 }
 
+// Compute the relative path from an Origin directory to a Destination directory
+static SmallString<128> computeRelativePath(StringRef Destination,
+                                            StringRef Origin) {
+  // If Origin is empty, the relative path to the Destination is its complete
+  // path.
+  if (Origin.empty())
+    return Destination;
+
+  // The relative path is an empty path if both directories are the same.
+  if (Destination == Origin)
+    return {};
+
+  // These iterators iterate through each of their parent directories
+  llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
+  llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
+  llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
+  llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
+  // Advance both iterators until the paths differ. Example:
+  //    Destination = A/B/C/D
+  //    Origin      = A/B/E/F
+  // FileI will point to C and DirI to E. The directories behind them is the
+  // directory they share (A/B).
+  while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
+    ++FileI;
+    ++DirI;
+  }
+  SmallString<128> Result; // This will hold the resulting path.
+  // Result has to go up one directory for each of the remaining directories in
+  // Origin
+  while (DirI != DirE) {
+    llvm::sys::path::append(Result, "..");
+    ++DirI;
+  }
+  // Result has to append each of the remaining directories in Destination
+  while (FileI != FileE) {
+    llvm::sys::path::append(Result, *FileI);
+    ++FileI;
+  }
+  return Result;
+}
 
 // HTML generation
 
@@ -1094,6 +1133,24 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
+static llvm::Error 
+copyFile(StringRef FilePath, StringRef OutDirectory) {
+  llvm::SmallString<128> PathWrite;
+  llvm::sys::path::native(OutDirectory, PathWrite);
+  llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
+  llvm::SmallString<128> PathRead;
+  llvm::sys::path::native(FilePath, PathRead);
+  std::error_code OK;
+  std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
+  if (FileErr != OK) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "error creating file " +
+                                       llvm::sys::path::filename(FilePath) +
+                                       ": " + FileErr.message() + "\n");
+  }
+  return llvm::Error::success();
+}
+
 llvm::Error HTMLGenerator::createResources(ClangDocContext &CDCtx) {
   auto Err = serializeIndex(CDCtx);
   if (Err)
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 6be4c795a68654..63def07c5fa804 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 #include "Generators.h"
 #include "Representation.h"
-#include "FileHelpersClangDoc.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Mustache.h"
 
@@ -49,12 +48,12 @@ class MustacheTemplateFile : public Template {
   Error registerPartialFile(StringRef Name, StringRef FileName) {
     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
         MemoryBuffer::getFile(FileName);
-    if (auto EC = BufferOrError.getError())
+    if (auto EC = BufferOrError.getError()) {
       return llvm::createFileError("cannot open file", EC);
+    }
     std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
     llvm::StringRef FileContent = Buffer->getBuffer();
     registerPartial(Name, FileContent);
-    return llvm::Error::success();
   }
 
   MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
@@ -65,54 +64,23 @@ static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
 static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
 
 
-llvm::Error setupTemplate(
-                   std::unique_ptr<MustacheTemplateFile> &Template,
-                   StringRef TemplatePath,
-                   std::vector<std::pair<StringRef, StringRef>> Partials) {
-  auto T = MustacheTemplateFile::createMustacheFile(TemplatePath);
-  if (auto EC = T.getError())
-     return llvm::createFileError("cannot open file", EC);
-  Template = std::move(T.get());
-  for (const auto &P : Partials) {
-    auto Err = Template->registerPartialFile(P.first, P.second);
-    if (Err)
-      return Err;
-  }
-  return llvm::Error::success();
-}
-
 llvm::Error 
 setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
-  auto NamespaceFilePath = CDCtx.MustacheTemplates.lookup("namespace-template");
-  auto ClassFilePath = CDCtx.MustacheTemplates.lookup("class-template");
-  auto CommentFilePath = CDCtx.MustacheTemplates.lookup("comments-template");
-  auto FunctionFilePath = CDCtx.MustacheTemplates.lookup("function-template");
-  auto EnumFilePath = CDCtx.MustacheTemplates.lookup("enum-template");
-  std::vector<std::pair<StringRef, StringRef>> Partials = {
-    {"Comments", CommentFilePath},
-    {"FunctionPartial", FunctionFilePath},
-    {"EnumPartial", EnumFilePath}
-  };
-  
-  auto Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials);
-  if (Err)
-    return Err;
-  
-  Err = setupTemplate(RecordTemplate, ClassFilePath, Partials);
-  
-  if (Err)
-    return Err;
-  
-  return llvm::Error::success();
+  auto TemplateFilePath = CDCtx.MustacheTemplates.lookup("template");
+  auto Template = MustacheTemplateFile::createMustacheFile(TemplateFilePath);
+  if (auto EC = Template.getError()) {
+    return llvm::createFileError("cannot open file", EC);
+  }
+  NamespaceTemplate = std::move(Template.get());
 }
 
-
 llvm::Error 
 MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir, 
                                     llvm::StringMap<std::unique_ptr<doc::Info>> Infos, 
                                     const clang::doc::ClangDocContext &CDCtx) {
-  if (auto Err = setupTemplateFiles(CDCtx))
+  if (auto Err = setupTemplateFiles(CDCtx)) {
     return Err;
+  }
   // Track which directories we already tried to create.
   llvm::StringSet<> CreatedDirs;
   // Collect all output by file name and create the necessary directories.
@@ -125,9 +93,10 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
     if (!CreatedDirs.contains(Path)) {
       if (std::error_code Err = llvm::sys::fs::create_directories(Path);
-          Err != std::error_code())
+          Err != std::error_code()) {
         return llvm::createStringError(Err, "Failed to create directory '%s'.",
                                        Path.c_str());
+      }
       CreatedDirs.insert(Path);
     }
 
@@ -139,33 +108,28 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     std::error_code FileErr;
     llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
                                 llvm::sys::fs::OF_None);
-    if (FileErr)
+    if (FileErr) {
       return llvm::createStringError(FileErr, "Error opening file '%s'",
                                      Group.getKey().str().c_str());
-    
+    }
     for (const auto &Info : Group.getValue()) {
-      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx))
+      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
         return Err;
+      }
     }
   }
-  return llvm::Error::success();
 }
 
 Value extractValue(const Location &L, 
                    std::optional<StringRef> RepositoryUrl = std::nullopt) {
   Object Obj = Object();
-  Obj.insert({"LineNumber", L.LineNumber});
-  Obj.insert({"Filename", L.Filename});
-  
   if (!L.IsFileInRootDir || !RepositoryUrl) {
-    return Obj;
+    Obj.insert({"LineNumber", L.LineNumber});
+    Obj.insert({"Filename", L.Filename});
   }
   SmallString<128> FileURL(*RepositoryUrl);
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
-  FileURL += "#" + std::to_string(L.LineNumber);
   Obj.insert({"FileURL", FileURL});
-  
-  return Obj;
 }
 
 Value extractValue(const Reference &I, StringRef CurrentDirectory) {
@@ -175,8 +139,6 @@ Value extractValue(const Reference &I, StringRef CurrentDirectory) {
   Object Obj = Object();
   Obj.insert({"Link", Path});
   Obj.insert({"Name", I.Name});
-  Obj.insert({"QualName", I.QualName});
-  Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
   return Obj;
 }
 
@@ -227,12 +189,8 @@ Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
   Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
   
   Value ParamArr = Array();
-  for (const auto Val : llvm::enumerate(I.Params)) {
-    Value V = Object();
-    V.getAsObject()->insert({"Name", Val.value().Name});
-    V.getAsObject()->insert({"Type", Val.value().Type.Name});
-    V.getAsObject()->insert({"End",  Val.index() + 1 == I.Params.size()});
-    ParamArr.getAsArray()->emplace_back(V);
+  for (const auto &P : I.Params) {
+    ParamArr.getAsArray()->emplace_back(extractValue(P.Type, ParentInfoDir));
   }
   Obj.insert({"Params", ParamArr});
   
@@ -242,13 +200,12 @@ Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
     Obj.insert({"FunctionComments", ArrDesc});
   }
-  if (I.DefLoc.has_value()) {
-    Location L = *I.DefLoc;
-    if (CDCtx.RepositoryUrl.has_value())
-      Obj.insert({"Location", extractValue(L,
-                                           StringRef{*CDCtx.RepositoryUrl})});
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
     else
-      Obj.insert({"Location", extractValue(L)});  
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
   }
   return Obj;
 }
@@ -263,6 +220,7 @@ Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
   Obj.insert({"EnumName", EnumType});
   Obj.insert({"HasComment", HasComment});
   Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
+  
   Value Arr = Array();
   for (const EnumValueInfo& M: I.Members) {
     Value EnumValue = Object();
@@ -289,75 +247,17 @@ Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
     Obj.insert({"EnumComments", ArrDesc});
   }
   
-  if (I.DefLoc.has_value()) {
-    Location L = *I.DefLoc;
-    if (CDCtx.RepositoryUrl.has_value())
-      Obj.insert({"Location", extractValue(L,
-                                           StringRef{*CDCtx.RepositoryUrl})});
+  if (I.DefLoc) {
+    if (!CDCtx.RepositoryUrl)
+      Obj.insert({"Location", extractValue(*I.DefLoc)});
     else
-      Obj.insert({"Location", extractValue(L)});  
+      Obj.insert({"Location", extractValue(*I.DefLoc, 
+                                           StringRef{*CDCtx.RepositoryUrl})});  
   }
   
   return Obj;
 }
 
-void extractScopeChildren(const ScopeChildren &S, Object &Obj, 
-                          StringRef ParentInfoDir,
-                          const ClangDocContext &CDCtx) {
-  Value ArrNamespace = Array();
-  for (const Reference& Child : S.Namespaces)
-    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
-  
-  if (!ArrNamespace.getAsArray()->empty())
-    Obj.insert({"Namespace", Object{{"Links", ArrNamespace}}});
-  
-  Value ArrRecord = Array();
-  for (const Reference& Child : S.Records)
-    ArrRecord.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
-  
-  if (!ArrRecord.getAsArray()->empty())
-    Obj.insert({"Record", Object{{"Links", ArrRecord}}});
-  
-  Value ArrFunction = Array();
-  Value PublicFunction = Array();
-  Value ProtectedFunction = Array();
-  Value PrivateFunction = Array();
-  
-  for (const FunctionInfo& Child : S.Functions) {
-    Value F = extractValue(Child, ParentInfoDir, CDCtx);
-    AccessSpecifier Access = Child.Access;
-    if (Access == AccessSpecifier::AS_public)
-      PublicFunction.getAsArray()->emplace_back(F);
-    else if (Access == AccessSpecifier::AS_protected)
-      ProtectedFunction.getAsArray()->emplace_back(F);
-    else
-      ArrFunction.getAsArray()->emplace_back(F);
-  }  
-  if (!ArrFunction.getAsArray()->empty())
-    Obj.insert({"Function", Object{{"Obj", ArrFunction}}});
-  
-  if (!PublicFunction.getAsArray()->empty())
-    Obj.insert({"PublicFunction", Object{{"Obj", PublicFunction}}});
-  
-  if (!ProtectedFunction.getAsArray()->empty())
-    Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunction}}});
-  
-  
-  Value ArrEnum = Array();
-  for (const EnumInfo& Child : S.Enums)
-    ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
-  
-  if (!ArrEnum.getAsArray()->empty())
-    Obj.insert({"Enums", Object{{"Obj", ArrEnum }}});
-  
-  Value ArrTypedefs = Array();
-  for (const TypedefInfo& Child : S.Typedefs) 
-    ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
-  
-  if (!ArrTypedefs.getAsArray()->empty())
-    Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
-}
-
 Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
   Object NamespaceValue = Object();
   std::string InfoTitle;
@@ -376,88 +276,36 @@ Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
     NamespaceValue.insert({"NamespaceComments", ArrDesc });
   }
-  extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx);
-  return NamespaceValue;
-}
 
-Value extractValue(const RecordInfo &I, const ClangDocContext &CDCtx) {
-  Object RecordValue = Object();
+  Value ArrNamespace = Array();
+  for (const Reference& Child : I.Children.Namespaces)
+    ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Namespace", ArrNamespace});
   
-  if (!I.Description.empty()) {
-    Value ArrDesc = Array();
-    for (const CommentInfo& Child : I.Description) 
-      ArrDesc.getAsArray()->emplace_back(extractValue(Child));
-    RecordValue.insert({"RecordComments", ArrDesc });
-  }
-  RecordValue.insert({"Name", I.Name});
-  RecordValue.insert({"FullName", I.FullName});
-  RecordValue.insert({"RecordType", getTagType(I.TagType)});
+  Value ArrRecord = Array();
+  for (const Reference& Child : I.Children.Records)
+    ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
+  NamespaceValue.insert({"Record", ArrRecord});
   
-  if (I.DefLoc.has_value()) {
-    Location L = *I.DefLoc;
-    if (CDCtx.RepositoryUrl.has_value())
-      RecordValue.insert({"Location", extractValue(L,
-                                           StringRef{*CDCtx.RepositoryUrl})});
-    else
-      RecordValue.insert({"Location", extractValue(L)});  
-  }
+  Value ArrFunction = Array();
+  for (const FunctionInfo& Child : I.Children.Functions)
+    ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
+                                                        CDCtx));
+  NamespaceValue.insert({"Function", ArrRecord});
   
-  StringRef BasePath = I.getRelativeFilePath("");
-  extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
-  Value PublicMembers = Array();
-  Value ProtectedMembers = Array();
-  Value PrivateMembers = Array();
-  for (const MemberTypeInfo &Member : I.Members ) {
-    Value MemberValue = Object();
-    MemberValue.getAsObject()->insert({"Name", Member.Name});
-    MemberValue.getAsObject()->insert({"Type", Member.Type.Name});
-    if (!Member.Description.empty()) {
-      Value ArrDesc = Array();
-      for (const CommentInfo& Child : Member.Description) 
-            ArrDesc.getAsArray()->emplace_back(extractValue(Child));
-      MemberValue.getAsObject()->insert({"MemberComments", ArrDesc });
-    }
-    
-    if (Member.Access == AccessSpecifier::AS_public)
-      PublicMembers.getAsArray()->emplace_back(MemberValue);
-    else if (Member.Access == AccessSpecifier::AS_protected)
-      ProtectedMembers.getAsArray()->emplace_back(MemberValue);
-    else if (Member.Access == AccessSpecifier::AS_private)
-      PrivateMembers.getAsArray()->emplace_back(MemberValue);
-  }
-  if (!PublicMembers.getAsArray()->empty())
-    RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}});
-  if (!ProtectedMembers.getAsArray()->empty())
-    RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
-  if (!PrivateMembers.getAsArray()->empty())
-    RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
+  Value ArrEnum = Array();
+  for (const EnumInfo& Child : I.Children.Enums)
+    ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
+  NamespaceValue.insert({"Enums", ArrEnum });
   
-  return RecordValue;
-}
-
-void setupTemplateValue(const ClangDocContext &CDCtx, Value &V, Info *I) {
-  V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName});
-  Value StylesheetArr = Array();
-  auto InfoPath = I->getRelativeFilePath("");
-  SmallString<128> RelativePath = computeRelativePath("", InfoPath);
-  for (const auto &FilePath  : CDCtx.UserStylesheets) {
-    SmallString<128> StylesheetPath = RelativePath;
-    llvm::sys::path::append(StylesheetPath,
-                            llvm::sys::path::filename(FilePath));
-    llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
-    StylesheetArr.getAsArray()->emplace_back(StylesheetPath);
-  }
-  V.getAsObject()->insert({"Stylesheets", StylesheetArr});
+  Value ArrTypedefs = Array();
+  for (const TypedefInfo& Child : I.Children.Typedefs) 
+    ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
+  NamespaceValue.insert({"Typedefs", ArrTypedefs });
   
-  Value ScriptArr = Array();
-  for (auto Script : CDCtx.JsScripts) {
-    SmallString<128> JsPath = RelativePath;
-    llvm::sys::path::append(JsPath, llvm::sys::path::filename(Script));
-    ScriptArr.getAsArray()->emplace_back(JsPath);
-  }
-  V.getAsObject()->insert({"Scripts", ScriptArr});
 }
- 
+
+
 
 llvm::Error
 MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
@@ -465,26 +313,16 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
-    setupTemplateValue(CDCtx, V, I);
     OS << NamespaceTemplate->render(V);
     break;
   }
-  case InfoType::IT_record: {
-    Value V = extractValue(*static_cast<clang::doc::RecordInfo *>(I), CDCtx);
-    setupTemplateValue(CDCtx, V, I);
-    // Serialize the JSON value to the output stream in a readable format.
-    llvm::outs() << llvm::formatv("{0:2}", V);
-    OS << RecordTemplate->render(V);
+  case InfoType::IT_record:
     break;
-  }  
   case InfoType::IT_enum:
-    llvm::outs() << "IT_enum\n";
     break;
   case InfoType::IT_function:
-    llvm::outs() << "IT_Function\n";
     break;
   case InfoType::IT_typedef:
-    llvm::outs() << "IT_typedef\n";
     break;
   case InfoType::IT_default:
     return createStringError(llvm::inconvertibleErrorCode(),
@@ -494,21 +332,10 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
 }
 
 llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
-  llvm::Error Err = llvm::Error::success();
-  for (const auto &FilePath : CDCtx.UserStylesheets) {
-    Err = copyFile(FilePath, CDCtx.OutDirectory);
-    if (Err)
-      return Err;
-  }
-  for (const auto &FilePath : CDCtx.JsScripts) {
-    Err = copyFile(FilePath, CDCtx.OutDirectory);
-    if (Err)
-      return Err;
-  }
-  return llvm::Error::success();
+  
 }
 
-const char *MustacheHTMLGenerator::Format = "mhtml";
+const char *MustacheHTMLGenerator::Format = "mustache";
 
 
 static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
@@ -516,7 +343,7 @@ static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator
 
 // This anchor is used to force the linker to link in the generated object
 // file and thus register the generator.
-volatile int MHTMLGeneratorAnchorSource = 0;
+volatile int HTMLGeneratorAnchorSource = 0;
 
 } // namespace doc
 } // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
new file mode 100644
index 00000000000000..af4c60182ae52c
--- /dev/null
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -0,0 +1,23 @@
+{{! 
+    Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+    See https://llvm.org/LICENSE.txt for license information.
+    SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+    
+    This file defines the template
+}}
+<!DOCTYPE html>
+<html lang="en-US">
+    <head>
+        <meta charset="utf-8"/>
+        <title>{{NamespaceTitle}}</title>
+    </head>
+    {{#NamespaceComments}}
+    <p>Namespace Comment Present!</p>
+    {{/NamespaceComments}}
+    {{#Namespace}}
+    <p>Namespace Present!</p>
+    {{/Namespace}}
+    {{#Record}}
+    <p>Record Present!</p>
+    {{/Record}}
+</html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
index eccbc99a7ecc4b..8eb067dbe6de87 100644
--- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -21,13 +21,7 @@ target_link_libraries(clang-doc
 
 set(assets
   index.js
-  mustache-index.js
-  class-template.mustache
-  comments-template.mustache
-  enum-template.mustache      
-  function-template.mustache
-  namespace-template.mustache      
-  clang-doc-mustache.css
+  template.mustache
   clang-doc-default-stylesheet.css
 )
 
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 256e29c3c9f894..fc5a9529111b16 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -103,7 +103,6 @@ enum OutputFormatTy {
   md,
   yaml,
   html,
-  mhtml
 };
 
 static llvm::cl::opt<OutputFormatTy>
@@ -113,9 +112,7 @@ static llvm::cl::opt<OutputFormatTy>
                                 clEnumValN(OutputFormatTy::md, "md",
                                            "Documentation in MD format."),
                                 clEnumValN(OutputFormatTy::html, "html",
-                                           "Documentation in HTML format."),
-                                clEnumValN(OutputFormatTy::mhtml, "mhtml",
-                                           "Documentation in mHTML format")),
+                                           "Documentation in HTML format.")),
                llvm::cl::init(OutputFormatTy::yaml),
                llvm::cl::cat(ClangDocCategory));
 
@@ -127,8 +124,6 @@ std::string getFormatString() {
     return "md";
   case OutputFormatTy::html:
     return "html";
-  case OutputFormatTy::mhtml:
-    return "mhtml";
   }
   llvm_unreachable("Unknown OutputFormatTy");
 }
@@ -163,15 +158,6 @@ llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-llvm::SmallString<128> appendPathNative(llvm::SmallString<128> Path, 
-                                    llvm::StringRef Asset) {
-  llvm::SmallString<128> Default;
-  llvm::sys::path::native(Path, Default);
-  llvm::sys::path::append(Default, Asset);
-  return Default;
-}
-
-
 llvm::Error getDefaultAssetFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   void *MainAddr = (void *)(intptr_t)getExecutablePath;
@@ -182,10 +168,13 @@ llvm::Error getDefaultAssetFiles(const char *Argv0,
   llvm::SmallString<128> AssetsPath;
   AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
   llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
-  llvm::SmallString<128> DefaultStylesheet =
-      appendPathNative(AssetsPath, "clang-doc-default-stylesheet.css");
-  llvm::SmallString<128> IndexJS =
-      appendPathNative(AssetsPath, "index.js");
+  llvm::SmallString<128> DefaultStylesheet;
+  llvm::sys::path::native(AssetsPath, DefaultStylesheet);
+  llvm::sys::path::append(DefaultStylesheet,
+                          "clang-doc-default-stylesheet.css");
+  llvm::SmallString<128> IndexJS;
+  llvm::sys::path::native(AssetsPath, IndexJS);
+  llvm::sys::path::append(IndexJS, "index.js");
 
   if (!llvm::sys::fs::is_regular_file(IndexJS))
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -216,7 +205,6 @@ llvm::Error getHtmlAssetFiles(const char *Argv0,
   return getDefaultAssetFiles(Argv0, CDCtx);
 }
 
-
 llvm::Error getMustacheHtmlFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   if (!UserAssetPath.empty() &&
@@ -235,36 +223,10 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
   AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
   llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
   
-  llvm::SmallString<128> DefaultStylesheet
-      = appendPathNative(AssetsPath, "clang-doc-mustache.css");
-  llvm::SmallString<128> NamespaceTemplate 
-      = appendPathNative(AssetsPath, "namespace-template.mustache");
-  llvm::SmallString<128> ClassTemplate
-      = appendPathNative(AssetsPath, "class-template.mustache");
-  llvm::SmallString<128> EnumTemplate
-      = appendPathNative(AssetsPath, "enum-template.mustache");
-  llvm::SmallString<128> FunctionTemplate
-      = appendPathNative(AssetsPath, "function-template.mustache");
-  llvm::SmallString<128> CommentTemplate
-      = appendPathNative(AssetsPath, "comments-template.mustache");
-  llvm::SmallString<128> IndexJS
-      = appendPathNative(AssetsPath, "mustache-index.js");
-  
-  CDCtx.JsScripts.insert(CDCtx.JsScripts.begin(), IndexJS.c_str());
-  CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
-                               std::string(DefaultStylesheet));
-  CDCtx.MustacheTemplates.insert({"namespace-template", 
-                                  NamespaceTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"class-template",
-                                  ClassTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"enum-template",
-                                  EnumTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"function-template",
-                                  FunctionTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"comments-template", 
-                                  CommentTemplate.c_str()});
-  
-  return llvm::Error::success();
+  llvm::SmallString<128> MustacheTemplate;
+  llvm::sys::path::native(AssetsPath, MustacheTemplate);
+  llvm::sys::path::append(MustacheTemplate, "template.mustache");
+  CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
 }
 
 /// Make the output of clang-doc deterministic by sorting the children of

>From 70de69247414e6ff22d336803e133a48c3c7fdf3 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Fri, 13 Sep 2024 17:50:03 -0400
Subject: [PATCH 57/57] [clang-doc] add a mustache backend init implementation

---
 .../clang-doc/HTMLMustacheGenerator.cpp       | 32 ++++++++++++----
 .../clang-doc/assets/template.mustache        | 37 +++++++++++++++++--
 .../clang-doc/tool/ClangDocMain.cpp           |  9 ++++-
 .../Inputs/basic-project/include/Shape.h      |  2 -
 4 files changed, 65 insertions(+), 15 deletions(-)

diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 63def07c5fa804..bfa563ebdc7b37 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -54,6 +54,7 @@ class MustacheTemplateFile : public Template {
     std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrError.get());
     llvm::StringRef FileContent = Buffer->getBuffer();
     registerPartial(Name, FileContent);
+    return llvm::Error::success();
   }
 
   MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
@@ -72,6 +73,7 @@ setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
     return llvm::createFileError("cannot open file", EC);
   }
   NamespaceTemplate = std::move(Template.get());
+  return llvm::Error::success();
 }
 
 llvm::Error 
@@ -118,6 +120,7 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
       }
     }
   }
+  return llvm::Error::success();
 }
 
 Value extractValue(const Location &L, 
@@ -130,6 +133,8 @@ Value extractValue(const Location &L,
   SmallString<128> FileURL(*RepositoryUrl);
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
   Obj.insert({"FileURL", FileURL});
+  
+  return Obj;
 }
 
 Value extractValue(const Reference &I, StringRef CurrentDirectory) {
@@ -280,29 +285,39 @@ Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
   Value ArrNamespace = Array();
   for (const Reference& Child : I.Children.Namespaces)
     ArrNamespace.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Namespace", ArrNamespace});
+  
+  if (!ArrNamespace.getAsArray()->empty())
+    NamespaceValue.insert({"Namespace", Object{{"Links", ArrNamespace}}});
   
   Value ArrRecord = Array();
   for (const Reference& Child : I.Children.Records)
     ArrRecord.getAsArray()->emplace_back(extractValue(Child, BasePath));
-  NamespaceValue.insert({"Record", ArrRecord});
+  
+  if (!ArrRecord.getAsArray()->empty())
+    NamespaceValue.insert({"Record", Object{{"Links", ArrRecord}}});
   
   Value ArrFunction = Array();
   for (const FunctionInfo& Child : I.Children.Functions)
     ArrFunction.getAsArray()->emplace_back(extractValue(Child, BasePath,
                                                         CDCtx));
-  NamespaceValue.insert({"Function", ArrRecord});
+  if (!ArrFunction.getAsArray()->empty())
+    NamespaceValue.insert({"Function", Object{{"Obj", ArrFunction}}});
   
   Value ArrEnum = Array();
   for (const EnumInfo& Child : I.Children.Enums)
     ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
-  NamespaceValue.insert({"Enums", ArrEnum });
+  
+  if (!ArrEnum.getAsArray()->empty())
+    NamespaceValue.insert({"Enums", Object{{"Obj", ArrEnum }}});
   
   Value ArrTypedefs = Array();
   for (const TypedefInfo& Child : I.Children.Typedefs) 
     ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
-  NamespaceValue.insert({"Typedefs", ArrTypedefs });
   
+  if (!ArrTypedefs.getAsArray()->empty())
+    NamespaceValue.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+  
+  return NamespaceValue;
 }
 
 
@@ -313,6 +328,7 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
   switch (I->IT) {
   case InfoType::IT_namespace: {
     Value V = extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+    llvm::outs() << V << "\n";
     OS << NamespaceTemplate->render(V);
     break;
   }
@@ -332,10 +348,10 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
 }
 
 llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
-  
+  return llvm::Error::success();
 }
 
-const char *MustacheHTMLGenerator::Format = "mustache";
+const char *MustacheHTMLGenerator::Format = "mhtml";
 
 
 static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
@@ -343,7 +359,7 @@ static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator
 
 // This anchor is used to force the linker to link in the generated object
 // file and thus register the generator.
-volatile int HTMLGeneratorAnchorSource = 0;
+volatile int MHTMLGeneratorAnchorSource = 0;
 
 } // namespace doc
 } // namespace clang
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/assets/template.mustache b/clang-tools-extra/clang-doc/assets/template.mustache
index af4c60182ae52c..1d3407f8b52920 100644
--- a/clang-tools-extra/clang-doc/assets/template.mustache
+++ b/clang-tools-extra/clang-doc/assets/template.mustache
@@ -3,7 +3,7 @@
     See https://llvm.org/LICENSE.txt for license information.
     SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     
-    This file defines the template
+    This file defines the template for generating Namespaces
 }}
 <!DOCTYPE html>
 <html lang="en-US">
@@ -11,13 +11,42 @@
         <meta charset="utf-8"/>
         <title>{{NamespaceTitle}}</title>
     </head>
+    <h1>{{NamespaceTitle}}</h1>
     {{#NamespaceComments}}
-    <p>Namespace Comment Present!</p>
+    <p>Namespace Comment</p>
     {{/NamespaceComments}}
     {{#Namespace}}
-    <p>Namespace Present!</p>
+    <h2 id="Namespace">Namespace</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Namespace}}
     {{#Record}}
-    <p>Record Present!</p>
+    <h2 id="Class">Class</h2>
+    <ul>
+        {{#Links}}
+        <li>
+            <a href="{{Link}}">{{Name}}</a>
+        </li>
+        {{/Links}}
+    </ul>
     {{/Record}}
+    {{#Function}}
+    <h2 id="Function">Function</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Function}}
+    {{#Enums}}
+    <h2 id="Enums">Enums</h2>
+    <div>
+        {{#Obj}}
+        {{/Obj}}
+    </div>
+    {{/Enums}}
 </html>
\ No newline at end of file
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index fc5a9529111b16..eee8dbf093cc53 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -103,6 +103,7 @@ enum OutputFormatTy {
   md,
   yaml,
   html,
+  mhtml
 };
 
 static llvm::cl::opt<OutputFormatTy>
@@ -112,7 +113,9 @@ static llvm::cl::opt<OutputFormatTy>
                                 clEnumValN(OutputFormatTy::md, "md",
                                            "Documentation in MD format."),
                                 clEnumValN(OutputFormatTy::html, "html",
-                                           "Documentation in HTML format.")),
+                                           "Documentation in HTML format."),
+                                clEnumValN(OutputFormatTy::mhtml, "mhtml",
+                                           "Documentation in mHTML format")),
                llvm::cl::init(OutputFormatTy::yaml),
                llvm::cl::cat(ClangDocCategory));
 
@@ -124,6 +127,8 @@ std::string getFormatString() {
     return "md";
   case OutputFormatTy::html:
     return "html";
+  case OutputFormatTy::mhtml:
+    return "mhtml";
   }
   llvm_unreachable("Unknown OutputFormatTy");
 }
@@ -227,6 +232,8 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
   llvm::sys::path::native(AssetsPath, MustacheTemplate);
   llvm::sys::path::append(MustacheTemplate, "template.mustache");
   CDCtx.MustacheTemplates.insert({"template", MustacheTemplate.c_str()});
+  
+  return llvm::Error::success();
 }
 
 /// Make the output of clang-doc deterministic by sorting the children of
diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
index e5c5d4c9e4412b..5354032f4d8323 100644
--- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
+++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
@@ -26,5 +26,3 @@ class Shape {
      */
     virtual double perimeter() const = 0;
 };
-
-



More information about the cfe-commits mailing list