@@ -56,6 +56,33 @@ static Accessor splitMustacheString(StringRef Str) {
5656
5757namespace llvm ::mustache {
5858
59+ class MustacheOutputStream : public raw_ostream {
60+ public:
61+ MustacheOutputStream () = default ;
62+ ~MustacheOutputStream () override = default ;
63+
64+ virtual void suspendIndentation () {}
65+ virtual void resumeIndentation () {}
66+
67+ private:
68+ void anchor () override ;
69+ };
70+
71+ void MustacheOutputStream::anchor () {}
72+
73+ class RawMustacheOutputStream : public MustacheOutputStream {
74+ public:
75+ RawMustacheOutputStream (raw_ostream &OS) : OS(OS) { SetUnbuffered (); }
76+
77+ private:
78+ raw_ostream &OS;
79+
80+ void write_impl (const char *Ptr, size_t Size) override {
81+ OS.write (Ptr, Size);
82+ }
83+ uint64_t current_pos () const override { return OS.tell (); }
84+ };
85+
5986class Token {
6087public:
6188 enum class Type {
@@ -156,29 +183,31 @@ class ASTNode {
156183
157184 void setIndentation (size_t NewIndentation) { Indentation = NewIndentation; };
158185
159- void render (const llvm::json::Value &Data, llvm::raw_ostream &OS);
186+ void render (const llvm::json::Value &Data, MustacheOutputStream &OS);
160187
161188private:
162- void renderLambdas (const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
163- Lambda &L);
189+ void renderLambdas (const llvm::json::Value &Contexts,
190+ MustacheOutputStream &OS, Lambda &L);
164191
165192 void renderSectionLambdas (const llvm::json::Value &Contexts,
166- llvm::raw_ostream &OS, SectionLambda &L);
193+ MustacheOutputStream &OS, SectionLambda &L);
167194
168- void renderPartial (const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
169- ASTNode *Partial);
195+ void renderPartial (const llvm::json::Value &Contexts,
196+ MustacheOutputStream &OS, ASTNode *Partial);
170197
171- void renderChild (const llvm::json::Value &Context, llvm::raw_ostream &OS);
198+ void renderChild (const llvm::json::Value &Context, MustacheOutputStream &OS);
172199
173200 const llvm::json::Value *findContext ();
174201
175- void renderRoot (const json::Value &CurrentCtx, raw_ostream &OS);
176- void renderText (raw_ostream &OS);
177- void renderPartial (const json::Value &CurrentCtx, raw_ostream &OS);
178- void renderVariable (const json::Value &CurrentCtx, raw_ostream &OS);
179- void renderUnescapeVariable (const json::Value &CurrentCtx, raw_ostream &OS);
180- void renderSection (const json::Value &CurrentCtx, raw_ostream &OS);
181- void renderInvertSection (const json::Value &CurrentCtx, raw_ostream &OS);
202+ void renderRoot (const json::Value &CurrentCtx, MustacheOutputStream &OS);
203+ void renderText (MustacheOutputStream &OS);
204+ void renderPartial (const json::Value &CurrentCtx, MustacheOutputStream &OS);
205+ void renderVariable (const json::Value &CurrentCtx, MustacheOutputStream &OS);
206+ void renderUnescapeVariable (const json::Value &CurrentCtx,
207+ MustacheOutputStream &OS);
208+ void renderSection (const json::Value &CurrentCtx, MustacheOutputStream &OS);
209+ void renderInvertSection (const json::Value &CurrentCtx,
210+ MustacheOutputStream &OS);
182211
183212 MustacheContext &Ctx;
184213 Type Ty;
@@ -455,7 +484,7 @@ static SmallVector<Token> tokenize(StringRef Template) {
455484}
456485
457486// Custom stream to escape strings.
458- class EscapeStringStream : public raw_ostream {
487+ class EscapeStringStream : public MustacheOutputStream {
459488public:
460489 explicit EscapeStringStream (llvm::raw_ostream &WrappedStream,
461490 EscapeMap &Escape)
@@ -497,28 +526,34 @@ class EscapeStringStream : public raw_ostream {
497526};
498527
499528// Custom stream to add indentation used to for rendering partials.
500- class AddIndentationStringStream : public raw_ostream {
529+ class AddIndentationStringStream : public MustacheOutputStream {
501530public:
502- explicit AddIndentationStringStream (llvm:: raw_ostream &WrappedStream,
531+ explicit AddIndentationStringStream (raw_ostream &WrappedStream,
503532 size_t Indentation)
504533 : Indentation(Indentation), WrappedStream(WrappedStream),
505- NeedsIndent(true ) {
534+ NeedsIndent(true ), IsSuspended( false ) {
506535 SetUnbuffered ();
507536 }
508537
538+ void suspendIndentation () override { IsSuspended = true ; }
539+ void resumeIndentation () override { IsSuspended = false ; }
540+
509541protected:
510542 void write_impl (const char *Ptr, size_t Size) override {
511543 llvm::StringRef Data (Ptr, Size);
512544 SmallString<0 > Indent;
513545 Indent.resize (Indentation, ' ' );
514546
515547 for (char C : Data) {
548+ LLVM_DEBUG (dbgs () << " IndentationStream: NeedsIndent=" << NeedsIndent
549+ << " , C='" << C << " ', Indentation=" << Indentation
550+ << " \n " );
516551 if (NeedsIndent && C != ' \n ' ) {
517552 WrappedStream << Indent;
518553 NeedsIndent = false ;
519554 }
520555 WrappedStream << C;
521- if (C == ' \n ' )
556+ if (C == ' \n ' && !IsSuspended )
522557 NeedsIndent = true ;
523558 }
524559 }
@@ -527,8 +562,9 @@ class AddIndentationStringStream : public raw_ostream {
527562
528563private:
529564 size_t Indentation;
530- llvm:: raw_ostream &WrappedStream;
565+ raw_ostream &WrappedStream;
531566 bool NeedsIndent;
567+ bool IsSuspended;
532568};
533569
534570class Parser {
@@ -618,6 +654,7 @@ void Parser::parseMustache(ASTNode *Parent) {
618654 }
619655}
620656static void toMustacheString (const json::Value &Data, raw_ostream &OS) {
657+ LLVM_DEBUG (dbgs () << " toMustacheString: kind=" << (int )Data.kind () << " \n " );
621658 switch (Data.kind ()) {
622659 case json::Value::Null:
623660 return ;
@@ -630,6 +667,7 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
630667 }
631668 case json::Value::String: {
632669 auto Str = *Data.getAsString ();
670+ LLVM_DEBUG (dbgs () << " --> writing string: \" " << Str << " \"\n " );
633671 OS << Str.str ();
634672 return ;
635673 }
@@ -649,19 +687,24 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
649687 }
650688}
651689
652- void ASTNode::renderRoot (const json::Value &CurrentCtx, raw_ostream &OS) {
690+ void ASTNode::renderRoot (const json::Value &CurrentCtx,
691+ MustacheOutputStream &OS) {
653692 renderChild (CurrentCtx, OS);
654693}
655694
656- void ASTNode::renderText (raw_ostream &OS) { OS << Body; }
695+ void ASTNode::renderText (MustacheOutputStream &OS) { OS << Body; }
657696
658- void ASTNode::renderPartial (const json::Value &CurrentCtx, raw_ostream &OS) {
697+ void ASTNode::renderPartial (const json::Value &CurrentCtx,
698+ MustacheOutputStream &OS) {
699+ LLVM_DEBUG (dbgs () << " renderPartial: Accessor=" << AccessorValue[0 ]
700+ << " , Indentation=" << Indentation << " \n " );
659701 auto Partial = Ctx.Partials .find (AccessorValue[0 ]);
660702 if (Partial != Ctx.Partials .end ())
661703 renderPartial (CurrentCtx, OS, Partial->getValue ().get ());
662704}
663705
664- void ASTNode::renderVariable (const json::Value &CurrentCtx, raw_ostream &OS) {
706+ void ASTNode::renderVariable (const json::Value &CurrentCtx,
707+ MustacheOutputStream &OS) {
665708 auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
666709 if (Lambda != Ctx.Lambdas .end ()) {
667710 renderLambdas (CurrentCtx, OS, Lambda->getValue ());
@@ -672,16 +715,22 @@ void ASTNode::renderVariable(const json::Value &CurrentCtx, raw_ostream &OS) {
672715}
673716
674717void ASTNode::renderUnescapeVariable (const json::Value &CurrentCtx,
675- raw_ostream &OS) {
718+ MustacheOutputStream &OS) {
719+ LLVM_DEBUG (dbgs () << " renderUnescapeVariable: Accessor=" << AccessorValue[0 ]
720+ << " \n " );
676721 auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
677722 if (Lambda != Ctx.Lambdas .end ()) {
678723 renderLambdas (CurrentCtx, OS, Lambda->getValue ());
679724 } else if (const json::Value *ContextPtr = findContext ()) {
725+ LLVM_DEBUG (dbgs () << " --> Found context value, writing to stream.\n " );
726+ OS.suspendIndentation ();
680727 toMustacheString (*ContextPtr, OS);
728+ OS.resumeIndentation ();
681729 }
682730}
683731
684- void ASTNode::renderSection (const json::Value &CurrentCtx, raw_ostream &OS) {
732+ void ASTNode::renderSection (const json::Value &CurrentCtx,
733+ MustacheOutputStream &OS) {
685734 auto SectionLambda = Ctx.SectionLambdas .find (AccessorValue[0 ]);
686735 if (SectionLambda != Ctx.SectionLambdas .end ()) {
687736 renderSectionLambdas (CurrentCtx, OS, SectionLambda->getValue ());
@@ -701,48 +750,50 @@ void ASTNode::renderSection(const json::Value &CurrentCtx, raw_ostream &OS) {
701750}
702751
703752void ASTNode::renderInvertSection (const json::Value &CurrentCtx,
704- raw_ostream &OS) {
753+ MustacheOutputStream &OS) {
705754 bool IsLambda = Ctx.SectionLambdas .contains (AccessorValue[0 ]);
706755 const json::Value *ContextPtr = findContext ();
707756 if (isContextFalsey (ContextPtr) && !IsLambda) {
708757 renderChild (CurrentCtx, OS);
709758 }
710759}
711760
712- void ASTNode::render (const json::Value &CurrentCtx, raw_ostream &OS) {
761+ void ASTNode::render (const llvm:: json::Value &Data, MustacheOutputStream &OS) {
713762 if (Ty != Root && Ty != Text && AccessorValue.empty ())
714763 return ;
715764 // Set the parent context to the incoming context so that we
716765 // can walk up the context tree correctly in findContext().
717- ParentContext = &CurrentCtx ;
766+ ParentContext = &Data ;
718767
719768 switch (Ty) {
720769 case Root:
721- renderRoot (CurrentCtx , OS);
770+ renderRoot (Data , OS);
722771 return ;
723772 case Text:
724773 renderText (OS);
725774 return ;
726775 case Partial:
727- renderPartial (CurrentCtx , OS);
776+ renderPartial (Data , OS);
728777 return ;
729778 case Variable:
730- renderVariable (CurrentCtx , OS);
779+ renderVariable (Data , OS);
731780 return ;
732781 case UnescapeVariable:
733- renderUnescapeVariable (CurrentCtx , OS);
782+ renderUnescapeVariable (Data , OS);
734783 return ;
735784 case Section:
736- renderSection (CurrentCtx , OS);
785+ renderSection (Data , OS);
737786 return ;
738787 case InvertSection:
739- renderInvertSection (CurrentCtx , OS);
788+ renderInvertSection (Data , OS);
740789 return ;
741790 }
742791 llvm_unreachable (" Invalid ASTNode type" );
743792}
744793
745794const json::Value *ASTNode::findContext () {
795+ LLVM_DEBUG (dbgs () << " findContext: AccessorValue[0]=" << AccessorValue[0 ]
796+ << " \n " );
746797 // The mustache spec allows for dot notation to access nested values
747798 // a single dot refers to the current context.
748799 // We attempt to find the JSON context in the current node, if it is not
@@ -757,12 +808,22 @@ const json::Value *ASTNode::findContext() {
757808 StringRef CurrentAccessor = AccessorValue[0 ];
758809 ASTNode *CurrentParent = Parent;
759810
811+ LLVM_DEBUG (dbgs () << " findContext: ParentContext: " ;
812+ if (ParentContext) ParentContext->print (dbgs ());
813+ else dbgs () << " nullptr" ; dbgs () << " \n " );
814+
760815 while (!CurrentContext || !CurrentContext->get (CurrentAccessor)) {
816+ LLVM_DEBUG (dbgs () << " findContext: climbing parent\n " );
761817 if (CurrentParent->Ty != Root) {
762818 CurrentContext = CurrentParent->ParentContext ->getAsObject ();
763819 CurrentParent = CurrentParent->Parent ;
820+ LLVM_DEBUG (dbgs () << " findContext: new ParentContext: " ;
821+ if (CurrentParent->ParentContext )
822+ CurrentParent->ParentContext ->print (dbgs ());
823+ else dbgs () << " nullptr" ; dbgs () << " \n " );
764824 continue ;
765825 }
826+ LLVM_DEBUG (dbgs () << " findContext: reached root, not found\n " );
766827 return nullptr ;
767828 }
768829 const json::Value *Context = nullptr ;
@@ -778,22 +839,28 @@ const json::Value *ASTNode::findContext() {
778839 Context = CurrentValue;
779840 }
780841 }
842+ LLVM_DEBUG (dbgs () << " findContext: found value: " ;
843+ if (Context) Context->print (dbgs ()); else dbgs () << " nullptr" ;
844+ dbgs () << " \n " );
781845 return Context;
782846}
783847
784- void ASTNode::renderChild (const json::Value &Contexts, llvm::raw_ostream &OS) {
848+ void ASTNode::renderChild (const json::Value &Contexts,
849+ MustacheOutputStream &OS) {
785850 for (AstPtr &Child : Children)
786851 Child->render (Contexts, OS);
787852}
788853
789- void ASTNode::renderPartial (const json::Value &Contexts, llvm::raw_ostream &OS,
790- ASTNode *Partial) {
854+ void ASTNode::renderPartial (const json::Value &Contexts,
855+ MustacheOutputStream &OS, ASTNode *Partial) {
856+ LLVM_DEBUG (dbgs () << " renderPartial (helper): Indentation=" << Indentation
857+ << " \n " );
791858 AddIndentationStringStream IS (OS, Indentation);
792859 Partial->render (Contexts, IS);
793860}
794861
795- void ASTNode::renderLambdas (const json::Value &Contexts, llvm::raw_ostream &OS,
796- Lambda &L) {
862+ void ASTNode::renderLambdas (const json::Value &Contexts,
863+ MustacheOutputStream &OS, Lambda &L) {
797864 json::Value LambdaResult = L ();
798865 std::string LambdaStr;
799866 raw_string_ostream Output (LambdaStr);
@@ -810,7 +877,7 @@ void ASTNode::renderLambdas(const json::Value &Contexts, llvm::raw_ostream &OS,
810877}
811878
812879void ASTNode::renderSectionLambdas (const json::Value &Contexts,
813- llvm::raw_ostream &OS, SectionLambda &L) {
880+ MustacheOutputStream &OS, SectionLambda &L) {
814881 json::Value Return = L (RawBody);
815882 if (isFalsey (Return))
816883 return ;
@@ -823,7 +890,8 @@ void ASTNode::renderSectionLambdas(const json::Value &Contexts,
823890}
824891
825892void Template::render (const json::Value &Data, llvm::raw_ostream &OS) {
826- Tree->render (Data, OS);
893+ RawMustacheOutputStream MOS (OS);
894+ Tree->render (Data, MOS);
827895}
828896
829897void Template::registerPartial (std::string Name, std::string Partial) {
0 commit comments