#pragma once #include #include #include #include namespace DB { /// Visits AST tree in depth, call functions for nodes according to Matcher type data. /// You need to define Data, visit() and needChildVisit() in Matcher class. template class InDepthNodeVisitor { public: using Data = typename Matcher::Data; InDepthNodeVisitor(Data & data_, std::ostream * ostr_ = nullptr) : data(data_), visit_depth(0), ostr(ostr_) {} void visit(T & ast) { DumpASTNode dump(*ast, ostr, visit_depth, typeid(Matcher).name()); if constexpr (!_top_to_bottom) visitChildren(ast); Matcher::visit(ast, data); if constexpr (_top_to_bottom) visitChildren(ast); } private: Data & data; size_t visit_depth; std::ostream * ostr; void visitChildren(T & ast) { for (auto & child : ast->children) if (Matcher::needChildVisit(ast, child)) visit(child); } }; template using ConstInDepthNodeVisitor = InDepthNodeVisitor; /// Simple matcher for one node type without complex traversal logic. template class OneTypeMatcher { public: using Data = Data_; using TypeToVisit = typename Data::TypeToVisit; static bool needChildVisit(const ASTPtr & node, const ASTPtr &) { if (node && node->as()) return visit_children; return true; } static void visit(T & ast, Data & data) { if (auto * t = typeid_cast(ast.get())) data.visit(*t, ast); } }; template using ConstOneTypeMatcher = OneTypeMatcher; }