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::ReplaceModuleExpr { expression, .. } => {
507 walk_expr(visitor, expression);
508 }
509 Statement::ReplaceBodyExpr { expression, .. } => {
510 walk_expr(visitor, expression);
511 }
512 Statement::ReplaceBody { body, .. } => {
513 for stmt in body {
514 walk_stmt(visitor, stmt);
515 }
516 }
517 }
518
519 visitor.leave_stmt(stmt);
520}
521
522pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr) {
530 if !visitor.visit_expr(expr) {
531 return;
532 }
533
534 match expr {
535 Expr::Literal(lit, span) => {
537 if visitor.visit_expr_literal(expr, *span) {
538 visitor.visit_literal(lit);
539 visitor.leave_literal(lit);
540 }
541 }
542 Expr::Identifier(_, span) => {
543 visitor.visit_expr_identifier(expr, *span);
544 }
545 Expr::DataRef(data_ref, span) => {
546 if visitor.visit_expr_data_ref(expr, *span) {
547 match &data_ref.index {
548 DataIndex::Expression(e) => walk_expr(visitor, e),
549 DataIndex::ExpressionRange(start, end) => {
550 walk_expr(visitor, start);
551 walk_expr(visitor, end);
552 }
553 DataIndex::Single(_) | DataIndex::Range(_, _) => {}
554 }
555 }
556 }
557 Expr::DataDateTimeRef(_, span) => {
558 visitor.visit_expr_data_datetime_ref(expr, *span);
559 }
560 Expr::DataRelativeAccess {
561 reference,
562 index,
563 span,
564 } => {
565 if visitor.visit_expr_data_relative_access(expr, *span) {
566 walk_expr(visitor, reference);
567 match index {
568 DataIndex::Expression(e) => walk_expr(visitor, e),
569 DataIndex::ExpressionRange(start, end) => {
570 walk_expr(visitor, start);
571 walk_expr(visitor, end);
572 }
573 DataIndex::Single(_) | DataIndex::Range(_, _) => {}
574 }
575 }
576 }
577 Expr::PropertyAccess { object, span, .. } => {
578 if visitor.visit_expr_property_access(expr, *span) {
579 walk_expr(visitor, object);
580 }
581 }
582 Expr::IndexAccess {
583 object,
584 index,
585 end_index,
586 span,
587 } => {
588 if visitor.visit_expr_index_access(expr, *span) {
589 walk_expr(visitor, object);
590 walk_expr(visitor, index);
591 if let Some(end) = end_index {
592 walk_expr(visitor, end);
593 }
594 }
595 }
596 Expr::BinaryOp {
597 left, right, span, ..
598 } => {
599 if visitor.visit_expr_binary_op(expr, *span) {
600 walk_expr(visitor, left);
601 walk_expr(visitor, right);
602 }
603 }
604 Expr::FuzzyComparison {
605 left, right, span, ..
606 } => {
607 if visitor.visit_expr_fuzzy_comparison(expr, *span) {
608 walk_expr(visitor, left);
609 walk_expr(visitor, right);
610 }
611 }
612 Expr::UnaryOp { operand, span, .. } => {
613 if visitor.visit_expr_unary_op(expr, *span) {
614 walk_expr(visitor, operand);
615 }
616 }
617 Expr::FunctionCall {
618 args,
619 named_args,
620 span,
621 ..
622 } => {
623 if visitor.visit_expr_function_call(expr, *span) {
624 for arg in args {
625 walk_expr(visitor, arg);
626 }
627 for (_, value) in named_args {
628 walk_expr(visitor, value);
629 }
630 }
631 }
632 Expr::EnumConstructor { payload, span, .. } => {
633 if visitor.visit_expr_enum_constructor(expr, *span) {
634 match payload {
635 EnumConstructorPayload::Unit => {}
636 EnumConstructorPayload::Tuple(values) => {
637 for value in values {
638 walk_expr(visitor, value);
639 }
640 }
641 EnumConstructorPayload::Struct(fields) => {
642 for (_, value) in fields {
643 walk_expr(visitor, value);
644 }
645 }
646 }
647 }
648 }
649 Expr::TimeRef(_, span) => {
650 visitor.visit_expr_time_ref(expr, *span);
651 }
652 Expr::DateTime(_, span) => {
653 visitor.visit_expr_datetime(expr, *span);
654 }
655 Expr::PatternRef(_, span) => {
656 visitor.visit_expr_pattern_ref(expr, *span);
657 }
658 Expr::Conditional {
659 condition,
660 then_expr,
661 else_expr,
662 span,
663 } => {
664 if visitor.visit_expr_conditional(expr, *span) {
665 walk_expr(visitor, condition);
666 walk_expr(visitor, then_expr);
667 if let Some(else_e) = else_expr {
668 walk_expr(visitor, else_e);
669 }
670 }
671 }
672 Expr::Object(entries, span) => {
673 if visitor.visit_expr_object(expr, *span) {
674 for entry in entries {
675 match entry {
676 ObjectEntry::Field { value, .. } => walk_expr(visitor, value),
677 ObjectEntry::Spread(spread_expr) => walk_expr(visitor, spread_expr),
678 }
679 }
680 }
681 }
682 Expr::Array(elements, span) => {
683 if visitor.visit_expr_array(expr, *span) {
684 for elem in elements {
685 walk_expr(visitor, elem);
686 }
687 }
688 }
689 Expr::TableRows(rows, _span) => {
690 for row in rows {
691 for elem in row {
692 walk_expr(visitor, elem);
693 }
694 }
695 }
696 Expr::ListComprehension(comp, span) => {
697 if visitor.visit_expr_list_comprehension(expr, *span) {
698 walk_expr(visitor, &comp.element);
699 for clause in &comp.clauses {
700 walk_expr(visitor, &clause.iterable);
701 if let Some(filter) = &clause.filter {
702 walk_expr(visitor, filter);
703 }
704 }
705 }
706 }
707 Expr::Block(block, span) => {
708 if visitor.visit_expr_block(expr, *span) {
709 if visitor.visit_block(block) {
710 for item in &block.items {
711 match item {
712 BlockItem::VariableDecl(decl) => {
713 if let Some(value) = &decl.value {
714 walk_expr(visitor, value);
715 }
716 }
717 BlockItem::Assignment(assign) => {
718 walk_expr(visitor, &assign.value);
719 }
720 BlockItem::Statement(stmt) => {
721 walk_stmt(visitor, stmt);
722 }
723 BlockItem::Expression(e) => walk_expr(visitor, e),
724 }
725 }
726 visitor.leave_block(block);
727 }
728 }
729 }
730 Expr::TypeAssertion {
731 expr: inner, span, ..
732 } => {
733 if visitor.visit_expr_type_assertion(expr, *span) {
734 walk_expr(visitor, inner);
735 }
736 }
737 Expr::InstanceOf {
738 expr: inner, span, ..
739 } => {
740 if visitor.visit_expr_instance_of(expr, *span) {
741 walk_expr(visitor, inner);
742 }
743 }
744 Expr::FunctionExpr {
745 params, body, span, ..
746 } => {
747 if visitor.visit_expr_function_expr(expr, *span) {
748 for param in params {
749 if let Some(default) = ¶m.default_value {
750 walk_expr(visitor, default);
751 }
752 }
753 for stmt in body {
754 walk_stmt(visitor, stmt);
755 }
756 }
757 }
758 Expr::Duration(_, span) => {
759 visitor.visit_expr_duration(expr, *span);
760 }
761 Expr::Spread(inner, span) => {
762 if visitor.visit_expr_spread(expr, *span) {
763 walk_expr(visitor, inner);
764 }
765 }
766 Expr::If(if_expr, span) => {
767 if visitor.visit_expr_if(expr, *span) {
768 walk_expr(visitor, &if_expr.condition);
769 walk_expr(visitor, &if_expr.then_branch);
770 if let Some(else_branch) = &if_expr.else_branch {
771 walk_expr(visitor, else_branch);
772 }
773 }
774 }
775 Expr::While(while_expr, span) => {
776 if visitor.visit_expr_while(expr, *span) {
777 walk_expr(visitor, &while_expr.condition);
778 walk_expr(visitor, &while_expr.body);
779 }
780 }
781 Expr::For(for_expr, span) => {
782 if visitor.visit_expr_for(expr, *span) {
783 walk_expr(visitor, &for_expr.iterable);
784 walk_expr(visitor, &for_expr.body);
785 }
786 }
787 Expr::Loop(loop_expr, span) => {
788 if visitor.visit_expr_loop(expr, *span) {
789 walk_expr(visitor, &loop_expr.body);
790 }
791 }
792 Expr::Let(let_expr, span) => {
793 if visitor.visit_expr_let(expr, *span) {
794 if let Some(value) = &let_expr.value {
795 walk_expr(visitor, value);
796 }
797 walk_expr(visitor, &let_expr.body);
798 }
799 }
800 Expr::Assign(assign, span) => {
801 if visitor.visit_expr_assign(expr, *span) {
802 walk_expr(visitor, &assign.target);
803 walk_expr(visitor, &assign.value);
804 }
805 }
806 Expr::Break(inner, span) => {
807 if visitor.visit_expr_break(expr, *span) {
808 if let Some(e) = inner {
809 walk_expr(visitor, e);
810 }
811 }
812 }
813 Expr::Continue(span) => {
814 visitor.visit_expr_continue(expr, *span);
815 }
816 Expr::Return(inner, span) => {
817 if visitor.visit_expr_return(expr, *span) {
818 if let Some(e) = inner {
819 walk_expr(visitor, e);
820 }
821 }
822 }
823 Expr::MethodCall {
824 receiver,
825 args,
826 named_args,
827 span,
828 ..
829 } => {
830 if visitor.visit_expr_method_call(expr, *span) {
831 walk_expr(visitor, receiver);
832 for arg in args {
833 walk_expr(visitor, arg);
834 }
835 for (_, value) in named_args {
836 walk_expr(visitor, value);
837 }
838 }
839 }
840 Expr::Match(match_expr, span) => {
841 if visitor.visit_expr_match(expr, *span) {
842 walk_expr(visitor, &match_expr.scrutinee);
843 for arm in &match_expr.arms {
844 if let Some(guard) = &arm.guard {
845 walk_expr(visitor, guard);
846 }
847 walk_expr(visitor, &arm.body);
848 }
849 }
850 }
851 Expr::Unit(span) => {
852 visitor.visit_expr_unit(expr, *span);
853 }
854 Expr::Range {
855 start, end, span, ..
856 } => {
857 if visitor.visit_expr_range(expr, *span) {
858 if let Some(s) = start {
859 walk_expr(visitor, s);
860 }
861 if let Some(e) = end {
862 walk_expr(visitor, e);
863 }
864 }
865 }
866 Expr::TimeframeContext {
867 expr: inner, span, ..
868 } => {
869 if visitor.visit_expr_timeframe_context(expr, *span) {
870 walk_expr(visitor, inner);
871 }
872 }
873 Expr::TryOperator(inner, span) => {
874 if visitor.visit_expr_try_operator(expr, *span) {
875 walk_expr(visitor, inner);
876 }
877 }
878 Expr::UsingImpl {
879 expr: inner, span, ..
880 } => {
881 if visitor.visit_expr_using_impl(expr, *span) {
882 walk_expr(visitor, inner);
883 }
884 }
885 Expr::SimulationCall { params, span, .. } => {
886 if visitor.visit_expr_simulation_call(expr, *span) {
887 for (_, value) in params {
888 walk_expr(visitor, value);
889 }
890 }
891 }
892 Expr::WindowExpr(window_expr, span) => {
893 if visitor.visit_expr_window_expr(expr, *span) {
894 match &window_expr.function {
896 WindowFunction::Lead { expr, default, .. }
897 | WindowFunction::Lag { expr, default, .. } => {
898 walk_expr(visitor, expr);
899 if let Some(d) = default {
900 walk_expr(visitor, d);
901 }
902 }
903 WindowFunction::FirstValue(e)
904 | WindowFunction::LastValue(e)
905 | WindowFunction::Sum(e)
906 | WindowFunction::Avg(e)
907 | WindowFunction::Min(e)
908 | WindowFunction::Max(e) => {
909 walk_expr(visitor, e);
910 }
911 WindowFunction::NthValue(e, _) => {
912 walk_expr(visitor, e);
913 }
914 WindowFunction::Count(opt_e) => {
915 if let Some(e) = opt_e {
916 walk_expr(visitor, e);
917 }
918 }
919 WindowFunction::RowNumber
920 | WindowFunction::Rank
921 | WindowFunction::DenseRank
922 | WindowFunction::Ntile(_) => {}
923 }
924 for e in &window_expr.over.partition_by {
926 walk_expr(visitor, e);
927 }
928 if let Some(order_by) = &window_expr.over.order_by {
930 for (e, _) in &order_by.columns {
931 walk_expr(visitor, e);
932 }
933 }
934 }
935 }
936 Expr::FromQuery(from_query, span) => {
937 if visitor.visit_expr_from_query(expr, *span) {
938 walk_expr(visitor, &from_query.source);
940 for clause in &from_query.clauses {
942 match clause {
943 QueryClause::Where(pred) => {
944 walk_expr(visitor, pred);
945 }
946 QueryClause::OrderBy(specs) => {
947 for spec in specs {
948 walk_expr(visitor, &spec.key);
949 }
950 }
951 QueryClause::GroupBy { element, key, .. } => {
952 walk_expr(visitor, element);
953 walk_expr(visitor, key);
954 }
955 QueryClause::Join {
956 source,
957 left_key,
958 right_key,
959 ..
960 } => {
961 walk_expr(visitor, source);
962 walk_expr(visitor, left_key);
963 walk_expr(visitor, right_key);
964 }
965 QueryClause::Let { value, .. } => {
966 walk_expr(visitor, value);
967 }
968 }
969 }
970 walk_expr(visitor, &from_query.select);
972 }
973 }
974 Expr::StructLiteral { fields, span, .. } => {
975 if visitor.visit_expr_struct_literal(expr, *span) {
976 for (_, value_expr) in fields {
977 walk_expr(visitor, value_expr);
978 }
979 }
980 }
981 Expr::Await(inner, span) => {
982 if visitor.visit_expr_await(expr, *span) {
983 walk_expr(visitor, inner);
984 }
985 }
986 Expr::Join(join_expr, span) => {
987 if visitor.visit_expr_join(expr, *span) {
988 for branch in &join_expr.branches {
989 walk_expr(visitor, &branch.expr);
990 }
991 }
992 }
993 Expr::Annotated { target, span, .. } => {
994 if visitor.visit_expr_annotated(expr, *span) {
995 walk_expr(visitor, target);
996 }
997 }
998 Expr::AsyncLet(async_let, span) => {
999 if visitor.visit_expr_async_let(expr, *span) {
1000 walk_expr(visitor, &async_let.expr);
1001 }
1002 }
1003 Expr::AsyncScope(inner, span) => {
1004 if visitor.visit_expr_async_scope(expr, *span) {
1005 walk_expr(visitor, inner);
1006 }
1007 }
1008 Expr::Comptime(stmts, span) => {
1009 if visitor.visit_expr_comptime(expr, *span) {
1010 for stmt in stmts {
1011 walk_stmt(visitor, stmt);
1012 }
1013 }
1014 }
1015 Expr::ComptimeFor(cf, span) => {
1016 if visitor.visit_expr_comptime_for(expr, *span) {
1017 walk_expr(visitor, &cf.iterable);
1018 for stmt in &cf.body {
1019 walk_stmt(visitor, stmt);
1020 }
1021 }
1022 }
1023 Expr::Reference {
1024 expr: inner, span, ..
1025 } => {
1026 if visitor.visit_expr_reference(expr, *span) {
1027 walk_expr(visitor, inner);
1028 }
1029 }
1030 }
1031
1032 visitor.leave_expr(expr);
1033}
1034
1035fn walk_test_statement<V: Visitor>(visitor: &mut V, test_stmt: &TestStatement) {
1037 match test_stmt {
1038 TestStatement::Statement(stmt) => walk_stmt(visitor, stmt),
1039 TestStatement::Assert(assert) => {
1040 walk_expr(visitor, &assert.condition);
1041 }
1042 TestStatement::Expect(expect) => {
1043 walk_expr(visitor, &expect.actual);
1044 match &expect.matcher {
1045 ExpectationMatcher::ToBe(e) => walk_expr(visitor, e),
1046 ExpectationMatcher::ToEqual(e) => walk_expr(visitor, e),
1047 ExpectationMatcher::ToBeCloseTo { expected, .. } => walk_expr(visitor, expected),
1048 ExpectationMatcher::ToBeGreaterThan(e) => walk_expr(visitor, e),
1049 ExpectationMatcher::ToBeLessThan(e) => walk_expr(visitor, e),
1050 ExpectationMatcher::ToContain(e) => walk_expr(visitor, e),
1051 ExpectationMatcher::ToBeTruthy => {}
1052 ExpectationMatcher::ToBeFalsy => {}
1053 ExpectationMatcher::ToThrow(_) => {}
1054 ExpectationMatcher::ToMatchPattern { .. } => {}
1055 }
1056 }
1057 TestStatement::Should(should) => {
1058 walk_expr(visitor, &should.subject);
1059 match &should.matcher {
1060 ShouldMatcher::Be(e) => walk_expr(visitor, e),
1061 ShouldMatcher::Equal(e) => walk_expr(visitor, e),
1062 ShouldMatcher::Contain(e) => walk_expr(visitor, e),
1063 ShouldMatcher::Match(_) => {}
1064 ShouldMatcher::BeCloseTo { expected, .. } => walk_expr(visitor, expected),
1065 }
1066 }
1067 TestStatement::Fixture(fixture) => match fixture {
1068 TestFixture::WithData { data, body } => {
1069 walk_expr(visitor, data);
1070 for stmt in body {
1071 walk_stmt(visitor, stmt);
1072 }
1073 }
1074 TestFixture::WithMock {
1075 mock_value, body, ..
1076 } => {
1077 if let Some(value) = mock_value {
1078 walk_expr(visitor, value);
1079 }
1080 for stmt in body {
1081 walk_stmt(visitor, stmt);
1082 }
1083 }
1084 },
1085 }
1086}
1087
1088#[cfg(test)]
1089mod tests {
1090 use super::*;
1091
1092 struct ExprCounter {
1094 count: usize,
1095 }
1096
1097 impl Visitor for ExprCounter {
1098 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1099 self.count += 1;
1100 true
1101 }
1102 }
1103
1104 #[test]
1105 fn test_visitor_counts_expressions() {
1106 let program = Program {
1107 items: vec![Item::Expression(
1108 Expr::BinaryOp {
1109 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1110 op: BinaryOp::Add,
1111 right: Box::new(Expr::Literal(Literal::Number(1.0), Span::DUMMY)),
1112 span: Span::DUMMY,
1113 },
1114 Span::DUMMY,
1115 )],
1116 };
1117
1118 let mut counter = ExprCounter { count: 0 };
1119 walk_program(&mut counter, &program);
1120
1121 assert_eq!(counter.count, 3);
1123 }
1124
1125 #[test]
1126 fn test_visitor_handles_try_operator() {
1127 let program = Program {
1128 items: vec![Item::Expression(
1129 Expr::TryOperator(
1130 Box::new(Expr::FunctionCall {
1131 name: "some_function".to_string(),
1132 args: vec![Expr::Literal(
1133 Literal::String("arg".to_string()),
1134 Span::DUMMY,
1135 )],
1136 named_args: vec![],
1137 span: Span::DUMMY,
1138 }),
1139 Span::DUMMY,
1140 ),
1141 Span::DUMMY,
1142 )],
1143 };
1144
1145 let mut counter = ExprCounter { count: 0 };
1146 walk_program(&mut counter, &program);
1147
1148 assert_eq!(counter.count, 3);
1150 }
1151
1152 struct IdentifierCollector {
1154 names: Vec<String>,
1155 }
1156
1157 impl Visitor for IdentifierCollector {
1158 fn visit_expr_identifier(&mut self, expr: &Expr, _span: Span) -> bool {
1159 if let Expr::Identifier(name, _) = expr {
1160 self.names.push(name.clone());
1161 }
1162 true
1163 }
1164 }
1165
1166 #[test]
1167 fn test_per_variant_visitor_identifier() {
1168 let program = Program {
1169 items: vec![Item::Expression(
1170 Expr::BinaryOp {
1171 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1172 op: BinaryOp::Add,
1173 right: Box::new(Expr::Identifier("y".to_string(), Span::DUMMY)),
1174 span: Span::DUMMY,
1175 },
1176 Span::DUMMY,
1177 )],
1178 };
1179
1180 let mut collector = IdentifierCollector { names: vec![] };
1181 walk_program(&mut collector, &program);
1182
1183 assert_eq!(collector.names, vec!["x", "y"]);
1184 }
1185
1186 struct SkippingVisitor {
1188 count: usize,
1189 }
1190
1191 impl Visitor for SkippingVisitor {
1192 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1193 self.count += 1;
1194 true
1195 }
1196 fn visit_expr_binary_op(&mut self, _expr: &Expr, _span: Span) -> bool {
1198 false
1199 }
1200 }
1201
1202 #[test]
1203 fn test_per_variant_skip_children() {
1204 let program = Program {
1205 items: vec![Item::Expression(
1206 Expr::BinaryOp {
1207 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1208 op: BinaryOp::Add,
1209 right: Box::new(Expr::Literal(Literal::Number(1.0), Span::DUMMY)),
1210 span: Span::DUMMY,
1211 },
1212 Span::DUMMY,
1213 )],
1214 };
1215
1216 let mut v = SkippingVisitor { count: 0 };
1217 walk_program(&mut v, &program);
1218
1219 assert_eq!(v.count, 1);
1221 }
1222
1223 struct MatchCollector {
1225 match_count: usize,
1226 total_expr_count: usize,
1227 }
1228
1229 impl Visitor for MatchCollector {
1230 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1231 self.total_expr_count += 1;
1232 true
1233 }
1234 fn visit_expr_match(&mut self, _expr: &Expr, _span: Span) -> bool {
1235 self.match_count += 1;
1236 true
1237 }
1238 }
1239
1240 #[test]
1241 fn test_coarse_and_per_variant_combined() {
1242 let program = Program {
1243 items: vec![Item::Expression(
1244 Expr::BinaryOp {
1245 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1246 op: BinaryOp::Add,
1247 right: Box::new(Expr::Identifier("y".to_string(), Span::DUMMY)),
1248 span: Span::DUMMY,
1249 },
1250 Span::DUMMY,
1251 )],
1252 };
1253
1254 let mut mc = MatchCollector {
1255 match_count: 0,
1256 total_expr_count: 0,
1257 };
1258 walk_program(&mut mc, &program);
1259
1260 assert_eq!(mc.total_expr_count, 3); assert_eq!(mc.match_count, 0); }
1263}