Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 33 additions & 24 deletions llvm/lib/Support/Mustache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Mustache.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
#include <sstream>

Expand All @@ -23,6 +22,13 @@ static bool isFalsey(const json::Value &V) {
(V.getAsArray() && V.getAsArray()->empty());
}

static bool isContextFalsey(const json::Value *V) {
// A missing context (represented by a nullptr) is defined as falsey.
if (!V)
return true;
return isFalsey(*V);
}

static Accessor splitMustacheString(StringRef Str) {
// We split the mustache string into an accessor.
// For example:
Expand Down Expand Up @@ -560,68 +566,71 @@ void toMustacheString(const json::Value &Data, raw_ostream &OS) {
}
}

void ASTNode::render(const json::Value &Data, raw_ostream &OS) {
ParentContext = &Data;
void ASTNode::render(const json::Value &CurrentCtx, raw_ostream &OS) {
// Set the parent context to the incoming context so that we
// can walk up the context tree correctly in findContext().
ParentContext = &CurrentCtx;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to your change, but seeing this, I wonder why we don't also have to reset ParentContext to the original value when leaving the recursion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That ... is a good point. I'll need to look at this code some more. @PeterChou1 do you recall?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, think the parent of the node at this point is default/root node. Here we're setting it to the actual parent. I don't think it needs to be reset on the way back up, since they're now fixed in the template/AST. This does make me wonder if there is a better way to set the context/parent relationships than in this recursive routine, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ASTNode is a tree of nodes with the parentContext originally set to null. As we render the moustache template we set the parent context from the incoming parent node. We don't need to reset the parentContext when leaving because its was null originally

const json::Value *ContextPtr = Ty == Root ? ParentContext : findContext();
const json::Value &Context = ContextPtr ? *ContextPtr : nullptr;

switch (Ty) {
case Root:
renderChild(Data, OS);
renderChild(CurrentCtx, OS);
return;
case Text:
OS << Body;
return;
case Partial: {
auto Partial = Partials.find(AccessorValue[0]);
if (Partial != Partials.end())
renderPartial(Data, OS, Partial->getValue().get());
renderPartial(CurrentCtx, OS, Partial->getValue().get());
return;
}
case Variable: {
auto Lambda = Lambdas.find(AccessorValue[0]);
if (Lambda != Lambdas.end())
renderLambdas(Data, OS, Lambda->getValue());
else {
if (Lambda != Lambdas.end()) {
renderLambdas(CurrentCtx, OS, Lambda->getValue());
} else if (ContextPtr) {
EscapeStringStream ES(OS, Escapes);
toMustacheString(Context, ES);
toMustacheString(*ContextPtr, ES);
}
return;
}
case UnescapeVariable: {
auto Lambda = Lambdas.find(AccessorValue[0]);
if (Lambda != Lambdas.end())
renderLambdas(Data, OS, Lambda->getValue());
else
toMustacheString(Context, OS);
if (Lambda != Lambdas.end()) {
renderLambdas(CurrentCtx, OS, Lambda->getValue());
} else if (ContextPtr) {
toMustacheString(*ContextPtr, OS);
}
return;
}
case Section: {
// Sections are not rendered if the context is falsey.
auto SectionLambda = SectionLambdas.find(AccessorValue[0]);
bool IsLambda = SectionLambda != SectionLambdas.end();
if (isFalsey(Context) && !IsLambda)
return;

if (IsLambda) {
renderSectionLambdas(Data, OS, SectionLambda->getValue());
renderSectionLambdas(CurrentCtx, OS, SectionLambda->getValue());
return;
}

if (Context.getAsArray()) {
const json::Array *Arr = Context.getAsArray();
if (isContextFalsey(ContextPtr))
return;

if (const json::Array *Arr = ContextPtr->getAsArray()) {
for (const json::Value &V : *Arr)
renderChild(V, OS);
return;
}
renderChild(Context, OS);
renderChild(*ContextPtr, OS);
return;
}
case InvertSection: {
bool IsLambda = SectionLambdas.contains(AccessorValue[0]);
if (!isFalsey(Context) || IsLambda)
return;
renderChild(Context, OS);
if (isContextFalsey(ContextPtr) && !IsLambda) {
// The context for the children remains unchanged from the parent's, so
// we pass this node's original incoming context.
renderChild(CurrentCtx, OS);
}
return;
}
}
Expand Down
Loading