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];
249 size_t NextIdx =
Idx + 1;
253 const Token &NextToken = Tokens[NextIdx];
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;
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;
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);
585 renderPartial(CurrentCtx,
OS,
Partial->getValue().get());
591 renderLambdas(CurrentCtx,
OS,
Lambda->getValue());
592 }
else if (ContextPtr) {
601 renderLambdas(CurrentCtx,
OS,
Lambda->getValue());
602 }
else if (ContextPtr) {
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;
668 if (
Idx < AccessorValue.size() - 1) {
680 for (
AstPtr &Child : Children)
681 Child->render(Contexts,
OS);
693 std::string LambdaStr;
697 AstPtr LambdaNode =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
701 LambdaNode->render(Contexts, ES);
704 LambdaNode->render(Contexts,
OS);
707void ASTNode::renderSectionLambdas(
const json::Value &Contexts,
710 if (isFalsey(Return))
712 std::string LambdaStr;
716 AstPtr LambdaNode =
P.parse(Partials, Lambdas, SectionLambdas, Escapes);
717 LambdaNode->render(Contexts,
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")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
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.
iterator find(const_arg_type_t< KeyT > Val)
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",...
iterator find(StringRef Key)
bool contains(StringRef Key) const
contains - Return true if the element is in the map, false otherwise.
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
StringRef - Represent a constant reference to a string, i.e.
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.
uint64_t tell() const
tell - Return the current offset with the file.
void SetUnbuffered()
Set the stream to be unbuffered.
A raw_ostream that writes to an std::string.
#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)
void stripTokenAhead(SmallVectorImpl< Token > &Tokens, size_t Idx)
bool hasTextAhead(size_t Idx, const ArrayRef< Token > &Tokens)
void stripTokenBefore(SmallVectorImpl< Token > &Tokens, size_t Idx, Token &CurrentToken, Token::Type CurrentType)
void toMustacheString(const json::Value &Data, raw_ostream &OS)
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)
std::function< llvm::json::Value()> Lambda
AstPtr createTextNode(std::string Body, ASTNode *Parent, llvm::StringMap< AstPtr > &Partials, llvm::StringMap< Lambda > &Lambdas, llvm::StringMap< SectionLambda > &SectionLambdas, EscapeMap &Escapes)
std::function< llvm::json::Value(std::string)> SectionLambda
SmallVector< Token > tokenize(StringRef Template)
bool hasTextBehind(size_t Idx, const ArrayRef< Token > &Tokens)
std::unique_ptr< ASTNode > AstPtr
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,...
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.