@@ -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=" 
537+                         << " , C='" " ', 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: \" " " \"\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=" 0 ]
688+                     << " , 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=" 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]=" 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=" 
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