Skip to main content

elo_rust/ast/
visitor.rs

1//! Visitor trait for traversing and transforming ELO AST
2//!
3//! This module defines the Visitor trait, which implements the visitor pattern
4//! for AST traversal. Implementors can transform or analyze AST nodes.
5
6use super::{BinaryOperator, Expr, Literal, TemporalKeyword, UnaryOperator};
7
8/// Visitor trait for AST traversal and transformation
9///
10/// Implement this trait to traverse and/or transform ELO AST nodes.
11/// The generic type parameter `T` specifies the return type of visitor methods.
12///
13/// # Example
14///
15/// ```ignore
16/// use elo_rust::ast::{Expr, Visitor};
17/// use proc_macro2::TokenStream;
18///
19/// struct CodegenVisitor {
20///     // ... fields
21/// }
22///
23/// impl Visitor<TokenStream> for CodegenVisitor {
24///     fn visit_expr(&mut self, expr: &Expr) -> TokenStream {
25///         match expr {
26///             Expr::Literal(lit) => self.visit_literal(lit),
27///             // ... handle other cases
28///         }
29///     }
30/// }
31/// ```
32pub trait Visitor<T> {
33    /// Visit a generic expression, dispatching to specific methods
34    fn visit_expr(&mut self, expr: &Expr) -> T;
35
36    /// Visit a literal value (number or boolean)
37    fn visit_literal(&mut self, lit: &Literal) -> T;
38
39    /// Visit a null literal
40    fn visit_null(&mut self) -> T;
41
42    /// Visit an identifier (variable reference)
43    fn visit_identifier(&mut self, name: &str) -> T;
44
45    /// Visit a field access expression
46    fn visit_field_access(&mut self, receiver: &Expr, field: &str) -> T;
47
48    /// Visit a binary operation
49    fn visit_binary_op(&mut self, op: BinaryOperator, left: &Expr, right: &Expr) -> T;
50
51    /// Visit a unary operation
52    fn visit_unary_op(&mut self, op: UnaryOperator, operand: &Expr) -> T;
53
54    /// Visit a function call
55    fn visit_function_call(&mut self, name: &str, args: &[Expr]) -> T;
56
57    /// Visit a lambda expression
58    fn visit_lambda(&mut self, param: &str, body: &Expr) -> T;
59
60    /// Visit a let binding
61    fn visit_let(&mut self, name: &str, value: &Expr, body: &Expr) -> T;
62
63    /// Visit an if conditional
64    fn visit_if(&mut self, condition: &Expr, then_branch: &Expr, else_branch: &Expr) -> T;
65
66    /// Visit an array literal
67    fn visit_array(&mut self, elements: &[Expr]) -> T;
68
69    /// Visit an object literal
70    fn visit_object(&mut self, fields: &[(String, Expr)]) -> T;
71
72    /// Visit a pipe operator
73    fn visit_pipe(&mut self, value: &Expr, functions: &[Expr]) -> T;
74
75    /// Visit an alternative operator (?|)
76    fn visit_alternative(&mut self, primary: &Expr, alternative: &Expr) -> T;
77
78    /// Visit a guard expression
79    fn visit_guard(&mut self, condition: &Expr, body: &Expr) -> T;
80
81    /// Visit a date literal
82    fn visit_date(&mut self, date: &str) -> T;
83
84    /// Visit a datetime literal
85    fn visit_datetime(&mut self, datetime: &str) -> T;
86
87    /// Visit a duration literal
88    fn visit_duration(&mut self, duration: &str) -> T;
89
90    /// Visit a temporal keyword
91    fn visit_temporal_keyword(&mut self, keyword: TemporalKeyword) -> T;
92
93    /// Visit a string literal
94    fn visit_string(&mut self, value: &str) -> T;
95}
96
97/// Default visitor implementation that dispatches to specific visitor methods
98///
99/// This provides the standard dispatch logic for visit_expr.
100/// Most implementations will use the default visit_expr from this trait.
101pub trait DefaultVisitor<T>: Visitor<T> {
102    /// Default implementation of visit_expr that dispatches to specific methods
103    fn default_visit_expr(&mut self, expr: &Expr) -> T {
104        match expr {
105            Expr::Literal(lit) => self.visit_literal(lit),
106            Expr::Null => self.visit_null(),
107            Expr::Identifier(name) => self.visit_identifier(name),
108            Expr::String(value) => self.visit_string(value),
109            Expr::FieldAccess { receiver, field } => self.visit_field_access(receiver, field),
110            Expr::BinaryOp { op, left, right } => self.visit_binary_op(*op, left, right),
111            Expr::UnaryOp { op, operand } => self.visit_unary_op(*op, operand),
112            Expr::FunctionCall { name, args } => self.visit_function_call(name, args),
113            Expr::Lambda { param, body } => self.visit_lambda(param, body),
114            Expr::Let { name, value, body } => self.visit_let(name, value, body),
115            Expr::If {
116                condition,
117                then_branch,
118                else_branch,
119            } => self.visit_if(condition, then_branch, else_branch),
120            Expr::Array(elements) => self.visit_array(elements),
121            Expr::Object(fields) => self.visit_object(fields),
122            Expr::Pipe { value, functions } => self.visit_pipe(value, functions),
123            Expr::Alternative {
124                primary,
125                alternative,
126            } => self.visit_alternative(primary, alternative),
127            Expr::Guard { condition, body } => self.visit_guard(condition, body),
128            Expr::Date(date) => self.visit_date(date),
129            Expr::DateTime(datetime) => self.visit_datetime(datetime),
130            Expr::Duration(duration) => self.visit_duration(duration),
131            Expr::TemporalKeyword(keyword) => self.visit_temporal_keyword(*keyword),
132        }
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use std::cell::RefCell;
140    use std::rc::Rc;
141
142    struct CountingVisitor {
143        count: Rc<RefCell<usize>>,
144    }
145
146    impl Visitor<()> for CountingVisitor {
147        fn visit_expr(&mut self, expr: &Expr) {
148            *self.count.borrow_mut() += 1;
149            match expr {
150                Expr::BinaryOp { left, right, .. } => {
151                    self.visit_expr(left);
152                    self.visit_expr(right);
153                }
154                Expr::UnaryOp { operand, .. } => {
155                    self.visit_expr(operand);
156                }
157                Expr::FieldAccess { receiver, .. } => {
158                    self.visit_expr(receiver);
159                }
160                _ => {}
161            }
162        }
163
164        fn visit_literal(&mut self, _lit: &Literal) {}
165        fn visit_null(&mut self) {}
166        fn visit_identifier(&mut self, _name: &str) {}
167        fn visit_field_access(&mut self, _receiver: &Expr, _field: &str) {}
168        fn visit_binary_op(&mut self, _op: BinaryOperator, _left: &Expr, _right: &Expr) {}
169        fn visit_unary_op(&mut self, _op: UnaryOperator, _operand: &Expr) {}
170        fn visit_function_call(&mut self, _name: &str, _args: &[Expr]) {}
171        fn visit_lambda(&mut self, _param: &str, _body: &Expr) {}
172        fn visit_let(&mut self, _name: &str, _value: &Expr, _body: &Expr) {}
173        fn visit_if(&mut self, _condition: &Expr, _then_branch: &Expr, _else_branch: &Expr) {}
174        fn visit_array(&mut self, _elements: &[Expr]) {}
175        fn visit_object(&mut self, _fields: &[(String, Expr)]) {}
176        fn visit_pipe(&mut self, _value: &Expr, _functions: &[Expr]) {}
177        fn visit_alternative(&mut self, _primary: &Expr, _alternative: &Expr) {}
178        fn visit_guard(&mut self, _condition: &Expr, _body: &Expr) {}
179        fn visit_date(&mut self, _date: &str) {}
180        fn visit_datetime(&mut self, _datetime: &str) {}
181        fn visit_duration(&mut self, _duration: &str) {}
182        fn visit_temporal_keyword(&mut self, _keyword: TemporalKeyword) {}
183        fn visit_string(&mut self, _value: &str) {}
184    }
185
186    #[test]
187    fn test_visitor_basic() {
188        let expr = Expr::Literal(Literal::Integer(42));
189        let mut visitor = CountingVisitor {
190            count: Rc::new(RefCell::new(0)),
191        };
192        visitor.visit_expr(&expr);
193        assert_eq!(*visitor.count.borrow(), 1);
194    }
195
196    #[test]
197    fn test_visitor_traversal() {
198        let expr = Expr::BinaryOp {
199            op: BinaryOperator::Add,
200            left: Box::new(Expr::Literal(Literal::Integer(1))),
201            right: Box::new(Expr::Literal(Literal::Integer(2))),
202        };
203        let mut visitor = CountingVisitor {
204            count: Rc::new(RefCell::new(0)),
205        };
206        visitor.visit_expr(&expr);
207        assert_eq!(*visitor.count.borrow(), 3); // binary op + 2 literals
208    }
209}