@@ -16,8 +16,8 @@ using namespace llvm::mustache;
1616
1717SmallString<0 > escapeString (StringRef Input,
1818 DenseMap<char , StringRef> &Escape) {
19-
2019 SmallString<0 > Output;
20+ Output.reserve (Input.size ());
2121 for (char C : Input) {
2222 auto It = Escape.find (C);
2323 if (It != Escape.end ())
@@ -91,24 +91,33 @@ Token::Type Token::getTokenType(char Identifier) {
9191
9292// Function to check if there's no meaningful text behind
9393bool noTextBehind (size_t Idx, const SmallVector<Token, 0 > &Tokens) {
94- if (Idx == 0 || Tokens[Idx - 1 ].getType () != Token::Type::Text)
94+ if (Idx == 0 )
95+ return false ;
96+
97+ int PrevIdx = Idx - 1 ;
98+ if (Tokens[PrevIdx].getType () != Token::Type::Text)
9599 return false ;
100+
96101 const Token &PrevToken = Tokens[Idx - 1 ];
97102 StringRef TokenBody = PrevToken.getRawBody ().rtrim (" \t\v\t " );
98- // We make a special exception for when previous token is empty
103+ // We make an exception for when previous token is empty
99104 // and the current token is the second token
100105 // ex.
101106 // " {{#section}}A{{/section}}"
102- // that's why we check if the token body is empty and the index is 1
107+ // the output of this is
108+ // "A"
103109 return TokenBody.ends_with (" \n " ) || (TokenBody.empty () && Idx == 1 );
104110}
105111
106112// Function to check if there's no meaningful text ahead
107113bool noTextAhead (size_t Idx, const SmallVector<Token, 0 > &Tokens) {
108- if (Idx >= Tokens.size () - 1 ||
109- Tokens[Idx + 1 ].getType () != Token::Type::Text)
114+ if (Idx >= Tokens.size () - 1 )
110115 return false ;
111-
116+
117+ int PrevIdx = Idx + 1 ;
118+ if (Tokens[Idx + 1 ].getType () != Token::Type::Text)
119+ return false ;
120+
112121 const Token &NextToken = Tokens[Idx + 1 ];
113122 StringRef TokenBody = NextToken.getRawBody ().ltrim (" " );
114123 return TokenBody.starts_with (" \r\n " ) || TokenBody.starts_with (" \n " );
@@ -121,10 +130,47 @@ bool requiresCleanUp(Token::Type T) {
121130 T == Token::Type::Partial;
122131}
123132
124- // Simple tokenizer that splits the template into tokens
125- // the mustache spec allows {{{ }}} to unescape variables
126- // but we don't support that here unescape variable
127- // is represented only by {{& variable}}
133+ // Adjust next token body if there is no text ahead
134+ // eg.
135+ // The template string
136+ // "{{! Comment }} \nLine 2"
137+ // would be considered as no text ahead and should be render as
138+ // " Line 2"
139+ void stripTokenAhead (SmallVector<Token, 0 >& Tokens, size_t Idx) {
140+ Token &NextToken = Tokens[Idx + 1 ];
141+ StringRef NextTokenBody = NextToken.getTokenBody ();
142+ // cut off the leading newline which could be \n or \r\n
143+ if (NextTokenBody.starts_with (" \r\n " ))
144+ NextToken.setTokenBody (NextTokenBody.substr (2 ));
145+ else if (NextTokenBody.starts_with (" \n " ))
146+ NextToken.setTokenBody (NextTokenBody.substr (1 ));
147+ }
148+
149+ // Adjust previous token body if there no text behind
150+ // eg.
151+ // The template string
152+ // " \t{{#section}}A{{/section}}"
153+ // would be considered as no text ahead and should be render as
154+ // "A"
155+ // The exception for this is partial tag which requires us to
156+ // keep track of the indentation once it's rendered
157+ void stripTokenBefore (SmallVector<Token, 0 >& Tokens,
158+ size_t Idx,
159+ Token& CurrentToken,
160+ Token::Type CurrentType) {
161+ Token &PrevToken = Tokens[Idx - 1 ];
162+ StringRef PrevTokenBody = PrevToken.getTokenBody ();
163+ StringRef Unindented = PrevTokenBody.rtrim (" \t\v " );
164+ size_t Indentation = PrevTokenBody.size () - Unindented.size ();
165+ if (CurrentType != Token::Type::Partial)
166+ PrevToken.setTokenBody (Unindented);
167+ CurrentToken.setIndentation (Indentation);
168+ }
169+
170+ // Simple tokenizer that splits the template into tokens.
171+ // The mustache spec allows {{{ }}} to unescape variables
172+ // but we don't support that here. An unescape variable
173+ // is represented only by {{& variable}}.
128174SmallVector<Token, 0 > tokenize (StringRef Template) {
129175 SmallVector<Token, 0 > Tokens;
130176 StringRef Open (" {{" );
@@ -160,7 +206,11 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
160206 Tokens.emplace_back (Template.substr (Start));
161207
162208 // Fix up white spaces for:
163- // open sections/inverted sections/close section/comment
209+ // - open sections
210+ // - inverted sections
211+ // - close sections
212+ // - comments
213+ //
164214 // This loop attempts to find standalone tokens and tries to trim out
165215 // the surrounding whitespace.
166216 // For example:
@@ -178,47 +228,22 @@ SmallVector<Token, 0> tokenize(StringRef Template) {
178228 if (!RequiresCleanUp)
179229 continue ;
180230
181- // We adjust the token body if there's no text behind or ahead a token is
182- // considered surrounded by no text if the right of the previous token
183- // is a newline followed by spaces or if the left of the next token
184- // is spaces followed by a newline
231+ // We adjust the token body if there's no text behind or ahead.
232+ // A token is considered to have no text ahead if the right of the previous
233+ // token is a newline followed by spaces.
234+ // A token is considered to have no text behind if the left of the next
235+ // token is spaces followed by a newline.
185236 // eg.
186237 // "Line 1\n {{#section}} \n Line 2 \n {{/section}} \n Line 3"
187-
188238 bool NoTextBehind = noTextBehind (Idx, Tokens);
189239 bool NoTextAhead = noTextAhead (Idx, Tokens);
190-
191- // Adjust next token body if there is no text ahead
192- // eg.
193- // The template string
194- // "{{! Comment }} \nLine 2"
195- // would be considered as no text ahead and should be render as
196- // " Line 2"
240+
197241 if ((NoTextBehind && NoTextAhead) || (NoTextAhead && Idx == 0 )) {
198- Token &NextToken = Tokens[Idx + 1 ];
199- StringRef NextTokenBody = NextToken.getTokenBody ();
200- // cut off the leading newline which could be \n or \r\n
201- if (NextTokenBody.starts_with (" \r\n " ))
202- NextToken.setTokenBody (NextTokenBody.substr (2 ));
203- else if (NextTokenBody.starts_with (" \n " ))
204- NextToken.setTokenBody (NextTokenBody.substr (1 ));
242+ stripTokenAhead (Tokens, Idx);
205243 }
206- // Adjust previous token body if there no text behind
207- // eg.
208- // The template string
209- // " \t{{#section}}A{{/section}}"
210- // would be considered as no text ahead and should be render as
211- // "A"
212- // The exception for this is partial tag which requires us to
213- // keep track of the indentation once it's rendered
244+
214245 if (((NoTextBehind && NoTextAhead) || (NoTextBehind && Idx == LastIdx))) {
215- Token &PrevToken = Tokens[Idx - 1 ];
216- StringRef PrevTokenBody = PrevToken.getTokenBody ();
217- StringRef Unindented = PrevTokenBody.rtrim (" \t\v " );
218- size_t Indentation = PrevTokenBody.size () - Unindented.size ();
219- if (CurrentType != Token::Type::Partial)
220- PrevToken.setTokenBody (Unindented);
221- CurrentToken.setIndentation (Indentation);
246+ stripTokenBefore (Tokens, Idx, CurrentToken, CurrentType);
222247 }
223248 }
224249 return Tokens;
@@ -304,25 +329,25 @@ void Parser::parseMustache(ASTNode *Parent) {
304329 Parent->addChild (CurrentNode);
305330 break ;
306331 }
332+ case Token::Type::Comment:
333+ break ;
307334 case Token::Type::SectionClose:
308335 return ;
309- default :
310- break ;
311336 }
312337 }
313338}
314339
315340StringRef Template::render (Value &Data) {
316- BumpPtrAllocator LocalAllocator;
317- Tree->setUpContext (&LocalAllocator);
318341 Tree->render (Data, Output);
342+ LocalAllocator.Reset ();
319343 return Output.str ();
320344}
321345
322346void Template::registerPartial (StringRef Name, StringRef Partial) {
323347 Parser P = Parser (Partial, Allocator);
324348 ASTNode *PartialTree = P.parse ();
325- PartialTree->setUpNode (Partials, Lambdas, SectionLambdas, Escapes);
349+ PartialTree->setUpNode (LocalAllocator, Partials, Lambdas, SectionLambdas,
350+ Escapes);
326351 Partials.insert (std::make_pair (Name, PartialTree));
327352}
328353
@@ -344,7 +369,8 @@ Template::Template(StringRef TemplateStr) {
344369 {' "' , " "" },
345370 {' \' ' , " '" }};
346371 registerEscape (HtmlEntities);
347- Tree->setUpNode (Partials, Lambdas, SectionLambdas, Escapes);
372+ Tree->setUpNode (LocalAllocator,
373+ Partials, Lambdas, SectionLambdas, Escapes);
348374}
349375
350376void toJsonString (const Value &Data, SmallString<0 > &Output) {
@@ -494,7 +520,6 @@ void ASTNode::renderChild(const Value &Contexts, SmallString<0> &Output) {
494520
495521void ASTNode::renderPartial (const Value &Contexts, SmallString<0 > &Output,
496522 ASTNode *Partial) {
497- Partial->setUpContext (Allocator);
498523 Partial->render (Contexts, Output);
499524 addIndentation (Output, Indentation);
500525}
@@ -506,8 +531,8 @@ void ASTNode::renderLambdas(const Value &Contexts, SmallString<0> &Output,
506531 toJsonString (LambdaResult, LambdaStr);
507532 Parser P = Parser (LambdaStr, *Allocator);
508533 ASTNode *LambdaNode = P.parse ();
509- LambdaNode->setUpNode (*Partials, *Lambdas, *SectionLambdas, *Escapes);
510- LambdaNode-> setUpContext (Allocator );
534+ LambdaNode->setUpNode (*Allocator, * Partials, *Lambdas, *SectionLambdas,
535+ *Escapes );
511536 LambdaNode->render (Contexts, Output);
512537 if (T == Variable)
513538 Output = escapeString (Output, *Escapes);
@@ -523,30 +548,24 @@ void ASTNode::renderSectionLambdas(const Value &Contexts,
523548 toJsonString (Return, LambdaStr);
524549 Parser P = Parser (LambdaStr, *Allocator);
525550 ASTNode *LambdaNode = P.parse ();
526- LambdaNode->setUpNode (*Partials, *Lambdas, *SectionLambdas, *Escapes);
527- LambdaNode-> setUpContext (Allocator );
551+ LambdaNode->setUpNode (*Allocator, * Partials, *Lambdas, *SectionLambdas,
552+ *Escapes );
528553 LambdaNode->render (Contexts, Output);
529554 return ;
530555}
531556
532- void ASTNode::setUpNode (StringMap<ASTNode *> &Par, StringMap<Lambda> &L,
557+ void ASTNode::setUpNode (llvm::BumpPtrAllocator &Alloc,
558+ StringMap<ASTNode *> &Par, StringMap<Lambda> &L,
533559 StringMap<SectionLambda> &SC,
534560 DenseMap<char , StringRef> &E) {
535561 // Passed down datastructures needed for rendering to
536562 // the children nodes. This must be called before rendering
563+ Allocator = &Alloc;
537564 Partials = &Par;
538565 Lambdas = &L;
539566 SectionLambdas = &SC;
540567 Escapes = &E;
541568 for (ASTNode *Child : Children)
542- Child->setUpNode (Par, L, SC, E);
569+ Child->setUpNode (Alloc, Par, L, SC, E);
543570}
544571
545- void ASTNode::setUpContext (llvm::BumpPtrAllocator *Alloc) {
546- // Passed down the allocator to the children nodes.
547- // Each render call requires a allocator for generating
548- // Partial/Section nodes
549- Allocator = Alloc;
550- for (ASTNode *Child : Children)
551- Child->setUpContext (Alloc);
552- }
0 commit comments