@@ -56,6 +56,33 @@ static Accessor splitMustacheString(StringRef Str) {
56
56
57
57
namespace llvm ::mustache {
58
58
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
+
59
86
class Token {
60
87
public:
61
88
enum class Type {
@@ -156,29 +183,31 @@ class ASTNode {
156
183
157
184
void setIndentation (size_t NewIndentation) { Indentation = NewIndentation; };
158
185
159
- void render (const llvm::json::Value &Data, llvm::raw_ostream &OS);
186
+ void render (const llvm::json::Value &Data, MustacheOutputStream &OS);
160
187
161
188
private:
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);
164
191
165
192
void renderSectionLambdas (const llvm::json::Value &Contexts,
166
- llvm::raw_ostream &OS, SectionLambda &L);
193
+ MustacheOutputStream &OS, SectionLambda &L);
167
194
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);
170
197
171
- void renderChild (const llvm::json::Value &Context, llvm::raw_ostream &OS);
198
+ void renderChild (const llvm::json::Value &Context, MustacheOutputStream &OS);
172
199
173
200
const llvm::json::Value *findContext ();
174
201
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);
182
211
183
212
MustacheContext &Ctx;
184
213
Type Ty;
@@ -455,7 +484,7 @@ static SmallVector<Token> tokenize(StringRef Template) {
455
484
}
456
485
457
486
// Custom stream to escape strings.
458
- class EscapeStringStream : public raw_ostream {
487
+ class EscapeStringStream : public MustacheOutputStream {
459
488
public:
460
489
explicit EscapeStringStream (llvm::raw_ostream &WrappedStream,
461
490
EscapeMap &Escape)
@@ -497,28 +526,34 @@ class EscapeStringStream : public raw_ostream {
497
526
};
498
527
499
528
// Custom stream to add indentation used to for rendering partials.
500
- class AddIndentationStringStream : public raw_ostream {
529
+ class AddIndentationStringStream : public MustacheOutputStream {
501
530
public:
502
- explicit AddIndentationStringStream (llvm:: raw_ostream &WrappedStream,
531
+ explicit AddIndentationStringStream (raw_ostream &WrappedStream,
503
532
size_t Indentation)
504
533
: Indentation(Indentation), WrappedStream(WrappedStream),
505
- NeedsIndent(true ) {
534
+ NeedsIndent(true ), IsSuspended( false ) {
506
535
SetUnbuffered ();
507
536
}
508
537
538
+ void suspendIndentation () override { IsSuspended = true ; }
539
+ void resumeIndentation () override { IsSuspended = false ; }
540
+
509
541
protected:
510
542
void write_impl (const char *Ptr, size_t Size) override {
511
543
llvm::StringRef Data (Ptr, Size);
512
544
SmallString<0 > Indent;
513
545
Indent.resize (Indentation, ' ' );
514
546
515
547
for (char C : Data) {
548
+ LLVM_DEBUG (dbgs () << " IndentationStream: NeedsIndent=" << NeedsIndent
549
+ << " , C='" << C << " ', Indentation=" << Indentation
550
+ << " \n " );
516
551
if (NeedsIndent && C != ' \n ' ) {
517
552
WrappedStream << Indent;
518
553
NeedsIndent = false ;
519
554
}
520
555
WrappedStream << C;
521
- if (C == ' \n ' )
556
+ if (C == ' \n ' && !IsSuspended )
522
557
NeedsIndent = true ;
523
558
}
524
559
}
@@ -527,8 +562,9 @@ class AddIndentationStringStream : public raw_ostream {
527
562
528
563
private:
529
564
size_t Indentation;
530
- llvm:: raw_ostream &WrappedStream;
565
+ raw_ostream &WrappedStream;
531
566
bool NeedsIndent;
567
+ bool IsSuspended;
532
568
};
533
569
534
570
class Parser {
@@ -618,6 +654,7 @@ void Parser::parseMustache(ASTNode *Parent) {
618
654
}
619
655
}
620
656
static void toMustacheString (const json::Value &Data, raw_ostream &OS) {
657
+ LLVM_DEBUG (dbgs () << " toMustacheString: kind=" << (int )Data.kind () << " \n " );
621
658
switch (Data.kind ()) {
622
659
case json::Value::Null:
623
660
return ;
@@ -630,6 +667,7 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
630
667
}
631
668
case json::Value::String: {
632
669
auto Str = *Data.getAsString ();
670
+ LLVM_DEBUG (dbgs () << " --> writing string: \" " << Str << " \"\n " );
633
671
OS << Str.str ();
634
672
return ;
635
673
}
@@ -649,19 +687,24 @@ static void toMustacheString(const json::Value &Data, raw_ostream &OS) {
649
687
}
650
688
}
651
689
652
- void ASTNode::renderRoot (const json::Value &CurrentCtx, raw_ostream &OS) {
690
+ void ASTNode::renderRoot (const json::Value &CurrentCtx,
691
+ MustacheOutputStream &OS) {
653
692
renderChild (CurrentCtx, OS);
654
693
}
655
694
656
- void ASTNode::renderText (raw_ostream &OS) { OS << Body; }
695
+ void ASTNode::renderText (MustacheOutputStream &OS) { OS << Body; }
657
696
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 " );
659
701
auto Partial = Ctx.Partials .find (AccessorValue[0 ]);
660
702
if (Partial != Ctx.Partials .end ())
661
703
renderPartial (CurrentCtx, OS, Partial->getValue ().get ());
662
704
}
663
705
664
- void ASTNode::renderVariable (const json::Value &CurrentCtx, raw_ostream &OS) {
706
+ void ASTNode::renderVariable (const json::Value &CurrentCtx,
707
+ MustacheOutputStream &OS) {
665
708
auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
666
709
if (Lambda != Ctx.Lambdas .end ()) {
667
710
renderLambdas (CurrentCtx, OS, Lambda->getValue ());
@@ -672,16 +715,22 @@ void ASTNode::renderVariable(const json::Value &CurrentCtx, raw_ostream &OS) {
672
715
}
673
716
674
717
void ASTNode::renderUnescapeVariable (const json::Value &CurrentCtx,
675
- raw_ostream &OS) {
718
+ MustacheOutputStream &OS) {
719
+ LLVM_DEBUG (dbgs () << " renderUnescapeVariable: Accessor=" << AccessorValue[0 ]
720
+ << " \n " );
676
721
auto Lambda = Ctx.Lambdas .find (AccessorValue[0 ]);
677
722
if (Lambda != Ctx.Lambdas .end ()) {
678
723
renderLambdas (CurrentCtx, OS, Lambda->getValue ());
679
724
} else if (const json::Value *ContextPtr = findContext ()) {
725
+ LLVM_DEBUG (dbgs () << " --> Found context value, writing to stream.\n " );
726
+ OS.suspendIndentation ();
680
727
toMustacheString (*ContextPtr, OS);
728
+ OS.resumeIndentation ();
681
729
}
682
730
}
683
731
684
- void ASTNode::renderSection (const json::Value &CurrentCtx, raw_ostream &OS) {
732
+ void ASTNode::renderSection (const json::Value &CurrentCtx,
733
+ MustacheOutputStream &OS) {
685
734
auto SectionLambda = Ctx.SectionLambdas .find (AccessorValue[0 ]);
686
735
if (SectionLambda != Ctx.SectionLambdas .end ()) {
687
736
renderSectionLambdas (CurrentCtx, OS, SectionLambda->getValue ());
@@ -701,48 +750,50 @@ void ASTNode::renderSection(const json::Value &CurrentCtx, raw_ostream &OS) {
701
750
}
702
751
703
752
void ASTNode::renderInvertSection (const json::Value &CurrentCtx,
704
- raw_ostream &OS) {
753
+ MustacheOutputStream &OS) {
705
754
bool IsLambda = Ctx.SectionLambdas .contains (AccessorValue[0 ]);
706
755
const json::Value *ContextPtr = findContext ();
707
756
if (isContextFalsey (ContextPtr) && !IsLambda) {
708
757
renderChild (CurrentCtx, OS);
709
758
}
710
759
}
711
760
712
- void ASTNode::render (const json::Value &CurrentCtx, raw_ostream &OS) {
761
+ void ASTNode::render (const llvm:: json::Value &Data, MustacheOutputStream &OS) {
713
762
if (Ty != Root && Ty != Text && AccessorValue.empty ())
714
763
return ;
715
764
// Set the parent context to the incoming context so that we
716
765
// can walk up the context tree correctly in findContext().
717
- ParentContext = &CurrentCtx ;
766
+ ParentContext = &Data ;
718
767
719
768
switch (Ty) {
720
769
case Root:
721
- renderRoot (CurrentCtx , OS);
770
+ renderRoot (Data , OS);
722
771
return ;
723
772
case Text:
724
773
renderText (OS);
725
774
return ;
726
775
case Partial:
727
- renderPartial (CurrentCtx , OS);
776
+ renderPartial (Data , OS);
728
777
return ;
729
778
case Variable:
730
- renderVariable (CurrentCtx , OS);
779
+ renderVariable (Data , OS);
731
780
return ;
732
781
case UnescapeVariable:
733
- renderUnescapeVariable (CurrentCtx , OS);
782
+ renderUnescapeVariable (Data , OS);
734
783
return ;
735
784
case Section:
736
- renderSection (CurrentCtx , OS);
785
+ renderSection (Data , OS);
737
786
return ;
738
787
case InvertSection:
739
- renderInvertSection (CurrentCtx , OS);
788
+ renderInvertSection (Data , OS);
740
789
return ;
741
790
}
742
791
llvm_unreachable (" Invalid ASTNode type" );
743
792
}
744
793
745
794
const json::Value *ASTNode::findContext () {
795
+ LLVM_DEBUG (dbgs () << " findContext: AccessorValue[0]=" << AccessorValue[0 ]
796
+ << " \n " );
746
797
// The mustache spec allows for dot notation to access nested values
747
798
// a single dot refers to the current context.
748
799
// We attempt to find the JSON context in the current node, if it is not
@@ -757,12 +808,22 @@ const json::Value *ASTNode::findContext() {
757
808
StringRef CurrentAccessor = AccessorValue[0 ];
758
809
ASTNode *CurrentParent = Parent;
759
810
811
+ LLVM_DEBUG (dbgs () << " findContext: ParentContext: " ;
812
+ if (ParentContext) ParentContext->print (dbgs ());
813
+ else dbgs () << " nullptr" ; dbgs () << " \n " );
814
+
760
815
while (!CurrentContext || !CurrentContext->get (CurrentAccessor)) {
816
+ LLVM_DEBUG (dbgs () << " findContext: climbing parent\n " );
761
817
if (CurrentParent->Ty != Root) {
762
818
CurrentContext = CurrentParent->ParentContext ->getAsObject ();
763
819
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 " );
764
824
continue ;
765
825
}
826
+ LLVM_DEBUG (dbgs () << " findContext: reached root, not found\n " );
766
827
return nullptr ;
767
828
}
768
829
const json::Value *Context = nullptr ;
@@ -778,22 +839,28 @@ const json::Value *ASTNode::findContext() {
778
839
Context = CurrentValue;
779
840
}
780
841
}
842
+ LLVM_DEBUG (dbgs () << " findContext: found value: " ;
843
+ if (Context) Context->print (dbgs ()); else dbgs () << " nullptr" ;
844
+ dbgs () << " \n " );
781
845
return Context;
782
846
}
783
847
784
- void ASTNode::renderChild (const json::Value &Contexts, llvm::raw_ostream &OS) {
848
+ void ASTNode::renderChild (const json::Value &Contexts,
849
+ MustacheOutputStream &OS) {
785
850
for (AstPtr &Child : Children)
786
851
Child->render (Contexts, OS);
787
852
}
788
853
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 " );
791
858
AddIndentationStringStream IS (OS, Indentation);
792
859
Partial->render (Contexts, IS);
793
860
}
794
861
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) {
797
864
json::Value LambdaResult = L ();
798
865
std::string LambdaStr;
799
866
raw_string_ostream Output (LambdaStr);
@@ -810,7 +877,7 @@ void ASTNode::renderLambdas(const json::Value &Contexts, llvm::raw_ostream &OS,
810
877
}
811
878
812
879
void ASTNode::renderSectionLambdas (const json::Value &Contexts,
813
- llvm::raw_ostream &OS, SectionLambda &L) {
880
+ MustacheOutputStream &OS, SectionLambda &L) {
814
881
json::Value Return = L (RawBody);
815
882
if (isFalsey (Return))
816
883
return ;
@@ -823,7 +890,8 @@ void ASTNode::renderSectionLambdas(const json::Value &Contexts,
823
890
}
824
891
825
892
void Template::render (const json::Value &Data, llvm::raw_ostream &OS) {
826
- Tree->render (Data, OS);
893
+ RawMustacheOutputStream MOS (OS);
894
+ Tree->render (Data, MOS);
827
895
}
828
896
829
897
void Template::registerPartial (std::string Name, std::string Partial) {
0 commit comments