1
1
//! AST visitors (i.e. on-the-fly mutation at different places in the AST).
2
2
//!
3
- //! Visitors are mutable objects that can mutate parts of an AST while traversing it. Visitors must
4
- //! implement the [`Visitor`] trait in order to be usable.
3
+ //! Visitors are mutable objects that can mutate parts of an AST while traversing it. You can see
4
+ //! them as flexible mutations taking place on *patterns* representing your AST – they get called
5
+ //! everytime an interesting node gets visited. Because of their mutable nature, you can accumulate
6
+ //! a state as you traverse the AST and implement exotic filtering.
7
+ //!
8
+ //! Visitors must implement the [`Visitor`] trait in order to be usable.
9
+ //!
10
+ //! In order to visit any part of an AST (from its very top root or from any part of it), you must
11
+ //! use the [`Host`] interface, that provides the `Host::visit` function.
5
12
6
13
use syntax;
7
14
8
15
/// Visit strategy after having visited an AST node.
9
16
#[ derive( Clone , Copy , Debug , Eq , Hash , PartialEq ) ]
10
17
pub enum Visit {
11
- /// The visitor will go deeper in the AST by visiting all the children.
18
+ /// The visitor will go deeper in the AST by visiting all the children, if any. If no children are
19
+ /// present are if having children doesn’t make sense for a specific part of the AST, this
20
+ /// strategy will be ignored.
12
21
Children ,
13
22
/// The visitor won’t visit children nor siblings and will go up.
14
23
Parent
15
24
}
16
25
26
+ /// Visitor object, visiting AST nodes.
17
27
pub trait Visitor {
18
28
fn visit_translation_unit ( & mut self , _: & mut syntax:: TranslationUnit ) -> Visit {
19
29
Visit :: Children
@@ -23,23 +33,27 @@ pub trait Visitor {
23
33
Visit :: Children
24
34
}
25
35
36
+ fn visit_identifier ( & mut self , _: & mut syntax:: Identifier ) -> Visit {
37
+ Visit :: Children
38
+ }
39
+
26
40
fn visit_arrayed_identifier ( & mut self , _: & mut syntax:: ArrayedIdentifier ) -> Visit {
27
41
Visit :: Children
28
42
}
29
43
30
- fn visit_block ( & mut self , _: & mut syntax:: Block ) -> Visit {
44
+ fn visit_type_name ( & mut self , _: & mut syntax:: TypeName ) -> Visit {
31
45
Visit :: Children
32
46
}
33
47
34
- fn visit_for_init_statement ( & mut self , _: & mut syntax:: ForInitStatement ) -> Visit {
48
+ fn visit_block ( & mut self , _: & mut syntax:: Block ) -> Visit {
35
49
Visit :: Children
36
50
}
37
51
38
- fn visit_for_rest_statement ( & mut self , _: & mut syntax:: ForRestStatement ) -> Visit {
52
+ fn visit_for_init_statement ( & mut self , _: & mut syntax:: ForInitStatement ) -> Visit {
39
53
Visit :: Children
40
54
}
41
55
42
- fn visit_full_specified_type ( & mut self , _: & mut syntax:: FullySpecifiedType ) -> Visit {
56
+ fn visit_for_rest_statement ( & mut self , _: & mut syntax:: ForRestStatement ) -> Visit {
43
57
Visit :: Children
44
58
}
45
59
@@ -123,6 +137,10 @@ pub trait Visitor {
123
137
Visit :: Children
124
138
}
125
139
140
+ fn visit_full_specified_type ( & mut self , _: & mut syntax:: FullySpecifiedType ) -> Visit {
141
+ Visit :: Children
142
+ }
143
+
126
144
fn visit_array_specifier ( & mut self , _: & mut syntax:: ArraySpecifier ) -> Visit {
127
145
Visit :: Children
128
146
}
@@ -214,17 +232,28 @@ pub trait Visitor {
214
232
fn visit_expr_statement ( & mut self , _: & mut syntax:: ExprStatement ) -> Visit {
215
233
Visit :: Children
216
234
}
217
-
218
- fn visit_identifier ( & mut self , _: & mut syntax:: Identifier ) -> Visit {
219
- Visit :: Children
220
- }
221
-
222
- fn visit_type_name ( & mut self , _: & mut syntax:: TypeName ) -> Visit {
223
- Visit :: Children
224
- }
225
235
}
226
236
237
+ /// Part of the AST that can be visited.
238
+ ///
239
+ /// You shouldn’t have to worry about this type nor how to implement it – it’s completely
240
+ /// implemented for you. However, it works in a pretty simple way: any implementor of [`Host`] can
241
+ /// be used with a [`Visitor`].
242
+ ///
243
+ /// The idea is that visiting an AST node is a two-step process:
244
+ ///
245
+ /// - First, you *can* get your visitor called once as soon as an interesting node gets visited.
246
+ /// For instance, if your visitor has an implementation for visiting expressions, everytime an
247
+ /// expression gets visited, your visitor will run.
248
+ /// - If your implementation of visiting an AST node returns `Visit::Children` and if the given
249
+ /// node has children, the visitor will go deeper, invoking other calls if you have defined any.
250
+ /// A typical pattern you might want to do is to implement your visitor to gets run on all
251
+ /// typenames. Since expressions contains variables, you will get your visitor called once again
252
+ /// there.
253
+ /// - Notice that since visitors are mutable, you can accumulate a state as you go deeper in the
254
+ /// AST to implement various checks and validations.
227
255
pub trait Host {
256
+ /// Visit an AST node.
228
257
fn visit < V > ( & mut self , visitor : & mut V ) where V : Visitor ;
229
258
}
230
259
0 commit comments