Skip to main content

visitor/
visitor.rs

1#![expect(clippy::print_stdout)]
2//! # AST Visitor Example
3//!
4//! This example demonstrates how to use the visitor pattern to traverse and analyze
5//! an AST. It counts different types of nodes (functions, classes, TypeScript imports).
6//!
7//! ## Usage
8//!
9//! Create a `test.js` file and run:
10//! ```bash
11//! cargo run -p oxc_parser --example visitor [filename]
12//! ```
13
14use std::{env, path::Path};
15
16use oxc_allocator::Allocator;
17use oxc_ast::ast::{Class, Function, TSImportType};
18use oxc_ast_visit::{Visit, walk};
19use oxc_parser::Parser;
20use oxc_span::SourceType;
21use oxc_syntax::scope::ScopeFlags;
22
23// Instruction:
24// create a `test.js`,
25// run `cargo run -p oxc_parser --example visitor`
26// or `cargo watch -x "run -p oxc_parser --example visitor"`
27
28/// Demonstrate AST traversal using the visitor pattern
29fn main() -> std::io::Result<()> {
30    let name = env::args().nth(1).unwrap_or_else(|| "test.js".to_string());
31    let path = Path::new(&name);
32    let source_text = std::fs::read_to_string(path)?;
33    let allocator = Allocator::default();
34    let source_type = SourceType::from_path(path).unwrap();
35    let ret = Parser::new(&allocator, &source_text, source_type).parse();
36
37    // Report any parsing errors
38    for error in ret.diagnostics {
39        let error = error.with_source_code(source_text.clone());
40        println!("{error:?}");
41    }
42
43    let program = ret.program;
44
45    // Use visitor to count different AST node types
46    let mut ast_pass = CountASTNodes::default();
47    ast_pass.visit_program(&program);
48    println!("{ast_pass:?}");
49
50    Ok(())
51}
52
53/// A visitor that counts different types of AST nodes
54#[derive(Debug, Default)]
55struct CountASTNodes {
56    functions: usize,
57    classes: usize,
58    ts_import_types: usize,
59}
60
61impl<'a> Visit<'a> for CountASTNodes {
62    fn visit_function(&mut self, func: &Function<'a>, flags: ScopeFlags) {
63        self.functions += 1;
64        walk::walk_function(self, func, flags);
65    }
66
67    fn visit_class(&mut self, class: &Class<'a>) {
68        self.classes += 1;
69        walk::walk_class(self, class);
70    }
71
72    fn visit_ts_import_type(&mut self, ty: &TSImportType<'a>) {
73        self.ts_import_types += 1;
74        walk::walk_ts_import_type(self, ty);
75    }
76}