| 1 | #pragma once |
| 2 | |
| 3 | #include <typeinfo> |
| 4 | #include <vector> |
| 5 | #include <Common/typeid_cast.h> |
| 6 | #include <Parsers/DumpASTNode.h> |
| 7 | |
| 8 | namespace 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. |
| 13 | template <typename Matcher, bool _top_to_bottom, typename T = ASTPtr> |
| 14 | class InDepthNodeVisitor |
| 15 | { |
| 16 | public: |
| 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 | |
| 38 | private: |
| 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 | |
| 51 | template <typename Matcher, bool top_to_bottom> |
| 52 | using ConstInDepthNodeVisitor = InDepthNodeVisitor<Matcher, top_to_bottom, const ASTPtr>; |
| 53 | |
| 54 | /// Simple matcher for one node type without complex traversal logic. |
| 55 | template <typename Data_, bool visit_children = true, typename T = ASTPtr> |
| 56 | class OneTypeMatcher |
| 57 | { |
| 58 | public: |
| 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 | |
| 71 | template <typename Data, bool visit_children = true> |
| 72 | using ConstOneTypeMatcher = OneTypeMatcher<Data, visit_children, const ASTPtr>; |
| 73 | |
| 74 | } |
| 75 | |