21 return V.getAsNull() || (V.getAsBoolean() && !V.getAsBoolean().value()) ||
22 (V.getAsArray() && V.getAsArray()->empty());
32static Accessor splitMustacheString(
StringRef Str) {
40 Tokens.emplace_back(Str);
43 while (!Str.empty()) {
45 std::tie(Part, Str) = Str.
split(
".");
46 Tokens.emplace_back(Part.
trim());
79 AccessorStr = AccessorStr.
substr(1);
135 : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
136 Escapes(Escapes), Ty(
Type::
Root), Parent(nullptr),
137 ParentContext(nullptr) {}
142 : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
143 Escapes(Escapes), Ty(
Type::
Text), Body(
std::
move(Body)), Parent(Parent),
144 ParentContext(nullptr) {}
150 : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
151 Escapes(Escapes), Ty(Ty), Parent(Parent),
152 AccessorValue(
std::
move(Accessor)), ParentContext(nullptr) {}
156 void setRawBody(std::string NewBody) { RawBody = std::move(NewBody); };
181 size_t Indentation = 0;
186 std::vector<AstPtr> Children;
187 const Accessor AccessorValue;
196 return std::make_unique<ASTNode>(Partials, Lambdas, SectionLambdas, Escapes);
204 return std::make_unique<ASTNode>(
T, std::move(
A), Parent, Partials, Lambdas,
205 SectionLambdas, Escapes);
213 return std::make_unique<ASTNode>(std::move(Body), Parent, Partials, Lambdas,
214 SectionLambdas, Escapes);
233 size_t PrevIdx = Idx - 1;
237 const Token &PrevToken = Tokens[PrevIdx];
239 return !TokenBody.
ends_with(
"\n") && !(TokenBody.
empty() && Idx == 1);
246 if (Idx >= Tokens.
size() - 1)
249 size_t NextIdx = Idx + 1;
253 const Token &NextToken = Tokens[NextIdx];
272 Token &NextToken = Tokens[Idx + 1];
291 Token &PrevToken = Tokens[Idx - 1];
294 size_t Indentation = PrevTokenBody.
size() - Unindented.
size();
311 size_t DelimiterStart =
Template.find(Open);
317 if (DelimiterStart != Start)
320 if (
Template.substr(DelimiterStart).starts_with(TripleOpen)) {
321 size_t DelimiterEnd =
Template.find(TripleClose, DelimiterStart);
324 size_t BodyStart = DelimiterStart + TripleOpen.
size();
326 Template.substr(BodyStart, DelimiterEnd - BodyStart).str();
327 std::string RawBody =
328 Template.substr(DelimiterStart, DelimiterEnd - DelimiterStart + 3)
331 Start = DelimiterEnd + TripleClose.
size();
333 size_t DelimiterEnd =
Template.find(Close, DelimiterStart);
338 size_t InterpolatedStart = DelimiterStart + Open.
size();
339 size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.
size();
340 std::string Interpolated =
341 Template.substr(InterpolatedStart, InterpolatedEnd).str();
342 std::string RawBody = Open.
str() + Interpolated + Close.
str();
343 Tokens.
emplace_back(RawBody, Interpolated, Interpolated[0]);
344 Start = DelimiterEnd + Close.
size();
346 DelimiterStart =
Template.find(Open, Start);
366 size_t LastIdx = Tokens.
size() - 1;
367 for (
size_t Idx = 0, End = Tokens.
size(); Idx < End; ++Idx) {
368 Token &CurrentToken = Tokens[Idx];
373 if (!RequiresCleanUp)
386 if ((!HasTextAhead && !HasTextBehind) || (!HasTextAhead && Idx == 0))
389 if ((!HasTextBehind && !HasTextAhead) || (!HasTextBehind && Idx == LastIdx))
400 : Escape(Escape), WrappedStream(WrappedStream) {
407 for (
char C :
Data) {
408 auto It = Escape.find(
C);
409 if (It != Escape.end())
410 WrappedStream << It->getSecond();
428 : Indentation(Indentation), WrappedStream(WrappedStream) {
436 Indent.
resize(Indentation,
' ');
437 for (
char C :
Data) {
440 WrappedStream << Indent;
478 parseMustache(RootNode.get(), Partials, Lambdas, SectionLambdas, Escapes);
487 while (CurrentPtr < Tokens.size()) {
488 Token CurrentToken = Tokens[CurrentPtr];
493 switch (CurrentToken.
getType()) {
496 Partials, Lambdas, SectionLambdas, Escapes);
497 Parent->
addChild(std::move(CurrentNode));
502 Partials, Lambdas, SectionLambdas, Escapes);
503 Parent->
addChild(std::move(CurrentNode));
508 Partials, Lambdas, SectionLambdas, Escapes);
509 Parent->
addChild(std::move(CurrentNode));
514 Lambdas, SectionLambdas, Escapes);
516 Parent->
addChild(std::move(CurrentNode));
521 SectionLambdas, Escapes);
522 size_t Start = CurrentPtr;
523 parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
525 const size_t End = CurrentPtr - 1;
527 for (std::size_t
I = Start;
I < End;
I++)
528 RawBody += Tokens[
I].RawBody;
529 CurrentNode->setRawBody(std::move(RawBody));
530 Parent->
addChild(std::move(CurrentNode));
535 Lambdas, SectionLambdas, Escapes);
536 size_t Start = CurrentPtr;
537 parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
539 const size_t End = CurrentPtr - 1;
541 for (
size_t Idx = Start; Idx < End; Idx++)
542 RawBody += Tokens[Idx].RawBody;
543 CurrentNode->setRawBody(std::move(RawBody));
544 Parent->
addChild(std::move(CurrentNode));
555 switch (
Data.kind()) {
559 auto Num = *
Data.getAsNumber();
560 std::ostringstream SS;
566 auto Str = *
Data.getAsString();
572 auto Arr = *
Data.getAsArray();
589 ParentContext = &CurrentCtx;
590 const json::Value *ContextPtr = Ty ==
Root ? ParentContext : findContext();
594 renderChild(CurrentCtx, OS);
600 auto Partial = Partials.find(AccessorValue[0]);
602 renderPartial(CurrentCtx, OS,
Partial->getValue().get());
606 auto Lambda = Lambdas.find(AccessorValue[0]);
607 if (
Lambda != Lambdas.end()) {
608 renderLambdas(CurrentCtx, OS,
Lambda->getValue());
609 }
else if (ContextPtr) {
616 auto Lambda = Lambdas.find(AccessorValue[0]);
617 if (
Lambda != Lambdas.end()) {
618 renderLambdas(CurrentCtx, OS,
Lambda->getValue());
619 }
else if (ContextPtr) {
629 renderSectionLambdas(CurrentCtx, OS,
SectionLambda->getValue());
633 if (isContextFalsey(ContextPtr))
641 renderChild(*ContextPtr, OS);
645 bool IsLambda = SectionLambdas.contains(AccessorValue[0]);
646 if (isContextFalsey(ContextPtr) && !IsLambda) {
649 renderChild(CurrentCtx, OS);
663 if (AccessorValue.empty())
665 if (AccessorValue[0] ==
".")
666 return ParentContext;
669 StringRef CurrentAccessor = AccessorValue[0];
670 ASTNode *CurrentParent = Parent;
672 while (!CurrentContext || !CurrentContext->
get(CurrentAccessor)) {
673 if (CurrentParent->Ty !=
Root) {
674 CurrentContext = CurrentParent->ParentContext->
getAsObject();
675 CurrentParent = CurrentParent->Parent;
681 for (
auto [Idx, Acc] :
enumerate(AccessorValue)) {
685 if (Idx < AccessorValue.size() - 1) {
696void ASTNode::renderChild(
const json::Value &Contexts, llvm::raw_ostream &OS) {
697 for (
AstPtr &Child : Children)
698 Child->render(Contexts, OS);
701void ASTNode::renderPartial(
const json::Value &Contexts, llvm::raw_ostream &OS,
703 AddIndentationStringStream IS(OS, Indentation);
707void ASTNode::renderLambdas(
const json::Value &Contexts, llvm::raw_ostream &OS,
709 json::Value LambdaResult =
L();
710 std::string LambdaStr;
711 raw_string_ostream Output(LambdaStr);
713 Parser
P = Parser(LambdaStr);
714 AstPtr LambdaNode =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
716 EscapeStringStream ES(OS, Escapes);
718 LambdaNode->render(Contexts, ES);
721 LambdaNode->render(Contexts, OS);
724void ASTNode::renderSectionLambdas(
const json::Value &Contexts,
726 json::Value
Return =
L(RawBody);
727 if (isFalsey(Return))
729 std::string LambdaStr;
730 raw_string_ostream Output(LambdaStr);
732 Parser
P = Parser(LambdaStr);
733 AstPtr LambdaNode =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
734 LambdaNode->render(Contexts, OS);
738 Tree->render(
Data, OS);
743 AstPtr PartialTree =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
744 Partials.insert(std::make_pair(Name, std::move(PartialTree)));
750 SectionLambdas[Name] = L;
757 Tree =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
759 const EscapeMap HtmlEntities = {{
'&',
"&"},
768 : Partials(std::move(
Other.Partials)), Lambdas(std::move(
Other.Lambdas)),
769 SectionLambdas(std::move(
Other.SectionLambdas)),
770 Escapes(std::move(
Other.Escapes)), Tree(std::move(
Other.Tree)) {}
775 if (
this != &
Other) {
776 Partials = std::move(
Other.Partials);
777 Lambdas = std::move(
Other.Lambdas);
778 SectionLambdas = std::move(
Other.SectionLambdas);
779 Escapes = std::move(
Other.Escapes);
780 Tree = std::move(
Other.Tree);
781 Other.Tree =
nullptr;
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file defines the SmallVector class.
static SymbolRef::Type getType(const Symbol *Sym)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
constexpr size_t size() const
size - Get the string size.
StringRef ltrim(char Char) const
Return string with consecutive Char characters starting from the the left removed.
StringRef rtrim(char Char) const
Return string with consecutive Char characters starting from the right removed.
StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
static constexpr size_t npos
The instances of the Type class are immutable: once they are created, they are never changed.
An Array is a JSON array, which contains heterogeneous JSON values.
json::OStream allows writing well-formed JSON without materializing all structures as json::Value ahe...
LLVM_ABI void value(const Value &V)
Emit a self-contained value (number, string, vector<string> etc).
An Object is a JSON object, which maps strings to heterogenous JSON values.
LLVM_ABI Value * get(StringRef K)
A Value is an JSON value of unknown type.
@ Number
Number values can store both int64s and doubles at full precision, depending on what they were constr...
const json::Object * getAsObject() const
const json::Array * getAsArray() const
ASTNode(Type Ty, Accessor Accessor, ASTNode *Parent, llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
void render(const llvm::json::Value &Data, llvm::raw_ostream &OS)
void setIndentation(size_t NewIndentation)
ASTNode(std::string Body, ASTNode *Parent, llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
void addChild(AstPtr Child)
void setRawBody(std::string NewBody)
ASTNode(llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
uint64_t current_pos() const override
Return the current position within the stream, not counting the bytes currently in the buffer.
AddIndentationStringStream(llvm::raw_ostream &WrappedStream, size_t Indentation)
void write_impl(const char *Ptr, size_t Size) override
The is the piece of the class that is implemented by subclasses.
uint64_t current_pos() const override
Return the current position within the stream, not counting the bytes currently in the buffer.
void write_impl(const char *Ptr, size_t Size) override
The is the piece of the class that is implemented by subclasses.
EscapeStringStream(llvm::raw_ostream &WrappedStream, EscapeMap &Escape)
AstPtr parse(llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
Parser(StringRef TemplateStr)
LLVM_ABI void registerPartial(std::string Name, std::string Partial)
Template & operator=(const Template &)=delete
LLVM_ABI void registerLambda(std::string Name, Lambda Lambda)
LLVM_ABI Template(StringRef TemplateStr)
LLVM_ABI void render(const llvm::json::Value &Data, llvm::raw_ostream &OS)
LLVM_ABI void overrideEscapeCharacters(DenseMap< char, std::string > Escapes)
size_t getIndentation() const
void setIndentation(size_t NewIndentation)
static Type getTokenType(char Identifier)
Token(std::string RawBody, std::string TokenBody, char Identifier)
Accessor getAccessor() const
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream(bool unbuffered=false, OStreamKind K=OStreamKind::OK_OStream)
void SetUnbuffered()
Set the stream to be unbuffered.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
AstPtr createRootNode(llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
std::unique_ptr< ASTNode > AstPtr
void stripTokenAhead(SmallVectorImpl< Token > &Tokens, size_t Idx)
bool hasTextAhead(size_t Idx, const ArrayRef< Token > &Tokens)
DenseMap< char, std::string > EscapeMap
void stripTokenBefore(SmallVectorImpl< Token > &Tokens, size_t Idx, Token &CurrentToken, Token::Type CurrentType)
void toMustacheString(const json::Value &Data, raw_ostream &OS)
std::function< llvm::json::Value(std::string)> SectionLambda
std::function< llvm::json::Value()> Lambda
AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent, llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
bool requiresCleanUp(Token::Type T)
AstPtr createTextNode(std::string Body, ASTNode *Parent, llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
SmallVector< Token > tokenize(StringRef Template)
bool hasTextBehind(size_t Idx, const ArrayRef< Token > &Tokens)
This is an optimization pass for GlobalISel generic memory operations.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
FunctionAddr VTableAddr uintptr_t uintptr_t Data
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Implement std::hash so that hash_code can be used in STL containers.