xref: /freebsd/contrib/llvm-project/llvm/lib/Support/Mustache.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===-- Mustache.cpp ------------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric #include "llvm/Support/Mustache.h"
9*700637cbSDimitry Andric #include "llvm/ADT/SmallVector.h"
10*700637cbSDimitry Andric #include "llvm/Support/raw_ostream.h"
11*700637cbSDimitry Andric #include <sstream>
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric using namespace llvm;
14*700637cbSDimitry Andric using namespace llvm::mustache;
15*700637cbSDimitry Andric 
16*700637cbSDimitry Andric namespace {
17*700637cbSDimitry Andric 
18*700637cbSDimitry Andric using Accessor = SmallVector<std::string>;
19*700637cbSDimitry Andric 
isFalsey(const json::Value & V)20*700637cbSDimitry Andric static bool isFalsey(const json::Value &V) {
21*700637cbSDimitry Andric   return V.getAsNull() || (V.getAsBoolean() && !V.getAsBoolean().value()) ||
22*700637cbSDimitry Andric          (V.getAsArray() && V.getAsArray()->empty());
23*700637cbSDimitry Andric }
24*700637cbSDimitry Andric 
isContextFalsey(const json::Value * V)25*700637cbSDimitry Andric static bool isContextFalsey(const json::Value *V) {
26*700637cbSDimitry Andric   // A missing context (represented by a nullptr) is defined as falsey.
27*700637cbSDimitry Andric   if (!V)
28*700637cbSDimitry Andric     return true;
29*700637cbSDimitry Andric   return isFalsey(*V);
30*700637cbSDimitry Andric }
31*700637cbSDimitry Andric 
splitMustacheString(StringRef Str)32*700637cbSDimitry Andric static Accessor splitMustacheString(StringRef Str) {
33*700637cbSDimitry Andric   // We split the mustache string into an accessor.
34*700637cbSDimitry Andric   // For example:
35*700637cbSDimitry Andric   //    "a.b.c" would be split into {"a", "b", "c"}
36*700637cbSDimitry Andric   // We make an exception for a single dot which
37*700637cbSDimitry Andric   // refers to the current context.
38*700637cbSDimitry Andric   Accessor Tokens;
39*700637cbSDimitry Andric   if (Str == ".") {
40*700637cbSDimitry Andric     Tokens.emplace_back(Str);
41*700637cbSDimitry Andric     return Tokens;
42*700637cbSDimitry Andric   }
43*700637cbSDimitry Andric   while (!Str.empty()) {
44*700637cbSDimitry Andric     StringRef Part;
45*700637cbSDimitry Andric     std::tie(Part, Str) = Str.split(".");
46*700637cbSDimitry Andric     Tokens.emplace_back(Part.trim());
47*700637cbSDimitry Andric   }
48*700637cbSDimitry Andric   return Tokens;
49*700637cbSDimitry Andric }
50*700637cbSDimitry Andric } // namespace
51*700637cbSDimitry Andric 
52*700637cbSDimitry Andric namespace llvm::mustache {
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric class Token {
55*700637cbSDimitry Andric public:
56*700637cbSDimitry Andric   enum class Type {
57*700637cbSDimitry Andric     Text,
58*700637cbSDimitry Andric     Variable,
59*700637cbSDimitry Andric     Partial,
60*700637cbSDimitry Andric     SectionOpen,
61*700637cbSDimitry Andric     SectionClose,
62*700637cbSDimitry Andric     InvertSectionOpen,
63*700637cbSDimitry Andric     UnescapeVariable,
64*700637cbSDimitry Andric     Comment,
65*700637cbSDimitry Andric   };
66*700637cbSDimitry Andric 
Token(std::string Str)67*700637cbSDimitry Andric   Token(std::string Str)
68*700637cbSDimitry Andric       : TokenType(Type::Text), RawBody(std::move(Str)), TokenBody(RawBody),
69*700637cbSDimitry Andric         AccessorValue({}), Indentation(0) {};
70*700637cbSDimitry Andric 
Token(std::string RawBody,std::string TokenBody,char Identifier)71*700637cbSDimitry Andric   Token(std::string RawBody, std::string TokenBody, char Identifier)
72*700637cbSDimitry Andric       : RawBody(std::move(RawBody)), TokenBody(std::move(TokenBody)),
73*700637cbSDimitry Andric         Indentation(0) {
74*700637cbSDimitry Andric     TokenType = getTokenType(Identifier);
75*700637cbSDimitry Andric     if (TokenType == Type::Comment)
76*700637cbSDimitry Andric       return;
77*700637cbSDimitry Andric     StringRef AccessorStr(this->TokenBody);
78*700637cbSDimitry Andric     if (TokenType != Type::Variable)
79*700637cbSDimitry Andric       AccessorStr = AccessorStr.substr(1);
80*700637cbSDimitry Andric     AccessorValue = splitMustacheString(StringRef(AccessorStr).trim());
81*700637cbSDimitry Andric   }
82*700637cbSDimitry Andric 
getAccessor() const83*700637cbSDimitry Andric   Accessor getAccessor() const { return AccessorValue; }
84*700637cbSDimitry Andric 
getType() const85*700637cbSDimitry Andric   Type getType() const { return TokenType; }
86*700637cbSDimitry Andric 
setIndentation(size_t NewIndentation)87*700637cbSDimitry Andric   void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; }
88*700637cbSDimitry Andric 
getIndentation() const89*700637cbSDimitry Andric   size_t getIndentation() const { return Indentation; }
90*700637cbSDimitry Andric 
getTokenType(char Identifier)91*700637cbSDimitry Andric   static Type getTokenType(char Identifier) {
92*700637cbSDimitry Andric     switch (Identifier) {
93*700637cbSDimitry Andric     case '#':
94*700637cbSDimitry Andric       return Type::SectionOpen;
95*700637cbSDimitry Andric     case '/':
96*700637cbSDimitry Andric       return Type::SectionClose;
97*700637cbSDimitry Andric     case '^':
98*700637cbSDimitry Andric       return Type::InvertSectionOpen;
99*700637cbSDimitry Andric     case '!':
100*700637cbSDimitry Andric       return Type::Comment;
101*700637cbSDimitry Andric     case '>':
102*700637cbSDimitry Andric       return Type::Partial;
103*700637cbSDimitry Andric     case '&':
104*700637cbSDimitry Andric       return Type::UnescapeVariable;
105*700637cbSDimitry Andric     default:
106*700637cbSDimitry Andric       return Type::Variable;
107*700637cbSDimitry Andric     }
108*700637cbSDimitry Andric   }
109*700637cbSDimitry Andric 
110*700637cbSDimitry Andric   Type TokenType;
111*700637cbSDimitry Andric   // RawBody is the original string that was tokenized.
112*700637cbSDimitry Andric   std::string RawBody;
113*700637cbSDimitry Andric   // TokenBody is the original string with the identifier removed.
114*700637cbSDimitry Andric   std::string TokenBody;
115*700637cbSDimitry Andric   Accessor AccessorValue;
116*700637cbSDimitry Andric   size_t Indentation;
117*700637cbSDimitry Andric };
118*700637cbSDimitry Andric 
119*700637cbSDimitry Andric using EscapeMap = DenseMap<char, std::string>;
120*700637cbSDimitry Andric 
121*700637cbSDimitry Andric class ASTNode {
122*700637cbSDimitry Andric public:
123*700637cbSDimitry Andric   enum Type {
124*700637cbSDimitry Andric     Root,
125*700637cbSDimitry Andric     Text,
126*700637cbSDimitry Andric     Partial,
127*700637cbSDimitry Andric     Variable,
128*700637cbSDimitry Andric     UnescapeVariable,
129*700637cbSDimitry Andric     Section,
130*700637cbSDimitry Andric     InvertSection,
131*700637cbSDimitry Andric   };
132*700637cbSDimitry Andric 
ASTNode(llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)133*700637cbSDimitry Andric   ASTNode(llvm::StringMap<AstPtr> &Partials, llvm::StringMap<Lambda> &Lambdas,
134*700637cbSDimitry Andric           llvm::StringMap<SectionLambda> &SectionLambdas, EscapeMap &Escapes)
135*700637cbSDimitry Andric       : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
136*700637cbSDimitry Andric         Escapes(Escapes), Ty(Type::Root), Parent(nullptr),
137*700637cbSDimitry Andric         ParentContext(nullptr) {}
138*700637cbSDimitry Andric 
ASTNode(std::string Body,ASTNode * Parent,llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)139*700637cbSDimitry Andric   ASTNode(std::string Body, ASTNode *Parent, llvm::StringMap<AstPtr> &Partials,
140*700637cbSDimitry Andric           llvm::StringMap<Lambda> &Lambdas,
141*700637cbSDimitry Andric           llvm::StringMap<SectionLambda> &SectionLambdas, EscapeMap &Escapes)
142*700637cbSDimitry Andric       : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
143*700637cbSDimitry Andric         Escapes(Escapes), Ty(Type::Text), Body(std::move(Body)), Parent(Parent),
144*700637cbSDimitry Andric         ParentContext(nullptr) {}
145*700637cbSDimitry Andric 
146*700637cbSDimitry Andric   // Constructor for Section/InvertSection/Variable/UnescapeVariable Nodes
ASTNode(Type Ty,Accessor Accessor,ASTNode * Parent,llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)147*700637cbSDimitry Andric   ASTNode(Type Ty, Accessor Accessor, ASTNode *Parent,
148*700637cbSDimitry Andric           llvm::StringMap<AstPtr> &Partials, llvm::StringMap<Lambda> &Lambdas,
149*700637cbSDimitry Andric           llvm::StringMap<SectionLambda> &SectionLambdas, EscapeMap &Escapes)
150*700637cbSDimitry Andric       : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
151*700637cbSDimitry Andric         Escapes(Escapes), Ty(Ty), Parent(Parent),
152*700637cbSDimitry Andric         AccessorValue(std::move(Accessor)), ParentContext(nullptr) {}
153*700637cbSDimitry Andric 
addChild(AstPtr Child)154*700637cbSDimitry Andric   void addChild(AstPtr Child) { Children.emplace_back(std::move(Child)); };
155*700637cbSDimitry Andric 
setRawBody(std::string NewBody)156*700637cbSDimitry Andric   void setRawBody(std::string NewBody) { RawBody = std::move(NewBody); };
157*700637cbSDimitry Andric 
setIndentation(size_t NewIndentation)158*700637cbSDimitry Andric   void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
159*700637cbSDimitry Andric 
160*700637cbSDimitry Andric   void render(const llvm::json::Value &Data, llvm::raw_ostream &OS);
161*700637cbSDimitry Andric 
162*700637cbSDimitry Andric private:
163*700637cbSDimitry Andric   void renderLambdas(const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
164*700637cbSDimitry Andric                      Lambda &L);
165*700637cbSDimitry Andric 
166*700637cbSDimitry Andric   void renderSectionLambdas(const llvm::json::Value &Contexts,
167*700637cbSDimitry Andric                             llvm::raw_ostream &OS, SectionLambda &L);
168*700637cbSDimitry Andric 
169*700637cbSDimitry Andric   void renderPartial(const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
170*700637cbSDimitry Andric                      ASTNode *Partial);
171*700637cbSDimitry Andric 
172*700637cbSDimitry Andric   void renderChild(const llvm::json::Value &Context, llvm::raw_ostream &OS);
173*700637cbSDimitry Andric 
174*700637cbSDimitry Andric   const llvm::json::Value *findContext();
175*700637cbSDimitry Andric 
176*700637cbSDimitry Andric   StringMap<AstPtr> &Partials;
177*700637cbSDimitry Andric   StringMap<Lambda> &Lambdas;
178*700637cbSDimitry Andric   StringMap<SectionLambda> &SectionLambdas;
179*700637cbSDimitry Andric   EscapeMap &Escapes;
180*700637cbSDimitry Andric   Type Ty;
181*700637cbSDimitry Andric   size_t Indentation = 0;
182*700637cbSDimitry Andric   std::string RawBody;
183*700637cbSDimitry Andric   std::string Body;
184*700637cbSDimitry Andric   ASTNode *Parent;
185*700637cbSDimitry Andric   // TODO: switch implementation to SmallVector<T>
186*700637cbSDimitry Andric   std::vector<AstPtr> Children;
187*700637cbSDimitry Andric   const Accessor AccessorValue;
188*700637cbSDimitry Andric   const llvm::json::Value *ParentContext;
189*700637cbSDimitry Andric };
190*700637cbSDimitry Andric 
191*700637cbSDimitry Andric // A wrapper for arena allocator for ASTNodes
createRootNode(llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)192*700637cbSDimitry Andric AstPtr createRootNode(llvm::StringMap<AstPtr> &Partials,
193*700637cbSDimitry Andric                       llvm::StringMap<Lambda> &Lambdas,
194*700637cbSDimitry Andric                       llvm::StringMap<SectionLambda> &SectionLambdas,
195*700637cbSDimitry Andric                       EscapeMap &Escapes) {
196*700637cbSDimitry Andric   return std::make_unique<ASTNode>(Partials, Lambdas, SectionLambdas, Escapes);
197*700637cbSDimitry Andric }
198*700637cbSDimitry Andric 
createNode(ASTNode::Type T,Accessor A,ASTNode * Parent,llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)199*700637cbSDimitry Andric AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
200*700637cbSDimitry Andric                   llvm::StringMap<AstPtr> &Partials,
201*700637cbSDimitry Andric                   llvm::StringMap<Lambda> &Lambdas,
202*700637cbSDimitry Andric                   llvm::StringMap<SectionLambda> &SectionLambdas,
203*700637cbSDimitry Andric                   EscapeMap &Escapes) {
204*700637cbSDimitry Andric   return std::make_unique<ASTNode>(T, std::move(A), Parent, Partials, Lambdas,
205*700637cbSDimitry Andric                                    SectionLambdas, Escapes);
206*700637cbSDimitry Andric }
207*700637cbSDimitry Andric 
createTextNode(std::string Body,ASTNode * Parent,llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)208*700637cbSDimitry Andric AstPtr createTextNode(std::string Body, ASTNode *Parent,
209*700637cbSDimitry Andric                       llvm::StringMap<AstPtr> &Partials,
210*700637cbSDimitry Andric                       llvm::StringMap<Lambda> &Lambdas,
211*700637cbSDimitry Andric                       llvm::StringMap<SectionLambda> &SectionLambdas,
212*700637cbSDimitry Andric                       EscapeMap &Escapes) {
213*700637cbSDimitry Andric   return std::make_unique<ASTNode>(std::move(Body), Parent, Partials, Lambdas,
214*700637cbSDimitry Andric                                    SectionLambdas, Escapes);
215*700637cbSDimitry Andric }
216*700637cbSDimitry Andric 
217*700637cbSDimitry Andric // Function to check if there is meaningful text behind.
218*700637cbSDimitry Andric // We determine if a token has meaningful text behind
219*700637cbSDimitry Andric // if the right of previous token contains anything that is
220*700637cbSDimitry Andric // not a newline.
221*700637cbSDimitry Andric // For example:
222*700637cbSDimitry Andric //  "Stuff {{#Section}}" (returns true)
223*700637cbSDimitry Andric //   vs
224*700637cbSDimitry Andric //  "{{#Section}} \n" (returns false)
225*700637cbSDimitry Andric // We make an exception for when previous token is empty
226*700637cbSDimitry Andric // and the current token is the second token.
227*700637cbSDimitry Andric // For example:
228*700637cbSDimitry Andric //  "{{#Section}}"
hasTextBehind(size_t Idx,const ArrayRef<Token> & Tokens)229*700637cbSDimitry Andric bool hasTextBehind(size_t Idx, const ArrayRef<Token> &Tokens) {
230*700637cbSDimitry Andric   if (Idx == 0)
231*700637cbSDimitry Andric     return true;
232*700637cbSDimitry Andric 
233*700637cbSDimitry Andric   size_t PrevIdx = Idx - 1;
234*700637cbSDimitry Andric   if (Tokens[PrevIdx].getType() != Token::Type::Text)
235*700637cbSDimitry Andric     return true;
236*700637cbSDimitry Andric 
237*700637cbSDimitry Andric   const Token &PrevToken = Tokens[PrevIdx];
238*700637cbSDimitry Andric   StringRef TokenBody = StringRef(PrevToken.RawBody).rtrim(" \r\t\v");
239*700637cbSDimitry Andric   return !TokenBody.ends_with("\n") && !(TokenBody.empty() && Idx == 1);
240*700637cbSDimitry Andric }
241*700637cbSDimitry Andric 
242*700637cbSDimitry Andric // Function to check if there's no meaningful text ahead.
243*700637cbSDimitry Andric // We determine if a token has text ahead if the left of previous
244*700637cbSDimitry Andric // token does not start with a newline.
hasTextAhead(size_t Idx,const ArrayRef<Token> & Tokens)245*700637cbSDimitry Andric bool hasTextAhead(size_t Idx, const ArrayRef<Token> &Tokens) {
246*700637cbSDimitry Andric   if (Idx >= Tokens.size() - 1)
247*700637cbSDimitry Andric     return true;
248*700637cbSDimitry Andric 
249*700637cbSDimitry Andric   size_t NextIdx = Idx + 1;
250*700637cbSDimitry Andric   if (Tokens[NextIdx].getType() != Token::Type::Text)
251*700637cbSDimitry Andric     return true;
252*700637cbSDimitry Andric 
253*700637cbSDimitry Andric   const Token &NextToken = Tokens[NextIdx];
254*700637cbSDimitry Andric   StringRef TokenBody = StringRef(NextToken.RawBody).ltrim(" ");
255*700637cbSDimitry Andric   return !TokenBody.starts_with("\r\n") && !TokenBody.starts_with("\n");
256*700637cbSDimitry Andric }
257*700637cbSDimitry Andric 
requiresCleanUp(Token::Type T)258*700637cbSDimitry Andric bool requiresCleanUp(Token::Type T) {
259*700637cbSDimitry Andric   // We must clean up all the tokens that could contain child nodes.
260*700637cbSDimitry Andric   return T == Token::Type::SectionOpen || T == Token::Type::InvertSectionOpen ||
261*700637cbSDimitry Andric          T == Token::Type::SectionClose || T == Token::Type::Comment ||
262*700637cbSDimitry Andric          T == Token::Type::Partial;
263*700637cbSDimitry Andric }
264*700637cbSDimitry Andric 
265*700637cbSDimitry Andric // Adjust next token body if there is no text ahead.
266*700637cbSDimitry Andric // For example:
267*700637cbSDimitry Andric // The template string
268*700637cbSDimitry Andric //  "{{! Comment }} \nLine 2"
269*700637cbSDimitry Andric // would be considered as no text ahead and should be rendered as
270*700637cbSDimitry Andric //  " Line 2"
stripTokenAhead(SmallVectorImpl<Token> & Tokens,size_t Idx)271*700637cbSDimitry Andric void stripTokenAhead(SmallVectorImpl<Token> &Tokens, size_t Idx) {
272*700637cbSDimitry Andric   Token &NextToken = Tokens[Idx + 1];
273*700637cbSDimitry Andric   StringRef NextTokenBody = NextToken.TokenBody;
274*700637cbSDimitry Andric   // Cut off the leading newline which could be \n or \r\n.
275*700637cbSDimitry Andric   if (NextTokenBody.starts_with("\r\n"))
276*700637cbSDimitry Andric     NextToken.TokenBody = NextTokenBody.substr(2).str();
277*700637cbSDimitry Andric   else if (NextTokenBody.starts_with("\n"))
278*700637cbSDimitry Andric     NextToken.TokenBody = NextTokenBody.substr(1).str();
279*700637cbSDimitry Andric }
280*700637cbSDimitry Andric 
281*700637cbSDimitry Andric // Adjust previous token body if there no text behind.
282*700637cbSDimitry Andric // For example:
283*700637cbSDimitry Andric //  The template string
284*700637cbSDimitry Andric //  " \t{{#section}}A{{/section}}"
285*700637cbSDimitry Andric // would be considered as having no text ahead and would be render as
286*700637cbSDimitry Andric //  "A"
287*700637cbSDimitry Andric // The exception for this is partial tag which requires us to
288*700637cbSDimitry Andric // keep track of the indentation once it's rendered.
stripTokenBefore(SmallVectorImpl<Token> & Tokens,size_t Idx,Token & CurrentToken,Token::Type CurrentType)289*700637cbSDimitry Andric void stripTokenBefore(SmallVectorImpl<Token> &Tokens, size_t Idx,
290*700637cbSDimitry Andric                       Token &CurrentToken, Token::Type CurrentType) {
291*700637cbSDimitry Andric   Token &PrevToken = Tokens[Idx - 1];
292*700637cbSDimitry Andric   StringRef PrevTokenBody = PrevToken.TokenBody;
293*700637cbSDimitry Andric   StringRef Unindented = PrevTokenBody.rtrim(" \r\t\v");
294*700637cbSDimitry Andric   size_t Indentation = PrevTokenBody.size() - Unindented.size();
295*700637cbSDimitry Andric   if (CurrentType != Token::Type::Partial)
296*700637cbSDimitry Andric     PrevToken.TokenBody = Unindented.str();
297*700637cbSDimitry Andric   CurrentToken.setIndentation(Indentation);
298*700637cbSDimitry Andric }
299*700637cbSDimitry Andric 
300*700637cbSDimitry Andric // Simple tokenizer that splits the template into tokens.
301*700637cbSDimitry Andric // The mustache spec allows {{{ }}} to unescape variables,
302*700637cbSDimitry Andric // but we don't support that here. An unescape variable
303*700637cbSDimitry Andric // is represented only by {{& variable}}.
tokenize(StringRef Template)304*700637cbSDimitry Andric SmallVector<Token> tokenize(StringRef Template) {
305*700637cbSDimitry Andric   SmallVector<Token> Tokens;
306*700637cbSDimitry Andric   StringLiteral Open("{{");
307*700637cbSDimitry Andric   StringLiteral Close("}}");
308*700637cbSDimitry Andric   size_t Start = 0;
309*700637cbSDimitry Andric   size_t DelimiterStart = Template.find(Open);
310*700637cbSDimitry Andric   if (DelimiterStart == StringRef::npos) {
311*700637cbSDimitry Andric     Tokens.emplace_back(Template.str());
312*700637cbSDimitry Andric     return Tokens;
313*700637cbSDimitry Andric   }
314*700637cbSDimitry Andric   while (DelimiterStart != StringRef::npos) {
315*700637cbSDimitry Andric     if (DelimiterStart != Start)
316*700637cbSDimitry Andric       Tokens.emplace_back(Template.substr(Start, DelimiterStart - Start).str());
317*700637cbSDimitry Andric     size_t DelimiterEnd = Template.find(Close, DelimiterStart);
318*700637cbSDimitry Andric     if (DelimiterEnd == StringRef::npos)
319*700637cbSDimitry Andric       break;
320*700637cbSDimitry Andric 
321*700637cbSDimitry Andric     // Extract the Interpolated variable without delimiters.
322*700637cbSDimitry Andric     size_t InterpolatedStart = DelimiterStart + Open.size();
323*700637cbSDimitry Andric     size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.size();
324*700637cbSDimitry Andric     std::string Interpolated =
325*700637cbSDimitry Andric         Template.substr(InterpolatedStart, InterpolatedEnd).str();
326*700637cbSDimitry Andric     std::string RawBody = Open.str() + Interpolated + Close.str();
327*700637cbSDimitry Andric     Tokens.emplace_back(RawBody, Interpolated, Interpolated[0]);
328*700637cbSDimitry Andric     Start = DelimiterEnd + Close.size();
329*700637cbSDimitry Andric     DelimiterStart = Template.find(Open, Start);
330*700637cbSDimitry Andric   }
331*700637cbSDimitry Andric 
332*700637cbSDimitry Andric   if (Start < Template.size())
333*700637cbSDimitry Andric     Tokens.emplace_back(Template.substr(Start).str());
334*700637cbSDimitry Andric 
335*700637cbSDimitry Andric   // Fix up white spaces for:
336*700637cbSDimitry Andric   //   - open sections
337*700637cbSDimitry Andric   //   - inverted sections
338*700637cbSDimitry Andric   //   - close sections
339*700637cbSDimitry Andric   //   - comments
340*700637cbSDimitry Andric   //
341*700637cbSDimitry Andric   // This loop attempts to find standalone tokens and tries to trim out
342*700637cbSDimitry Andric   // the surrounding whitespace.
343*700637cbSDimitry Andric   // For example:
344*700637cbSDimitry Andric   // if you have the template string
345*700637cbSDimitry Andric   //  {{#section}} \n Example \n{{/section}}
346*700637cbSDimitry Andric   // The output should would be
347*700637cbSDimitry Andric   // For example:
348*700637cbSDimitry Andric   //  \n Example \n
349*700637cbSDimitry Andric   size_t LastIdx = Tokens.size() - 1;
350*700637cbSDimitry Andric   for (size_t Idx = 0, End = Tokens.size(); Idx < End; ++Idx) {
351*700637cbSDimitry Andric     Token &CurrentToken = Tokens[Idx];
352*700637cbSDimitry Andric     Token::Type CurrentType = CurrentToken.getType();
353*700637cbSDimitry Andric     // Check if token type requires cleanup.
354*700637cbSDimitry Andric     bool RequiresCleanUp = requiresCleanUp(CurrentType);
355*700637cbSDimitry Andric 
356*700637cbSDimitry Andric     if (!RequiresCleanUp)
357*700637cbSDimitry Andric       continue;
358*700637cbSDimitry Andric 
359*700637cbSDimitry Andric     // We adjust the token body if there's no text behind or ahead.
360*700637cbSDimitry Andric     // A token is considered to have no text ahead if the right of the previous
361*700637cbSDimitry Andric     // token is a newline followed by spaces.
362*700637cbSDimitry Andric     // A token is considered to have no text behind if the left of the next
363*700637cbSDimitry Andric     // token is spaces followed by a newline.
364*700637cbSDimitry Andric     // eg.
365*700637cbSDimitry Andric     //  "Line 1\n {{#section}} \n Line 2 \n {{/section}} \n Line 3"
366*700637cbSDimitry Andric     bool HasTextBehind = hasTextBehind(Idx, Tokens);
367*700637cbSDimitry Andric     bool HasTextAhead = hasTextAhead(Idx, Tokens);
368*700637cbSDimitry Andric 
369*700637cbSDimitry Andric     if ((!HasTextAhead && !HasTextBehind) || (!HasTextAhead && Idx == 0))
370*700637cbSDimitry Andric       stripTokenAhead(Tokens, Idx);
371*700637cbSDimitry Andric 
372*700637cbSDimitry Andric     if ((!HasTextBehind && !HasTextAhead) || (!HasTextBehind && Idx == LastIdx))
373*700637cbSDimitry Andric       stripTokenBefore(Tokens, Idx, CurrentToken, CurrentType);
374*700637cbSDimitry Andric   }
375*700637cbSDimitry Andric   return Tokens;
376*700637cbSDimitry Andric }
377*700637cbSDimitry Andric 
378*700637cbSDimitry Andric // Custom stream to escape strings.
379*700637cbSDimitry Andric class EscapeStringStream : public raw_ostream {
380*700637cbSDimitry Andric public:
EscapeStringStream(llvm::raw_ostream & WrappedStream,EscapeMap & Escape)381*700637cbSDimitry Andric   explicit EscapeStringStream(llvm::raw_ostream &WrappedStream,
382*700637cbSDimitry Andric                               EscapeMap &Escape)
383*700637cbSDimitry Andric       : Escape(Escape), WrappedStream(WrappedStream) {
384*700637cbSDimitry Andric     SetUnbuffered();
385*700637cbSDimitry Andric   }
386*700637cbSDimitry Andric 
387*700637cbSDimitry Andric protected:
write_impl(const char * Ptr,size_t Size)388*700637cbSDimitry Andric   void write_impl(const char *Ptr, size_t Size) override {
389*700637cbSDimitry Andric     llvm::StringRef Data(Ptr, Size);
390*700637cbSDimitry Andric     for (char C : Data) {
391*700637cbSDimitry Andric       auto It = Escape.find(C);
392*700637cbSDimitry Andric       if (It != Escape.end())
393*700637cbSDimitry Andric         WrappedStream << It->getSecond();
394*700637cbSDimitry Andric       else
395*700637cbSDimitry Andric         WrappedStream << C;
396*700637cbSDimitry Andric     }
397*700637cbSDimitry Andric   }
398*700637cbSDimitry Andric 
current_pos() const399*700637cbSDimitry Andric   uint64_t current_pos() const override { return WrappedStream.tell(); }
400*700637cbSDimitry Andric 
401*700637cbSDimitry Andric private:
402*700637cbSDimitry Andric   EscapeMap &Escape;
403*700637cbSDimitry Andric   llvm::raw_ostream &WrappedStream;
404*700637cbSDimitry Andric };
405*700637cbSDimitry Andric 
406*700637cbSDimitry Andric // Custom stream to add indentation used to for rendering partials.
407*700637cbSDimitry Andric class AddIndentationStringStream : public raw_ostream {
408*700637cbSDimitry Andric public:
AddIndentationStringStream(llvm::raw_ostream & WrappedStream,size_t Indentation)409*700637cbSDimitry Andric   explicit AddIndentationStringStream(llvm::raw_ostream &WrappedStream,
410*700637cbSDimitry Andric                                       size_t Indentation)
411*700637cbSDimitry Andric       : Indentation(Indentation), WrappedStream(WrappedStream) {
412*700637cbSDimitry Andric     SetUnbuffered();
413*700637cbSDimitry Andric   }
414*700637cbSDimitry Andric 
415*700637cbSDimitry Andric protected:
write_impl(const char * Ptr,size_t Size)416*700637cbSDimitry Andric   void write_impl(const char *Ptr, size_t Size) override {
417*700637cbSDimitry Andric     llvm::StringRef Data(Ptr, Size);
418*700637cbSDimitry Andric     SmallString<0> Indent;
419*700637cbSDimitry Andric     Indent.resize(Indentation, ' ');
420*700637cbSDimitry Andric     for (char C : Data) {
421*700637cbSDimitry Andric       WrappedStream << C;
422*700637cbSDimitry Andric       if (C == '\n')
423*700637cbSDimitry Andric         WrappedStream << Indent;
424*700637cbSDimitry Andric     }
425*700637cbSDimitry Andric   }
426*700637cbSDimitry Andric 
current_pos() const427*700637cbSDimitry Andric   uint64_t current_pos() const override { return WrappedStream.tell(); }
428*700637cbSDimitry Andric 
429*700637cbSDimitry Andric private:
430*700637cbSDimitry Andric   size_t Indentation;
431*700637cbSDimitry Andric   llvm::raw_ostream &WrappedStream;
432*700637cbSDimitry Andric };
433*700637cbSDimitry Andric 
434*700637cbSDimitry Andric class Parser {
435*700637cbSDimitry Andric public:
Parser(StringRef TemplateStr)436*700637cbSDimitry Andric   Parser(StringRef TemplateStr) : TemplateStr(TemplateStr) {}
437*700637cbSDimitry Andric 
438*700637cbSDimitry Andric   AstPtr parse(llvm::StringMap<AstPtr> &Partials,
439*700637cbSDimitry Andric                llvm::StringMap<Lambda> &Lambdas,
440*700637cbSDimitry Andric                llvm::StringMap<SectionLambda> &SectionLambdas,
441*700637cbSDimitry Andric                EscapeMap &Escapes);
442*700637cbSDimitry Andric 
443*700637cbSDimitry Andric private:
444*700637cbSDimitry Andric   void parseMustache(ASTNode *Parent, llvm::StringMap<AstPtr> &Partials,
445*700637cbSDimitry Andric                      llvm::StringMap<Lambda> &Lambdas,
446*700637cbSDimitry Andric                      llvm::StringMap<SectionLambda> &SectionLambdas,
447*700637cbSDimitry Andric                      EscapeMap &Escapes);
448*700637cbSDimitry Andric 
449*700637cbSDimitry Andric   SmallVector<Token> Tokens;
450*700637cbSDimitry Andric   size_t CurrentPtr;
451*700637cbSDimitry Andric   StringRef TemplateStr;
452*700637cbSDimitry Andric };
453*700637cbSDimitry Andric 
parse(llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)454*700637cbSDimitry Andric AstPtr Parser::parse(llvm::StringMap<AstPtr> &Partials,
455*700637cbSDimitry Andric                      llvm::StringMap<Lambda> &Lambdas,
456*700637cbSDimitry Andric                      llvm::StringMap<SectionLambda> &SectionLambdas,
457*700637cbSDimitry Andric                      EscapeMap &Escapes) {
458*700637cbSDimitry Andric   Tokens = tokenize(TemplateStr);
459*700637cbSDimitry Andric   CurrentPtr = 0;
460*700637cbSDimitry Andric   AstPtr RootNode = createRootNode(Partials, Lambdas, SectionLambdas, Escapes);
461*700637cbSDimitry Andric   parseMustache(RootNode.get(), Partials, Lambdas, SectionLambdas, Escapes);
462*700637cbSDimitry Andric   return RootNode;
463*700637cbSDimitry Andric }
464*700637cbSDimitry Andric 
parseMustache(ASTNode * Parent,llvm::StringMap<AstPtr> & Partials,llvm::StringMap<Lambda> & Lambdas,llvm::StringMap<SectionLambda> & SectionLambdas,EscapeMap & Escapes)465*700637cbSDimitry Andric void Parser::parseMustache(ASTNode *Parent, llvm::StringMap<AstPtr> &Partials,
466*700637cbSDimitry Andric                            llvm::StringMap<Lambda> &Lambdas,
467*700637cbSDimitry Andric                            llvm::StringMap<SectionLambda> &SectionLambdas,
468*700637cbSDimitry Andric                            EscapeMap &Escapes) {
469*700637cbSDimitry Andric 
470*700637cbSDimitry Andric   while (CurrentPtr < Tokens.size()) {
471*700637cbSDimitry Andric     Token CurrentToken = Tokens[CurrentPtr];
472*700637cbSDimitry Andric     CurrentPtr++;
473*700637cbSDimitry Andric     Accessor A = CurrentToken.getAccessor();
474*700637cbSDimitry Andric     AstPtr CurrentNode;
475*700637cbSDimitry Andric 
476*700637cbSDimitry Andric     switch (CurrentToken.getType()) {
477*700637cbSDimitry Andric     case Token::Type::Text: {
478*700637cbSDimitry Andric       CurrentNode = createTextNode(std::move(CurrentToken.TokenBody), Parent,
479*700637cbSDimitry Andric                                    Partials, Lambdas, SectionLambdas, Escapes);
480*700637cbSDimitry Andric       Parent->addChild(std::move(CurrentNode));
481*700637cbSDimitry Andric       break;
482*700637cbSDimitry Andric     }
483*700637cbSDimitry Andric     case Token::Type::Variable: {
484*700637cbSDimitry Andric       CurrentNode = createNode(ASTNode::Variable, std::move(A), Parent,
485*700637cbSDimitry Andric                                Partials, Lambdas, SectionLambdas, Escapes);
486*700637cbSDimitry Andric       Parent->addChild(std::move(CurrentNode));
487*700637cbSDimitry Andric       break;
488*700637cbSDimitry Andric     }
489*700637cbSDimitry Andric     case Token::Type::UnescapeVariable: {
490*700637cbSDimitry Andric       CurrentNode = createNode(ASTNode::UnescapeVariable, std::move(A), Parent,
491*700637cbSDimitry Andric                                Partials, Lambdas, SectionLambdas, Escapes);
492*700637cbSDimitry Andric       Parent->addChild(std::move(CurrentNode));
493*700637cbSDimitry Andric       break;
494*700637cbSDimitry Andric     }
495*700637cbSDimitry Andric     case Token::Type::Partial: {
496*700637cbSDimitry Andric       CurrentNode = createNode(ASTNode::Partial, std::move(A), Parent, Partials,
497*700637cbSDimitry Andric                                Lambdas, SectionLambdas, Escapes);
498*700637cbSDimitry Andric       CurrentNode->setIndentation(CurrentToken.getIndentation());
499*700637cbSDimitry Andric       Parent->addChild(std::move(CurrentNode));
500*700637cbSDimitry Andric       break;
501*700637cbSDimitry Andric     }
502*700637cbSDimitry Andric     case Token::Type::SectionOpen: {
503*700637cbSDimitry Andric       CurrentNode = createNode(ASTNode::Section, A, Parent, Partials, Lambdas,
504*700637cbSDimitry Andric                                SectionLambdas, Escapes);
505*700637cbSDimitry Andric       size_t Start = CurrentPtr;
506*700637cbSDimitry Andric       parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
507*700637cbSDimitry Andric                     Escapes);
508*700637cbSDimitry Andric       const size_t End = CurrentPtr - 1;
509*700637cbSDimitry Andric       std::string RawBody;
510*700637cbSDimitry Andric       for (std::size_t I = Start; I < End; I++)
511*700637cbSDimitry Andric         RawBody += Tokens[I].RawBody;
512*700637cbSDimitry Andric       CurrentNode->setRawBody(std::move(RawBody));
513*700637cbSDimitry Andric       Parent->addChild(std::move(CurrentNode));
514*700637cbSDimitry Andric       break;
515*700637cbSDimitry Andric     }
516*700637cbSDimitry Andric     case Token::Type::InvertSectionOpen: {
517*700637cbSDimitry Andric       CurrentNode = createNode(ASTNode::InvertSection, A, Parent, Partials,
518*700637cbSDimitry Andric                                Lambdas, SectionLambdas, Escapes);
519*700637cbSDimitry Andric       size_t Start = CurrentPtr;
520*700637cbSDimitry Andric       parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
521*700637cbSDimitry Andric                     Escapes);
522*700637cbSDimitry Andric       const size_t End = CurrentPtr - 1;
523*700637cbSDimitry Andric       std::string RawBody;
524*700637cbSDimitry Andric       for (size_t Idx = Start; Idx < End; Idx++)
525*700637cbSDimitry Andric         RawBody += Tokens[Idx].RawBody;
526*700637cbSDimitry Andric       CurrentNode->setRawBody(std::move(RawBody));
527*700637cbSDimitry Andric       Parent->addChild(std::move(CurrentNode));
528*700637cbSDimitry Andric       break;
529*700637cbSDimitry Andric     }
530*700637cbSDimitry Andric     case Token::Type::Comment:
531*700637cbSDimitry Andric       break;
532*700637cbSDimitry Andric     case Token::Type::SectionClose:
533*700637cbSDimitry Andric       return;
534*700637cbSDimitry Andric     }
535*700637cbSDimitry Andric   }
536*700637cbSDimitry Andric }
toMustacheString(const json::Value & Data,raw_ostream & OS)537*700637cbSDimitry Andric void toMustacheString(const json::Value &Data, raw_ostream &OS) {
538*700637cbSDimitry Andric   switch (Data.kind()) {
539*700637cbSDimitry Andric   case json::Value::Null:
540*700637cbSDimitry Andric     return;
541*700637cbSDimitry Andric   case json::Value::Number: {
542*700637cbSDimitry Andric     auto Num = *Data.getAsNumber();
543*700637cbSDimitry Andric     std::ostringstream SS;
544*700637cbSDimitry Andric     SS << Num;
545*700637cbSDimitry Andric     OS << SS.str();
546*700637cbSDimitry Andric     return;
547*700637cbSDimitry Andric   }
548*700637cbSDimitry Andric   case json::Value::String: {
549*700637cbSDimitry Andric     auto Str = *Data.getAsString();
550*700637cbSDimitry Andric     OS << Str.str();
551*700637cbSDimitry Andric     return;
552*700637cbSDimitry Andric   }
553*700637cbSDimitry Andric 
554*700637cbSDimitry Andric   case json::Value::Array: {
555*700637cbSDimitry Andric     auto Arr = *Data.getAsArray();
556*700637cbSDimitry Andric     if (Arr.empty())
557*700637cbSDimitry Andric       return;
558*700637cbSDimitry Andric     [[fallthrough]];
559*700637cbSDimitry Andric   }
560*700637cbSDimitry Andric   case json::Value::Object:
561*700637cbSDimitry Andric   case json::Value::Boolean: {
562*700637cbSDimitry Andric     llvm::json::OStream JOS(OS, 2);
563*700637cbSDimitry Andric     JOS.value(Data);
564*700637cbSDimitry Andric     break;
565*700637cbSDimitry Andric   }
566*700637cbSDimitry Andric   }
567*700637cbSDimitry Andric }
568*700637cbSDimitry Andric 
render(const json::Value & CurrentCtx,raw_ostream & OS)569*700637cbSDimitry Andric void ASTNode::render(const json::Value &CurrentCtx, raw_ostream &OS) {
570*700637cbSDimitry Andric   // Set the parent context to the incoming context so that we
571*700637cbSDimitry Andric   // can walk up the context tree correctly in findContext().
572*700637cbSDimitry Andric   ParentContext = &CurrentCtx;
573*700637cbSDimitry Andric   const json::Value *ContextPtr = Ty == Root ? ParentContext : findContext();
574*700637cbSDimitry Andric 
575*700637cbSDimitry Andric   switch (Ty) {
576*700637cbSDimitry Andric   case Root:
577*700637cbSDimitry Andric     renderChild(CurrentCtx, OS);
578*700637cbSDimitry Andric     return;
579*700637cbSDimitry Andric   case Text:
580*700637cbSDimitry Andric     OS << Body;
581*700637cbSDimitry Andric     return;
582*700637cbSDimitry Andric   case Partial: {
583*700637cbSDimitry Andric     auto Partial = Partials.find(AccessorValue[0]);
584*700637cbSDimitry Andric     if (Partial != Partials.end())
585*700637cbSDimitry Andric       renderPartial(CurrentCtx, OS, Partial->getValue().get());
586*700637cbSDimitry Andric     return;
587*700637cbSDimitry Andric   }
588*700637cbSDimitry Andric   case Variable: {
589*700637cbSDimitry Andric     auto Lambda = Lambdas.find(AccessorValue[0]);
590*700637cbSDimitry Andric     if (Lambda != Lambdas.end()) {
591*700637cbSDimitry Andric       renderLambdas(CurrentCtx, OS, Lambda->getValue());
592*700637cbSDimitry Andric     } else if (ContextPtr) {
593*700637cbSDimitry Andric       EscapeStringStream ES(OS, Escapes);
594*700637cbSDimitry Andric       toMustacheString(*ContextPtr, ES);
595*700637cbSDimitry Andric     }
596*700637cbSDimitry Andric     return;
597*700637cbSDimitry Andric   }
598*700637cbSDimitry Andric   case UnescapeVariable: {
599*700637cbSDimitry Andric     auto Lambda = Lambdas.find(AccessorValue[0]);
600*700637cbSDimitry Andric     if (Lambda != Lambdas.end()) {
601*700637cbSDimitry Andric       renderLambdas(CurrentCtx, OS, Lambda->getValue());
602*700637cbSDimitry Andric     } else if (ContextPtr) {
603*700637cbSDimitry Andric       toMustacheString(*ContextPtr, OS);
604*700637cbSDimitry Andric     }
605*700637cbSDimitry Andric     return;
606*700637cbSDimitry Andric   }
607*700637cbSDimitry Andric   case Section: {
608*700637cbSDimitry Andric     auto SectionLambda = SectionLambdas.find(AccessorValue[0]);
609*700637cbSDimitry Andric     bool IsLambda = SectionLambda != SectionLambdas.end();
610*700637cbSDimitry Andric 
611*700637cbSDimitry Andric     if (IsLambda) {
612*700637cbSDimitry Andric       renderSectionLambdas(CurrentCtx, OS, SectionLambda->getValue());
613*700637cbSDimitry Andric       return;
614*700637cbSDimitry Andric     }
615*700637cbSDimitry Andric 
616*700637cbSDimitry Andric     if (isContextFalsey(ContextPtr))
617*700637cbSDimitry Andric       return;
618*700637cbSDimitry Andric 
619*700637cbSDimitry Andric     if (const json::Array *Arr = ContextPtr->getAsArray()) {
620*700637cbSDimitry Andric       for (const json::Value &V : *Arr)
621*700637cbSDimitry Andric         renderChild(V, OS);
622*700637cbSDimitry Andric       return;
623*700637cbSDimitry Andric     }
624*700637cbSDimitry Andric     renderChild(*ContextPtr, OS);
625*700637cbSDimitry Andric     return;
626*700637cbSDimitry Andric   }
627*700637cbSDimitry Andric   case InvertSection: {
628*700637cbSDimitry Andric     bool IsLambda = SectionLambdas.contains(AccessorValue[0]);
629*700637cbSDimitry Andric     if (isContextFalsey(ContextPtr) && !IsLambda) {
630*700637cbSDimitry Andric       // The context for the children remains unchanged from the parent's, so
631*700637cbSDimitry Andric       // we pass this node's original incoming context.
632*700637cbSDimitry Andric       renderChild(CurrentCtx, OS);
633*700637cbSDimitry Andric     }
634*700637cbSDimitry Andric     return;
635*700637cbSDimitry Andric   }
636*700637cbSDimitry Andric   }
637*700637cbSDimitry Andric   llvm_unreachable("Invalid ASTNode type");
638*700637cbSDimitry Andric }
639*700637cbSDimitry Andric 
findContext()640*700637cbSDimitry Andric const json::Value *ASTNode::findContext() {
641*700637cbSDimitry Andric   // The mustache spec allows for dot notation to access nested values
642*700637cbSDimitry Andric   // a single dot refers to the current context.
643*700637cbSDimitry Andric   // We attempt to find the JSON context in the current node, if it is not
644*700637cbSDimitry Andric   // found, then we traverse the parent nodes to find the context until we
645*700637cbSDimitry Andric   // reach the root node or the context is found.
646*700637cbSDimitry Andric   if (AccessorValue.empty())
647*700637cbSDimitry Andric     return nullptr;
648*700637cbSDimitry Andric   if (AccessorValue[0] == ".")
649*700637cbSDimitry Andric     return ParentContext;
650*700637cbSDimitry Andric 
651*700637cbSDimitry Andric   const json::Object *CurrentContext = ParentContext->getAsObject();
652*700637cbSDimitry Andric   StringRef CurrentAccessor = AccessorValue[0];
653*700637cbSDimitry Andric   ASTNode *CurrentParent = Parent;
654*700637cbSDimitry Andric 
655*700637cbSDimitry Andric   while (!CurrentContext || !CurrentContext->get(CurrentAccessor)) {
656*700637cbSDimitry Andric     if (CurrentParent->Ty != Root) {
657*700637cbSDimitry Andric       CurrentContext = CurrentParent->ParentContext->getAsObject();
658*700637cbSDimitry Andric       CurrentParent = CurrentParent->Parent;
659*700637cbSDimitry Andric       continue;
660*700637cbSDimitry Andric     }
661*700637cbSDimitry Andric     return nullptr;
662*700637cbSDimitry Andric   }
663*700637cbSDimitry Andric   const json::Value *Context = nullptr;
664*700637cbSDimitry Andric   for (auto [Idx, Acc] : enumerate(AccessorValue)) {
665*700637cbSDimitry Andric     const json::Value *CurrentValue = CurrentContext->get(Acc);
666*700637cbSDimitry Andric     if (!CurrentValue)
667*700637cbSDimitry Andric       return nullptr;
668*700637cbSDimitry Andric     if (Idx < AccessorValue.size() - 1) {
669*700637cbSDimitry Andric       CurrentContext = CurrentValue->getAsObject();
670*700637cbSDimitry Andric       if (!CurrentContext)
671*700637cbSDimitry Andric         return nullptr;
672*700637cbSDimitry Andric     } else {
673*700637cbSDimitry Andric       Context = CurrentValue;
674*700637cbSDimitry Andric     }
675*700637cbSDimitry Andric   }
676*700637cbSDimitry Andric   return Context;
677*700637cbSDimitry Andric }
678*700637cbSDimitry Andric 
renderChild(const json::Value & Contexts,llvm::raw_ostream & OS)679*700637cbSDimitry Andric void ASTNode::renderChild(const json::Value &Contexts, llvm::raw_ostream &OS) {
680*700637cbSDimitry Andric   for (AstPtr &Child : Children)
681*700637cbSDimitry Andric     Child->render(Contexts, OS);
682*700637cbSDimitry Andric }
683*700637cbSDimitry Andric 
renderPartial(const json::Value & Contexts,llvm::raw_ostream & OS,ASTNode * Partial)684*700637cbSDimitry Andric void ASTNode::renderPartial(const json::Value &Contexts, llvm::raw_ostream &OS,
685*700637cbSDimitry Andric                             ASTNode *Partial) {
686*700637cbSDimitry Andric   AddIndentationStringStream IS(OS, Indentation);
687*700637cbSDimitry Andric   Partial->render(Contexts, IS);
688*700637cbSDimitry Andric }
689*700637cbSDimitry Andric 
renderLambdas(const json::Value & Contexts,llvm::raw_ostream & OS,Lambda & L)690*700637cbSDimitry Andric void ASTNode::renderLambdas(const json::Value &Contexts, llvm::raw_ostream &OS,
691*700637cbSDimitry Andric                             Lambda &L) {
692*700637cbSDimitry Andric   json::Value LambdaResult = L();
693*700637cbSDimitry Andric   std::string LambdaStr;
694*700637cbSDimitry Andric   raw_string_ostream Output(LambdaStr);
695*700637cbSDimitry Andric   toMustacheString(LambdaResult, Output);
696*700637cbSDimitry Andric   Parser P = Parser(LambdaStr);
697*700637cbSDimitry Andric   AstPtr LambdaNode = P.parse(Partials, Lambdas, SectionLambdas, Escapes);
698*700637cbSDimitry Andric 
699*700637cbSDimitry Andric   EscapeStringStream ES(OS, Escapes);
700*700637cbSDimitry Andric   if (Ty == Variable) {
701*700637cbSDimitry Andric     LambdaNode->render(Contexts, ES);
702*700637cbSDimitry Andric     return;
703*700637cbSDimitry Andric   }
704*700637cbSDimitry Andric   LambdaNode->render(Contexts, OS);
705*700637cbSDimitry Andric }
706*700637cbSDimitry Andric 
renderSectionLambdas(const json::Value & Contexts,llvm::raw_ostream & OS,SectionLambda & L)707*700637cbSDimitry Andric void ASTNode::renderSectionLambdas(const json::Value &Contexts,
708*700637cbSDimitry Andric                                    llvm::raw_ostream &OS, SectionLambda &L) {
709*700637cbSDimitry Andric   json::Value Return = L(RawBody);
710*700637cbSDimitry Andric   if (isFalsey(Return))
711*700637cbSDimitry Andric     return;
712*700637cbSDimitry Andric   std::string LambdaStr;
713*700637cbSDimitry Andric   raw_string_ostream Output(LambdaStr);
714*700637cbSDimitry Andric   toMustacheString(Return, Output);
715*700637cbSDimitry Andric   Parser P = Parser(LambdaStr);
716*700637cbSDimitry Andric   AstPtr LambdaNode = P.parse(Partials, Lambdas, SectionLambdas, Escapes);
717*700637cbSDimitry Andric   LambdaNode->render(Contexts, OS);
718*700637cbSDimitry Andric }
719*700637cbSDimitry Andric 
render(const json::Value & Data,llvm::raw_ostream & OS)720*700637cbSDimitry Andric void Template::render(const json::Value &Data, llvm::raw_ostream &OS) {
721*700637cbSDimitry Andric   Tree->render(Data, OS);
722*700637cbSDimitry Andric }
723*700637cbSDimitry Andric 
registerPartial(std::string Name,std::string Partial)724*700637cbSDimitry Andric void Template::registerPartial(std::string Name, std::string Partial) {
725*700637cbSDimitry Andric   Parser P = Parser(Partial);
726*700637cbSDimitry Andric   AstPtr PartialTree = P.parse(Partials, Lambdas, SectionLambdas, Escapes);
727*700637cbSDimitry Andric   Partials.insert(std::make_pair(Name, std::move(PartialTree)));
728*700637cbSDimitry Andric }
729*700637cbSDimitry Andric 
registerLambda(std::string Name,Lambda L)730*700637cbSDimitry Andric void Template::registerLambda(std::string Name, Lambda L) { Lambdas[Name] = L; }
731*700637cbSDimitry Andric 
registerLambda(std::string Name,SectionLambda L)732*700637cbSDimitry Andric void Template::registerLambda(std::string Name, SectionLambda L) {
733*700637cbSDimitry Andric   SectionLambdas[Name] = L;
734*700637cbSDimitry Andric }
735*700637cbSDimitry Andric 
overrideEscapeCharacters(EscapeMap E)736*700637cbSDimitry Andric void Template::overrideEscapeCharacters(EscapeMap E) { Escapes = std::move(E); }
737*700637cbSDimitry Andric 
Template(StringRef TemplateStr)738*700637cbSDimitry Andric Template::Template(StringRef TemplateStr) {
739*700637cbSDimitry Andric   Parser P = Parser(TemplateStr);
740*700637cbSDimitry Andric   Tree = P.parse(Partials, Lambdas, SectionLambdas, Escapes);
741*700637cbSDimitry Andric   // The default behavior is to escape html entities.
742*700637cbSDimitry Andric   const EscapeMap HtmlEntities = {{'&', "&amp;"},
743*700637cbSDimitry Andric                                   {'<', "&lt;"},
744*700637cbSDimitry Andric                                   {'>', "&gt;"},
745*700637cbSDimitry Andric                                   {'"', "&quot;"},
746*700637cbSDimitry Andric                                   {'\'', "&#39;"}};
747*700637cbSDimitry Andric   overrideEscapeCharacters(HtmlEntities);
748*700637cbSDimitry Andric }
749*700637cbSDimitry Andric 
Template(Template && Other)750*700637cbSDimitry Andric Template::Template(Template &&Other) noexcept
751*700637cbSDimitry Andric     : Partials(std::move(Other.Partials)), Lambdas(std::move(Other.Lambdas)),
752*700637cbSDimitry Andric       SectionLambdas(std::move(Other.SectionLambdas)),
753*700637cbSDimitry Andric       Escapes(std::move(Other.Escapes)), Tree(std::move(Other.Tree)) {}
754*700637cbSDimitry Andric 
755*700637cbSDimitry Andric Template::~Template() = default;
756*700637cbSDimitry Andric 
operator =(Template && Other)757*700637cbSDimitry Andric Template &Template::operator=(Template &&Other) noexcept {
758*700637cbSDimitry Andric   if (this != &Other) {
759*700637cbSDimitry Andric     Partials = std::move(Other.Partials);
760*700637cbSDimitry Andric     Lambdas = std::move(Other.Lambdas);
761*700637cbSDimitry Andric     SectionLambdas = std::move(Other.SectionLambdas);
762*700637cbSDimitry Andric     Escapes = std::move(Other.Escapes);
763*700637cbSDimitry Andric     Tree = std::move(Other.Tree);
764*700637cbSDimitry Andric     Other.Tree = nullptr;
765*700637cbSDimitry Andric   }
766*700637cbSDimitry Andric   return *this;
767*700637cbSDimitry Andric }
768*700637cbSDimitry Andric } // namespace llvm::mustache
769