1use crate::ast::*;
24use crate::error::Result;
25
26pub trait Visitor: Sized {
31 fn visit_schema(&mut self, schema: &Schema) -> Result<()> {
33 walk_schema(self, schema)
34 }
35
36 fn visit_declaration(&mut self, decl: &Declaration) -> Result<()> {
38 walk_declaration(self, decl)
39 }
40
41 fn visit_datasource(&mut self, datasource: &DatasourceDecl) -> Result<()> {
43 walk_datasource(self, datasource)
44 }
45
46 fn visit_generator(&mut self, generator: &GeneratorDecl) -> Result<()> {
48 walk_generator(self, generator)
49 }
50
51 fn visit_model(&mut self, model: &ModelDecl) -> Result<()> {
53 walk_model(self, model)
54 }
55
56 fn visit_enum(&mut self, enum_decl: &EnumDecl) -> Result<()> {
58 walk_enum(self, enum_decl)
59 }
60
61 fn visit_field(&mut self, field: &FieldDecl) -> Result<()> {
63 walk_field(self, field)
64 }
65
66 fn visit_enum_variant(&mut self, variant: &EnumVariant) -> Result<()> {
68 walk_enum_variant(self, variant)
69 }
70
71 fn visit_field_attribute(&mut self, attr: &FieldAttribute) -> Result<()> {
73 walk_field_attribute(self, attr)
74 }
75
76 fn visit_model_attribute(&mut self, attr: &ModelAttribute) -> Result<()> {
78 walk_model_attribute(self, attr)
79 }
80
81 fn visit_expr(&mut self, expr: &Expr) -> Result<()> {
83 walk_expr(self, expr)
84 }
85
86 fn visit_config_field(&mut self, field: &ConfigField) -> Result<()> {
88 walk_config_field(self, field)
89 }
90
91 fn visit_type_decl(&mut self, type_decl: &TypeDecl) -> Result<()> {
93 walk_type_decl(self, type_decl)
94 }
95}
96
97pub fn walk_schema<V: Visitor>(visitor: &mut V, schema: &Schema) -> Result<()> {
99 for decl in &schema.declarations {
100 visitor.visit_declaration(decl)?;
101 }
102 Ok(())
103}
104
105pub fn walk_declaration<V: Visitor>(visitor: &mut V, decl: &Declaration) -> Result<()> {
107 match decl {
108 Declaration::Datasource(ds) => visitor.visit_datasource(ds),
109 Declaration::Generator(gen) => visitor.visit_generator(gen),
110 Declaration::Model(model) => visitor.visit_model(model),
111 Declaration::Enum(enum_decl) => visitor.visit_enum(enum_decl),
112 Declaration::Type(type_decl) => visitor.visit_type_decl(type_decl),
113 }
114}
115
116pub fn walk_datasource<V: Visitor>(visitor: &mut V, datasource: &DatasourceDecl) -> Result<()> {
118 for field in &datasource.fields {
119 visitor.visit_config_field(field)?;
120 }
121 Ok(())
122}
123
124pub fn walk_generator<V: Visitor>(visitor: &mut V, generator: &GeneratorDecl) -> Result<()> {
126 for field in &generator.fields {
127 visitor.visit_config_field(field)?;
128 }
129 Ok(())
130}
131
132pub fn walk_model<V: Visitor>(visitor: &mut V, model: &ModelDecl) -> Result<()> {
134 for field in &model.fields {
135 visitor.visit_field(field)?;
136 }
137 for attr in &model.attributes {
138 visitor.visit_model_attribute(attr)?;
139 }
140 Ok(())
141}
142
143pub fn walk_enum<V: Visitor>(visitor: &mut V, enum_decl: &EnumDecl) -> Result<()> {
145 for variant in &enum_decl.variants {
146 visitor.visit_enum_variant(variant)?;
147 }
148 Ok(())
149}
150
151pub fn walk_field<V: Visitor>(visitor: &mut V, field: &FieldDecl) -> Result<()> {
153 for attr in &field.attributes {
154 visitor.visit_field_attribute(attr)?;
155 }
156 Ok(())
157}
158
159pub fn walk_enum_variant<V: Visitor>(_visitor: &mut V, _variant: &EnumVariant) -> Result<()> {
161 Ok(())
162}
163
164pub fn walk_field_attribute<V: Visitor>(visitor: &mut V, attr: &FieldAttribute) -> Result<()> {
166 match attr {
167 FieldAttribute::Default(expr, _) => visitor.visit_expr(expr),
168 FieldAttribute::Relation { .. } => {
169 Ok(())
171 }
172 _ => Ok(()),
173 }
174}
175
176pub fn walk_model_attribute<V: Visitor>(_visitor: &mut V, _attr: &ModelAttribute) -> Result<()> {
178 Ok(())
179}
180
181pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr) -> Result<()> {
183 match expr {
184 Expr::FunctionCall { args, .. } => {
185 for arg in args {
186 visitor.visit_expr(arg)?;
187 }
188 Ok(())
189 }
190 Expr::Array { elements, .. } => {
191 for elem in elements {
192 visitor.visit_expr(elem)?;
193 }
194 Ok(())
195 }
196 Expr::NamedArg { value, .. } => visitor.visit_expr(value),
197 Expr::Literal(_) | Expr::Ident(_) => Ok(()),
198 }
199}
200
201pub fn walk_config_field<V: Visitor>(visitor: &mut V, field: &ConfigField) -> Result<()> {
203 visitor.visit_expr(&field.value)
204}
205
206pub fn walk_type_decl<V: Visitor>(visitor: &mut V, type_decl: &TypeDecl) -> Result<()> {
208 for field in &type_decl.fields {
209 visitor.visit_field(field)?;
210 }
211 Ok(())
212}
213
214#[derive(Debug, Default)]
216pub struct CountingVisitor {
217 pub models: usize,
219 pub enums: usize,
221 pub fields: usize,
223 pub datasources: usize,
225 pub generators: usize,
227}
228
229impl Visitor for CountingVisitor {
230 fn visit_datasource(&mut self, datasource: &DatasourceDecl) -> Result<()> {
231 self.datasources += 1;
232 walk_datasource(self, datasource)
233 }
234
235 fn visit_generator(&mut self, generator: &GeneratorDecl) -> Result<()> {
236 self.generators += 1;
237 walk_generator(self, generator)
238 }
239
240 fn visit_model(&mut self, model: &ModelDecl) -> Result<()> {
241 self.models += 1;
242 walk_model(self, model)
243 }
244
245 fn visit_enum(&mut self, enum_decl: &EnumDecl) -> Result<()> {
246 self.enums += 1;
247 walk_enum(self, enum_decl)
248 }
249
250 fn visit_field(&mut self, field: &FieldDecl) -> Result<()> {
251 self.fields += 1;
252 walk_field(self, field)
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259 use crate::span::Span;
260
261 #[test]
262 fn test_walk_expression() {
263 let expr = Expr::FunctionCall {
264 name: Ident::new("now".to_string(), Span::new(0, 3)),
265 args: vec![],
266 span: Span::new(0, 5),
267 };
268
269 let mut visitor = CountingVisitor::default();
270 visitor.visit_expr(&expr).unwrap();
271 }
272
273 #[test]
274 fn test_walk_nested_expr() {
275 let expr = Expr::Array {
276 elements: vec![
277 Expr::Literal(Literal::String("test".to_string(), Span::new(0, 4))),
278 Expr::FunctionCall {
279 name: Ident::new("env".to_string(), Span::new(0, 3)),
280 args: vec![Expr::Literal(Literal::String(
281 "VAR".to_string(),
282 Span::new(0, 3),
283 ))],
284 span: Span::new(0, 10),
285 },
286 ],
287 span: Span::new(0, 20),
288 };
289
290 let mut visitor = CountingVisitor::default();
291 visitor.visit_expr(&expr).unwrap();
292 }
293}