Author: Sam McCall Date: 2022-03-25T14:17:38+01:00 New Revision: 72864d9bfec929b2427981d99c2ac67ff5fcfe19
URL: https://github.com/llvm/llvm-project/commit/72864d9bfec929b2427981d99c2ac67ff5fcfe19 DIFF: https://github.com/llvm/llvm-project/commit/72864d9bfec929b2427981d99c2ac67ff5fcfe19.diff LOG: [pseudo] Use box-drawing chars to prettify debug dumps. NFC Added: Modified: clang-tools-extra/pseudo/lib/Forest.cpp clang-tools-extra/pseudo/unittests/ForestTest.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/pseudo/lib/Forest.cpp b/clang-tools-extra/pseudo/lib/Forest.cpp index 41b9be8a8d30f..6948422a23a6e 100644 --- a/clang-tools-extra/pseudo/lib/Forest.cpp +++ b/clang-tools-extra/pseudo/lib/Forest.cpp @@ -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; } diff --git a/clang-tools-extra/pseudo/unittests/ForestTest.cpp b/clang-tools-extra/pseudo/unittests/ForestTest.cpp index b9bd08d78288a..a734a8f7f8616 100644 --- a/clang-tools-extra/pseudo/unittests/ForestTest.cpp +++ b/clang-tools-extra/pseudo/unittests/ForestTest.cpp @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits