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::ListComprehension(comp, span) => {
690 if visitor.visit_expr_list_comprehension(expr, *span) {
691 walk_expr(visitor, &comp.element);
692 for clause in &comp.clauses {
693 walk_expr(visitor, &clause.iterable);
694 if let Some(filter) = &clause.filter {
695 walk_expr(visitor, filter);
696 }
697 }
698 }
699 }
700 Expr::Block(block, span) => {
701 if visitor.visit_expr_block(expr, *span) {
702 if visitor.visit_block(block) {
703 for item in &block.items {
704 match item {
705 BlockItem::VariableDecl(decl) => {
706 if let Some(value) = &decl.value {
707 walk_expr(visitor, value);
708 }
709 }
710 BlockItem::Assignment(assign) => {
711 walk_expr(visitor, &assign.value);
712 }
713 BlockItem::Statement(stmt) => {
714 walk_stmt(visitor, stmt);
715 }
716 BlockItem::Expression(e) => walk_expr(visitor, e),
717 }
718 }
719 visitor.leave_block(block);
720 }
721 }
722 }
723 Expr::TypeAssertion {
724 expr: inner, span, ..
725 } => {
726 if visitor.visit_expr_type_assertion(expr, *span) {
727 walk_expr(visitor, inner);
728 }
729 }
730 Expr::InstanceOf {
731 expr: inner, span, ..
732 } => {
733 if visitor.visit_expr_instance_of(expr, *span) {
734 walk_expr(visitor, inner);
735 }
736 }
737 Expr::FunctionExpr {
738 params, body, span, ..
739 } => {
740 if visitor.visit_expr_function_expr(expr, *span) {
741 for param in params {
742 if let Some(default) = ¶m.default_value {
743 walk_expr(visitor, default);
744 }
745 }
746 for stmt in body {
747 walk_stmt(visitor, stmt);
748 }
749 }
750 }
751 Expr::Duration(_, span) => {
752 visitor.visit_expr_duration(expr, *span);
753 }
754 Expr::Spread(inner, span) => {
755 if visitor.visit_expr_spread(expr, *span) {
756 walk_expr(visitor, inner);
757 }
758 }
759 Expr::If(if_expr, span) => {
760 if visitor.visit_expr_if(expr, *span) {
761 walk_expr(visitor, &if_expr.condition);
762 walk_expr(visitor, &if_expr.then_branch);
763 if let Some(else_branch) = &if_expr.else_branch {
764 walk_expr(visitor, else_branch);
765 }
766 }
767 }
768 Expr::While(while_expr, span) => {
769 if visitor.visit_expr_while(expr, *span) {
770 walk_expr(visitor, &while_expr.condition);
771 walk_expr(visitor, &while_expr.body);
772 }
773 }
774 Expr::For(for_expr, span) => {
775 if visitor.visit_expr_for(expr, *span) {
776 walk_expr(visitor, &for_expr.iterable);
777 walk_expr(visitor, &for_expr.body);
778 }
779 }
780 Expr::Loop(loop_expr, span) => {
781 if visitor.visit_expr_loop(expr, *span) {
782 walk_expr(visitor, &loop_expr.body);
783 }
784 }
785 Expr::Let(let_expr, span) => {
786 if visitor.visit_expr_let(expr, *span) {
787 if let Some(value) = &let_expr.value {
788 walk_expr(visitor, value);
789 }
790 walk_expr(visitor, &let_expr.body);
791 }
792 }
793 Expr::Assign(assign, span) => {
794 if visitor.visit_expr_assign(expr, *span) {
795 walk_expr(visitor, &assign.target);
796 walk_expr(visitor, &assign.value);
797 }
798 }
799 Expr::Break(inner, span) => {
800 if visitor.visit_expr_break(expr, *span) {
801 if let Some(e) = inner {
802 walk_expr(visitor, e);
803 }
804 }
805 }
806 Expr::Continue(span) => {
807 visitor.visit_expr_continue(expr, *span);
808 }
809 Expr::Return(inner, span) => {
810 if visitor.visit_expr_return(expr, *span) {
811 if let Some(e) = inner {
812 walk_expr(visitor, e);
813 }
814 }
815 }
816 Expr::MethodCall {
817 receiver,
818 args,
819 named_args,
820 span,
821 ..
822 } => {
823 if visitor.visit_expr_method_call(expr, *span) {
824 walk_expr(visitor, receiver);
825 for arg in args {
826 walk_expr(visitor, arg);
827 }
828 for (_, value) in named_args {
829 walk_expr(visitor, value);
830 }
831 }
832 }
833 Expr::Match(match_expr, span) => {
834 if visitor.visit_expr_match(expr, *span) {
835 walk_expr(visitor, &match_expr.scrutinee);
836 for arm in &match_expr.arms {
837 if let Some(guard) = &arm.guard {
838 walk_expr(visitor, guard);
839 }
840 walk_expr(visitor, &arm.body);
841 }
842 }
843 }
844 Expr::Unit(span) => {
845 visitor.visit_expr_unit(expr, *span);
846 }
847 Expr::Range {
848 start, end, span, ..
849 } => {
850 if visitor.visit_expr_range(expr, *span) {
851 if let Some(s) = start {
852 walk_expr(visitor, s);
853 }
854 if let Some(e) = end {
855 walk_expr(visitor, e);
856 }
857 }
858 }
859 Expr::TimeframeContext {
860 expr: inner, span, ..
861 } => {
862 if visitor.visit_expr_timeframe_context(expr, *span) {
863 walk_expr(visitor, inner);
864 }
865 }
866 Expr::TryOperator(inner, span) => {
867 if visitor.visit_expr_try_operator(expr, *span) {
868 walk_expr(visitor, inner);
869 }
870 }
871 Expr::UsingImpl {
872 expr: inner, span, ..
873 } => {
874 if visitor.visit_expr_using_impl(expr, *span) {
875 walk_expr(visitor, inner);
876 }
877 }
878 Expr::SimulationCall { params, span, .. } => {
879 if visitor.visit_expr_simulation_call(expr, *span) {
880 for (_, value) in params {
881 walk_expr(visitor, value);
882 }
883 }
884 }
885 Expr::WindowExpr(window_expr, span) => {
886 if visitor.visit_expr_window_expr(expr, *span) {
887 match &window_expr.function {
889 WindowFunction::Lead { expr, default, .. }
890 | WindowFunction::Lag { expr, default, .. } => {
891 walk_expr(visitor, expr);
892 if let Some(d) = default {
893 walk_expr(visitor, d);
894 }
895 }
896 WindowFunction::FirstValue(e)
897 | WindowFunction::LastValue(e)
898 | WindowFunction::Sum(e)
899 | WindowFunction::Avg(e)
900 | WindowFunction::Min(e)
901 | WindowFunction::Max(e) => {
902 walk_expr(visitor, e);
903 }
904 WindowFunction::NthValue(e, _) => {
905 walk_expr(visitor, e);
906 }
907 WindowFunction::Count(opt_e) => {
908 if let Some(e) = opt_e {
909 walk_expr(visitor, e);
910 }
911 }
912 WindowFunction::RowNumber
913 | WindowFunction::Rank
914 | WindowFunction::DenseRank
915 | WindowFunction::Ntile(_) => {}
916 }
917 for e in &window_expr.over.partition_by {
919 walk_expr(visitor, e);
920 }
921 if let Some(order_by) = &window_expr.over.order_by {
923 for (e, _) in &order_by.columns {
924 walk_expr(visitor, e);
925 }
926 }
927 }
928 }
929 Expr::FromQuery(from_query, span) => {
930 if visitor.visit_expr_from_query(expr, *span) {
931 walk_expr(visitor, &from_query.source);
933 for clause in &from_query.clauses {
935 match clause {
936 QueryClause::Where(pred) => {
937 walk_expr(visitor, pred);
938 }
939 QueryClause::OrderBy(specs) => {
940 for spec in specs {
941 walk_expr(visitor, &spec.key);
942 }
943 }
944 QueryClause::GroupBy { element, key, .. } => {
945 walk_expr(visitor, element);
946 walk_expr(visitor, key);
947 }
948 QueryClause::Join {
949 source,
950 left_key,
951 right_key,
952 ..
953 } => {
954 walk_expr(visitor, source);
955 walk_expr(visitor, left_key);
956 walk_expr(visitor, right_key);
957 }
958 QueryClause::Let { value, .. } => {
959 walk_expr(visitor, value);
960 }
961 }
962 }
963 walk_expr(visitor, &from_query.select);
965 }
966 }
967 Expr::StructLiteral { fields, span, .. } => {
968 if visitor.visit_expr_struct_literal(expr, *span) {
969 for (_, value_expr) in fields {
970 walk_expr(visitor, value_expr);
971 }
972 }
973 }
974 Expr::Await(inner, span) => {
975 if visitor.visit_expr_await(expr, *span) {
976 walk_expr(visitor, inner);
977 }
978 }
979 Expr::Join(join_expr, span) => {
980 if visitor.visit_expr_join(expr, *span) {
981 for branch in &join_expr.branches {
982 walk_expr(visitor, &branch.expr);
983 }
984 }
985 }
986 Expr::Annotated { target, span, .. } => {
987 if visitor.visit_expr_annotated(expr, *span) {
988 walk_expr(visitor, target);
989 }
990 }
991 Expr::AsyncLet(async_let, span) => {
992 if visitor.visit_expr_async_let(expr, *span) {
993 walk_expr(visitor, &async_let.expr);
994 }
995 }
996 Expr::AsyncScope(inner, span) => {
997 if visitor.visit_expr_async_scope(expr, *span) {
998 walk_expr(visitor, inner);
999 }
1000 }
1001 Expr::Comptime(stmts, span) => {
1002 if visitor.visit_expr_comptime(expr, *span) {
1003 for stmt in stmts {
1004 walk_stmt(visitor, stmt);
1005 }
1006 }
1007 }
1008 Expr::ComptimeFor(cf, span) => {
1009 if visitor.visit_expr_comptime_for(expr, *span) {
1010 walk_expr(visitor, &cf.iterable);
1011 for stmt in &cf.body {
1012 walk_stmt(visitor, stmt);
1013 }
1014 }
1015 }
1016 Expr::Reference {
1017 expr: inner, span, ..
1018 } => {
1019 if visitor.visit_expr_reference(expr, *span) {
1020 walk_expr(visitor, inner);
1021 }
1022 }
1023 }
1024
1025 visitor.leave_expr(expr);
1026}
1027
1028fn walk_test_statement<V: Visitor>(visitor: &mut V, test_stmt: &TestStatement) {
1030 match test_stmt {
1031 TestStatement::Statement(stmt) => walk_stmt(visitor, stmt),
1032 TestStatement::Assert(assert) => {
1033 walk_expr(visitor, &assert.condition);
1034 }
1035 TestStatement::Expect(expect) => {
1036 walk_expr(visitor, &expect.actual);
1037 match &expect.matcher {
1038 ExpectationMatcher::ToBe(e) => walk_expr(visitor, e),
1039 ExpectationMatcher::ToEqual(e) => walk_expr(visitor, e),
1040 ExpectationMatcher::ToBeCloseTo { expected, .. } => walk_expr(visitor, expected),
1041 ExpectationMatcher::ToBeGreaterThan(e) => walk_expr(visitor, e),
1042 ExpectationMatcher::ToBeLessThan(e) => walk_expr(visitor, e),
1043 ExpectationMatcher::ToContain(e) => walk_expr(visitor, e),
1044 ExpectationMatcher::ToBeTruthy => {}
1045 ExpectationMatcher::ToBeFalsy => {}
1046 ExpectationMatcher::ToThrow(_) => {}
1047 ExpectationMatcher::ToMatchPattern { .. } => {}
1048 }
1049 }
1050 TestStatement::Should(should) => {
1051 walk_expr(visitor, &should.subject);
1052 match &should.matcher {
1053 ShouldMatcher::Be(e) => walk_expr(visitor, e),
1054 ShouldMatcher::Equal(e) => walk_expr(visitor, e),
1055 ShouldMatcher::Contain(e) => walk_expr(visitor, e),
1056 ShouldMatcher::Match(_) => {}
1057 ShouldMatcher::BeCloseTo { expected, .. } => walk_expr(visitor, expected),
1058 }
1059 }
1060 TestStatement::Fixture(fixture) => match fixture {
1061 TestFixture::WithData { data, body } => {
1062 walk_expr(visitor, data);
1063 for stmt in body {
1064 walk_stmt(visitor, stmt);
1065 }
1066 }
1067 TestFixture::WithMock {
1068 mock_value, body, ..
1069 } => {
1070 if let Some(value) = mock_value {
1071 walk_expr(visitor, value);
1072 }
1073 for stmt in body {
1074 walk_stmt(visitor, stmt);
1075 }
1076 }
1077 },
1078 }
1079}
1080
1081#[cfg(test)]
1082mod tests {
1083 use super::*;
1084
1085 struct ExprCounter {
1087 count: usize,
1088 }
1089
1090 impl Visitor for ExprCounter {
1091 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1092 self.count += 1;
1093 true
1094 }
1095 }
1096
1097 #[test]
1098 fn test_visitor_counts_expressions() {
1099 let program = Program {
1100 items: vec![Item::Expression(
1101 Expr::BinaryOp {
1102 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1103 op: BinaryOp::Add,
1104 right: Box::new(Expr::Literal(Literal::Number(1.0), Span::DUMMY)),
1105 span: Span::DUMMY,
1106 },
1107 Span::DUMMY,
1108 )],
1109 };
1110
1111 let mut counter = ExprCounter { count: 0 };
1112 walk_program(&mut counter, &program);
1113
1114 assert_eq!(counter.count, 3);
1116 }
1117
1118 #[test]
1119 fn test_visitor_handles_try_operator() {
1120 let program = Program {
1121 items: vec![Item::Expression(
1122 Expr::TryOperator(
1123 Box::new(Expr::FunctionCall {
1124 name: "some_function".to_string(),
1125 args: vec![Expr::Literal(
1126 Literal::String("arg".to_string()),
1127 Span::DUMMY,
1128 )],
1129 named_args: vec![],
1130 span: Span::DUMMY,
1131 }),
1132 Span::DUMMY,
1133 ),
1134 Span::DUMMY,
1135 )],
1136 };
1137
1138 let mut counter = ExprCounter { count: 0 };
1139 walk_program(&mut counter, &program);
1140
1141 assert_eq!(counter.count, 3);
1143 }
1144
1145 struct IdentifierCollector {
1147 names: Vec<String>,
1148 }
1149
1150 impl Visitor for IdentifierCollector {
1151 fn visit_expr_identifier(&mut self, expr: &Expr, _span: Span) -> bool {
1152 if let Expr::Identifier(name, _) = expr {
1153 self.names.push(name.clone());
1154 }
1155 true
1156 }
1157 }
1158
1159 #[test]
1160 fn test_per_variant_visitor_identifier() {
1161 let program = Program {
1162 items: vec![Item::Expression(
1163 Expr::BinaryOp {
1164 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1165 op: BinaryOp::Add,
1166 right: Box::new(Expr::Identifier("y".to_string(), Span::DUMMY)),
1167 span: Span::DUMMY,
1168 },
1169 Span::DUMMY,
1170 )],
1171 };
1172
1173 let mut collector = IdentifierCollector { names: vec![] };
1174 walk_program(&mut collector, &program);
1175
1176 assert_eq!(collector.names, vec!["x", "y"]);
1177 }
1178
1179 struct SkippingVisitor {
1181 count: usize,
1182 }
1183
1184 impl Visitor for SkippingVisitor {
1185 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1186 self.count += 1;
1187 true
1188 }
1189 fn visit_expr_binary_op(&mut self, _expr: &Expr, _span: Span) -> bool {
1191 false
1192 }
1193 }
1194
1195 #[test]
1196 fn test_per_variant_skip_children() {
1197 let program = Program {
1198 items: vec![Item::Expression(
1199 Expr::BinaryOp {
1200 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1201 op: BinaryOp::Add,
1202 right: Box::new(Expr::Literal(Literal::Number(1.0), Span::DUMMY)),
1203 span: Span::DUMMY,
1204 },
1205 Span::DUMMY,
1206 )],
1207 };
1208
1209 let mut v = SkippingVisitor { count: 0 };
1210 walk_program(&mut v, &program);
1211
1212 assert_eq!(v.count, 1);
1214 }
1215
1216 struct MatchCollector {
1218 match_count: usize,
1219 total_expr_count: usize,
1220 }
1221
1222 impl Visitor for MatchCollector {
1223 fn visit_expr(&mut self, _expr: &Expr) -> bool {
1224 self.total_expr_count += 1;
1225 true
1226 }
1227 fn visit_expr_match(&mut self, _expr: &Expr, _span: Span) -> bool {
1228 self.match_count += 1;
1229 true
1230 }
1231 }
1232
1233 #[test]
1234 fn test_coarse_and_per_variant_combined() {
1235 let program = Program {
1236 items: vec![Item::Expression(
1237 Expr::BinaryOp {
1238 left: Box::new(Expr::Identifier("x".to_string(), Span::DUMMY)),
1239 op: BinaryOp::Add,
1240 right: Box::new(Expr::Identifier("y".to_string(), Span::DUMMY)),
1241 span: Span::DUMMY,
1242 },
1243 Span::DUMMY,
1244 )],
1245 };
1246
1247 let mut mc = MatchCollector {
1248 match_count: 0,
1249 total_expr_count: 0,
1250 };
1251 walk_program(&mut mc, &program);
1252
1253 assert_eq!(mc.total_expr_count, 3); assert_eq!(mc.match_count, 0); }
1256}