Skip to main content

ruff_python_ast/visitor/
source_order.rs

1use crate::{
2    Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator, ElifElseClause,
3    ExceptHandler, Expr, FString, InterpolatedStringElement, Keyword, MatchCase, Mod, Operator,
4    Parameter, ParameterWithDefault, Parameters, Pattern, PatternArguments, PatternKeyword,
5    Singleton, Stmt, StringLiteral, TString, TypeParam, TypeParams, UnaryOp, WithItem,
6};
7use crate::{AnyNodeRef, Identifier};
8
9/// Visitor that traverses all nodes recursively in the order they appear in the source.
10///
11/// If you need a visitor that visits the nodes in the order they're evaluated at runtime,
12/// use [`Visitor`](super::Visitor) instead.
13pub trait SourceOrderVisitor<'a> {
14    #[inline]
15    fn enter_node(&mut self, _node: AnyNodeRef<'a>) -> TraversalSignal {
16        TraversalSignal::Traverse
17    }
18
19    #[inline(always)]
20    fn leave_node(&mut self, _node: AnyNodeRef<'a>) {}
21
22    #[inline]
23    fn visit_mod(&mut self, module: &'a Mod) {
24        walk_module(self, module);
25    }
26
27    #[inline]
28    fn visit_stmt(&mut self, stmt: &'a Stmt) {
29        walk_stmt(self, stmt);
30    }
31
32    #[inline]
33    fn visit_annotation(&mut self, expr: &'a Expr) {
34        walk_annotation(self, expr);
35    }
36
37    #[inline]
38    fn visit_expr(&mut self, expr: &'a Expr) {
39        walk_expr(self, expr);
40    }
41
42    #[inline]
43    fn visit_decorator(&mut self, decorator: &'a Decorator) {
44        walk_decorator(self, decorator);
45    }
46
47    #[inline]
48    fn visit_singleton(&mut self, _singleton: &'a Singleton) {}
49
50    #[inline]
51    fn visit_bool_op(&mut self, bool_op: &'a BoolOp) {
52        walk_bool_op(self, bool_op);
53    }
54
55    #[inline]
56    fn visit_operator(&mut self, operator: &'a Operator) {
57        walk_operator(self, operator);
58    }
59
60    #[inline]
61    fn visit_unary_op(&mut self, unary_op: &'a UnaryOp) {
62        walk_unary_op(self, unary_op);
63    }
64
65    #[inline]
66    fn visit_cmp_op(&mut self, cmp_op: &'a CmpOp) {
67        walk_cmp_op(self, cmp_op);
68    }
69
70    #[inline]
71    fn visit_comprehension(&mut self, comprehension: &'a Comprehension) {
72        walk_comprehension(self, comprehension);
73    }
74
75    #[inline]
76    fn visit_except_handler(&mut self, except_handler: &'a ExceptHandler) {
77        walk_except_handler(self, except_handler);
78    }
79
80    #[inline]
81    fn visit_arguments(&mut self, arguments: &'a Arguments) {
82        walk_arguments(self, arguments);
83    }
84
85    #[inline]
86    fn visit_parameters(&mut self, parameters: &'a Parameters) {
87        walk_parameters(self, parameters);
88    }
89
90    #[inline]
91    fn visit_parameter(&mut self, arg: &'a Parameter) {
92        walk_parameter(self, arg);
93    }
94
95    fn visit_parameter_with_default(&mut self, parameter_with_default: &'a ParameterWithDefault) {
96        walk_parameter_with_default(self, parameter_with_default);
97    }
98
99    #[inline]
100    fn visit_keyword(&mut self, keyword: &'a Keyword) {
101        walk_keyword(self, keyword);
102    }
103
104    #[inline]
105    fn visit_alias(&mut self, alias: &'a Alias) {
106        walk_alias(self, alias);
107    }
108
109    #[inline]
110    fn visit_with_item(&mut self, with_item: &'a WithItem) {
111        walk_with_item(self, with_item);
112    }
113
114    #[inline]
115    fn visit_type_params(&mut self, type_params: &'a TypeParams) {
116        walk_type_params(self, type_params);
117    }
118
119    #[inline]
120    fn visit_type_param(&mut self, type_param: &'a TypeParam) {
121        walk_type_param(self, type_param);
122    }
123
124    #[inline]
125    fn visit_match_case(&mut self, match_case: &'a MatchCase) {
126        walk_match_case(self, match_case);
127    }
128
129    #[inline]
130    fn visit_pattern(&mut self, pattern: &'a Pattern) {
131        walk_pattern(self, pattern);
132    }
133
134    #[inline]
135    fn visit_pattern_arguments(&mut self, pattern_arguments: &'a PatternArguments) {
136        walk_pattern_arguments(self, pattern_arguments);
137    }
138
139    #[inline]
140    fn visit_pattern_keyword(&mut self, pattern_keyword: &'a PatternKeyword) {
141        walk_pattern_keyword(self, pattern_keyword);
142    }
143
144    #[inline]
145    fn visit_body(&mut self, body: &'a [Stmt]) {
146        walk_body(self, body);
147    }
148
149    #[inline]
150    fn visit_elif_else_clause(&mut self, elif_else_clause: &'a ElifElseClause) {
151        walk_elif_else_clause(self, elif_else_clause);
152    }
153
154    #[inline]
155    fn visit_f_string(&mut self, f_string: &'a FString) {
156        walk_f_string(self, f_string);
157    }
158
159    #[inline]
160    fn visit_interpolated_string_element(
161        &mut self,
162        interpolated_string_element: &'a InterpolatedStringElement,
163    ) {
164        walk_interpolated_string_element(self, interpolated_string_element);
165    }
166
167    #[inline]
168    fn visit_t_string(&mut self, t_string: &'a TString) {
169        walk_t_string(self, t_string);
170    }
171
172    #[inline]
173    fn visit_string_literal(&mut self, string_literal: &'a StringLiteral) {
174        walk_string_literal(self, string_literal);
175    }
176
177    #[inline]
178    fn visit_bytes_literal(&mut self, bytes_literal: &'a BytesLiteral) {
179        walk_bytes_literal(self, bytes_literal);
180    }
181
182    #[inline]
183    fn visit_identifier(&mut self, identifier: &'a Identifier) {
184        walk_identifier(self, identifier);
185    }
186}
187
188pub fn walk_module<'a, V>(visitor: &mut V, module: &'a Mod)
189where
190    V: SourceOrderVisitor<'a> + ?Sized,
191{
192    let node = AnyNodeRef::from(module);
193    if visitor.enter_node(node).is_traverse() {
194        match module {
195            Mod::Module(module) => module.visit_source_order(visitor),
196            Mod::Expression(module) => module.visit_source_order(visitor),
197        }
198    }
199
200    visitor.leave_node(node);
201}
202
203pub fn walk_body<'a, V>(visitor: &mut V, body: &'a [Stmt])
204where
205    V: SourceOrderVisitor<'a> + ?Sized,
206{
207    for stmt in body {
208        visitor.visit_stmt(stmt);
209    }
210}
211
212pub fn walk_stmt<'a, V>(visitor: &mut V, stmt: &'a Stmt)
213where
214    V: SourceOrderVisitor<'a> + ?Sized,
215{
216    let node = AnyNodeRef::from(stmt);
217
218    if visitor.enter_node(node).is_traverse() {
219        stmt.visit_source_order(visitor);
220    }
221
222    visitor.leave_node(node);
223}
224
225pub fn walk_node<'a, V>(visitor: &mut V, node: AnyNodeRef<'a>)
226where
227    V: SourceOrderVisitor<'a> + ?Sized,
228{
229    if visitor.enter_node(node).is_traverse() {
230        node.visit_source_order(visitor);
231    }
232
233    visitor.leave_node(node);
234}
235
236#[derive(Copy, Clone, Eq, PartialEq, Debug)]
237pub enum TraversalSignal {
238    Traverse,
239    Skip,
240}
241
242impl TraversalSignal {
243    pub const fn is_traverse(self) -> bool {
244        matches!(self, TraversalSignal::Traverse)
245    }
246}
247
248pub fn walk_annotation<'a, V: SourceOrderVisitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
249    visitor.visit_expr(expr);
250}
251
252pub fn walk_decorator<'a, V>(visitor: &mut V, decorator: &'a Decorator)
253where
254    V: SourceOrderVisitor<'a> + ?Sized,
255{
256    let node = AnyNodeRef::from(decorator);
257    if visitor.enter_node(node).is_traverse() {
258        decorator.visit_source_order(visitor);
259    }
260
261    visitor.leave_node(node);
262}
263
264pub fn walk_expr<'a, V>(visitor: &mut V, expr: &'a Expr)
265where
266    V: SourceOrderVisitor<'a> + ?Sized,
267{
268    let node = AnyNodeRef::from(expr);
269    if visitor.enter_node(node).is_traverse() {
270        match expr {
271            Expr::BoolOp(expr) => expr.visit_source_order(visitor),
272            Expr::Named(expr) => expr.visit_source_order(visitor),
273            Expr::BinOp(expr) => expr.visit_source_order(visitor),
274            Expr::UnaryOp(expr) => expr.visit_source_order(visitor),
275            Expr::Lambda(expr) => expr.visit_source_order(visitor),
276            Expr::If(expr) => expr.visit_source_order(visitor),
277            Expr::Dict(expr) => expr.visit_source_order(visitor),
278            Expr::Set(expr) => expr.visit_source_order(visitor),
279            Expr::ListComp(expr) => expr.visit_source_order(visitor),
280            Expr::SetComp(expr) => expr.visit_source_order(visitor),
281            Expr::DictComp(expr) => expr.visit_source_order(visitor),
282            Expr::Generator(expr) => expr.visit_source_order(visitor),
283            Expr::Await(expr) => expr.visit_source_order(visitor),
284            Expr::Yield(expr) => expr.visit_source_order(visitor),
285            Expr::YieldFrom(expr) => expr.visit_source_order(visitor),
286            Expr::Compare(expr) => expr.visit_source_order(visitor),
287            Expr::Call(expr) => expr.visit_source_order(visitor),
288            Expr::FString(expr) => expr.visit_source_order(visitor),
289            Expr::TString(expr) => expr.visit_source_order(visitor),
290            Expr::StringLiteral(expr) => expr.visit_source_order(visitor),
291            Expr::BytesLiteral(expr) => expr.visit_source_order(visitor),
292            Expr::NumberLiteral(expr) => expr.visit_source_order(visitor),
293            Expr::BooleanLiteral(expr) => expr.visit_source_order(visitor),
294            Expr::NoneLiteral(expr) => expr.visit_source_order(visitor),
295            Expr::EllipsisLiteral(expr) => expr.visit_source_order(visitor),
296            Expr::Attribute(expr) => expr.visit_source_order(visitor),
297            Expr::Subscript(expr) => expr.visit_source_order(visitor),
298            Expr::Starred(expr) => expr.visit_source_order(visitor),
299            Expr::Name(expr) => expr.visit_source_order(visitor),
300            Expr::List(expr) => expr.visit_source_order(visitor),
301            Expr::Tuple(expr) => expr.visit_source_order(visitor),
302            Expr::Slice(expr) => expr.visit_source_order(visitor),
303            Expr::IpyEscapeCommand(expr) => expr.visit_source_order(visitor),
304        }
305    }
306
307    visitor.leave_node(node);
308}
309
310pub fn walk_comprehension<'a, V>(visitor: &mut V, comprehension: &'a Comprehension)
311where
312    V: SourceOrderVisitor<'a> + ?Sized,
313{
314    let node = AnyNodeRef::from(comprehension);
315    if visitor.enter_node(node).is_traverse() {
316        comprehension.visit_source_order(visitor);
317    }
318
319    visitor.leave_node(node);
320}
321
322pub fn walk_elif_else_clause<'a, V>(visitor: &mut V, elif_else_clause: &'a ElifElseClause)
323where
324    V: SourceOrderVisitor<'a> + ?Sized,
325{
326    let node = AnyNodeRef::from(elif_else_clause);
327    if visitor.enter_node(node).is_traverse() {
328        elif_else_clause.visit_source_order(visitor);
329    }
330
331    visitor.leave_node(node);
332}
333
334pub fn walk_except_handler<'a, V>(visitor: &mut V, except_handler: &'a ExceptHandler)
335where
336    V: SourceOrderVisitor<'a> + ?Sized,
337{
338    let node = AnyNodeRef::from(except_handler);
339    if visitor.enter_node(node).is_traverse() {
340        match except_handler {
341            ExceptHandler::ExceptHandler(except_handler) => {
342                except_handler.visit_source_order(visitor);
343            }
344        }
345    }
346    visitor.leave_node(node);
347}
348
349pub fn walk_format_spec<'a, V: SourceOrderVisitor<'a> + ?Sized>(
350    visitor: &mut V,
351    format_spec: &'a Expr,
352) {
353    let node = AnyNodeRef::from(format_spec);
354    if visitor.enter_node(node).is_traverse() {
355        visitor.visit_expr(format_spec);
356    }
357
358    visitor.leave_node(node);
359}
360
361pub fn walk_arguments<'a, V>(visitor: &mut V, arguments: &'a Arguments)
362where
363    V: SourceOrderVisitor<'a> + ?Sized,
364{
365    let node = AnyNodeRef::from(arguments);
366    if visitor.enter_node(node).is_traverse() {
367        arguments.visit_source_order(visitor);
368    }
369
370    visitor.leave_node(node);
371}
372
373pub fn walk_parameters<'a, V>(visitor: &mut V, parameters: &'a Parameters)
374where
375    V: SourceOrderVisitor<'a> + ?Sized,
376{
377    let node = AnyNodeRef::from(parameters);
378    if visitor.enter_node(node).is_traverse() {
379        parameters.visit_source_order(visitor);
380    }
381
382    visitor.leave_node(node);
383}
384
385pub fn walk_parameter<'a, V>(visitor: &mut V, parameter: &'a Parameter)
386where
387    V: SourceOrderVisitor<'a> + ?Sized,
388{
389    let node = AnyNodeRef::from(parameter);
390
391    if visitor.enter_node(node).is_traverse() {
392        parameter.visit_source_order(visitor);
393    }
394    visitor.leave_node(node);
395}
396
397pub fn walk_parameter_with_default<'a, V>(
398    visitor: &mut V,
399    parameter_with_default: &'a ParameterWithDefault,
400) where
401    V: SourceOrderVisitor<'a> + ?Sized,
402{
403    let node = AnyNodeRef::from(parameter_with_default);
404    if visitor.enter_node(node).is_traverse() {
405        parameter_with_default.visit_source_order(visitor);
406    }
407
408    visitor.leave_node(node);
409}
410
411#[inline]
412pub fn walk_keyword<'a, V>(visitor: &mut V, keyword: &'a Keyword)
413where
414    V: SourceOrderVisitor<'a> + ?Sized,
415{
416    let node = AnyNodeRef::from(keyword);
417
418    if visitor.enter_node(node).is_traverse() {
419        keyword.visit_source_order(visitor);
420    }
421    visitor.leave_node(node);
422}
423
424pub fn walk_with_item<'a, V>(visitor: &mut V, with_item: &'a WithItem)
425where
426    V: SourceOrderVisitor<'a> + ?Sized,
427{
428    let node = AnyNodeRef::from(with_item);
429    if visitor.enter_node(node).is_traverse() {
430        with_item.visit_source_order(visitor);
431    }
432    visitor.leave_node(node);
433}
434
435pub fn walk_type_params<'a, V>(visitor: &mut V, type_params: &'a TypeParams)
436where
437    V: SourceOrderVisitor<'a> + ?Sized,
438{
439    let node = AnyNodeRef::from(type_params);
440    if visitor.enter_node(node).is_traverse() {
441        type_params.visit_source_order(visitor);
442    }
443    visitor.leave_node(node);
444}
445
446pub fn walk_type_param<'a, V>(visitor: &mut V, type_param: &'a TypeParam)
447where
448    V: SourceOrderVisitor<'a> + ?Sized,
449{
450    let node = AnyNodeRef::from(type_param);
451    if visitor.enter_node(node).is_traverse() {
452        type_param.visit_source_order(visitor);
453    }
454    visitor.leave_node(node);
455}
456
457pub fn walk_match_case<'a, V>(visitor: &mut V, match_case: &'a MatchCase)
458where
459    V: SourceOrderVisitor<'a> + ?Sized,
460{
461    let node = AnyNodeRef::from(match_case);
462    if visitor.enter_node(node).is_traverse() {
463        match_case.visit_source_order(visitor);
464    }
465    visitor.leave_node(node);
466}
467
468pub fn walk_pattern<'a, V>(visitor: &mut V, pattern: &'a Pattern)
469where
470    V: SourceOrderVisitor<'a> + ?Sized,
471{
472    let node = AnyNodeRef::from(pattern);
473    if visitor.enter_node(node).is_traverse() {
474        match pattern {
475            Pattern::MatchValue(pattern) => pattern.visit_source_order(visitor),
476            Pattern::MatchSingleton(pattern) => pattern.visit_source_order(visitor),
477            Pattern::MatchSequence(pattern) => pattern.visit_source_order(visitor),
478            Pattern::MatchMapping(pattern) => pattern.visit_source_order(visitor),
479            Pattern::MatchClass(pattern) => pattern.visit_source_order(visitor),
480            Pattern::MatchStar(pattern) => pattern.visit_source_order(visitor),
481            Pattern::MatchAs(pattern) => pattern.visit_source_order(visitor),
482            Pattern::MatchOr(pattern) => pattern.visit_source_order(visitor),
483        }
484    }
485    visitor.leave_node(node);
486}
487
488pub fn walk_pattern_arguments<'a, V>(visitor: &mut V, pattern_arguments: &'a PatternArguments)
489where
490    V: SourceOrderVisitor<'a> + ?Sized,
491{
492    let node = AnyNodeRef::from(pattern_arguments);
493    if visitor.enter_node(node).is_traverse() {
494        for pattern in &pattern_arguments.patterns {
495            visitor.visit_pattern(pattern);
496        }
497        for keyword in &pattern_arguments.keywords {
498            visitor.visit_pattern_keyword(keyword);
499        }
500    }
501    visitor.leave_node(node);
502}
503
504pub fn walk_pattern_keyword<'a, V>(visitor: &mut V, pattern_keyword: &'a PatternKeyword)
505where
506    V: SourceOrderVisitor<'a> + ?Sized,
507{
508    let node = AnyNodeRef::from(pattern_keyword);
509    if visitor.enter_node(node).is_traverse() {
510        pattern_keyword.visit_source_order(visitor);
511    }
512    visitor.leave_node(node);
513}
514
515pub fn walk_interpolated_string_element<'a, V: SourceOrderVisitor<'a> + ?Sized>(
516    visitor: &mut V,
517    f_string_element: &'a InterpolatedStringElement,
518) {
519    let node = AnyNodeRef::from(f_string_element);
520    if visitor.enter_node(node).is_traverse() {
521        match f_string_element {
522            InterpolatedStringElement::Interpolation(element) => {
523                element.visit_source_order(visitor);
524            }
525            InterpolatedStringElement::Literal(element) => element.visit_source_order(visitor),
526        }
527    }
528    visitor.leave_node(node);
529}
530
531pub fn walk_bool_op<'a, V>(_visitor: &mut V, _bool_op: &'a BoolOp)
532where
533    V: SourceOrderVisitor<'a> + ?Sized,
534{
535}
536
537#[inline]
538pub fn walk_operator<'a, V>(_visitor: &mut V, _operator: &'a Operator)
539where
540    V: SourceOrderVisitor<'a> + ?Sized,
541{
542}
543
544#[inline]
545pub fn walk_unary_op<'a, V>(_visitor: &mut V, _unary_op: &'a UnaryOp)
546where
547    V: SourceOrderVisitor<'a> + ?Sized,
548{
549}
550
551#[inline]
552pub fn walk_cmp_op<'a, V>(_visitor: &mut V, _cmp_op: &'a CmpOp)
553where
554    V: SourceOrderVisitor<'a> + ?Sized,
555{
556}
557
558#[inline]
559pub fn walk_f_string<'a, V>(visitor: &mut V, f_string: &'a FString)
560where
561    V: SourceOrderVisitor<'a> + ?Sized,
562{
563    let node = AnyNodeRef::from(f_string);
564    if visitor.enter_node(node).is_traverse() {
565        f_string.visit_source_order(visitor);
566    }
567    visitor.leave_node(node);
568}
569
570#[inline]
571pub fn walk_t_string<'a, V>(visitor: &mut V, t_string: &'a TString)
572where
573    V: SourceOrderVisitor<'a> + ?Sized,
574{
575    let node = AnyNodeRef::from(t_string);
576    if visitor.enter_node(node).is_traverse() {
577        t_string.visit_source_order(visitor);
578    }
579    visitor.leave_node(node);
580}
581
582#[inline]
583pub fn walk_string_literal<'a, V>(visitor: &mut V, string_literal: &'a StringLiteral)
584where
585    V: SourceOrderVisitor<'a> + ?Sized,
586{
587    let node = AnyNodeRef::from(string_literal);
588    if visitor.enter_node(node).is_traverse() {
589        string_literal.visit_source_order(visitor);
590    }
591    visitor.leave_node(node);
592}
593
594#[inline]
595pub fn walk_bytes_literal<'a, V>(visitor: &mut V, bytes_literal: &'a BytesLiteral)
596where
597    V: SourceOrderVisitor<'a> + ?Sized,
598{
599    let node = AnyNodeRef::from(bytes_literal);
600    if visitor.enter_node(node).is_traverse() {
601        bytes_literal.visit_source_order(visitor);
602    }
603    visitor.leave_node(node);
604}
605
606#[inline]
607pub fn walk_alias<'a, V>(visitor: &mut V, alias: &'a Alias)
608where
609    V: SourceOrderVisitor<'a> + ?Sized,
610{
611    let node = AnyNodeRef::from(alias);
612    if visitor.enter_node(node).is_traverse() {
613        alias.visit_source_order(visitor);
614    }
615    visitor.leave_node(node);
616}
617
618#[inline]
619pub fn walk_identifier<'a, V: SourceOrderVisitor<'a> + ?Sized>(
620    visitor: &mut V,
621    identifier: &'a Identifier,
622) {
623    let node = AnyNodeRef::from(identifier);
624    if visitor.enter_node(node).is_traverse() {
625        identifier.visit_source_order(visitor);
626    }
627    visitor.leave_node(node);
628}