1#pragma once
2
3#include <typeinfo>
4#include <vector>
5#include <Common/typeid_cast.h>
6#include <Parsers/DumpASTNode.h>
7
8namespace DB
9{
10
11/// Visits AST tree in depth, call functions for nodes according to Matcher type data.
12/// You need to define Data, visit() and needChildVisit() in Matcher class.
13template <typename Matcher, bool _top_to_bottom, typename T = ASTPtr>
14class InDepthNodeVisitor
15{
16public:
17 using Data = typename Matcher::Data;
18
19 InDepthNodeVisitor(Data & data_, std::ostream * ostr_ = nullptr)
20 : data(data_),
21 visit_depth(0),
22 ostr(ostr_)
23 {}
24
25 void visit(T & ast)
26 {
27 DumpASTNode dump(*ast, ostr, visit_depth, typeid(Matcher).name());
28
29 if constexpr (!_top_to_bottom)
30 visitChildren(ast);
31
32 Matcher::visit(ast, data);
33
34 if constexpr (_top_to_bottom)
35 visitChildren(ast);
36 }
37
38private:
39 Data & data;
40 size_t visit_depth;
41 std::ostream * ostr;
42
43 void visitChildren(T & ast)
44 {
45 for (auto & child : ast->children)
46 if (Matcher::needChildVisit(ast, child))
47 visit(child);
48 }
49};
50
51template <typename Matcher, bool top_to_bottom>
52using ConstInDepthNodeVisitor = InDepthNodeVisitor<Matcher, top_to_bottom, const ASTPtr>;
53
54/// Simple matcher for one node type without complex traversal logic.
55template <typename Data_, bool visit_children = true, typename T = ASTPtr>
56class OneTypeMatcher
57{
58public:
59 using Data = Data_;
60 using TypeToVisit = typename Data::TypeToVisit;
61
62 static bool needChildVisit(const ASTPtr &, const ASTPtr &) { return visit_children; }
63
64 static void visit(T & ast, Data & data)
65 {
66 if (auto * t = typeid_cast<TypeToVisit *>(ast.get()))
67 data.visit(*t, ast);
68 }
69};
70
71template <typename Data, bool visit_children = true>
72using ConstOneTypeMatcher = OneTypeMatcher<Data, visit_children, const ASTPtr>;
73
74}
75