mz_sql_parser/ast/visit.rs
1// Copyright Syn Developers.
2// Copyright Materialize, Inc. and contributors. All rights reserved.
3//
4// This file is derived from the syn project, available at
5// https://github.com/dtolnay/syn. It was incorporated
6// directly into Materialize on June 8, 2020.
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License in the LICENSE file at the
11// root of this repository, or online at
12//
13// http://www.apache.org/licenses/LICENSE-2.0
14//
15// Unless required by applicable law or agreed to in writing, software
16// distributed under the License is distributed on an "AS IS" BASIS,
17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18// See the License for the specific language governing permissions and
19// limitations under the License.
20
21//! Traversal of an immutable AST.
22//!
23//! Each method of the [`Visit`] trait is a hook that can be overridden to
24//! customize the behavior when visiting the corresponding type of node. By
25//! default, every method recursively visits the substructure of the input
26//! by invoking the right visitor method of each of its fields.
27//!
28//! ```
29//! # use mz_sql_parser::ast::{Expr, Function, FunctionArgs, WindowSpec, Raw, AstInfo};
30//! #
31//! pub trait Visit<'ast, T: AstInfo> {
32//! /* ... */
33//!
34//! fn visit_function(&mut self, node: &'ast Function<T>) {
35//! visit_function(self, node);
36//! }
37//!
38//! /* ... */
39//! # fn visit_item_name(&mut self, node: &'ast <T as AstInfo>::ItemName);
40//! # fn visit_function_args(&mut self, node: &'ast FunctionArgs<T>);
41//! # fn visit_expr(&mut self, node: &'ast Expr<T>);
42//! # fn visit_window_spec(&mut self, node: &'ast WindowSpec<T>);
43//! }
44//!
45//! pub fn visit_function<'ast, V, T: AstInfo>(visitor: &mut V, node: &'ast Function<T>)
46//! where
47//! V: Visit<'ast, T> + ?Sized,
48//! {
49//! visitor.visit_item_name(&node.name);
50//! visitor.visit_function_args(&node.args);
51//! if let Some(filter) = &node.filter {
52//! visitor.visit_expr(&*filter);
53//! }
54//! if let Some(over) = &node.over {
55//! visitor.visit_window_spec(over);
56//! }
57//! }
58//! ```
59//!
60//! See also the [`visit_mut`] module for traversing mutable ASTs.
61//!
62//! # Examples
63//!
64//! This visitor will count the number of subqueries in a SQL statement.
65//!
66//! ```
67//! use std::error::Error;
68//!
69//! use mz_sql_parser::ast::{AstInfo, Query, Raw};
70//! use mz_sql_parser::ast::visit::{self, Visit};
71//!
72//! struct SubqueryCounter {
73//! count: usize,
74//! }
75//!
76//! impl<'ast> Visit<'ast, Raw> for SubqueryCounter {
77//! fn visit_query(&mut self, query: &'ast Query<Raw>) {
78//! self.count += 1;
79//!
80//! // Delegate to the default implementation to visit any nested
81//! // subqueries. Placing this call at the end of the method results
82//! // in a pre-order traversal. Place it at the beginning for a
83//! // post-order traversal instead.
84//! visit::visit_query(self, query);
85//! }
86//! }
87//!
88//! fn main() -> Result<(), Box<dyn Error>> {
89//! let sql = "SELECT (SELECT 1) FROM (SELECT 1) WHERE EXISTS (SELECT (SELECT 1))";
90//! let stmts = mz_sql_parser::parser::parse_statements(sql.into())?;
91//!
92//! let mut counter = SubqueryCounter { count: 0 };
93//! for stmt in &stmts {
94//! counter.visit_statement(&stmt.ast);
95//! }
96//! assert_eq!(counter.count, 5);
97//! Ok(())
98//! }
99//! ```
100//!
101//! The `'ast` lifetime on the input references means that the syntax tree
102//! outlives the complete recursive visit call, so the visitor is allowed to
103//! hold on to references into the syntax tree.
104//!
105//! ```
106//! use std::error::Error;
107//!
108//! use mz_sql_parser::ast::{Ident, Raw, AstInfo, RawItemName};
109//! use mz_sql_parser::ast::visit::{self, Visit};
110//!
111//! struct IdentCollector<'ast> {
112//! idents: Vec<&'ast Ident>,
113//! }
114//!
115//! impl<'ast> Visit<'ast, Raw> for IdentCollector<'ast> {
116//! fn visit_ident(&mut self, node: &'ast Ident) {
117//! self.idents.push(node);
118//! visit::visit_ident(self, node);
119//! }
120//! fn visit_item_name(&mut self, name: &'ast <Raw as AstInfo>::ItemName) {
121//! match name {
122//! RawItemName::Name(n) | RawItemName::Id(_, n, _) => {
123//! for node in &n.0 {
124//! self.idents.push(node);
125//! visit::visit_ident(self, node);
126//! }
127//! }
128//! }
129//! }
130//! }
131//!
132//! fn main() -> Result<(), Box<dyn Error>> {
133//! let sql = "SELECT a FROM b.c WHERE 1 + d(e)";
134//! let stmts = mz_sql_parser::parser::parse_statements(sql.into())?;
135//!
136//! let mut collector = IdentCollector { idents: vec![] };
137//! for stmt in &stmts {
138//! collector.visit_statement(&stmt.ast);
139//! }
140//! assert_eq!(collector.idents, &[
141//! &Ident::new_unchecked("a"), &Ident::new_unchecked("b"),
142//! &Ident::new_unchecked("c"), &Ident::new_unchecked("d"),
143//! &Ident::new_unchecked("e"),
144//! ]);
145//! Ok(())
146//! }
147//! ```
148//!
149//! The [`VisitNode`] trait is implemented for every node in the AST and can be
150//! used to write generic functions that apply a `Visit` implementation to any
151//! node in the AST.
152//!
153//! # Implementation notes
154//!
155//! This module is automatically generated by the crate's build script. Changes
156//! to the AST will be automatically propagated to the visitor.
157//!
158//! This approach to AST visitors is inspired by the [`syn`] crate. These
159//! module docs are directly derived from the [`syn::visit`] module docs.
160//!
161//! [`syn`]: https://docs.rs/syn/1.*/syn/index.html
162//! [`syn::visit`]: https://docs.rs/syn/1.*/syn/visit/index.html
163
164#![allow(clippy::all)]
165#![allow(unused_variables)]
166
167use crate::ast::*;
168
169include!(concat!(env!("OUT_DIR"), "/visit.rs"));