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::Constant(expr) => expr.visit_source_order(visitor),
294            Expr::BooleanLiteral(expr) => expr.visit_source_order(visitor),
295            Expr::NoneLiteral(expr) => expr.visit_source_order(visitor),
296            Expr::EllipsisLiteral(expr) => expr.visit_source_order(visitor),
297            Expr::Attribute(expr) => expr.visit_source_order(visitor),
298            Expr::Subscript(expr) => expr.visit_source_order(visitor),
299            Expr::Starred(expr) => expr.visit_source_order(visitor),
300            Expr::Name(expr) => expr.visit_source_order(visitor),
301            Expr::List(expr) => expr.visit_source_order(visitor),
302            Expr::Tuple(expr) => expr.visit_source_order(visitor),
303            Expr::Slice(expr) => expr.visit_source_order(visitor),
304            Expr::IpyEscapeCommand(expr) => expr.visit_source_order(visitor),
305        }
306    }
307
308    visitor.leave_node(node);
309}
310
311pub fn walk_comprehension<'a, V>(visitor: &mut V, comprehension: &'a Comprehension)
312where
313    V: SourceOrderVisitor<'a> + ?Sized,
314{
315    let node = AnyNodeRef::from(comprehension);
316    if visitor.enter_node(node).is_traverse() {
317        comprehension.visit_source_order(visitor);
318    }
319
320    visitor.leave_node(node);
321}
322
323pub fn walk_elif_else_clause<'a, V>(visitor: &mut V, elif_else_clause: &'a ElifElseClause)
324where
325    V: SourceOrderVisitor<'a> + ?Sized,
326{
327    let node = AnyNodeRef::from(elif_else_clause);
328    if visitor.enter_node(node).is_traverse() {
329        elif_else_clause.visit_source_order(visitor);
330    }
331
332    visitor.leave_node(node);
333}
334
335pub fn walk_except_handler<'a, V>(visitor: &mut V, except_handler: &'a ExceptHandler)
336where
337    V: SourceOrderVisitor<'a> + ?Sized,
338{
339    let node = AnyNodeRef::from(except_handler);
340    if visitor.enter_node(node).is_traverse() {
341        match except_handler {
342            ExceptHandler::ExceptHandler(except_handler) => {
343                except_handler.visit_source_order(visitor);
344            }
345        }
346    }
347    visitor.leave_node(node);
348}
349
350pub fn walk_format_spec<'a, V: SourceOrderVisitor<'a> + ?Sized>(
351    visitor: &mut V,
352    format_spec: &'a Expr,
353) {
354    let node = AnyNodeRef::from(format_spec);
355    if visitor.enter_node(node).is_traverse() {
356        visitor.visit_expr(format_spec);
357    }
358
359    visitor.leave_node(node);
360}
361
362pub fn walk_arguments<'a, V>(visitor: &mut V, arguments: &'a Arguments)
363where
364    V: SourceOrderVisitor<'a> + ?Sized,
365{
366    let node = AnyNodeRef::from(arguments);
367    if visitor.enter_node(node).is_traverse() {
368        arguments.visit_source_order(visitor);
369    }
370
371    visitor.leave_node(node);
372}
373
374pub fn walk_parameters<'a, V>(visitor: &mut V, parameters: &'a Parameters)
375where
376    V: SourceOrderVisitor<'a> + ?Sized,
377{
378    let node = AnyNodeRef::from(parameters);
379    if visitor.enter_node(node).is_traverse() {
380        parameters.visit_source_order(visitor);
381    }
382
383    visitor.leave_node(node);
384}
385
386pub fn walk_parameter<'a, V>(visitor: &mut V, parameter: &'a Parameter)
387where
388    V: SourceOrderVisitor<'a> + ?Sized,
389{
390    let node = AnyNodeRef::from(parameter);
391
392    if visitor.enter_node(node).is_traverse() {
393        parameter.visit_source_order(visitor);
394    }
395    visitor.leave_node(node);
396}
397
398pub fn walk_parameter_with_default<'a, V>(
399    visitor: &mut V,
400    parameter_with_default: &'a ParameterWithDefault,
401) where
402    V: SourceOrderVisitor<'a> + ?Sized,
403{
404    let node = AnyNodeRef::from(parameter_with_default);
405    if visitor.enter_node(node).is_traverse() {
406        parameter_with_default.visit_source_order(visitor);
407    }
408
409    visitor.leave_node(node);
410}
411
412#[inline]
413pub fn walk_keyword<'a, V>(visitor: &mut V, keyword: &'a Keyword)
414where
415    V: SourceOrderVisitor<'a> + ?Sized,
416{
417    let node = AnyNodeRef::from(keyword);
418
419    if visitor.enter_node(node).is_traverse() {
420        keyword.visit_source_order(visitor);
421    }
422    visitor.leave_node(node);
423}
424
425pub fn walk_with_item<'a, V>(visitor: &mut V, with_item: &'a WithItem)
426where
427    V: SourceOrderVisitor<'a> + ?Sized,
428{
429    let node = AnyNodeRef::from(with_item);
430    if visitor.enter_node(node).is_traverse() {
431        with_item.visit_source_order(visitor);
432    }
433    visitor.leave_node(node);
434}
435
436pub fn walk_type_params<'a, V>(visitor: &mut V, type_params: &'a TypeParams)
437where
438    V: SourceOrderVisitor<'a> + ?Sized,
439{
440    let node = AnyNodeRef::from(type_params);
441    if visitor.enter_node(node).is_traverse() {
442        type_params.visit_source_order(visitor);
443    }
444    visitor.leave_node(node);
445}
446
447pub fn walk_type_param<'a, V>(visitor: &mut V, type_param: &'a TypeParam)
448where
449    V: SourceOrderVisitor<'a> + ?Sized,
450{
451    let node = AnyNodeRef::from(type_param);
452    if visitor.enter_node(node).is_traverse() {
453        type_param.visit_source_order(visitor);
454    }
455    visitor.leave_node(node);
456}
457
458pub fn walk_match_case<'a, V>(visitor: &mut V, match_case: &'a MatchCase)
459where
460    V: SourceOrderVisitor<'a> + ?Sized,
461{
462    let node = AnyNodeRef::from(match_case);
463    if visitor.enter_node(node).is_traverse() {
464        match_case.visit_source_order(visitor);
465    }
466    visitor.leave_node(node);
467}
468
469pub fn walk_pattern<'a, V>(visitor: &mut V, pattern: &'a Pattern)
470where
471    V: SourceOrderVisitor<'a> + ?Sized,
472{
473    let node = AnyNodeRef::from(pattern);
474    if visitor.enter_node(node).is_traverse() {
475        match pattern {
476            Pattern::MatchValue(pattern) => pattern.visit_source_order(visitor),
477            Pattern::MatchSingleton(pattern) => pattern.visit_source_order(visitor),
478            Pattern::MatchSequence(pattern) => pattern.visit_source_order(visitor),
479            Pattern::MatchMapping(pattern) => pattern.visit_source_order(visitor),
480            Pattern::MatchClass(pattern) => pattern.visit_source_order(visitor),
481            Pattern::MatchStar(pattern) => pattern.visit_source_order(visitor),
482            Pattern::MatchAs(pattern) => pattern.visit_source_order(visitor),
483            Pattern::MatchOr(pattern) => pattern.visit_source_order(visitor),
484        }
485    }
486    visitor.leave_node(node);
487}
488
489pub fn walk_pattern_arguments<'a, V>(visitor: &mut V, pattern_arguments: &'a PatternArguments)
490where
491    V: SourceOrderVisitor<'a> + ?Sized,
492{
493    let node = AnyNodeRef::from(pattern_arguments);
494    if visitor.enter_node(node).is_traverse() {
495        pattern_arguments.visit_source_order(visitor);
496    }
497    visitor.leave_node(node);
498}
499
500pub fn walk_pattern_keyword<'a, V>(visitor: &mut V, pattern_keyword: &'a PatternKeyword)
501where
502    V: SourceOrderVisitor<'a> + ?Sized,
503{
504    let node = AnyNodeRef::from(pattern_keyword);
505    if visitor.enter_node(node).is_traverse() {
506        pattern_keyword.visit_source_order(visitor);
507    }
508    visitor.leave_node(node);
509}
510
511pub fn walk_interpolated_string_element<'a, V: SourceOrderVisitor<'a> + ?Sized>(
512    visitor: &mut V,
513    f_string_element: &'a InterpolatedStringElement,
514) {
515    let node = AnyNodeRef::from(f_string_element);
516    if visitor.enter_node(node).is_traverse() {
517        match f_string_element {
518            InterpolatedStringElement::Interpolation(element) => {
519                element.visit_source_order(visitor);
520            }
521            InterpolatedStringElement::Literal(element) => element.visit_source_order(visitor),
522        }
523    }
524    visitor.leave_node(node);
525}
526
527pub fn walk_bool_op<'a, V>(_visitor: &mut V, _bool_op: &'a BoolOp)
528where
529    V: SourceOrderVisitor<'a> + ?Sized,
530{
531}
532
533#[inline]
534pub fn walk_operator<'a, V>(_visitor: &mut V, _operator: &'a Operator)
535where
536    V: SourceOrderVisitor<'a> + ?Sized,
537{
538}
539
540#[inline]
541pub fn walk_unary_op<'a, V>(_visitor: &mut V, _unary_op: &'a UnaryOp)
542where
543    V: SourceOrderVisitor<'a> + ?Sized,
544{
545}
546
547#[inline]
548pub fn walk_cmp_op<'a, V>(_visitor: &mut V, _cmp_op: &'a CmpOp)
549where
550    V: SourceOrderVisitor<'a> + ?Sized,
551{
552}
553
554#[inline]
555pub fn walk_f_string<'a, V>(visitor: &mut V, f_string: &'a FString)
556where
557    V: SourceOrderVisitor<'a> + ?Sized,
558{
559    let node = AnyNodeRef::from(f_string);
560    if visitor.enter_node(node).is_traverse() {
561        f_string.visit_source_order(visitor);
562    }
563    visitor.leave_node(node);
564}
565
566#[inline]
567pub fn walk_t_string<'a, V>(visitor: &mut V, t_string: &'a TString)
568where
569    V: SourceOrderVisitor<'a> + ?Sized,
570{
571    let node = AnyNodeRef::from(t_string);
572    if visitor.enter_node(node).is_traverse() {
573        t_string.visit_source_order(visitor);
574    }
575    visitor.leave_node(node);
576}
577
578#[inline]
579pub fn walk_string_literal<'a, V>(visitor: &mut V, string_literal: &'a StringLiteral)
580where
581    V: SourceOrderVisitor<'a> + ?Sized,
582{
583    let node = AnyNodeRef::from(string_literal);
584    if visitor.enter_node(node).is_traverse() {
585        string_literal.visit_source_order(visitor);
586    }
587    visitor.leave_node(node);
588}
589
590#[inline]
591pub fn walk_bytes_literal<'a, V>(visitor: &mut V, bytes_literal: &'a BytesLiteral)
592where
593    V: SourceOrderVisitor<'a> + ?Sized,
594{
595    let node = AnyNodeRef::from(bytes_literal);
596    if visitor.enter_node(node).is_traverse() {
597        bytes_literal.visit_source_order(visitor);
598    }
599    visitor.leave_node(node);
600}
601
602#[inline]
603pub fn walk_alias<'a, V>(visitor: &mut V, alias: &'a Alias)
604where
605    V: SourceOrderVisitor<'a> + ?Sized,
606{
607    let node = AnyNodeRef::from(alias);
608    if visitor.enter_node(node).is_traverse() {
609        alias.visit_source_order(visitor);
610    }
611    visitor.leave_node(node);
612}
613
614#[inline]
615pub fn walk_identifier<'a, V: SourceOrderVisitor<'a> + ?Sized>(
616    visitor: &mut V,
617    identifier: &'a Identifier,
618) {
619    let node = AnyNodeRef::from(identifier);
620    if visitor.enter_node(node).is_traverse() {
621        identifier.visit_source_order(visitor);
622    }
623    visitor.leave_node(node);
624}