1 | #pragma once |
2 | |
3 | #include <sstream> |
4 | #include <common/logger_useful.h> |
5 | #include <Poco/Util/Application.h> |
6 | |
7 | #include <Parsers/IAST.h> |
8 | |
9 | namespace DB |
10 | { |
11 | |
12 | /// If output stream set dumps node with indents and some additional info. Do nothing otherwise. |
13 | /// Allow to print kay-value pairs inside of tree dump. |
14 | class DumpASTNode |
15 | { |
16 | public: |
17 | DumpASTNode(const IAST & ast_, std::ostream * ostr_, size_t & depth, const char * label_ = nullptr) |
18 | : ast(ast_), |
19 | ostr(ostr_), |
20 | indent(depth), |
21 | visit_depth(depth), |
22 | label(label_) |
23 | { |
24 | if (!ostr) |
25 | return; |
26 | if (label && visit_depth == 0) |
27 | (*ostr) << "-- " << label << std::endl; |
28 | ++visit_depth; |
29 | |
30 | (*ostr) << String(indent, ' '); |
31 | printNode(); |
32 | (*ostr) << std::endl; |
33 | } |
34 | |
35 | ~DumpASTNode() |
36 | { |
37 | if (!ostr) |
38 | return; |
39 | --visit_depth; |
40 | if (label && visit_depth == 0) |
41 | (*ostr) << "--" << std::endl; |
42 | } |
43 | |
44 | template <typename T, typename U> |
45 | void print(const T & name, const U & value, const char * str_indent = nullptr) const |
46 | { |
47 | if (!ostr) |
48 | return; |
49 | |
50 | (*ostr) << (str_indent ? String(str_indent) : String(indent, ' ')); |
51 | (*ostr) << '(' << name << ' ' << value << ')'; |
52 | if (!str_indent) |
53 | (*ostr) << std::endl; |
54 | } |
55 | |
56 | size_t & getDepth() { return visit_depth; } |
57 | |
58 | private: |
59 | const IAST & ast; |
60 | std::ostream * ostr; |
61 | size_t indent; |
62 | size_t & visit_depth; /// shared with children |
63 | const char * label; |
64 | |
65 | String nodeId() const { return ast.getID(' '); } |
66 | |
67 | void printNode() const |
68 | { |
69 | (*ostr) << nodeId(); |
70 | |
71 | String alias = ast.tryGetAlias(); |
72 | if (!alias.empty()) |
73 | print("alias" , alias, " " ); |
74 | |
75 | if (!ast.children.empty()) |
76 | print("children" , ast.children.size(), " " ); |
77 | } |
78 | }; |
79 | |
80 | inline void dumpAST(const IAST & ast, std::ostream & ostr, DumpASTNode * parent = nullptr) |
81 | { |
82 | size_t depth = 0; |
83 | DumpASTNode dump(ast, &ostr, (parent ? parent->getDepth() : depth)); |
84 | |
85 | for (const auto & child : ast.children) |
86 | dumpAST(*child, ostr, &dump); |
87 | } |
88 | |
89 | |
90 | /// String stream dumped in dtor |
91 | template <bool _enable> |
92 | class DebugASTLog |
93 | { |
94 | public: |
95 | DebugASTLog() |
96 | : log(nullptr) |
97 | { |
98 | if constexpr (_enable) |
99 | log = &Poco::Logger::get("AST" ); |
100 | } |
101 | |
102 | ~DebugASTLog() |
103 | { |
104 | if constexpr (_enable) |
105 | LOG_DEBUG(log, ss.str()); |
106 | } |
107 | |
108 | std::ostream * stream() { return (_enable ? &ss : nullptr); } |
109 | |
110 | private: |
111 | Poco::Logger * log; |
112 | std::stringstream ss; |
113 | }; |
114 | |
115 | |
116 | } |
117 | |