Skip to content

Commit ece59a8

Browse files
ilovepiPeterChou1
andauthored
Reland Support for mustache templating language (#132467)
The last version of this patch had memory leaks due to using the BumpPtrAllocator for data types that required destructors to run to release heap memory (e.g. via std::vector and std::string). This version avoids that by using smart pointers, and dropping support for BumpPtrAllocator. We should refactor this code to use the BumpPtrAllocator again, but that can be addressed in future patches, since those are more invasive changes that need to refactor many of the core data types to avoid owning allocations. Adds Support for the Mustache Templating Language. See specs here: https://mustache.github.io/mustache.5.html This patch implements support+tests for majority of the features of the language including: - Variables - Comments - Lambdas - Sections This meant as a library to support places where we have to generate HTML, such as in clang-doc. Co-authored-by: Peter Chou <[email protected]>
1 parent 25bf4e2 commit ece59a8

File tree

5 files changed

+2119
-0
lines changed

5 files changed

+2119
-0
lines changed

llvm/include/llvm/Support/Mustache.h

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//===--- Mustache.h ---------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Implementation of the Mustache templating language supports version 1.4.2
10+
// currently relies on llvm::json::Value for data input.
11+
// See the Mustache spec for more information
12+
// (https://mustache.github.io/mustache.5.html).
13+
//
14+
// Current Features Supported:
15+
// - Variables
16+
// - Sections
17+
// - Inverted Sections
18+
// - Partials
19+
// - Comments
20+
// - Lambdas
21+
// - Unescaped Variables
22+
//
23+
// Features Not Supported:
24+
// - Set Delimiter
25+
// - Blocks
26+
// - Parents
27+
// - Dynamic Names
28+
//
29+
// The Template class is a container class that outputs the Mustache template
30+
// string and is the main class for users. It stores all the lambdas and the
31+
// ASTNode Tree. When the Template is instantiated it tokenizes the Template
32+
// String and creates a vector of Tokens. Then it calls a basic recursive
33+
// descent parser to construct the ASTNode Tree. The ASTNodes are all stored
34+
// in an arena allocator which is freed once the template class goes out of
35+
// scope.
36+
//
37+
// Usage:
38+
// \code
39+
// // Creating a simple template and rendering it
40+
// auto Template = Template("Hello, {{name}}!");
41+
// Value Data = {{"name", "World"}};
42+
// std::string Out;
43+
// raw_string_ostream OS(Out);
44+
// T.render(Data, OS);
45+
// // Out == "Hello, World!"
46+
//
47+
// // Creating a template with a partial and rendering it
48+
// auto Template = Template("{{>partial}}");
49+
// Template.registerPartial("partial", "Hello, {{name}}!");
50+
// Value Data = {{"name", "World"}};
51+
// std::string Out;
52+
// raw_string_ostream OS(Out);
53+
// T.render(Data, OS);
54+
// // Out == "Hello, World!"
55+
//
56+
// // Creating a template with a lambda and rendering it
57+
// Value D = Object{};
58+
// auto T = Template("Hello, {{lambda}}!");
59+
// Lambda L = []() -> llvm::json::Value { return "World"; };
60+
// T.registerLambda("lambda", L);
61+
// std::string Out;
62+
// raw_string_ostream OS(Out);
63+
// T.render(D, OS);
64+
// // Out == "Hello, World!"
65+
// \endcode
66+
//
67+
//===----------------------------------------------------------------------===//
68+
69+
#ifndef LLVM_SUPPORT_MUSTACHE
70+
#define LLVM_SUPPORT_MUSTACHE
71+
72+
#include "Error.h"
73+
#include "llvm/ADT/StringMap.h"
74+
#include "llvm/Support/Allocator.h"
75+
#include "llvm/Support/JSON.h"
76+
#include "llvm/Support/StringSaver.h"
77+
#include <functional>
78+
#include <vector>
79+
80+
namespace llvm::mustache {
81+
82+
using Lambda = std::function<llvm::json::Value()>;
83+
using SectionLambda = std::function<llvm::json::Value(std::string)>;
84+
85+
class ASTNode;
86+
using AstPtr = std::unique_ptr<ASTNode>;
87+
88+
// A Template represents the container for the AST and the partials
89+
// and Lambdas that are registered with it.
90+
class Template {
91+
public:
92+
Template(StringRef TemplateStr);
93+
94+
Template(const Template &) = delete;
95+
96+
Template &operator=(const Template &) = delete;
97+
98+
Template(Template &&Other) noexcept;
99+
100+
// Define this in the cpp file to work around ASTNode being an incomplete
101+
// type.
102+
~Template();
103+
104+
Template &operator=(Template &&Other) noexcept;
105+
106+
void render(const llvm::json::Value &Data, llvm::raw_ostream &OS);
107+
108+
void registerPartial(std::string Name, std::string Partial);
109+
110+
void registerLambda(std::string Name, Lambda Lambda);
111+
112+
void registerLambda(std::string Name, SectionLambda Lambda);
113+
114+
// By default the Mustache Spec Specifies that HTML special characters
115+
// should be escaped. This function allows the user to specify which
116+
// characters should be escaped.
117+
void overrideEscapeCharacters(DenseMap<char, std::string> Escapes);
118+
119+
private:
120+
StringMap<AstPtr> Partials;
121+
StringMap<Lambda> Lambdas;
122+
StringMap<SectionLambda> SectionLambdas;
123+
DenseMap<char, std::string> Escapes;
124+
AstPtr Tree;
125+
};
126+
} // namespace llvm::mustache
127+
128+
#endif // LLVM_SUPPORT_MUSTACHE

llvm/lib/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ add_llvm_component_library(LLVMSupport
220220
MD5.cpp
221221
MSP430Attributes.cpp
222222
MSP430AttributeParser.cpp
223+
Mustache.cpp
223224
NativeFormatting.cpp
224225
OptimizedStructLayout.cpp
225226
Optional.cpp

0 commit comments

Comments
 (0)