@@ -57,6 +57,33 @@ static Accessor splitMustacheString(StringRef Str) {
5757
5858namespace llvm ::mustache {
5959
60+ class MustacheOutputStream : public raw_ostream {
61+ public:
62+ MustacheOutputStream () = default ;
63+ ~MustacheOutputStream () override = default ;
64+
65+ virtual void suspendIndentation () {}
66+ virtual void resumeIndentation () {}
67+
68+ private:
69+ void anchor () override ;
70+ };
71+
72+ void MustacheOutputStream::anchor () {}
73+
74+ class RawMustacheOutputStream : public MustacheOutputStream {
75+ public:
76+ RawMustacheOutputStream (raw_ostream &OS) : OS(OS) { SetUnbuffered (); }
77+
78+ private:
79+ raw_ostream &OS;
80+
81+ void write_impl (const char *Ptr, size_t Size) override {
82+ OS.write (Ptr, Size);
83+ }
84+ uint64_t current_pos () const override { return OS.tell (); }
85+ };
86+
6087class Token {
6188public:
6289 enum class Type {
@@ -157,29 +184,29 @@ class ASTNode {
157184
158185 void setIndentation (size_t NewIndentation) { Indentation = NewIndentation; };
159186
160- void render (const llvm::json::Value &Data, llvm::raw_ostream &OS);
187+ void render (const llvm::json::Value &Data, MustacheOutputStream &OS);
161188
162189private:
163- void renderLambdas (const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
190+ void renderLambdas (const llvm::json::Value &Contexts, MustacheOutputStream &OS,
164191 Lambda &L);
165192
166193 void renderSectionLambdas (const llvm::json::Value &Contexts,
167- llvm::raw_ostream &OS, SectionLambda &L);
194+ MustacheOutputStream &OS, SectionLambda &L);
168195
169- void renderPartial (const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
196+ void renderPartial (const llvm::json::Value &Contexts, MustacheOutputStream &OS,
170197 ASTNode *Partial);
171198
172- void renderChild (const llvm::json::Value &Context, llvm::raw_ostream &OS);
199+ void renderChild (const llvm::json::Value &Context, MustacheOutputStream &OS);
173200
174201 const llvm::json::Value *findContext ();
175202
176- void renderRoot (const json::Value &CurrentCtx, raw_ostream &OS);
177- void renderText (raw_ostream &OS);
178- void renderPartial (const json::Value &CurrentCtx, raw_ostream &OS);
179- void renderVariable (const json::Value &CurrentCtx, raw_ostream &OS);
180- void renderUnescapeVariable (const json::Value &CurrentCtx, raw_ostream &OS);
181- void renderSection (const json::Value &CurrentCtx, raw_ostream &OS);
182- void renderInvertSection (const json::Value &CurrentCtx, raw_ostream &OS);
203+ void renderRoot (const json::Value &CurrentCtx, MustacheOutputStream &OS);
204+ void renderText (MustacheOutputStream &OS);
205+ void renderPartial (const json::Value &CurrentCtx, MustacheOutputStream &OS);
206+ void renderVariable (const json::Value &CurrentCtx, MustacheOutputStream &OS);
207+ void renderUnescapeVariable (const json::Value &CurrentCtx, MustacheOutputStream &OS);
208+ void renderSection (const json::Value &CurrentCtx, MustacheOutputStream &OS);
209+ void renderInvertSection (const json::Value &CurrentCtx, MustacheOutputStream &OS);
183210
184211 MustacheContext &Ctx;
185212 Type Ty;
@@ -393,7 +420,7 @@ static SmallVector<Token> tokenize(StringRef Template) {
393420 if (T.TagKind == Tag::Kind::None) {
394421 // No more tags, the rest is text.
395422 Tokens.emplace_back (Template.substr (Start).str ());
396- LLVM_DEBUG (dbgs () << " No more tags. Created final Text token: \" "
423+ LLVM_DEBUG (dbgs () << " No more tags. Created final Text token: \" "
397424 << Template.substr (Start) << " \"\n " );
398425 break ;
399426 }
@@ -458,9 +485,9 @@ static SmallVector<Token> tokenize(StringRef Template) {
458485}
459486
460487// Custom stream to escape strings.
461- class EscapeStringStream : public raw_ostream {
488+ class EscapeStringStream : public MustacheOutputStream {
462489public:
463- explicit EscapeStringStream (llvm:: raw_ostream &WrappedStream,
490+ explicit EscapeStringStream (raw_ostream &WrappedStream,
464491 EscapeMap &Escape)
465492 : Escape(Escape), WrappedStream(WrappedStream) {
466493 SetUnbuffered ();
@@ -482,32 +509,38 @@ class EscapeStringStream : public raw_ostream {
482509
483510private:
484511 EscapeMap &Escape;
485- llvm:: raw_ostream &WrappedStream;
512+ raw_ostream &WrappedStream;
486513};
487514
488515// Custom stream to add indentation used to for rendering partials.
489- class AddIndentationStringStream : public raw_ostream {
516+ class AddIndentationStringStream : public MustacheOutputStream {
490517public:
491- explicit AddIndentationStringStream (llvm:: raw_ostream &WrappedStream,
518+ explicit AddIndentationStringStream (raw_ostream &WrappedStream,
492519 size_t Indentation)
493520 : Indentation(Indentation), WrappedStream(WrappedStream),
494- NeedsIndent(true ) {
521+ NeedsIndent(true ), IsSuspended( false ) {
495522 SetUnbuffered ();
496523 }
497524
525+ void suspendIndentation () override { IsSuspended = true ; }
526+ void resumeIndentation () override { IsSuspended = false ; }
527+
498528protected:
499529 void write_impl (const char *Ptr, size_t Size) override {
500530 llvm::StringRef Data (Ptr, Size);
501531 SmallString<0 > Indent;
502532 Indent.resize (Indentation, ' ' );
503533
504534 for (char C : Data) {
535+ LLVM_DEBUG (dbgs () << " IndentationStream: NeedsIndent=" << NeedsIndent
536+ << " , C='" << C << " ', Indentation=" << Indentation
537+ << " \n " );
505538 if (NeedsIndent && C != ' \n ' ) {
506539 WrappedStream << Indent;
507540 NeedsIndent = false ;
508541 }
509542 WrappedStream << C;
510- if (C == ' \n ' )
543+ if (C == ' \n ' && !IsSuspended )
511544 NeedsIndent = true ;
512545 }
513546 }
@@ -516,8 +549,9 @@ class AddIndentationStringStream : public raw_ostream {
516549
517550private:
518551 size_t Indentation;
519- llvm:: raw_ostream &WrappedStream;
552+ raw_ostream &WrappedStream;
520553 bool NeedsIndent;
554+ bool IsSuspended;
521555};
522556
523557class Parser {
@@ -607,6 +641,7 @@ void Parser::parseMustache(ASTNode *Parent) {
607641 }
608642}
609643static void toMustacheString (const json::Value &Data, raw_ostream &OS) {
644+ LLVM_DEBUG (dbgs () << " toMustacheString: kind=" << (int )Data.kind () << " \n " );
610645 switch (Data.kind ()) {
611646 case json::Value::Null:
612647 return ;
@@ -619,6 +654,7 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
619654 }
620655 case json::Value::String: {
621656 auto Str = *Data.getAsString ();
657+ LLVM_DEBUG (dbgs () << " --> writing string: \" " << Str << " \"\n " );
622658 OS << Str.str ();
623659 return ;
624660 }
@@ -638,19 +674,21 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
638674 }
639675}
640676
641- void ASTNode::renderRoot (const json::Value &CurrentCtx, raw_ostream &OS) {
677+ void ASTNode::renderRoot (const json::Value &CurrentCtx, MustacheOutputStream &OS) {
642678 renderChild (CurrentCtx, OS);
643679}
644680
645- void ASTNode::renderText (raw_ostream &OS) { OS << Body; }
681+ void ASTNode::renderText (MustacheOutputStream &OS) { OS << Body; }
646682
647- void ASTNode::renderPartial (const json::Value &CurrentCtx, raw_ostream &OS) {
683+ void ASTNode::renderPartial (const json::Value &CurrentCtx, MustacheOutputStream &OS) {
684+ LLVM_DEBUG (dbgs () << " renderPartial: Accessor=" << AccessorValue[0 ]
685+ << " , Indentation=" << Indentation << " \n " );
648686 auto Partial = Ctx.Partials .find (AccessorValue[0 ]);
649687 if (Partial != Ctx.Partials .end ())
650688 renderPartial (CurrentCtx, OS, Partial->getValue ().get ());
651689}
652690
653- void ASTNode::renderVariable (const json::Value &CurrentCtx, raw_ostream &OS) {
691+ void ASTNode::renderVariable (const json::Value &CurrentCtx, MustacheOutputStream &OS) {
654692 auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
655693 if (Lambda != Ctx.Lambdas .end ()) {
656694 renderLambdas (CurrentCtx, OS, Lambda->getValue ());
@@ -661,16 +699,22 @@ void ASTNode::renderVariable(const json::Value &CurrentCtx, raw_ostream &OS) {
661699}
662700
663701void ASTNode::renderUnescapeVariable (const json::Value &CurrentCtx,
664- raw_ostream &OS) {
702+ MustacheOutputStream &OS) {
703+ LLVM_DEBUG (dbgs () << " renderUnescapeVariable: Accessor=" << AccessorValue[0 ]
704+ << " \n " );
665705 auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
666706 if (Lambda != Ctx.Lambdas .end ()) {
667707 renderLambdas (CurrentCtx, OS, Lambda->getValue ());
668708 } else if (const json::Value *ContextPtr = findContext ()) {
709+ LLVM_DEBUG (dbgs () << " --> Found context value, writing to stream.\n " );
710+ OS.suspendIndentation ();
669711 toMustacheString (*ContextPtr, OS);
712+ OS.resumeIndentation ();
670713 }
671714}
672715
673- void ASTNode::renderSection (const json::Value &CurrentCtx, raw_ostream &OS) {
716+ void ASTNode::renderSection (const json::Value &CurrentCtx,
717+ MustacheOutputStream &OS) {
674718 auto SectionLambda = Ctx.SectionLambdas .find (AccessorValue[0 ]);
675719 if (SectionLambda != Ctx.SectionLambdas .end ()) {
676720 renderSectionLambdas (CurrentCtx, OS, SectionLambda->getValue ());
@@ -690,48 +734,50 @@ void ASTNode::renderSection(const json::Value &CurrentCtx, raw_ostream &OS) {
690734}
691735
692736void ASTNode::renderInvertSection (const json::Value &CurrentCtx,
693- raw_ostream &OS) {
737+ MustacheOutputStream &OS) {
694738 bool IsLambda = Ctx.SectionLambdas .contains (AccessorValue[0 ]);
695739 const json::Value *ContextPtr = findContext ();
696740 if (isContextFalsey (ContextPtr) && !IsLambda) {
697741 renderChild (CurrentCtx, OS);
698742 }
699743}
700744
701- void ASTNode::render (const json::Value &CurrentCtx, raw_ostream &OS) {
745+ void ASTNode::render (const llvm:: json::Value &Data, MustacheOutputStream &OS) {
702746 if (Ty != Root && Ty != Text && AccessorValue.empty ())
703747 return ;
704748 // Set the parent context to the incoming context so that we
705749 // can walk up the context tree correctly in findContext().
706- ParentContext = &CurrentCtx ;
750+ ParentContext = &Data ;
707751
708752 switch (Ty) {
709753 case Root:
710- renderRoot (CurrentCtx , OS);
754+ renderRoot (Data , OS);
711755 return ;
712756 case Text:
713757 renderText (OS);
714758 return ;
715759 case Partial:
716- renderPartial (CurrentCtx , OS);
760+ renderPartial (Data , OS);
717761 return ;
718762 case Variable:
719- renderVariable (CurrentCtx , OS);
763+ renderVariable (Data , OS);
720764 return ;
721765 case UnescapeVariable:
722- renderUnescapeVariable (CurrentCtx , OS);
766+ renderUnescapeVariable (Data , OS);
723767 return ;
724768 case Section:
725- renderSection (CurrentCtx , OS);
769+ renderSection (Data , OS);
726770 return ;
727771 case InvertSection:
728- renderInvertSection (CurrentCtx , OS);
772+ renderInvertSection (Data , OS);
729773 return ;
730774 }
731775 llvm_unreachable (" Invalid ASTNode type" );
732776}
733777
734778const json::Value *ASTNode::findContext () {
779+ LLVM_DEBUG (dbgs () << " findContext: AccessorValue[0]=" << AccessorValue[0 ]
780+ << " \n " );
735781 // The mustache spec allows for dot notation to access nested values
736782 // a single dot refers to the current context.
737783 // We attempt to find the JSON context in the current node, if it is not
@@ -746,12 +792,24 @@ const json::Value *ASTNode::findContext() {
746792 StringRef CurrentAccessor = AccessorValue[0 ];
747793 ASTNode *CurrentParent = Parent;
748794
795+ LLVM_DEBUG (dbgs () << " findContext: ParentContext: " ;
796+ if (ParentContext) ParentContext->print (dbgs ());
797+ else dbgs () << " nullptr" ;
798+ dbgs () << " \n " );
799+
749800 while (!CurrentContext || !CurrentContext->get (CurrentAccessor)) {
801+ LLVM_DEBUG (dbgs () << " findContext: climbing parent\n " );
750802 if (CurrentParent->Ty != Root) {
751803 CurrentContext = CurrentParent->ParentContext ->getAsObject ();
752804 CurrentParent = CurrentParent->Parent ;
805+ LLVM_DEBUG (dbgs () << " findContext: new ParentContext: " ;
806+ if (CurrentParent->ParentContext )
807+ CurrentParent->ParentContext ->print (dbgs ());
808+ else dbgs () << " nullptr" ;
809+ dbgs () << " \n " );
753810 continue ;
754811 }
812+ LLVM_DEBUG (dbgs () << " findContext: reached root, not found\n " );
755813 return nullptr ;
756814 }
757815 const json::Value *Context = nullptr ;
@@ -767,21 +825,27 @@ const json::Value *ASTNode::findContext() {
767825 Context = CurrentValue;
768826 }
769827 }
828+ LLVM_DEBUG (dbgs () << " findContext: found value: " ;
829+ if (Context) Context->print (dbgs ());
830+ else dbgs () << " nullptr" ;
831+ dbgs () << " \n " );
770832 return Context;
771833}
772834
773- void ASTNode::renderChild (const json::Value &Contexts, llvm::raw_ostream &OS) {
835+ void ASTNode::renderChild (const json::Value &Contexts, MustacheOutputStream &OS) {
774836 for (AstPtr &Child : Children)
775837 Child->render (Contexts, OS);
776838}
777839
778- void ASTNode::renderPartial (const json::Value &Contexts, llvm::raw_ostream &OS,
840+ void ASTNode::renderPartial (const json::Value &Contexts, MustacheOutputStream &OS,
779841 ASTNode *Partial) {
842+ LLVM_DEBUG (dbgs () << " renderPartial (helper): Indentation=" << Indentation
843+ << " \n " );
780844 AddIndentationStringStream IS (OS, Indentation);
781845 Partial->render (Contexts, IS);
782846}
783847
784- void ASTNode::renderLambdas (const json::Value &Contexts, llvm::raw_ostream &OS,
848+ void ASTNode::renderLambdas (const json::Value &Contexts, MustacheOutputStream &OS,
785849 Lambda &L) {
786850 json::Value LambdaResult = L ();
787851 std::string LambdaStr;
@@ -799,7 +863,7 @@ void ASTNode::renderLambdas(const json::Value &Contexts, llvm::raw_ostream &OS,
799863}
800864
801865void ASTNode::renderSectionLambdas (const json::Value &Contexts,
802- llvm::raw_ostream &OS, SectionLambda &L) {
866+ MustacheOutputStream &OS, SectionLambda &L) {
803867 json::Value Return = L (RawBody);
804868 if (isFalsey (Return))
805869 return ;
@@ -812,7 +876,8 @@ void ASTNode::renderSectionLambdas(const json::Value &Contexts,
812876}
813877
814878void Template::render (const json::Value &Data, llvm::raw_ostream &OS) {
815- Tree->render (Data, OS);
879+ RawMustacheOutputStream MOS (OS);
880+ Tree->render (Data, MOS);
816881}
817882
818883void Template::registerPartial (std::string Name, std::string Partial) {
0 commit comments