[pseudo] Use box-drawing chars to prettify debug dumps. NFC

This commit is contained in:
Sam McCall 2022-03-25 14:17:31 +01:00
parent f6b60b3b79
commit 72864d9bfe
2 changed files with 51 additions and 30 deletions

View File

@ -46,15 +46,23 @@ std::string ForestNode::dumpRecursive(const Grammar &G,
};
CountVisits(this);
// The box-drawing characters that should be added as a child is rendered.
struct LineDecoration {
std::string Prefix; // Prepended to every line.
llvm::StringRef First; // added to the child's line.
llvm::StringRef Subsequent; // added to descendants' lines.
};
// We print a "#<id>" for nonterminal forest nodes that are being dumped
// multiple times.
llvm::DenseMap<const ForestNode *, size_t> ReferenceIds;
std::string Result;
constexpr Token::Index KEnd = std::numeric_limits<Token::Index>::max();
std::function<void(const ForestNode *, unsigned, Token::Index,
llvm::Optional<SymbolID>)>
Dump = [&](const ForestNode *P, unsigned Level, Token::Index End,
llvm::Optional<SymbolID> ElidedParent) {
std::function<void(const ForestNode *, Token::Index, llvm::Optional<SymbolID>,
LineDecoration &LineDec)>
Dump = [&](const ForestNode *P, Token::Index End,
llvm::Optional<SymbolID> ElidedParent,
LineDecoration LineDec) {
llvm::ArrayRef<const ForestNode *> Children;
auto EndOfElement = [&](size_t ChildIndex) {
return ChildIndex + 1 == Children.size()
@ -72,18 +80,19 @@ std::string ForestNode::dumpRecursive(const Grammar &G,
if (Children[I]->startTokenIndex() == P->startTokenIndex() &&
EndOfElement(I) == End) {
return Dump(
Children[I], Level, End,
/*ElidedParent=*/ElidedParent.getValueOr(P->symbol()));
Children[I], End,
/*ElidedParent=*/ElidedParent.getValueOr(P->symbol()),
LineDec);
}
}
}
// FIXME: pretty ascii trees
if (End == KEnd)
Result += llvm::formatv("[{0,3}, end) ", P->startTokenIndex());
else
Result += llvm::formatv("[{0,3}, {1,3}) ", P->startTokenIndex(), End);
Result.append(2 * Level, ' ');
Result += LineDec.Prefix;
Result += LineDec.First;
if (ElidedParent.hasValue()) {
Result += G.symbolName(*ElidedParent);
Result += "~";
@ -99,12 +108,23 @@ std::string ForestNode::dumpRecursive(const Grammar &G,
}
Result.push_back('\n');
++Level;
for (size_t I = 0; I < Children.size(); ++I)
Dump(Children[I], Level,
P->kind() == Sequence ? EndOfElement(I) : End, llvm::None);
auto OldPrefixSize = LineDec.Prefix.size();
LineDec.Prefix += LineDec.Subsequent;
for (size_t I = 0; I < Children.size(); ++I) {
if (I == Children.size() - 1) {
LineDec.First = "└─";
LineDec.Subsequent = " ";
} else {
LineDec.First = "├─";
LineDec.Subsequent = "";
}
Dump(Children[I], P->kind() == Sequence ? EndOfElement(I) : End,
llvm::None, LineDec);
}
LineDec.Prefix.resize(OldPrefixSize);
};
Dump(this, 0, KEnd, llvm::None);
LineDecoration LineDec;
Dump(this, KEnd, llvm::None, LineDec);
return Result;
}

View File

@ -71,19 +71,20 @@ TEST_F(ForestTest, DumpBasic) {
ruleFor("id-expression"), {&T[2]});
const auto *Add =
&Arena.createSequence(symbol("add-expression"), ruleFor("add-expression"), {Left, &T[1], Right});
&Arena.createSequence(symbol("add-expression"), ruleFor("add-expression"),
{Left, &T[1], Right});
EXPECT_EQ(Add->dumpRecursive(*G, true),
"[ 0, end) add-expression := id-expression + id-expression\n"
"[ 0, 1) id-expression~IDENTIFIER := tok[0]\n"
"[ 1, 2) + := tok[1]\n"
"[ 2, end) id-expression~IDENTIFIER := tok[2]\n");
"[ 0, 1) ├─id-expression~IDENTIFIER := tok[0]\n"
"[ 1, 2) ├─+ := tok[1]\n"
"[ 2, end) └─id-expression~IDENTIFIER := tok[2]\n");
EXPECT_EQ(Add->dumpRecursive(*G, false),
"[ 0, end) add-expression := id-expression + id-expression\n"
"[ 0, 1) id-expression := IDENTIFIER\n"
"[ 0, 1) IDENTIFIER := tok[0]\n"
"[ 1, 2) + := tok[1]\n"
"[ 2, end) id-expression := IDENTIFIER\n"
"[ 2, end) IDENTIFIER := tok[2]\n");
"[ 0, 1) ├─id-expression := IDENTIFIER\n"
"[ 0, 1) │ └─IDENTIFIER := tok[0]\n"
"[ 1, 2) ├─+ := tok[1]\n"
"[ 2, end) └─id-expression := IDENTIFIER\n"
"[ 2, end) └─IDENTIFIER := tok[2]\n");
}
TEST_F(ForestTest, DumpAmbiguousAndRefs) {
@ -115,14 +116,14 @@ TEST_F(ForestTest, DumpAmbiguousAndRefs) {
&Arena.createAmbiguous(symbol("type"), {Alternative1, Alternative2});
EXPECT_EQ(Type->dumpRecursive(*G),
"[ 0, end) type := <ambiguous>\n"
"[ 0, end) class-type := shared-type\n"
"[ 0, end) class-type := shared-type\n"
"[ 0, end) shared-type := IDENTIFIER #1\n"
"[ 0, end) IDENTIFIER := tok[0]\n"
"[ 0, end) enum-type := shared-type\n"
"[ 0, end) enum-type := shared-type\n"
"[ 0, end) shared-type := IDENTIFIER =#1\n"
"[ 0, end) IDENTIFIER := tok[0]\n");
"[ 0, end) ├─class-type := shared-type\n"
"[ 0, end) │ └─class-type := shared-type\n"
"[ 0, end) │ └─shared-type := IDENTIFIER #1\n"
"[ 0, end) │ └─IDENTIFIER := tok[0]\n"
"[ 0, end) └─enum-type := shared-type\n"
"[ 0, end) └─enum-type := shared-type\n"
"[ 0, end) └─shared-type := IDENTIFIER =#1\n"
"[ 0, end) └─IDENTIFIER := tok[0]\n");
}
} // namespace