Module mz_sql_parser::ast::visit
source · Expand description
Traversal of an immutable AST.
Each method of the Visit
trait is a hook that can be overridden to
customize the behavior when visiting the corresponding type of node. By
default, every method recursively visits the substructure of the input
by invoking the right visitor method of each of its fields.
pub trait Visit<'ast, T: AstInfo> {
/* ... */
fn visit_function(&mut self, node: &'ast Function<T>) {
visit_function(self, node);
}
/* ... */
}
pub fn visit_function<'ast, V, T: AstInfo>(visitor: &mut V, node: &'ast Function<T>)
where
V: Visit<'ast, T> + ?Sized,
{
visitor.visit_item_name(&node.name);
visitor.visit_function_args(&node.args);
if let Some(filter) = &node.filter {
visitor.visit_expr(&*filter);
}
if let Some(over) = &node.over {
visitor.visit_window_spec(over);
}
}
See also the visit_mut
module for traversing mutable ASTs.
§Examples
This visitor will count the number of subqueries in a SQL statement.
use std::error::Error;
use mz_sql_parser::ast::{AstInfo, Query, Raw};
use mz_sql_parser::ast::visit::{self, Visit};
struct SubqueryCounter {
count: usize,
}
impl<'ast> Visit<'ast, Raw> for SubqueryCounter {
fn visit_query(&mut self, query: &'ast Query<Raw>) {
self.count += 1;
// Delegate to the default implementation to visit any nested
// subqueries. Placing this call at the end of the method results
// in a pre-order traversal. Place it at the beginning for a
// post-order traversal instead.
visit::visit_query(self, query);
}
}
fn main() -> Result<(), Box<dyn Error>> {
let sql = "SELECT (SELECT 1) FROM (SELECT 1) WHERE EXISTS (SELECT (SELECT 1))";
let stmts = mz_sql_parser::parser::parse_statements(sql.into())?;
let mut counter = SubqueryCounter { count: 0 };
for stmt in &stmts {
counter.visit_statement(&stmt.ast);
}
assert_eq!(counter.count, 5);
Ok(())
}
The 'ast
lifetime on the input references means that the syntax tree
outlives the complete recursive visit call, so the visitor is allowed to
hold on to references into the syntax tree.
use std::error::Error;
use mz_sql_parser::ast::{Ident, Raw, AstInfo, RawItemName};
use mz_sql_parser::ast::visit::{self, Visit};
struct IdentCollector<'ast> {
idents: Vec<&'ast Ident>,
}
impl<'ast> Visit<'ast, Raw> for IdentCollector<'ast> {
fn visit_ident(&mut self, node: &'ast Ident) {
self.idents.push(node);
visit::visit_ident(self, node);
}
fn visit_item_name(&mut self, name: &'ast <Raw as AstInfo>::ItemName) {
match name {
RawItemName::Name(n) | RawItemName::Id(_, n, _) => {
for node in &n.0 {
self.idents.push(node);
visit::visit_ident(self, node);
}
}
}
}
}
fn main() -> Result<(), Box<dyn Error>> {
let sql = "SELECT a FROM b.c WHERE 1 + d(e)";
let stmts = mz_sql_parser::parser::parse_statements(sql.into())?;
let mut collector = IdentCollector { idents: vec![] };
for stmt in &stmts {
collector.visit_statement(&stmt.ast);
}
assert_eq!(collector.idents, &[
&Ident::new_unchecked("a"), &Ident::new_unchecked("b"),
&Ident::new_unchecked("c"), &Ident::new_unchecked("d"),
&Ident::new_unchecked("e"),
]);
Ok(())
}
The VisitNode
trait is implemented for every node in the AST and can be
used to write generic functions that apply a Visit
implementation to any
node in the AST.
§Implementation notes
This module is automatically generated by the crate’s build script. Changes to the AST will be automatically propagated to the visitor.
This approach to AST visitors is inspired by the syn
crate. These
module docs are directly derived from the syn::visit
module docs.