@@ -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,31 @@ 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,
164- Lambda &L);
190+ void renderLambdas (const llvm::json::Value &Contexts,
191+ MustacheOutputStream &OS, 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,
170- ASTNode *Partial);
196+ void renderPartial (const llvm::json::Value &Contexts,
197+ MustacheOutputStream &OS, 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,
208+ MustacheOutputStream &OS);
209+ void renderSection (const json::Value &CurrentCtx, MustacheOutputStream &OS);
210+ void renderInvertSection (const json::Value &CurrentCtx,
211+ MustacheOutputStream &OS);
183212
184213 MustacheContext &Ctx;
185214 Type Ty;
@@ -458,10 +487,9 @@ static SmallVector<Token> tokenize(StringRef Template) {
458487}
459488
460489// Custom stream to escape strings.
461- class EscapeStringStream : public raw_ostream {
490+ class EscapeStringStream : public MustacheOutputStream {
462491public:
463- explicit EscapeStringStream (llvm::raw_ostream &WrappedStream,
464- EscapeMap &Escape)
492+ explicit EscapeStringStream (raw_ostream &WrappedStream, EscapeMap &Escape)
465493 : Escape(Escape), WrappedStream(WrappedStream) {
466494 SetUnbuffered ();
467495 }
@@ -482,32 +510,38 @@ class EscapeStringStream : public raw_ostream {
482510
483511private:
484512 EscapeMap &Escape;
485- llvm:: raw_ostream &WrappedStream;
513+ raw_ostream &WrappedStream;
486514};
487515
488516// Custom stream to add indentation used to for rendering partials.
489- class AddIndentationStringStream : public raw_ostream {
517+ class AddIndentationStringStream : public MustacheOutputStream {
490518public:
491- explicit AddIndentationStringStream (llvm:: raw_ostream &WrappedStream,
519+ explicit AddIndentationStringStream (raw_ostream &WrappedStream,
492520 size_t Indentation)
493521 : Indentation(Indentation), WrappedStream(WrappedStream),
494- NeedsIndent(true ) {
522+ NeedsIndent(true ), IsSuspended( false ) {
495523 SetUnbuffered ();
496524 }
497525
526+ void suspendIndentation () override { IsSuspended = true ; }
527+ void resumeIndentation () override { IsSuspended = false ; }
528+
498529protected:
499530 void write_impl (const char *Ptr, size_t Size) override {
500531 llvm::StringRef Data (Ptr, Size);
501532 SmallString<0 > Indent;
502533 Indent.resize (Indentation, ' ' );
503534
504535 for (char C : Data) {
536+ LLVM_DEBUG (dbgs () << " IndentationStream: NeedsIndent=" << NeedsIndent
537+ << " , C='" << C << " ', Indentation=" << Indentation
538+ << " \n " );
505539 if (NeedsIndent && C != ' \n ' ) {
506540 WrappedStream << Indent;
507541 NeedsIndent = false ;
508542 }
509543 WrappedStream << C;
510- if (C == ' \n ' )
544+ if (C == ' \n ' && !IsSuspended )
511545 NeedsIndent = true ;
512546 }
513547 }
@@ -516,8 +550,9 @@ class AddIndentationStringStream : public raw_ostream {
516550
517551private:
518552 size_t Indentation;
519- llvm:: raw_ostream &WrappedStream;
553+ raw_ostream &WrappedStream;
520554 bool NeedsIndent;
555+ bool IsSuspended;
521556};
522557
523558class Parser {
@@ -607,6 +642,7 @@ void Parser::parseMustache(ASTNode *Parent) {
607642 }
608643}
609644static void toMustacheString (const json::Value &Data, raw_ostream &OS) {
645+ LLVM_DEBUG (dbgs () << " toMustacheString: kind=" << (int )Data.kind () << " \n " );
610646 switch (Data.kind ()) {
611647 case json::Value::Null:
612648 return ;
@@ -619,6 +655,7 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
619655 }
620656 case json::Value::String: {
621657 auto Str = *Data.getAsString ();
658+ LLVM_DEBUG (dbgs () << " --> writing string: \" " << Str << " \"\n " );
622659 OS << Str.str ();
623660 return ;
624661 }
@@ -638,19 +675,24 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
638675 }
639676}
640677
641- void ASTNode::renderRoot (const json::Value &CurrentCtx, raw_ostream &OS) {
678+ void ASTNode::renderRoot (const json::Value &CurrentCtx,
679+ MustacheOutputStream &OS) {
642680 renderChild (CurrentCtx, OS);
643681}
644682
645- void ASTNode::renderText (raw_ostream &OS) { OS << Body; }
683+ void ASTNode::renderText (MustacheOutputStream &OS) { OS << Body; }
646684
647- void ASTNode::renderPartial (const json::Value &CurrentCtx, raw_ostream &OS) {
685+ void ASTNode::renderPartial (const json::Value &CurrentCtx,
686+ MustacheOutputStream &OS) {
687+ LLVM_DEBUG (dbgs () << " renderPartial: Accessor=" << AccessorValue[0 ]
688+ << " , Indentation=" << Indentation << " \n " );
648689 auto Partial = Ctx.Partials .find (AccessorValue[0 ]);
649690 if (Partial != Ctx.Partials .end ())
650691 renderPartial (CurrentCtx, OS, Partial->getValue ().get ());
651692}
652693
653- void ASTNode::renderVariable (const json::Value &CurrentCtx, raw_ostream &OS) {
694+ void ASTNode::renderVariable (const json::Value &CurrentCtx,
695+ MustacheOutputStream &OS) {
654696 auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
655697 if (Lambda != Ctx.Lambdas .end ()) {
656698 renderLambdas (CurrentCtx, OS, Lambda->getValue ());
@@ -661,16 +703,22 @@ void ASTNode::renderVariable(const json::Value &CurrentCtx, raw_ostream &OS) {
661703}
662704
663705void ASTNode::renderUnescapeVariable (const json::Value &CurrentCtx,
664- raw_ostream &OS) {
706+ MustacheOutputStream &OS) {
707+ LLVM_DEBUG (dbgs () << " renderUnescapeVariable: Accessor=" << AccessorValue[0 ]
708+ << " \n " );
665709 auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
666710 if (Lambda != Ctx.Lambdas .end ()) {
667711 renderLambdas (CurrentCtx, OS, Lambda->getValue ());
668712 } else if (const json::Value *ContextPtr = findContext ()) {
713+ LLVM_DEBUG (dbgs () << " --> Found context value, writing to stream.\n " );
714+ OS.suspendIndentation ();
669715 toMustacheString (*ContextPtr, OS);
716+ OS.resumeIndentation ();
670717 }
671718}
672719
673- void ASTNode::renderSection (const json::Value &CurrentCtx, raw_ostream &OS) {
720+ void ASTNode::renderSection (const json::Value &CurrentCtx,
721+ MustacheOutputStream &OS) {
674722 auto SectionLambda = Ctx.SectionLambdas .find (AccessorValue[0 ]);
675723 if (SectionLambda != Ctx.SectionLambdas .end ()) {
676724 renderSectionLambdas (CurrentCtx, OS, SectionLambda->getValue ());
@@ -690,48 +738,50 @@ void ASTNode::renderSection(const json::Value &CurrentCtx, raw_ostream &OS) {
690738}
691739
692740void ASTNode::renderInvertSection (const json::Value &CurrentCtx,
693- raw_ostream &OS) {
741+ MustacheOutputStream &OS) {
694742 bool IsLambda = Ctx.SectionLambdas .contains (AccessorValue[0 ]);
695743 const json::Value *ContextPtr = findContext ();
696744 if (isContextFalsey (ContextPtr) && !IsLambda) {
697745 renderChild (CurrentCtx, OS);
698746 }
699747}
700748
701- void ASTNode::render (const json::Value &CurrentCtx, raw_ostream &OS) {
749+ void ASTNode::render (const llvm:: json::Value &Data, MustacheOutputStream &OS) {
702750 if (Ty != Root && Ty != Text && AccessorValue.empty ())
703751 return ;
704752 // Set the parent context to the incoming context so that we
705753 // can walk up the context tree correctly in findContext().
706- ParentContext = &CurrentCtx ;
754+ ParentContext = &Data ;
707755
708756 switch (Ty) {
709757 case Root:
710- renderRoot (CurrentCtx , OS);
758+ renderRoot (Data , OS);
711759 return ;
712760 case Text:
713761 renderText (OS);
714762 return ;
715763 case Partial:
716- renderPartial (CurrentCtx , OS);
764+ renderPartial (Data , OS);
717765 return ;
718766 case Variable:
719- renderVariable (CurrentCtx , OS);
767+ renderVariable (Data , OS);
720768 return ;
721769 case UnescapeVariable:
722- renderUnescapeVariable (CurrentCtx , OS);
770+ renderUnescapeVariable (Data , OS);
723771 return ;
724772 case Section:
725- renderSection (CurrentCtx , OS);
773+ renderSection (Data , OS);
726774 return ;
727775 case InvertSection:
728- renderInvertSection (CurrentCtx , OS);
776+ renderInvertSection (Data , OS);
729777 return ;
730778 }
731779 llvm_unreachable (" Invalid ASTNode type" );
732780}
733781
734782const json::Value *ASTNode::findContext () {
783+ LLVM_DEBUG (dbgs () << " findContext: AccessorValue[0]=" << AccessorValue[0 ]
784+ << " \n " );
735785 // The mustache spec allows for dot notation to access nested values
736786 // a single dot refers to the current context.
737787 // We attempt to find the JSON context in the current node, if it is not
@@ -746,12 +796,22 @@ const json::Value *ASTNode::findContext() {
746796 StringRef CurrentAccessor = AccessorValue[0 ];
747797 ASTNode *CurrentParent = Parent;
748798
799+ LLVM_DEBUG (dbgs () << " findContext: ParentContext: " ;
800+ if (ParentContext) ParentContext->print (dbgs ());
801+ else dbgs () << " nullptr" ; dbgs () << " \n " );
802+
749803 while (!CurrentContext || !CurrentContext->get (CurrentAccessor)) {
804+ LLVM_DEBUG (dbgs () << " findContext: climbing parent\n " );
750805 if (CurrentParent->Ty != Root) {
751806 CurrentContext = CurrentParent->ParentContext ->getAsObject ();
752807 CurrentParent = CurrentParent->Parent ;
808+ LLVM_DEBUG (dbgs () << " findContext: new ParentContext: " ;
809+ if (CurrentParent->ParentContext )
810+ CurrentParent->ParentContext ->print (dbgs ());
811+ else dbgs () << " nullptr" ; dbgs () << " \n " );
753812 continue ;
754813 }
814+ LLVM_DEBUG (dbgs () << " findContext: reached root, not found\n " );
755815 return nullptr ;
756816 }
757817 const json::Value *Context = nullptr ;
@@ -767,22 +827,28 @@ const json::Value *ASTNode::findContext() {
767827 Context = CurrentValue;
768828 }
769829 }
830+ LLVM_DEBUG (dbgs () << " findContext: found value: " ;
831+ if (Context) Context->print (dbgs ()); else dbgs () << " nullptr" ;
832+ dbgs () << " \n " );
770833 return Context;
771834}
772835
773- void ASTNode::renderChild (const json::Value &Contexts, llvm::raw_ostream &OS) {
836+ void ASTNode::renderChild (const json::Value &Contexts,
837+ MustacheOutputStream &OS) {
774838 for (AstPtr &Child : Children)
775839 Child->render (Contexts, OS);
776840}
777841
778- void ASTNode::renderPartial (const json::Value &Contexts, llvm::raw_ostream &OS,
779- ASTNode *Partial) {
842+ void ASTNode::renderPartial (const json::Value &Contexts,
843+ MustacheOutputStream &OS, ASTNode *Partial) {
844+ LLVM_DEBUG (dbgs () << " renderPartial (helper): Indentation=" << Indentation
845+ << " \n " );
780846 AddIndentationStringStream IS (OS, Indentation);
781847 Partial->render (Contexts, IS);
782848}
783849
784- void ASTNode::renderLambdas (const json::Value &Contexts, llvm::raw_ostream &OS,
785- Lambda &L) {
850+ void ASTNode::renderLambdas (const json::Value &Contexts,
851+ MustacheOutputStream &OS, Lambda &L) {
786852 json::Value LambdaResult = L ();
787853 std::string LambdaStr;
788854 raw_string_ostream Output (LambdaStr);
@@ -799,7 +865,7 @@ void ASTNode::renderLambdas(const json::Value &Contexts, llvm::raw_ostream &OS,
799865}
800866
801867void ASTNode::renderSectionLambdas (const json::Value &Contexts,
802- llvm::raw_ostream &OS, SectionLambda &L) {
868+ MustacheOutputStream &OS, SectionLambda &L) {
803869 json::Value Return = L (RawBody);
804870 if (isFalsey (Return))
805871 return ;
@@ -812,7 +878,8 @@ void ASTNode::renderSectionLambdas(const json::Value &Contexts,
812878}
813879
814880void Template::render (const json::Value &Data, llvm::raw_ostream &OS) {
815- Tree->render (Data, OS);
881+ RawMustacheOutputStream MOS (OS);
882+ Tree->render (Data, MOS);
816883}
817884
818885void Template::registerPartial (std::string Name, std::string Partial) {
0 commit comments