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();
309 size_t DelimiterStart =
Template.find(Open);
315 if (DelimiterStart != Start)
317 size_t DelimiterEnd =
Template.find(Close, DelimiterStart);
322 size_t InterpolatedStart = DelimiterStart + Open.
size();
323 size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.
size();
324 std::string Interpolated =
325 Template.substr(InterpolatedStart, InterpolatedEnd).str();
326 std::string RawBody = Open.
str() + Interpolated + Close.
str();
327 Tokens.
emplace_back(RawBody, Interpolated, Interpolated[0]);
328 Start = DelimiterEnd + Close.
size();
329 DelimiterStart =
Template.find(Open, Start);
349 size_t LastIdx = Tokens.
size() - 1;
350 for (
size_t Idx = 0, End = Tokens.
size(); Idx < End; ++Idx) {
351 Token &CurrentToken = Tokens[Idx];
356 if (!RequiresCleanUp)
369 if ((!HasTextAhead && !HasTextBehind) || (!HasTextAhead && Idx == 0))
372 if ((!HasTextBehind && !HasTextAhead) || (!HasTextBehind && Idx == LastIdx))
383 : Escape(Escape), WrappedStream(WrappedStream) {
390 for (
char C :
Data) {
391 auto It = Escape.find(
C);
392 if (It != Escape.end())
393 WrappedStream << It->getSecond();
411 : Indentation(Indentation), WrappedStream(WrappedStream) {
419 Indent.
resize(Indentation,
' ');
420 for (
char C :
Data) {
423 WrappedStream << Indent;
461 parseMustache(RootNode.get(), Partials, Lambdas, SectionLambdas, Escapes);
470 while (CurrentPtr < Tokens.size()) {
471 Token CurrentToken = Tokens[CurrentPtr];
476 switch (CurrentToken.
getType()) {
479 Partials, Lambdas, SectionLambdas, Escapes);
480 Parent->
addChild(std::move(CurrentNode));
485 Partials, Lambdas, SectionLambdas, Escapes);
486 Parent->
addChild(std::move(CurrentNode));
491 Partials, Lambdas, SectionLambdas, Escapes);
492 Parent->
addChild(std::move(CurrentNode));
497 Lambdas, SectionLambdas, Escapes);
499 Parent->
addChild(std::move(CurrentNode));
504 SectionLambdas, Escapes);
505 size_t Start = CurrentPtr;
506 parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
508 const size_t End = CurrentPtr - 1;
510 for (std::size_t
I = Start;
I < End;
I++)
511 RawBody += Tokens[
I].RawBody;
512 CurrentNode->setRawBody(std::move(RawBody));
513 Parent->
addChild(std::move(CurrentNode));
518 Lambdas, SectionLambdas, Escapes);
519 size_t Start = CurrentPtr;
520 parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
522 const size_t End = CurrentPtr - 1;
524 for (
size_t Idx = Start; Idx < End; Idx++)
525 RawBody += Tokens[Idx].RawBody;
526 CurrentNode->setRawBody(std::move(RawBody));
527 Parent->
addChild(std::move(CurrentNode));
538 switch (
Data.kind()) {
542 auto Num = *
Data.getAsNumber();
543 std::ostringstream SS;
549 auto Str = *
Data.getAsString();
555 auto Arr = *
Data.getAsArray();
572 ParentContext = &CurrentCtx;
573 const json::Value *ContextPtr = Ty ==
Root ? ParentContext : findContext();
577 renderChild(CurrentCtx, OS);
583 auto Partial = Partials.find(AccessorValue[0]);
585 renderPartial(CurrentCtx, OS,
Partial->getValue().get());
589 auto Lambda = Lambdas.find(AccessorValue[0]);
590 if (
Lambda != Lambdas.end()) {
591 renderLambdas(CurrentCtx, OS,
Lambda->getValue());
592 }
else if (ContextPtr) {
599 auto Lambda = Lambdas.find(AccessorValue[0]);
600 if (
Lambda != Lambdas.end()) {
601 renderLambdas(CurrentCtx, OS,
Lambda->getValue());
602 }
else if (ContextPtr) {
612 renderSectionLambdas(CurrentCtx, OS,
SectionLambda->getValue());
616 if (isContextFalsey(ContextPtr))
624 renderChild(*ContextPtr, OS);
628 bool IsLambda = SectionLambdas.contains(AccessorValue[0]);
629 if (isContextFalsey(ContextPtr) && !IsLambda) {
632 renderChild(CurrentCtx, OS);
646 if (AccessorValue.empty())
648 if (AccessorValue[0] ==
".")
649 return ParentContext;
652 StringRef CurrentAccessor = AccessorValue[0];
653 ASTNode *CurrentParent = Parent;
655 while (!CurrentContext || !CurrentContext->
get(CurrentAccessor)) {
656 if (CurrentParent->Ty !=
Root) {
657 CurrentContext = CurrentParent->ParentContext->
getAsObject();
658 CurrentParent = CurrentParent->Parent;
664 for (
auto [Idx, Acc] :
enumerate(AccessorValue)) {
668 if (Idx < AccessorValue.size() - 1) {
679void ASTNode::renderChild(
const json::Value &Contexts, llvm::raw_ostream &OS) {
680 for (
AstPtr &Child : Children)
681 Child->render(Contexts, OS);
684void ASTNode::renderPartial(
const json::Value &Contexts, llvm::raw_ostream &OS,
686 AddIndentationStringStream IS(OS, Indentation);
690void ASTNode::renderLambdas(
const json::Value &Contexts, llvm::raw_ostream &OS,
692 json::Value LambdaResult =
L();
693 std::string LambdaStr;
694 raw_string_ostream Output(LambdaStr);
696 Parser
P = Parser(LambdaStr);
697 AstPtr LambdaNode =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
699 EscapeStringStream ES(OS, Escapes);
701 LambdaNode->render(Contexts, ES);
704 LambdaNode->render(Contexts, OS);
707void ASTNode::renderSectionLambdas(
const json::Value &Contexts,
709 json::Value
Return =
L(RawBody);
710 if (isFalsey(Return))
712 std::string LambdaStr;
713 raw_string_ostream Output(LambdaStr);
715 Parser
P = Parser(LambdaStr);
716 AstPtr LambdaNode =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
717 LambdaNode->render(Contexts, OS);
721 Tree->render(
Data, OS);
726 AstPtr PartialTree =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
727 Partials.insert(std::make_pair(Name, std::move(PartialTree)));
733 SectionLambdas[Name] = L;
740 Tree =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
742 const EscapeMap HtmlEntities = {{
'&',
"&"},
751 : Partials(std::move(
Other.Partials)), Lambdas(std::move(
Other.Lambdas)),
752 SectionLambdas(std::move(
Other.SectionLambdas)),
753 Escapes(std::move(
Other.Escapes)), Tree(std::move(
Other.Tree)) {}
758 if (
this != &
Other) {
759 Partials = std::move(
Other.Partials);
760 Lambdas = std::move(
Other.Lambdas);
761 SectionLambdas = std::move(
Other.SectionLambdas);
762 Escapes = std::move(
Other.Escapes);
763 Tree = std::move(
Other.Tree);
764 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.