plc_ast/visitor.rs
1//! This module defines the `AstVisitor` trait and its associated macros.
2//! The `AstVisitor` trait provides a set of methods for traversing and visiting ASTs
3
4use crate::ast::{
5 flatten_expression_list, Allocation, Assignment, AstNode, AstStatement, BinaryExpression, CallStatement,
6 CompilationUnit, ConfigVariable, DataType, DataTypeDeclaration, DefaultValue, DirectAccess,
7 EmptyStatement, HardwareAccess, Implementation, Interface, JumpStatement, LabelStatement,
8 MultipliedStatement, Pou, PropertyBlock, RangeStatement, ReferenceAccess, ReferenceExpr, UnaryExpression,
9 UserTypeDeclaration, Variable, VariableBlock,
10};
11use crate::control_statements::{
12 AstControlStatement, ConditionalBlock, ForLoopStatement, LoopStatement, ReturnStatement,
13};
14use crate::literals::AstLiteral;
15
16/// Macro that calls the visitor's `visit` method for every AstNode in the passed iterator `iter`.
17macro_rules! visit_all_nodes {
18 ($visitor:expr, $iter:expr) => {
19 // Note: The `allow` is needed to suppress warnings about `while let Some(...)` warnings
20 // because `visit_all_nodes!` is used for both Option and Non-Option types
21 #[allow(warnings)]
22 {
23 for node in $iter {
24 $visitor.visit(node);
25 }
26 }
27 };
28}
29
30/// Macro that calls the visitor's `visit` method for every AstNode in the passed sequence of nodes.
31macro_rules! visit_nodes {
32 ($visitor:expr, $($node:expr),*) => {
33 $(
34 $visitor.visit($node);
35 )*
36 };
37}
38
39/// The `Walker` implements the traversal of the AST nodes and Ast-related objects (e.g. CompilationUnit).
40/// The `walk` method is called on the object to visit its children.
41/// If the object passed to a `AstVisitor`'s `visit` method implements the `Walker` trait,
42/// a call to the it's walk function continues the visiting process on its children.
43///
44/// Spliting the traversal logic into a separate trait allows to call the default traversal logic
45/// from the visitor while overriding the visitor's `visit` method for specific nodes.
46///
47/// # Example
48/// ```
49/// use plc_ast::ast::AstNode;
50/// use plc_ast::visitor::Walker;
51/// use plc_ast::visitor::AstVisitor;
52///
53/// struct MyAssignment {
54/// left: AstNode,
55/// right: AstNode,
56/// }
57///
58/// impl Walker for MyAssignment {
59/// fn walk<V>(&self, visitor: &mut V)
60/// where
61/// V: AstVisitor,
62/// {
63/// visitor.visit(&self.right);
64/// visitor.visit(&self.left);
65/// }
66/// }
67/// ```
68///
69pub trait Walker {
70 fn walk<V>(&self, visitor: &mut V)
71 where
72 V: AstVisitor;
73}
74
75/// The `AstVisitor` trait provides a set of methods for visiting different types of AST nodes.
76/// Implementors can individually override the methods they are interested in. When overriding a method,
77/// make sure to call `walk` on the visited statement to visit its children. DO NOT call walk on
78/// the node itself to avoid a recursion (last parameter). Implementors may also decide to not call
79/// the statement's `walk` method to avoid visiting the children of the statement.
80///
81/// The visitor offers strongly typed `visit_X` functions for every node type. The function's signature
82/// is `fn visit_X(&mut self, stmt: &X, node: &AstNode)`. The `stmt` parameter is the unwrapped, typed
83/// node and the `node` parameter is the `AstNode` wrapping the stmt. The `AstNode` node offers access to location
84/// information and the AstId. Note that some nodes are not wrapped in an `AstNode` node (e.g. `CompilationUnit`)
85/// and therefore only the strongly typed node is passed to the `visit_X` function.
86///
87/// # Example
88/// ```
89/// use plc_ast::{
90/// ast::{Assignment, AstNode},
91/// visitor::{AstVisitor, Walker},
92/// };
93///
94/// struct AssignmentCounter {
95/// count: usize,
96/// }
97///
98/// impl AstVisitor for AssignmentCounter {
99/// fn visit_assignment(&mut self, stmt: &Assignment, _node: &AstNode) {
100/// self.count += 1;
101/// // visit child nodes
102/// stmt.walk(self);
103/// }
104///
105/// fn visit_output_assignment(&mut self, stmt: &Assignment, _node: &AstNode) {
106/// self.count += 1;
107/// // visit child nodes
108/// stmt.walk(self);
109/// }
110/// }
111/// ```
112pub trait AstVisitor: Sized {
113 /// Visits this `AstNode`. The default implementation calls the `walk` method on the node
114 /// and will eventually call the strongly typed `visit` method for the node (e.g. visit_assignment
115 /// if the node is an `AstStatement::Assignment`).
116 /// # Arguments
117 /// * `node` - The `AstNode` node to visit.
118 fn visit(&mut self, node: &AstNode) {
119 node.walk(self)
120 }
121
122 /// Called when visiting a list of statements (e.g. implementation bodies, control flow branches).
123 /// Override this to intercept statement-list processing.
124 fn visit_statement_list(&mut self, stmts: &[AstNode]) {
125 for node in stmts {
126 self.visit(node);
127 }
128 }
129
130 /// Visits a `CompilationUnit` node.
131 /// Make sure to call `walk` on the `CompilationUnit` node to visit its children.
132 /// # Arguments
133 /// * `unit` - The unwraped, typed `CompilationUnit` node to visit.
134 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
135 fn visit_compilation_unit(&mut self, unit: &CompilationUnit) {
136 unit.walk(self)
137 }
138
139 /// Visits an `Implementation` node.
140 /// Make sure to call `walk` on the `Implementation` node to visit its children.
141 /// # Arguments
142 /// * `implementation` - The unwraped, typed `Implementation` node to visit.
143 fn visit_implementation(&mut self, implementation: &Implementation) {
144 implementation.walk(self);
145 }
146
147 /// Visits a `DataTypeDeclaration` node.
148 /// Make sure to call `walk` on the `VariableBlock` node to visit its children.
149 /// # Arguments
150 /// * `block` - The unwraped, typed `VariableBlock` node to visit.
151 fn visit_variable_block(&mut self, block: &VariableBlock) {
152 block.walk(self)
153 }
154
155 /// Visits a `Variable` node.
156 /// Make sure to call `walk` on the `Variable` node to visit its children.
157 /// # Arguments
158 /// * `variable` - The unwraped, typed `Variable` node to visit.
159 fn visit_variable(&mut self, variable: &Variable) {
160 variable.walk(self);
161 }
162
163 /// Visits a `ConfigVariable` node.
164 /// Make sure to call `walk` on the `ConfigVariable` node to visit its children.
165 /// # Arguments
166 /// * `variable` - The unwraped, typed `Variable` node to visit.
167 fn visit_config_variable(&mut self, config_variable: &ConfigVariable) {
168 config_variable.walk(self);
169 }
170
171 /// Visits a `Interface`.
172 /// Make sure to call `walk` on the `Interface` to visit its children.
173 /// # Arguments
174 /// * `interface` - The unwraped, typed `Interface` node to visit.
175 fn visit_interface(&mut self, interface: &Interface) {
176 interface.walk(self);
177 }
178
179 /// Visits a `Property`.
180 /// Make sure to call `walk` on the `PropertyBlock` to visit its children.
181 fn visit_property(&mut self, property: &PropertyBlock) {
182 property.walk(self);
183 }
184
185 /// Visits an enum element `AstNode` node.
186 /// Make sure to call `walk` on the `AstNode` node to visit its children.
187 /// # Arguments
188 /// * `element` - The unwraped, typed `AstNode` node to visit.
189 fn visit_enum_element(&mut self, element: &AstNode) {
190 element.walk(self);
191 }
192
193 /// Visits a `DataTypeDeclaration` node.
194 /// Make sure to call `walk` on the `DataTypeDeclaration` node to visit its children.
195 /// # Arguments
196 /// * `data_type_declaration` - The unwraped, typed `DataTypeDeclaration` node to visit.
197 fn visit_data_type_declaration(&mut self, data_type_declaration: &DataTypeDeclaration) {
198 data_type_declaration.walk(self);
199 }
200
201 /// Visits a `UserTypeDeclaration` node.
202 /// Make sure to call `walk` on the `UserTypeDeclaration` node to visit its children.
203 /// # Arguments
204 /// * `user_type` - The unwraped, typed `UserTypeDeclaration` node to visit.
205 fn visit_user_type_declaration(&mut self, user_type: &UserTypeDeclaration) {
206 user_type.walk(self);
207 }
208
209 /// Visits a `UserTypeDeclaration` node.
210 /// Make sure to call `walk` on the `DataType` node to visit its children.
211 /// # Arguments
212 /// * `data_type` - The unwraped, typed `DataType` node to visit.
213 fn visit_data_type(&mut self, data_type: &DataType) {
214 data_type.walk(self);
215 }
216
217 /// Visits a `Pou` node.
218 /// Make sure to call `walk` on the `Pou` node to visit its children.
219 /// # Arguments
220 /// * `pou` - The unwraped, typed `Pou` node to visit.
221 fn visit_pou(&mut self, pou: &Pou) {
222 pou.walk(self);
223 }
224
225 /// Visits an `EmptyStatement` node.
226 /// # Arguments
227 /// * `stmt` - The unwraped, typed `EmptyStatement` node to visit.
228 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
229 fn visit_empty_statement(&mut self, _stmt: &EmptyStatement, _node: &AstNode) {}
230
231 /// Visits a `DefaultValue` node.
232 /// # Arguments
233 /// * `stmt` - The unwraped, typed `DefaultValue` node to visit.
234 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
235 fn visit_default_value(&mut self, _stmt: &DefaultValue, _node: &AstNode) {}
236
237 /// Visits an `AstLiteral` node.
238 /// Make sure to call `walk` on the `AstLiteral` node to visit its children.
239 /// # Arguments
240 /// * `stmt` - The unwraped, typed `AstLiteral` node to visit.
241 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
242 fn visit_literal(&mut self, stmt: &AstLiteral, _node: &AstNode) {
243 stmt.walk(self)
244 }
245
246 /// Visits a `MultipliedStatement` node.
247 /// Make sure to call `walk` on the `MultipliedStatement` node to visit its children.
248 /// # Arguments
249 /// * `stmt` - The unwraped, typed `MultipliedStatement` node to visit.
250 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
251 fn visit_multiplied_statement(&mut self, stmt: &MultipliedStatement, _node: &AstNode) {
252 stmt.walk(self)
253 }
254
255 /// Visits a `ReferenceExpr` node.
256 /// Make sure to call `walk` on the `ReferenceExpr` node to visit its children.
257 /// # Arguments
258 /// * `stmt` - The unwraped, typed `ReferenceExpr` node to visit.
259 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
260 fn visit_reference_expr(&mut self, stmt: &ReferenceExpr, _node: &AstNode) {
261 stmt.walk(self)
262 }
263
264 /// Visits an `Identifier` node.
265 /// Make sure to call `walk` on the `Identifier` node to visit its children.
266 /// # Arguments
267 /// * `stmt` - The unwraped, typed `Identifier` node to visit.
268 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
269 fn visit_identifier(&mut self, _stmt: &str, _node: &AstNode) {}
270
271 /// Visits a `DirectAccess` node.
272 /// Make sure to call `walk` on the `DirectAccess` node to visit its children.
273 /// # Arguments
274 /// * `stmt` - The unwraped, typed `DirectAccess` node to visit.
275 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
276 fn visit_direct_access(&mut self, stmt: &DirectAccess, _node: &AstNode) {
277 stmt.walk(self)
278 }
279
280 /// Visits a `HardwareAccess` node.
281 /// Make sure to call `walk` on the `HardwareAccess` node to visit its children.
282 /// # Arguments
283 /// * `stmt` - The unwraped, typed `HardwareAccess` node to visit.
284 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
285 fn visit_hardware_access(&mut self, stmt: &HardwareAccess, _node: &AstNode) {
286 stmt.walk(self)
287 }
288
289 /// Visits a `BinaryExpression` node.
290 /// Make sure to call `walk` on the `BinaryExpression` node to visit its children.
291 /// # Arguments
292 /// * `stmt` - The unwraped, typed `BinaryExpression` node to visit.
293 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
294 fn visit_binary_expression(&mut self, stmt: &BinaryExpression, _node: &AstNode) {
295 stmt.walk(self)
296 }
297
298 /// Visits a `UnaryExpression` node.
299 /// Make sure to call `walk` on the `UnaryExpression` node to visit its children.
300 /// # Arguments
301 /// * `stmt` - The unwraped, typed `UnaryExpression` node to visit.
302 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
303 fn visit_unary_expression(&mut self, stmt: &UnaryExpression, _node: &AstNode) {
304 stmt.walk(self)
305 }
306
307 /// Visits an `ExpressionList` node.
308 /// Make sure to call `walk` on the `Vec<AstNode>` node to visit its children.
309 /// # Arguments
310 /// * `stmt` - The unwraped, typed `ExpressionList` node to visit.
311 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
312 fn visit_expression_list(&mut self, stmt: &Vec<AstNode>, _node: &AstNode) {
313 visit_all_nodes!(self, stmt);
314 }
315
316 /// Visits a `ParenExpression` node.
317 /// Make sure to call `walk` on the inner `AstNode` node to visit its children.
318 /// # Arguments
319 /// * `inner` - The unwraped, typed inner `AstNode` node to visit.
320 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
321 fn visit_paren_expression(&mut self, inner: &AstNode, _node: &AstNode) {
322 inner.walk(self)
323 }
324
325 /// Visits a `RangeStatement` node.
326 /// Make sure to call `walk` on the `RangeStatement` node to visit its children.
327 /// # Arguments
328 /// * `stmt` - The unwraped, typed `RangeStatement` node to visit.
329 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
330 fn visit_range_statement(&mut self, stmt: &RangeStatement, _node: &AstNode) {
331 stmt.walk(self)
332 }
333
334 /// Visits a `VlaRangeStatement` node.
335 /// # Arguments
336 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
337 fn visit_vla_range_statement(&mut self, _node: &AstNode) {}
338
339 /// Visits an `Assignment` node.
340 /// Make sure to call `walk` on the `Assignment` node to visit its children.
341 /// # Arguments
342 /// * `stmt` - The unwraped, typed `Assignment` node to visit.
343 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
344 fn visit_assignment(&mut self, stmt: &Assignment, _node: &AstNode) {
345 stmt.walk(self)
346 }
347
348 /// Visits an `OutputAssignment` node.
349 /// Make sure to call `walk` on the `Assignment` node to visit its children.
350 /// # Arguments
351 /// * `stmt` - The unwraped, typed `Assignment` node to visit.
352 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
353 fn visit_output_assignment(&mut self, stmt: &Assignment, _node: &AstNode) {
354 stmt.walk(self)
355 }
356
357 /// Visits an `RefAssignment` node.
358 /// Make sure to call `walk` on the `Assignment` node to visit its children.
359 /// # Arguments
360 /// * `stmt` - The unwraped, typed `Assignment` node to visit.
361 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
362 fn visit_ref_assignment(&mut self, stmt: &Assignment, _node: &AstNode) {
363 stmt.walk(self)
364 }
365
366 /// Visits a `CallStatement` node.
367 /// Make sure to call `walk` on the `CallStatement` node to visit its children.
368 /// # Arguments
369 /// * `stmt` - The unwraped, typed `CallStatement` node to visit.
370 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
371 fn visit_call_statement(&mut self, stmt: &CallStatement, _node: &AstNode) {
372 stmt.walk(self)
373 }
374
375 /// Visits an `AstControlStatement` node.
376 /// Make sure to call `walk` on the `AstControlStatement` node to visit its children.
377 /// # Arguments
378 /// * `stmt` - The unwraped, typed `AstControlStatement` node to visit.
379 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
380 fn visit_control_statement(&mut self, stmt: &AstControlStatement, node: &AstNode) {
381 match stmt {
382 AstControlStatement::WhileLoop(loop_stmt) => self.visit_while_loop_statement(loop_stmt, node),
383 AstControlStatement::RepeatLoop(loop_stmt) => self.visit_repeat_loop_statement(loop_stmt, node),
384 AstControlStatement::ForLoop(for_stmt) => self.visit_for_loop_statement(for_stmt, node),
385 _ => stmt.walk(self),
386 }
387 }
388
389 /// Visits a `ForLoop` control statement.
390 /// # Arguments
391 /// * `stmt` - The unwraped, typed `ForLoopStatement` node to visit.
392 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
393 fn visit_for_loop_statement(&mut self, stmt: &ForLoopStatement, _node: &AstNode) {
394 visit_nodes!(self, &stmt.counter, &stmt.start, &stmt.end);
395 visit_all_nodes!(self, &stmt.by_step);
396 self.visit_statement_list(&stmt.body);
397 }
398
399 /// Visits a `WhileLoop` control statement.
400 /// Make sure to call `walk` on the `LoopStatement` node to visit its children.
401 /// # Arguments
402 /// * `stmt` - The unwraped, typed `LoopStatement` node to visit.
403 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
404 fn visit_while_loop_statement(&mut self, stmt: &LoopStatement, _node: &AstNode) {
405 visit_nodes!(self, &stmt.condition);
406 self.visit_statement_list(&stmt.body);
407 }
408
409 /// Visits a `RepeatLoop` control statement.
410 /// Make sure to call `walk` on the `LoopStatement` node to visit its children.
411 /// # Arguments
412 /// * `stmt` - The unwraped, typed `LoopStatement` node to visit.
413 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
414 fn visit_repeat_loop_statement(&mut self, stmt: &LoopStatement, _node: &AstNode) {
415 visit_nodes!(self, &stmt.condition);
416 self.visit_statement_list(&stmt.body);
417 }
418
419 /// Visits a `CaseCondition` node.
420 /// Make sure to call `walk` on the child-`AstNode` node to visit its children.
421 /// # Arguments
422 /// * `stmt` - The unwraped, typed `CaseCondition` node to visit.
423 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
424 fn visit_case_condition(&mut self, child: &AstNode, _node: &AstNode) {
425 child.walk(self)
426 }
427
428 /// Visits an `ExitStatement` node.
429 /// # Arguments
430 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
431 fn visit_exit_statement(&mut self, _node: &AstNode) {}
432
433 /// Visits a `ContinueStatement` node.
434 /// # Arguments
435 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
436 fn visit_continue_statement(&mut self, _node: &AstNode) {}
437
438 /// Visits a `ReturnStatement` node.
439 /// Make sure to call `walk` on the `ReturnStatement` node to visit its children.
440 /// # Arguments
441 /// * `stmt` - The unwraped, typed `ReturnStatement` node to visit.
442 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
443 fn visit_return_statement(&mut self, stmt: &ReturnStatement, _node: &AstNode) {
444 stmt.walk(self)
445 }
446
447 /// Visits a `JumpStatement` node.
448 /// Make sure to call `walk` on the `JumpStatement` node to visit its children.
449 /// # Arguments
450 /// * `stmt` - The unwraped, typed `JumpStatement` node to visit.
451 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
452 fn visit_jump_statement(&mut self, stmt: &JumpStatement, _node: &AstNode) {
453 stmt.walk(self)
454 }
455
456 /// Visits a `LabelStatement` node.
457 /// # Arguments
458 /// * `stmt` - The unwraped, typed `LabelStatement` node to visit.
459 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
460 fn visit_label_statement(&mut self, _stmt: &LabelStatement, _node: &AstNode) {}
461
462 /// Visits an `Allocation` node
463 /// # Arguments
464 /// * `stmt` - The unwraped, typed `Allocation` node to visit.
465 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
466 fn visit_allocation(&mut self, _stmt: &Allocation, _node: &AstNode) {}
467
468 /// Visits a `Super` node.
469 /// # Arguments
470 /// * `stmt` - The unwraped, typed `Super` node to visit.
471 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
472 fn visit_super(&mut self, _stmt: &AstStatement, _node: &AstNode) {}
473
474 /// Visits a `This` node.
475 /// # Arguments
476 /// * `stmt` - The unwraped, typed `This` node to visit.
477 /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
478 fn visit_this(&mut self, _stmt: &AstStatement, _node: &AstNode) {}
479}
480
481/// Helper method that walks through a slice of `ConditionalBlock` and applies the visitor's `walk` method to each node.
482fn walk_conditional_blocks<V>(visitor: &mut V, blocks: &[ConditionalBlock])
483where
484 V: AstVisitor,
485{
486 for b in blocks {
487 visit_nodes!(visitor, &b.condition);
488 visitor.visit_statement_list(&b.body);
489 }
490}
491
492impl Walker for AstLiteral {
493 fn walk<V>(&self, _visitor: &mut V)
494 where
495 V: AstVisitor,
496 {
497 // do nothing
498 }
499}
500
501impl Walker for MultipliedStatement {
502 fn walk<V>(&self, visitor: &mut V)
503 where
504 V: AstVisitor,
505 {
506 visitor.visit(&self.element)
507 }
508}
509
510impl Walker for ReferenceExpr {
511 fn walk<V>(&self, visitor: &mut V)
512 where
513 V: AstVisitor,
514 {
515 if let Some(base) = &self.base {
516 visitor.visit(base);
517 }
518
519 match &self.access {
520 ReferenceAccess::Member(t) | ReferenceAccess::Index(t) | ReferenceAccess::Cast(t) => {
521 visitor.visit(t)
522 }
523 _ => {}
524 }
525 }
526}
527
528impl Walker for DirectAccess {
529 fn walk<V>(&self, visitor: &mut V)
530 where
531 V: AstVisitor,
532 {
533 visit_nodes!(visitor, &self.index);
534 }
535}
536
537impl Walker for HardwareAccess {
538 fn walk<V>(&self, visitor: &mut V)
539 where
540 V: AstVisitor,
541 {
542 visit_all_nodes!(visitor, &self.address);
543 }
544}
545
546impl Walker for BinaryExpression {
547 fn walk<V>(&self, visitor: &mut V)
548 where
549 V: AstVisitor,
550 {
551 visit_nodes!(visitor, &self.left, &self.right);
552 }
553}
554
555impl Walker for UnaryExpression {
556 fn walk<V>(&self, visitor: &mut V)
557 where
558 V: AstVisitor,
559 {
560 visit_nodes!(visitor, &self.value);
561 }
562}
563
564impl Walker for Assignment {
565 fn walk<V>(&self, visitor: &mut V)
566 where
567 V: AstVisitor,
568 {
569 visit_nodes!(visitor, &self.left, &self.right);
570 }
571}
572
573impl Walker for RangeStatement {
574 fn walk<V>(&self, visitor: &mut V)
575 where
576 V: AstVisitor,
577 {
578 visit_nodes!(visitor, &self.start, &self.end);
579 }
580}
581
582impl Walker for CallStatement {
583 fn walk<V>(&self, visitor: &mut V)
584 where
585 V: AstVisitor,
586 {
587 visit_nodes!(visitor, &self.operator);
588 if let Some(params) = &self.parameters {
589 visit_nodes!(visitor, params);
590 }
591 }
592}
593
594impl Walker for AstControlStatement {
595 fn walk<V>(&self, visitor: &mut V)
596 where
597 V: AstVisitor,
598 {
599 match self {
600 AstControlStatement::If(stmt) => {
601 walk_conditional_blocks(visitor, &stmt.blocks);
602 visitor.visit_statement_list(&stmt.else_block);
603 }
604 AstControlStatement::WhileLoop(stmt) | AstControlStatement::RepeatLoop(stmt) => {
605 visit_nodes!(visitor, &stmt.condition);
606 visitor.visit_statement_list(&stmt.body);
607 }
608 AstControlStatement::ForLoop(stmt) => {
609 visit_nodes!(visitor, &stmt.counter, &stmt.start, &stmt.end);
610 visit_all_nodes!(visitor, &stmt.by_step);
611 visitor.visit_statement_list(&stmt.body);
612 }
613 AstControlStatement::Case(stmt) => {
614 visit_nodes!(visitor, &stmt.selector);
615 walk_conditional_blocks(visitor, &stmt.case_blocks);
616 visitor.visit_statement_list(&stmt.else_block);
617 }
618 }
619 }
620}
621
622impl Walker for ReturnStatement {
623 fn walk<V>(&self, visitor: &mut V)
624 where
625 V: AstVisitor,
626 {
627 visit_all_nodes!(visitor, &self.condition);
628 }
629}
630
631impl Walker for JumpStatement {
632 fn walk<V>(&self, visitor: &mut V)
633 where
634 V: AstVisitor,
635 {
636 visit_nodes!(visitor, &self.condition, &self.target);
637 }
638}
639
640impl Walker for AstNode {
641 fn walk<V>(&self, visitor: &mut V)
642 where
643 V: AstVisitor,
644 {
645 let node = self;
646 match &self.stmt {
647 AstStatement::EmptyStatement(stmt) => visitor.visit_empty_statement(stmt, node),
648 AstStatement::DefaultValue(stmt) => visitor.visit_default_value(stmt, node),
649 AstStatement::Literal(stmt) => visitor.visit_literal(stmt, node),
650 AstStatement::MultipliedStatement(stmt) => visitor.visit_multiplied_statement(stmt, node),
651 AstStatement::ReferenceExpr(stmt) => visitor.visit_reference_expr(stmt, node),
652 AstStatement::Identifier(stmt) => visitor.visit_identifier(stmt, node),
653 AstStatement::DirectAccess(stmt) => visitor.visit_direct_access(stmt, node),
654 AstStatement::HardwareAccess(stmt) => visitor.visit_hardware_access(stmt, node),
655 AstStatement::BinaryExpression(stmt) => visitor.visit_binary_expression(stmt, node),
656 AstStatement::UnaryExpression(stmt) => visitor.visit_unary_expression(stmt, node),
657 AstStatement::ExpressionList(stmt) => visitor.visit_expression_list(stmt, node),
658 AstStatement::ParenExpression(stmt) => visitor.visit_paren_expression(stmt, node),
659 AstStatement::RangeStatement(stmt) => visitor.visit_range_statement(stmt, node),
660 AstStatement::VlaRangeStatement => visitor.visit_vla_range_statement(node),
661 AstStatement::Assignment(stmt) => visitor.visit_assignment(stmt, node),
662 AstStatement::OutputAssignment(stmt) => visitor.visit_output_assignment(stmt, node),
663 AstStatement::RefAssignment(stmt) => visitor.visit_ref_assignment(stmt, node),
664 AstStatement::CallStatement(stmt) => visitor.visit_call_statement(stmt, node),
665 AstStatement::ControlStatement(stmt) => visitor.visit_control_statement(stmt, node),
666 AstStatement::CaseCondition(stmt) => visitor.visit_case_condition(stmt, node),
667 AstStatement::ExitStatement(_stmt) => visitor.visit_exit_statement(node),
668 AstStatement::ContinueStatement(_stmt) => visitor.visit_continue_statement(node),
669 AstStatement::ReturnStatement(stmt) => visitor.visit_return_statement(stmt, node),
670 AstStatement::JumpStatement(stmt) => visitor.visit_jump_statement(stmt, node),
671 AstStatement::LabelStatement(stmt) => visitor.visit_label_statement(stmt, node),
672 AstStatement::AllocationStatement(stmt) => visitor.visit_allocation(stmt, node),
673 AstStatement::Super(_) => visitor.visit_super(&self.stmt, node),
674 AstStatement::This => visitor.visit_this(&self.stmt, node),
675 }
676 }
677}
678
679impl Walker for CompilationUnit {
680 fn walk<V>(&self, visitor: &mut V)
681 where
682 V: AstVisitor,
683 {
684 for user_type in &self.user_types {
685 visitor.visit_user_type_declaration(user_type);
686 }
687
688 for block in &self.global_vars {
689 visitor.visit_variable_block(block);
690 }
691 for config_variable in &self.var_config {
692 visitor.visit_config_variable(config_variable);
693 }
694
695 for interface in &self.interfaces {
696 visitor.visit_interface(interface);
697 }
698
699 for pou in &self.pous {
700 visitor.visit_pou(pou);
701 }
702
703 for i in &self.implementations {
704 visitor.visit_implementation(i);
705 }
706 }
707}
708
709impl Walker for UserTypeDeclaration {
710 fn walk<V>(&self, visitor: &mut V)
711 where
712 V: AstVisitor,
713 {
714 visitor.visit_data_type(&self.data_type);
715 visit_all_nodes!(visitor, &self.initializer);
716 }
717}
718
719impl Walker for VariableBlock {
720 fn walk<V>(&self, visitor: &mut V)
721 where
722 V: AstVisitor,
723 {
724 for v in self.variables.iter() {
725 visitor.visit_variable(v);
726 }
727 }
728}
729
730impl Walker for Variable {
731 fn walk<V>(&self, visitor: &mut V)
732 where
733 V: AstVisitor,
734 {
735 visit_all_nodes!(visitor, &self.address);
736 visitor.visit_data_type_declaration(&self.data_type_declaration);
737 visit_all_nodes!(visitor, &self.initializer);
738 }
739}
740
741impl Walker for ConfigVariable {
742 fn walk<V>(&self, _visitor: &mut V)
743 where
744 V: AstVisitor,
745 {
746 // do nothing
747 }
748}
749
750impl Walker for Interface {
751 fn walk<V>(&self, visitor: &mut V)
752 where
753 V: AstVisitor,
754 {
755 for method in &self.methods {
756 visitor.visit_pou(method);
757 }
758
759 for property in &self.properties {
760 visitor.visit_property(property);
761 }
762 }
763}
764
765impl Walker for PropertyBlock {
766 fn walk<V>(&self, visitor: &mut V)
767 where
768 V: AstVisitor,
769 {
770 for implementation in &self.implementations {
771 visitor.visit_data_type_declaration(&implementation.datatype);
772 for block in &implementation.variable_blocks {
773 visitor.visit_variable_block(block);
774 }
775 visitor.visit_statement_list(&implementation.body);
776 }
777 }
778}
779
780impl Walker for DataType {
781 fn walk<V>(&self, visitor: &mut V)
782 where
783 V: AstVisitor,
784 {
785 match self {
786 DataType::StructType { variables, .. } => {
787 for v in variables.iter() {
788 visitor.visit_variable(v);
789 }
790 }
791 DataType::EnumType { elements, .. } => {
792 for ele in flatten_expression_list(elements) {
793 visitor.visit_enum_element(ele);
794 }
795 }
796 DataType::SubRangeType { bounds, .. } => {
797 visit_all_nodes!(visitor, bounds);
798 }
799 DataType::ArrayType { bounds, referenced_type, .. } => {
800 visitor.visit(bounds);
801 visitor.visit_data_type_declaration(referenced_type);
802 }
803 DataType::PointerType { referenced_type, .. } => {
804 visitor.visit_data_type_declaration(referenced_type);
805 }
806 DataType::StringType { size, .. } => {
807 visit_all_nodes!(visitor, size);
808 }
809 DataType::VarArgs { referenced_type, .. } => {
810 if let Some(data_type_declaration) = referenced_type {
811 visitor.visit_data_type_declaration(data_type_declaration);
812 }
813 }
814 DataType::GenericType { .. } => {
815 //no further visits
816 }
817 }
818 }
819}
820
821impl Walker for DataTypeDeclaration {
822 fn walk<V>(&self, visitor: &mut V)
823 where
824 V: AstVisitor,
825 {
826 if let DataTypeDeclaration::Definition { data_type, .. } = self {
827 visitor.visit_data_type(data_type);
828 }
829 }
830}
831
832impl<T> Walker for Option<T>
833where
834 T: Walker,
835{
836 fn walk<V>(&self, visitor: &mut V)
837 where
838 V: AstVisitor,
839 {
840 if let Some(node) = self {
841 node.walk(visitor);
842 }
843 }
844}
845
846impl Walker for Pou {
847 fn walk<V>(&self, visitor: &mut V)
848 where
849 V: AstVisitor,
850 {
851 for block in &self.variable_blocks {
852 visitor.visit_variable_block(block);
853 }
854
855 for property in &self.properties {
856 visitor.visit_property(property);
857 }
858
859 self.return_type.as_ref().inspect(|rt| visitor.visit_data_type_declaration(rt));
860 }
861}
862
863impl Walker for Implementation {
864 fn walk<V>(&self, visitor: &mut V)
865 where
866 V: AstVisitor,
867 {
868 visitor.visit_statement_list(&self.statements);
869 }
870}