1use shape_ast::ast::*;
19
20pub trait Visitor: Sized {
35 fn visit_expr(&mut self, _expr: &Expr) -> bool {
40 true
41 }
42 fn leave_expr(&mut self, _expr: &Expr) {}
44
45 fn visit_stmt(&mut self, _stmt: &Statement) -> bool {
47 true
48 }
49 fn leave_stmt(&mut self, _stmt: &Statement) {}
50
51 fn visit_item(&mut self, _item: &Item) -> bool {
53 true
54 }
55 fn leave_item(&mut self, _item: &Item) {}
56
57 fn visit_function(&mut self, _func: &FunctionDef) -> bool {
59 true
60 }
61 fn leave_function(&mut self, _func: &FunctionDef) {}
62
63 fn visit_literal(&mut self, _lit: &Literal) -> bool {
65 true
66 }
67 fn leave_literal(&mut self, _lit: &Literal) {}
68
69 fn visit_block(&mut self, _block: &BlockExpr) -> bool {
71 true
72 }
73 fn leave_block(&mut self, _block: &BlockExpr) {}
74
75 fn visit_expr_literal(&mut self, _expr: &Expr, _span: Span) -> bool {
83 true
84 }
85 fn visit_expr_identifier(&mut self, _expr: &Expr, _span: Span) -> bool {
86 true
87 }
88 fn visit_expr_data_ref(&mut self, _expr: &Expr, _span: Span) -> bool {
89 true
90 }
91 fn visit_expr_data_datetime_ref(&mut self, _expr: &Expr, _span: Span) -> bool {
92 true
93 }
94 fn visit_expr_data_relative_access(&mut self, _expr: &Expr, _span: Span) -> bool {
95 true
96 }
97 fn visit_expr_property_access(&mut self, _expr: &Expr, _span: Span) -> bool {
98 true
99 }
100 fn visit_expr_index_access(&mut self, _expr: &Expr, _span: Span) -> bool {
101 true
102 }
103 fn visit_expr_binary_op(&mut self, _expr: &Expr, _span: Span) -> bool {
104 true
105 }
106 fn visit_expr_fuzzy_comparison(&mut self, _expr: &Expr, _span: Span) -> bool {
107 true
108 }
109 fn visit_expr_unary_op(&mut self, _expr: &Expr, _span: Span) -> bool {
110 true
111 }
112 fn visit_expr_function_call(&mut self, _expr: &Expr, _span: Span) -> bool {
113 true
114 }
115 fn visit_expr_enum_constructor(&mut self, _expr: &Expr, _span: Span) -> bool {
116 true
117 }
118 fn visit_expr_time_ref(&mut self, _expr: &Expr, _span: Span) -> bool {
119 true
120 }
121 fn visit_expr_datetime(&mut self, _expr: &Expr, _span: Span) -> bool {
122 true
123 }
124 fn visit_expr_pattern_ref(&mut self, _expr: &Expr, _span: Span) -> bool {
125 true
126 }
127 fn visit_expr_conditional(&mut self, _expr: &Expr, _span: Span) -> bool {
128 true
129 }
130 fn visit_expr_object(&mut self, _expr: &Expr, _span: Span) -> bool {
131 true
132 }
133 fn visit_expr_array(&mut self, _expr: &Expr, _span: Span) -> bool {
134 true
135 }
136 fn visit_expr_list_comprehension(&mut self, _expr: &Expr, _span: Span) -> bool {
137 true
138 }
139 fn visit_expr_block(&mut self, _expr: &Expr, _span: Span) -> bool {
140 true
141 }
142 fn visit_expr_type_assertion(&mut self, _expr: &Expr, _span: Span) -> bool {
143 true
144 }
145 fn visit_expr_instance_of(&mut self, _expr: &Expr, _span: Span) -> bool {
146 true
147 }
148 fn visit_expr_function_expr(&mut self, _expr: &Expr, _span: Span) -> bool {
149 true
150 }
151 fn visit_expr_duration(&mut self, _expr: &Expr, _span: Span) -> bool {
152 true
153 }
154 fn visit_expr_spread(&mut self, _expr: &Expr, _span: Span) -> bool {
155 true
156 }
157 fn visit_expr_if(&mut self, _expr: &Expr, _span: Span) -> bool {
158 true
159 }
160 fn visit_expr_while(&mut self, _expr: &Expr, _span: Span) -> bool {
161 true
162 }
163 fn visit_expr_for(&mut self, _expr: &Expr, _span: Span) -> bool {
164 true
165 }
166 fn visit_expr_loop(&mut self, _expr: &Expr, _span: Span) -> bool {
167 true
168 }
169 fn visit_expr_let(&mut self, _expr: &Expr, _span: Span) -> bool {
170 true
171 }
172 fn visit_expr_assign(&mut self, _expr: &Expr, _span: Span) -> bool {
173 true
174 }
175 fn visit_expr_break(&mut self, _expr: &Expr, _span: Span) -> bool {
176 true
177 }
178 fn visit_expr_continue(&mut self, _expr: &Expr, _span: Span) -> bool {
179 true
180 }
181 fn visit_expr_return(&mut self, _expr: &Expr, _span: Span) -> bool {
182 true
183 }
184 fn visit_expr_method_call(&mut self, _expr: &Expr, _span: Span) -> bool {
185 true
186 }
187 fn visit_expr_match(&mut self, _expr: &Expr, _span: Span) -> bool {
188 true
189 }
190 fn visit_expr_unit(&mut self, _expr: &Expr, _span: Span) -> bool {
191 true
192 }
193 fn visit_expr_range(&mut self, _expr: &Expr, _span: Span) -> bool {
194 true
195 }
196 fn visit_expr_timeframe_context(&mut self, _expr: &Expr, _span: Span) -> bool {
197 true
198 }
199 fn visit_expr_try_operator(&mut self, _expr: &Expr, _span: Span) -> bool {
200 true
201 }
202 fn visit_expr_using_impl(&mut self, _expr: &Expr, _span: Span) -> bool {
203 true
204 }
205 fn visit_expr_simulation_call(&mut self, _expr: &Expr, _span: Span) -> bool {
206 true
207 }
208 fn visit_expr_window_expr(&mut self, _expr: &Expr, _span: Span) -> bool {
209 true
210 }
211 fn visit_expr_from_query(&mut self, _expr: &Expr, _span: Span) -> bool {
212 true
213 }
214 fn visit_expr_struct_literal(&mut self, _expr: &Expr, _span: Span) -> bool {
215 true
216 }
217 fn visit_expr_await(&mut self, _expr: &Expr, _span: Span) -> bool {
218 true
219 }
220 fn visit_expr_join(&mut self, _expr: &Expr, _span: Span) -> bool {
221 true
222 }
223 fn visit_expr_annotated(&mut self, _expr: &Expr, _span: Span) -> bool {
224 true
225 }
226 fn visit_expr_async_let(&mut self, _expr: &Expr, _span: Span) -> bool {
227 true
228 }
229 fn visit_expr_async_scope(&mut self, _expr: &Expr, _span: Span) -> bool {
230 true
231 }
232 fn visit_expr_comptime(&mut self, _expr: &Expr, _span: Span) -> bool {
233 true
234 }
235 fn visit_expr_comptime_for(&mut self, _expr: &Expr, _span: Span) -> bool {
236 true
237 }
238 fn visit_expr_reference(&mut self, _expr: &Expr, _span: Span) -> bool {
239 true
240 }
241}
242
243pub fn walk_program<V: Visitor>(visitor: &mut V, program: &Program) {
247 for item in &program.items {
248 walk_item(visitor, item);
249 }
250}
251
252pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) {
254 if !visitor.visit_item(item) {
255 return;
256 }
257
258 match item {
259 Item::Import(_, _) => {}
260 Item::Module(module_def, _) => {
261 for inner in &module_def.items {
262 walk_item(visitor, inner);
263 }
264 }
265 Item::Export(export, _) => match &export.item {
266 ExportItem::Function(func) => walk_function(visitor, func),
267 ExportItem::TypeAlias(_) => {}
268 ExportItem::Named(_) => {}
269 ExportItem::Enum(_) => {}
270 ExportItem::Struct(_) => {}
271 ExportItem::Interface(_) => {}
272 ExportItem::Trait(_) => {}
273 ExportItem::ForeignFunction(_) => {} },
275 Item::TypeAlias(_, _) => {}
276 Item::Interface(_, _) => {}
277 Item::Trait(_, _) => {}
278 Item::Enum(_, _) => {}
279 Item::Extend(extend, _) => {
280 for method in &extend.methods {
281 for stmt in &method.body {
282 walk_stmt(visitor, stmt);
283 }
284 }
285 }
286 Item::Impl(impl_block, _) => {
287 for method in &impl_block.methods {
288 for stmt in &method.body {
289 walk_stmt(visitor, stmt);
290 }
291 }
292 }
293 Item::Function(func, _) => walk_function(visitor, func),
294 Item::Query(query, _) => walk_query(visitor, query),
295 Item::VariableDecl(decl, _) => {
296 if let Some(value) = &decl.value {
297 walk_expr(visitor, value);
298 }
299 }
300 Item::Assignment(assign, _) => {
301 walk_expr(visitor, &assign.value);
302 }
303 Item::Expression(expr, _) => walk_expr(visitor, expr),
304 Item::Stream(stream, _) => {
305 for decl in &stream.state {
306 if let Some(value) = &decl.value {
307 walk_expr(visitor, value);
308 }
309 }
310 if let Some(stmts) = &stream.on_connect {
311 for stmt in stmts {
312 walk_stmt(visitor, stmt);
313 }
314 }
315 if let Some(stmts) = &stream.on_disconnect {
316 for stmt in stmts {
317 walk_stmt(visitor, stmt);
318 }
319 }
320 if let Some(on_event) = &stream.on_event {
321 for stmt in &on_event.body {
322 walk_stmt(visitor, stmt);
323 }
324 }
325 if let Some(on_window) = &stream.on_window {
326 for stmt in &on_window.body {
327 walk_stmt(visitor, stmt);
328 }
329 }
330 if let Some(on_error) = &stream.on_error {
331 for stmt in &on_error.body {
332 walk_stmt(visitor, stmt);
333 }
334 }
335 }
336 Item::Test(test, _) => {
337 if let Some(setup) = &test.setup {
338 for stmt in setup {
339 walk_stmt(visitor, stmt);
340 }
341 }
342 if let Some(teardown) = &test.teardown {
343 for stmt in teardown {
344 walk_stmt(visitor, stmt);
345 }
346 }
347 for case in &test.test_cases {
348 for test_stmt in &case.body {
349 walk_test_statement(visitor, test_stmt);
350 }
351 }
352 }
353 Item::Optimize(opt, _) => {
354 walk_expr(visitor, &opt.range.0);
355 walk_expr(visitor, &opt.range.1);
356 if let OptimizationMetric::Custom(expr) = &opt.metric {
357 walk_expr(visitor, expr);
358 }
359 }
360 Item::Statement(stmt, _) => walk_stmt(visitor, stmt),
361 Item::AnnotationDef(ann_def, _) => {
362 for handler in &ann_def.handlers {
364 walk_expr(visitor, &handler.body);
365 }
366 }
367 Item::StructType(_, _) => {
368 }
370 Item::DataSource(ds, _) => {
371 walk_expr(visitor, &ds.provider_expr);
372 }
373 Item::QueryDecl(_, _) => {
374 }
376 Item::Comptime(stmts, _) => {
377 for stmt in stmts {
378 walk_stmt(visitor, stmt);
379 }
380 }
381 Item::BuiltinTypeDecl(_, _) => {
382 }
384 Item::BuiltinFunctionDecl(_, _) => {
385 }
387 Item::ForeignFunction(_, _) => {
388 }
390 }
391
392 visitor.leave_item(item);
393}
394
395pub fn walk_function<V: Visitor>(visitor: &mut V, func: &FunctionDef) {
397 if !visitor.visit_function(func) {
398 return;
399 }
400
401 for param in &func.params {
403 if let Some(default) = ¶m.default_value {
404 walk_expr(visitor, default);
405 }
406 }
407
408 for stmt in &func.body {
410 walk_stmt(visitor, stmt);
411 }
412
413 visitor.leave_function(func);
414}
415
416pub fn walk_query<V: Visitor>(visitor: &mut V, query: &Query) {
418 match query {
419 Query::Backtest(backtest) => {
420 for (_, expr) in &backtest.parameters {
421 walk_expr(visitor, expr);
422 }
423 }
424 Query::Alert(alert) => {
425 walk_expr(visitor, &alert.condition);
426 }
427 Query::With(with_query) => {
428 for cte in &with_query.ctes {
430 walk_query(visitor, &cte.query);
431 }
432 walk_query(visitor, &with_query.query);
434 }
435 }
436}
437
438pub fn walk_stmt<V: Visitor>(visitor: &mut V, stmt: &Statement) {
440 if !visitor.visit_stmt(stmt) {
441 return;
442 }
443
444 match stmt {
445 Statement::Return(expr, _) => {
446 if let Some(e) = expr {
447 walk_expr(visitor, e);
448 }
449 }
450 Statement::Break(_) => {}
451 Statement::Continue(_) => {}
452 Statement::VariableDecl(decl, _) => {
453 if let Some(value) = &decl.value {
454 walk_expr(visitor, value);
455 }
456 }
457 Statement::Assignment(assign, _) => {
458 walk_expr(visitor, &assign.value);
459 }
460 Statement::Expression(expr, _) => walk_expr(visitor, expr),
461 Statement::For(for_loop, _) => {
462 match &for_loop.init {
463 ForInit::ForIn { iter, .. } => walk_expr(visitor, iter),
464 ForInit::ForC {
465 init,
466 condition,
467 update,
468 } => {
469 walk_stmt(visitor, init);
470 walk_expr(visitor, condition);
471 walk_expr(visitor, update);
472 }
473 }
474 for stmt in &for_loop.body {
475 walk_stmt(visitor, stmt);
476 }
477 }
478 Statement::While(while_loop, _) => {
479 walk_expr(visitor, &while_loop.condition);
480 for stmt in &while_loop.body {
481 walk_stmt(visitor, stmt);
482 }
483 }
484 Statement::If(if_stmt, _) => {
485 walk_expr(visitor, &if_stmt.condition);
486 for stmt in &if_stmt.then_body {
487 walk_stmt(visitor, stmt);
488 }
489 if let Some(else_body) = &if_stmt.else_body {
490 for stmt in else_body {
491 walk_stmt(visitor, stmt);
492 }
493 }
494 }
495 Statement::Extend(ext, _) => {
496 for method in &ext.methods {
497 for stmt in &method.body {
498 walk_stmt(visitor, stmt);
499 }
500 }
501 }
502 Statement::RemoveTarget(_) => {}
503 Statement::SetParamType { .. }
504 | Statement::SetReturnType { .. }
505 | Statement::SetReturnExpr { .. } => {}
506 Statement::SetParamValue { expression, .. } => {
507 walk_expr(visitor, expression);
508 }
509 Statement::ReplaceModuleExpr { expression, .. } => {
510 walk_expr(visitor, expression);
511 }
512 Statement::ReplaceBodyExpr { expression, .. } => {
513 walk_expr(visitor, expression);
514 }
515 Statement::ReplaceBody { body, .. } => {
516 for stmt in body {
517 walk_stmt(visitor, stmt);
518 }
519 }
520 }
521
522 visitor.leave_stmt(stmt);
523}
524
525pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr) {
533 if !visitor.visit_expr(expr) {
534 return;
535 }
536
537 match expr {
538 Expr::Literal(lit, span) => {
540 if visitor.visit_expr_literal(expr, *span) {
541 visitor.visit_literal(lit);
542 visitor.leave_literal(lit);
543 }
544 }
545 Expr::Identifier(_, span) => {
546 visitor.visit_expr_identifier(expr, *span);
547 }
548 Expr::DataRef(data_ref, span) => {
549 if visitor.visit_expr_data_ref(expr, *span) {
550 match &data_ref.index {
551 DataIndex::Expression(e) => walk_expr(visitor, e),
552 DataIndex::ExpressionRange(start, end) => {
553 walk_expr(visitor, start);
554 walk_expr(visitor, end);
555 }
556 DataIndex::Single(_) | DataIndex::Range(_, _) => {}
557 }
558 }
559 }
560 Expr::DataDateTimeRef(_, span) => {
561 visitor.visit_expr_data_datetime_ref(expr, *span);
562 }
563 Expr::DataRelativeAccess {
564 reference,
565 index,
566 span,
567 } => {
568 if visitor.visit_expr_data_relative_access(expr, *span) {
569 walk_expr(visitor, reference);
570 match index {
571 DataIndex::Expression(e) => walk_expr(visitor, e),
572 DataIndex::ExpressionRange(start, end) => {
573 walk_expr(visitor, start);
574 walk_expr(visitor, end);
575 }
576 DataIndex::Single(_) | DataIndex::Range(_, _) => {}
577 }
578 }
579 }
580 Expr::PropertyAccess { object, span, .. } => {
581 if visitor.visit_expr_property_access(expr, *span) {
582 walk_expr(visitor, object);
583 }
584 }
585 Expr::IndexAccess {
586 object,
587 index,
588 end_index,
589 span,
590 } => {
591 if visitor.visit_expr_index_access(expr, *span) {
592 walk_expr(visitor, object);
593 walk_expr(visitor, index);
594 if let Some(end) = end_index {
595 walk_expr(visitor, end);
596 }
597 }
598 }
599 Expr::BinaryOp {
600 left, right, span, ..
601 } => {
602 if visitor.visit_expr_binary_op(expr, *span) {
603 walk_expr(visitor, left);
604 walk_expr(visitor, right);
605 }
606 }
607 Expr::FuzzyComparison {
608 left, right, span, ..
609 } => {
610 if visitor.visit_expr_fuzzy_comparison(expr, *span) {
611 walk_expr(visitor, left);
612 walk_expr(visitor, right);
613 }
614 }
615 Expr::UnaryOp { operand, span, .. } => {
616 if visitor.visit_expr_unary_op(expr, *span) {
617 walk_expr(visitor, operand);
618 }
619 }
620 Expr::FunctionCall {
621 args,
622 named_args,
623 span,
624 ..
625 } => {
626 if visitor.visit_expr_function_call(expr, *span) {
627 for arg in args {
628 walk_expr(visitor, arg);
629 }
630 for (_, value) in named_args {
631 walk_expr(visitor, value);
632 }
633 }
634 }
635 Expr::EnumConstructor { payload, span, .. } => {
636 if visitor.visit_expr_enum_constructor(expr, *span) {
637 match payload {
638 EnumConstructorPayload::Unit => {}
639 EnumConstructorPayload::Tuple(values) => {
640 for value in values {
641 walk_expr(visitor, value);
642 }
643 }
644 EnumConstructorPayload::Struct(fields) => {
645 for (_, value) in fields {
646 walk_expr(visitor, value);
647 }
648 }
649 }
650 }
651 }
652 Expr::TimeRef(_, span) => {
653 visitor.visit_expr_time_ref(expr, *span);
654 }
655 Expr::DateTime(_, span) => {
656 visitor.visit_expr_datetime(expr, *span);
657 }
658 Expr::PatternRef(_, span) => {
659 visitor.visit_expr_pattern_ref(expr, *span);
660 }
661 Expr::Conditional {
662 condition,
663 then_expr,
664 else_expr,
665 span,
666 } => {
667 if visitor.visit_expr_conditional(expr, *span) {
668 walk_expr(visitor, condition);
669 walk_expr(visitor, then_expr);
670 if let Some(else_e) = else_expr {
671 walk_expr(visitor, else_e);
672 }
673 }
674 }
675 Expr::Object(entries, span) => {
676 if visitor.visit_expr_object(expr, *span) {
677 for entry in entries {
678 match entry {
679 ObjectEntry::Field { value, .. } => walk_expr(visitor, value),
680 ObjectEntry::Spread(spread_expr) => walk_expr(visitor, spread_expr),
681 }
682 }
683 }
684 }
685 Expr::Array(elements, span) => {
686 if visitor.visit_expr_array(expr, *span) {
687 for elem in elements {
688 walk_expr(visitor, elem);
689 }
690 }
691 }
692 Expr::TableRows(rows, _span) => {
693 for row in rows {
694 for elem in row {
695 walk_expr(visitor, elem);
696 }
697 }
698 }
699 Expr::ListComprehension(comp, span) => {
700 if visitor.visit_expr_list_comprehension(expr, *span) {
701 walk_expr(visitor, &comp.element);
702 for clause in &comp.clauses {
703 walk_expr(visitor, &clause.iterable);
704 if let Some(filter) = &clause.filter {
705 walk_expr(visitor, filter);
706 }
707 }
708 }
709 }
710 Expr::Block(block, span) => {
711 if visitor.visit_expr_block(expr, *span) {
712 if visitor.visit_block(block) {
713 for item in &block.items {
714 match item {
715 BlockItem::VariableDecl(decl) => {
716 if let Some(value) = &decl.value {
717 walk_expr(visitor, value);
718 }
719 }
720 BlockItem::Assignment(assign) => {
721 walk_expr(visitor, &assign.value);
722 }
723 BlockItem::Statement(stmt) => {
724 walk_stmt(visitor, stmt);
725 }
726 BlockItem::Expression(e) => walk_expr(visitor, e),
727 }
728 }
729 visitor.leave_block(block);
730 }
731 }
732 }
733 Expr::TypeAssertion {
734 expr: inner, span, ..
735 } => {
736 if visitor.visit_expr_type_assertion(expr, *span) {
737 walk_expr(visitor, inner);
738 }
739 }
740 Expr::InstanceOf {
741 expr: inner, span, ..
742 } => {
743 if visitor.visit_expr_instance_of(expr, *span) {
744 walk_expr(visitor, inner);
745 }
746 }
747 Expr::FunctionExpr {
748 params, body, span, ..
749 } => {
750 if visitor.visit_expr_function_expr(expr, *span) {
751 for param in params {
752 if let Some(default) = ¶m.default_value {
753 walk_expr(visitor, default);
754 }
755 }
756 for stmt in body {
757 walk_stmt(visitor, stmt);
758 }
759 }
760 }
761 Expr::Duration(_, span) => {
762 visitor.visit_expr_duration(expr, *span);
763 }
764 Expr::Spread(inner, span) => {
765 if visitor.visit_expr_spread(expr, *span) {
766 walk_expr(visitor, inner);
767 }
768 }
769 Expr::If(if_expr, span) => {
770 if visitor.visit_expr_if(expr, *span) {
771 walk_expr(visitor, &if_expr.condition);
772 walk_expr(visitor, &if_expr.then_branch);
773 if let Some(else_branch) = &if_expr.else_branch {
774 walk_expr(visitor, else_branch);
775 }
776 }
777 }
778 Expr::While(while_expr, span) => {
779 if visitor.visit_expr_while(expr, *span) {
780 walk_expr(visitor, &while_expr.condition);
781 walk_expr(visitor, &while_expr.body);
782 }
783 }
784 Expr::For(for_expr, span) => {
785 if visitor.visit_expr_for(expr, *span) {
786 walk_expr(visitor, &for_expr.iterable);
787 walk_expr(visitor, &for_expr.body);
788 }
789 }
790 Expr::Loop(loop_expr, span) => {
791 if visitor.visit_expr_loop(expr, *span) {
792 walk_expr(visitor, &loop_expr.body);
793 }
794 }
795 Expr::Let(let_expr, span) => {
796 if visitor.visit_expr_let(expr, *span) {
797 if let Some(value) = &let_expr.value {
798 walk_expr(visitor, value);
799 }
800 walk_expr(visitor, &let_expr.body);
801 }
802 }
803 Expr::Assign(assign, span) => {
804 if visitor.visit_expr_assign(expr, *span) {
805 walk_expr(visitor, &assign.target);
806 walk_expr(visitor, &assign.value);
807 }
808 }
809 Expr::Break(inner, span) => {
810 if visitor.visit_expr_break(expr, *span) {
811 if let Some(e) = inner {
812 walk_expr(visitor, e);
813 }
814 }
815 }
816 Expr::Continue(span) => {
817 visitor.visit_expr_continue(expr, *span);
818 }
819 Expr::Return(inner, span) => {
820 if visitor.visit_expr_return(expr, *span) {
821 if let Some(e) = inner {
822 walk_expr(visitor, e);
823 }
824 }
825 }
826 Expr::MethodCall {
827 receiver,
828 args,
829 named_args,
830 span,
831 ..
832 } => {
833 if visitor.visit_expr_method_call(expr, *span) {
834 walk_expr(visitor, receiver);
835 for arg in args {
836 walk_expr(visitor, arg);
837 }
838 for (_, value) in named_args {
839 walk_expr(visitor, value);
840 }
841 }
842 }
843 Expr::Match(match_expr, span) => {
844 if visitor.visit_expr_match(expr, *span) {
845 walk_expr(visitor, &match_expr.scrutinee);
846 for arm in &match_expr.arms {
847 if let Some(guard) = &arm.guard {
848 walk_expr(visitor, guard);
849 }
850 walk_expr(visitor, &arm.body);
851 }
852 }
853 }
854 Expr::Unit(span) => {
855 visitor.visit_expr_unit(expr, *span);
856 }
857 Expr::Range {
858 start, end, span, ..
859 } => {
860 if visitor.visit_expr_range(expr, *span) {
861 if let Some(s) = start {
862 walk_expr(visitor, s);
863 }
864 if let Some(e) = end {
865 walk_expr(visitor, e);
866 }
867 }
868 }
869 Expr::TimeframeContext {
870 expr: inner, span, ..
871 } => {
872 if visitor.visit_expr_timeframe_context(expr, *span) {
873 walk_expr(visitor, inner);
874 }
875 }
876 Expr::TryOperator(inner, span) => {
877 if visitor.visit_expr_try_operator(expr, *span) {
878 walk_expr(visitor, inner);
879 }
880 }
881 Expr::UsingImpl {
882 expr: inner, span, ..
883 } => {
884 if visitor.visit_expr_using_impl(expr, *span) {
885 walk_expr(visitor, inner);
886 }
887 }
888 Expr::SimulationCall { params, span, .. } => {
889 if visitor.visit_expr_simulation_call(expr, *span) {
890 for (_, value) in params {
891 walk_expr(visitor, value);
892 }
893 }
894 }
895 Expr::WindowExpr(window_expr, span) => {
896 if visitor.visit_expr_window_expr(expr, *span) {
897 match &window_expr.function {
899 WindowFunction::Lead { expr, default, .. }
900 | WindowFunction::Lag { expr, default, .. } => {
901 walk_expr(visitor, expr);
902 if let Some(d) = default {
903 walk_expr(visitor, d);
904 }
905 }
906 WindowFunction::FirstValue(e)
907 | WindowFunction::LastValue(e)
908 | WindowFunction::Sum(e)
909 | WindowFunction::Avg(e)
910 | WindowFunction::Min(e)
911 | WindowFunction::Max(e) => {
912 walk_expr(visitor, e);
913 }
914 WindowFunction::NthValue(e, _) => {
915 walk_expr(visitor, e);
916 }
917 WindowFunction::Count(opt_e) => {
918 if let Some(e) = opt_e {
919 walk_expr(visitor, e);
920 }
921 }
922 WindowFunction::RowNumber
923 | WindowFunction::Rank
924 | WindowFunction::DenseRank
925 | WindowFunction::Ntile(_) => {}
926 }
927 for e in &window_expr.over.partition_by {
929 walk_expr(visitor, e);
930 }
931 if let Some(order_by) = &window_expr.over.order_by {
933 for (e, _) in &order_by.columns {
934 walk_expr(visitor, e);
935 }
936 }
937 }
938 }
939 Expr::FromQuery(from_query, span) => {
940 if visitor.visit_expr_from_query(expr, *span) {
941 walk_expr(visitor, &from_query.source);
943 for clause in &from_query.clauses {
945 match clause {
946 QueryClause::Where(pred) => {
947 walk_expr(visitor, pred);
948 }
949 QueryClause::OrderBy(specs) => {
950 for spec in specs {
951 walk_expr(visitor, &spec.key);
952 }
953 }
954 QueryClause::GroupBy { element, key, .. } => {
955 walk_expr(visitor, element);
956 walk_expr(visitor, key);
957 }
958 QueryClause::Join {
959 source,
960 left_key,
961 right_key,
962 ..
963 } => {
964 walk_expr(visitor, source);
965 walk_expr(visitor, left_key);
966 walk_expr(visitor, right_key);
967 }
968 QueryClause::Let { value, .. } => {
969 walk_expr(visitor, value);
970 }
971 }
972 }
973 walk_expr(visitor, &from_query.select);
975 }
976 }
977 Expr::StructLiteral { fields, span, .. } => {
978 if visitor.visit_expr_struct_literal(expr, *span) {
979 for (_, value_expr) in fields {
980 walk_expr(visitor, value_expr);
981 }
982 }
983 }
984 Expr::Await(inner, span) => {
985 if visitor.visit_expr_await(expr, *span) {
986 walk_expr(visitor, inner);
987 }
988 }
989 Expr::Join(join_expr, span) => {
990 if visitor.visit_expr_join(expr, *span) {
991 for branch in &join_expr.branches {
992 walk_expr(visitor, &branch.expr);
993 }
994 }
995 }
996 Expr::Annotated { target, span, .. } => {
997 if visitor.visit_expr_annotated(expr, *span) {
998 walk_expr(visitor, target);
999 }
1000 }
1001 Expr::AsyncLet(async_let, span) => {
1002 if visitor.visit_expr_async_let(expr, *span) {
1003 walk_expr(visitor, &async_let.expr);
1004 }
1005 }
1006 Expr::AsyncScope(inner, span) => {
1007 if visitor.visit_expr_async_scope(expr, *span) {
1008 walk_expr(visitor, inner);
1009 }
1010 }
1011 Expr::Comptime(stmts, span) => {
1012 if visitor.visit_expr_comptime(expr, *span) {
1013 for stmt in stmts {
1014 walk_stmt(visitor, stmt);
1015 }
1016 }
1017 }
1018 Expr::ComptimeFor(cf, span) => {
1019 if visitor.visit_expr_comptime_for(expr, *span) {
1020 walk_expr(visitor, &cf.iterable);
1021 for stmt in &cf.body {
1022 walk_stmt(visitor, stmt);
1023 }
1024 }
1025 }
1026 Expr::Reference {
1027 expr: inner, span, ..
1028 } => {
1029 if visitor.visit_expr_reference(expr, *span) {
1030 walk_expr(visitor, inner);
1031 }
1032 }
1033 }
1034
1035 visitor.leave_expr(expr);
1036}
1037
1038fn walk_test_statement<V: Visitor>(visitor: &mut V, test_stmt: &TestStatement) {
1040 match test_stmt {
1041 TestStatement::Statement(stmt) => walk_stmt(visitor, stmt),
1042 TestStatement::Assert(assert) => {
1043 walk_expr(visitor, &assert.condition);
1044 }
1045 TestStatement::Expect(expect) => {
1046 walk_expr(visitor, &expect.actual);
1047 match &expect.matcher {
1048 ExpectationMatcher::ToBe(e) => walk_expr(visitor, e),
1049 ExpectationMatcher::ToEqual(e) => walk_expr(visitor, e),
1050 ExpectationMatcher::ToBeCloseTo { expected, .. } => walk_expr(visitor, expected),
1051 ExpectationMatcher::ToBeGreaterThan(e) => walk_expr(visitor, e),
1052 ExpectationMatcher::ToBeLessThan(e) => walk_expr(visitor, e),
1053 ExpectationMatcher::ToContain(e) => walk_expr(visitor, e),
1054 ExpectationMatcher::ToBeTruthy => {}
1055 ExpectationMatcher::ToBeFalsy => {}
1056 ExpectationMatcher::ToThrow(_) => {}
1057 ExpectationMatcher::ToMatchPattern { .. } => {}
1058 }
1059 }
1060 TestStatement::Should(should) => {
1061 walk_expr(visitor, &should.subject);
1062 match &should.matcher {
1063 ShouldMatcher::Be(e) => walk_expr(visitor, e),
1064 ShouldMatcher::Equal(e) => walk_expr(visitor, e),
1065 ShouldMatcher::Contain(e) => walk_expr(visitor, e),
1066 ShouldMatcher::Match(_) => {}
1067 ShouldMatcher::BeCloseTo { expected, .. } => walk_expr(visitor, expected),
1068 }
1069 }
1070 TestStatement::Fixture(fixture) => match fixture {
1071 TestFixture::WithData { data, body } => {
1072 walk_expr(visitor, data);
1073 for stmt in body {
1074 walk_stmt(visitor, stmt);
1075 }
1076 }
1077 TestFixture::WithMock {
1078 mock_value, body, ..
1079 } => {
1080 if let Some(value) = mock_value {
1081 walk_expr(visitor, value);
1082 }
1083 for stmt in body {
1084 walk_stmt(visitor, stmt);
1085 }
1086 }
1087 },
1088 }
1089}
1090
1091#[cfg(test)]
1092mod tests {
1093 use super::*;
1094
1095 struct ExprCounter {
1097 count: usize,
1098 }
1099
1100 impl Visitor for ExprCounter {
1101 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1102 self.count += 1;
1103 true
1104 }
1105 }
1106
1107 #[test]
1108 fn test_visitor_counts_expressions() {
1109 let program = Program {
1110 items: vec![Item::Expression(
1111 Expr::BinaryOp {
1112 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1113 op: BinaryOp::Add,
1114 right: Box::new(Expr::Literal(Literal::Number(1.0), Span::DUMMY)),
1115 span: Span::DUMMY,
1116 },
1117 Span::DUMMY,
1118 )],
1119 docs: shape_ast::ast::ProgramDocs::default(),
1120 };
1121
1122 let mut counter = ExprCounter { count: 0 };
1123 walk_program(&mut counter, &program);
1124
1125 assert_eq!(counter.count, 3);
1127 }
1128
1129 #[test]
1130 fn test_visitor_handles_try_operator() {
1131 let program = Program {
1132 items: vec![Item::Expression(
1133 Expr::TryOperator(
1134 Box::new(Expr::FunctionCall {
1135 name: "some_function".to_string(),
1136 args: vec![Expr::Literal(
1137 Literal::String("arg".to_string()),
1138 Span::DUMMY,
1139 )],
1140 named_args: vec![],
1141 span: Span::DUMMY,
1142 }),
1143 Span::DUMMY,
1144 ),
1145 Span::DUMMY,
1146 )],
1147 docs: shape_ast::ast::ProgramDocs::default(),
1148 };
1149
1150 let mut counter = ExprCounter { count: 0 };
1151 walk_program(&mut counter, &program);
1152
1153 assert_eq!(counter.count, 3);
1155 }
1156
1157 struct IdentifierCollector {
1159 names: Vec<String>,
1160 }
1161
1162 impl Visitor for IdentifierCollector {
1163 fn visit_expr_identifier(&mut self, expr: &Expr, _span: Span) -> bool {
1164 if let Expr::Identifier(name, _) = expr {
1165 self.names.push(name.clone());
1166 }
1167 true
1168 }
1169 }
1170
1171 #[test]
1172 fn test_per_variant_visitor_identifier() {
1173 let program = Program {
1174 items: vec![Item::Expression(
1175 Expr::BinaryOp {
1176 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1177 op: BinaryOp::Add,
1178 right: Box::new(Expr::Identifier("y".to_string(), Span::DUMMY)),
1179 span: Span::DUMMY,
1180 },
1181 Span::DUMMY,
1182 )],
1183 docs: shape_ast::ast::ProgramDocs::default(),
1184 };
1185
1186 let mut collector = IdentifierCollector { names: vec![] };
1187 walk_program(&mut collector, &program);
1188
1189 assert_eq!(collector.names, vec!["x", "y"]);
1190 }
1191
1192 struct SkippingVisitor {
1194 count: usize,
1195 }
1196
1197 impl Visitor for SkippingVisitor {
1198 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1199 self.count += 1;
1200 true
1201 }
1202 fn visit_expr_binary_op(&mut self, _expr: &Expr, _span: Span) -> bool {
1204 false
1205 }
1206 }
1207
1208 #[test]
1209 fn test_per_variant_skip_children() {
1210 let program = Program {
1211 items: vec![Item::Expression(
1212 Expr::BinaryOp {
1213 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1214 op: BinaryOp::Add,
1215 right: Box::new(Expr::Literal(Literal::Number(1.0), Span::DUMMY)),
1216 span: Span::DUMMY,
1217 },
1218 Span::DUMMY,
1219 )],
1220 docs: shape_ast::ast::ProgramDocs::default(),
1221 };
1222
1223 let mut v = SkippingVisitor { count: 0 };
1224 walk_program(&mut v, &program);
1225
1226 assert_eq!(v.count, 1);
1228 }
1229
1230 struct MatchCollector {
1232 match_count: usize,
1233 total_expr_count: usize,
1234 }
1235
1236 impl Visitor for MatchCollector {
1237 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1238 self.total_expr_count += 1;
1239 true
1240 }
1241 fn visit_expr_match(&mut self, _expr: &Expr, _span: Span) -> bool {
1242 self.match_count += 1;
1243 true
1244 }
1245 }
1246
1247 #[test]
1248 fn test_coarse_and_per_variant_combined() {
1249 let program = Program {
1250 items: vec![Item::Expression(
1251 Expr::BinaryOp {
1252 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1253 op: BinaryOp::Add,
1254 right: Box::new(Expr::Identifier("y".to_string(), Span::DUMMY)),
1255 span: Span::DUMMY,
1256 },
1257 Span::DUMMY,
1258 )],
1259 docs: shape_ast::ast::ProgramDocs::default(),
1260 };
1261
1262 let mut mc = MatchCollector {
1263 match_count: 0,
1264 total_expr_count: 0,
1265 };
1266 walk_program(&mut mc, &program);
1267
1268 assert_eq!(mc.total_expr_count, 3); assert_eq!(mc.match_count, 0); }
1271}