darklua_core/process/
visitors.rs

1use crate::nodes::*;
2use crate::process::NodeProcessor;
3
4use std::marker::PhantomData;
5
6/// A trait that defines method that iterates on nodes and process them using a NodeProcessor.
7pub trait NodeVisitor<T: NodeProcessor> {
8    fn visit_block(block: &mut Block, processor: &mut T) {
9        processor.process_block(block);
10
11        block
12            .iter_mut_statements()
13            .for_each(|statement| Self::visit_statement(statement, processor));
14
15        if let Some(last_statement) = block.mutate_last_statement() {
16            Self::visit_last_statement(last_statement, processor);
17        };
18    }
19
20    fn visit_statement(statement: &mut Statement, processor: &mut T) {
21        processor.process_statement(statement);
22
23        match statement {
24            Statement::Assign(statement) => Self::visit_assign_statement(statement, processor),
25            Statement::Do(statement) => Self::visit_do_statement(statement, processor),
26            Statement::Call(statement) => Self::visit_function_call(statement, processor),
27            Statement::CompoundAssign(statement) => {
28                Self::visit_compound_assign(statement, processor)
29            }
30            Statement::Function(statement) => Self::visit_function_statement(statement, processor),
31            Statement::GenericFor(statement) => Self::visit_generic_for(statement, processor),
32            Statement::If(statement) => Self::visit_if_statement(statement, processor),
33            Statement::LocalAssign(statement) => Self::visit_local_assign(statement, processor),
34            Statement::LocalFunction(statement) => Self::visit_local_function(statement, processor),
35            Statement::NumericFor(statement) => Self::visit_numeric_for(statement, processor),
36            Statement::Repeat(statement) => Self::visit_repeat_statement(statement, processor),
37            Statement::While(statement) => Self::visit_while_statement(statement, processor),
38            Statement::TypeDeclaration(statement) => {
39                Self::visit_type_declaration(statement, processor)
40            }
41        };
42    }
43
44    fn visit_last_statement(last_statement: &mut LastStatement, processor: &mut T) {
45        processor.process_last_statement(last_statement);
46
47        if let LastStatement::Return(expressions) = last_statement {
48            expressions
49                .iter_mut_expressions()
50                .for_each(|expression| Self::visit_expression(expression, processor));
51        };
52    }
53
54    fn visit_expression(expression: &mut Expression, processor: &mut T) {
55        processor.process_expression(expression);
56
57        match expression {
58            Expression::Binary(expression) => {
59                processor.process_binary_expression(expression);
60                Self::visit_expression(expression.mutate_left(), processor);
61                Self::visit_expression(expression.mutate_right(), processor);
62            }
63            Expression::Call(expression) => Self::visit_function_call(expression, processor),
64            Expression::Field(field) => Self::visit_field_expression(field, processor),
65            Expression::Function(function) => Self::visit_function_expression(function, processor),
66            Expression::Identifier(identifier) => processor.process_variable_expression(identifier),
67            Expression::If(if_expression) => Self::visit_if_expression(if_expression, processor),
68            Expression::Index(index) => Self::visit_index_expression(index, processor),
69            Expression::Number(number) => processor.process_number_expression(number),
70            Expression::Parenthese(expression) => {
71                processor.process_parenthese_expression(expression);
72                Self::visit_expression(expression.mutate_inner_expression(), processor)
73            }
74            Expression::String(string) => processor.process_string_expression(string),
75            Expression::InterpolatedString(interpolated_string) => {
76                processor.process_interpolated_string_expression(interpolated_string);
77
78                for segment in interpolated_string.iter_mut_segments() {
79                    match segment {
80                        InterpolationSegment::String(_) => {}
81                        InterpolationSegment::Value(value) => {
82                            Self::visit_expression(value.mutate_expression(), processor)
83                        }
84                    }
85                }
86            }
87            Expression::Table(table) => Self::visit_table(table, processor),
88            Expression::Unary(unary) => {
89                processor.process_unary_expression(unary);
90                Self::visit_expression(unary.mutate_expression(), processor);
91            }
92            Expression::TypeCast(type_cast) => {
93                processor.process_type_cast_expression(type_cast);
94
95                Self::visit_expression(type_cast.mutate_expression(), processor);
96                Self::visit_type(type_cast.mutate_type(), processor);
97            }
98            Expression::False(_)
99            | Expression::Nil(_)
100            | Expression::True(_)
101            | Expression::VariableArguments(_) => {}
102        }
103    }
104
105    fn visit_function_expression(function: &mut FunctionExpression, processor: &mut T) {
106        processor.process_function_expression(function);
107
108        processor.process_scope(function.mutate_block(), None);
109
110        Self::visit_block(function.mutate_block(), processor);
111
112        for r#type in function
113            .iter_mut_parameters()
114            .filter_map(TypedIdentifier::mutate_type)
115        {
116            Self::visit_type(r#type, processor);
117        }
118
119        if let Some(variadic_type) = function.mutate_variadic_type() {
120            Self::visit_function_variadic_type(variadic_type, processor);
121        }
122
123        if let Some(return_type) = function.mutate_return_type() {
124            Self::visit_function_return_type(return_type, processor);
125        }
126    }
127
128    fn visit_assign_statement(statement: &mut AssignStatement, processor: &mut T) {
129        processor.process_assign_statement(statement);
130
131        statement
132            .mutate_variables()
133            .iter_mut()
134            .for_each(|variable| Self::visit_variable(variable, processor));
135
136        statement
137            .iter_mut_values()
138            .for_each(|expression| Self::visit_expression(expression, processor));
139    }
140
141    fn visit_do_statement(statement: &mut DoStatement, processor: &mut T) {
142        processor.process_do_statement(statement);
143        processor.process_scope(statement.mutate_block(), None);
144        Self::visit_block(statement.mutate_block(), processor);
145    }
146
147    fn visit_compound_assign(statement: &mut CompoundAssignStatement, processor: &mut T) {
148        processor.process_compound_assign_statement(statement);
149        Self::visit_variable(statement.mutate_variable(), processor);
150        Self::visit_expression(statement.mutate_value(), processor);
151    }
152
153    fn visit_function_statement(statement: &mut FunctionStatement, processor: &mut T) {
154        processor.process_function_statement(statement);
155        processor.process_variable_expression(statement.mutate_function_name().mutate_identifier());
156
157        processor.process_scope(statement.mutate_block(), None);
158        Self::visit_block(statement.mutate_block(), processor);
159
160        for r#type in statement
161            .iter_mut_parameters()
162            .filter_map(TypedIdentifier::mutate_type)
163        {
164            Self::visit_type(r#type, processor);
165        }
166
167        if let Some(variadic_type) = statement.mutate_variadic_type() {
168            Self::visit_function_variadic_type(variadic_type, processor);
169        }
170
171        if let Some(return_type) = statement.mutate_return_type() {
172            Self::visit_function_return_type(return_type, processor);
173        }
174    }
175
176    fn visit_generic_for(statement: &mut GenericForStatement, processor: &mut T) {
177        processor.process_generic_for_statement(statement);
178
179        statement
180            .iter_mut_expressions()
181            .for_each(|expression| Self::visit_expression(expression, processor));
182
183        processor.process_scope(statement.mutate_block(), None);
184        Self::visit_block(statement.mutate_block(), processor);
185
186        for r#type in statement
187            .iter_mut_identifiers()
188            .filter_map(TypedIdentifier::mutate_type)
189        {
190            Self::visit_type(r#type, processor);
191        }
192    }
193
194    fn visit_if_statement(statement: &mut IfStatement, processor: &mut T) {
195        processor.process_if_statement(statement);
196
197        statement.mutate_branches().iter_mut().for_each(|branch| {
198            Self::visit_expression(branch.mutate_condition(), processor);
199            processor.process_scope(branch.mutate_block(), None);
200            Self::visit_block(branch.mutate_block(), processor);
201        });
202
203        if let Some(block) = statement.mutate_else_block() {
204            processor.process_scope(block, None);
205            Self::visit_block(block, processor);
206        }
207    }
208
209    fn visit_local_assign(statement: &mut LocalAssignStatement, processor: &mut T) {
210        processor.process_local_assign_statement(statement);
211
212        statement
213            .iter_mut_values()
214            .for_each(|value| Self::visit_expression(value, processor));
215
216        for r#type in statement
217            .iter_mut_variables()
218            .filter_map(TypedIdentifier::mutate_type)
219        {
220            Self::visit_type(r#type, processor);
221        }
222    }
223
224    fn visit_local_function(statement: &mut LocalFunctionStatement, processor: &mut T) {
225        processor.process_local_function_statement(statement);
226        processor.process_scope(statement.mutate_block(), None);
227        Self::visit_block(statement.mutate_block(), processor);
228
229        for r#type in statement
230            .iter_mut_parameters()
231            .filter_map(TypedIdentifier::mutate_type)
232        {
233            Self::visit_type(r#type, processor);
234        }
235
236        if let Some(variadic_type) = statement.mutate_variadic_type() {
237            Self::visit_function_variadic_type(variadic_type, processor);
238        }
239
240        if let Some(return_type) = statement.mutate_return_type() {
241            Self::visit_function_return_type(return_type, processor);
242        }
243    }
244
245    fn visit_function_variadic_type(variadic_type: &mut FunctionVariadicType, processor: &mut T) {
246        match variadic_type {
247            FunctionVariadicType::Type(r#type) => {
248                Self::visit_type(r#type, processor);
249            }
250            FunctionVariadicType::GenericTypePack(generic) => {
251                processor.process_generic_type_pack(generic);
252            }
253        }
254    }
255
256    fn visit_numeric_for(statement: &mut NumericForStatement, processor: &mut T) {
257        processor.process_numeric_for_statement(statement);
258
259        Self::visit_expression(statement.mutate_start(), processor);
260        Self::visit_expression(statement.mutate_end(), processor);
261
262        if let Some(step) = statement.mutate_step() {
263            Self::visit_expression(step, processor);
264        };
265
266        processor.process_scope(statement.mutate_block(), None);
267        Self::visit_block(statement.mutate_block(), processor);
268
269        if let Some(r#type) = statement.mutate_identifier().mutate_type() {
270            Self::visit_type(r#type, processor);
271        }
272    }
273
274    fn visit_repeat_statement(statement: &mut RepeatStatement, processor: &mut T) {
275        processor.process_repeat_statement(statement);
276
277        let (block, condition) = statement.mutate_block_and_condition();
278        processor.process_scope(block, Some(condition));
279
280        Self::visit_expression(statement.mutate_condition(), processor);
281        Self::visit_block(statement.mutate_block(), processor);
282    }
283
284    fn visit_while_statement(statement: &mut WhileStatement, processor: &mut T) {
285        processor.process_while_statement(statement);
286
287        Self::visit_expression(statement.mutate_condition(), processor);
288
289        processor.process_scope(statement.mutate_block(), None);
290        Self::visit_block(statement.mutate_block(), processor);
291    }
292
293    fn visit_type_declaration(statement: &mut TypeDeclarationStatement, processor: &mut T) {
294        processor.process_type_declaration(statement);
295
296        if let Some(generic_parameters) = statement.mutate_generic_parameters() {
297            for parameter in generic_parameters {
298                match parameter {
299                    GenericParameterMutRef::TypeVariable(_) => {}
300                    GenericParameterMutRef::TypeVariableWithDefault(type_variable) => {
301                        Self::visit_type(type_variable.mutate_default_type(), processor);
302                    }
303                    GenericParameterMutRef::GenericTypePack(generic_type_pack) => {
304                        processor.process_generic_type_pack(generic_type_pack);
305                    }
306                    GenericParameterMutRef::GenericTypePackWithDefault(
307                        generic_type_pack_with_default,
308                    ) => {
309                        processor.process_generic_type_pack(
310                            generic_type_pack_with_default.mutate_generic_type_pack(),
311                        );
312
313                        match generic_type_pack_with_default.mutate_default_type() {
314                            GenericTypePackDefault::TypePack(type_pack) => {
315                                Self::visit_type_pack(type_pack, processor);
316                            }
317                            GenericTypePackDefault::VariadicTypePack(variadic_type_pack) => {
318                                Self::visit_variadic_type_pack(variadic_type_pack, processor);
319                            }
320                            GenericTypePackDefault::GenericTypePack(generic_type_pack) => {
321                                processor.process_generic_type_pack(generic_type_pack);
322                            }
323                        }
324                    }
325                }
326            }
327        }
328
329        Self::visit_type(statement.mutate_type(), processor);
330    }
331
332    fn visit_variable(variable: &mut Variable, processor: &mut T) {
333        processor.process_variable(variable);
334
335        match variable {
336            Variable::Identifier(identifier) => processor.process_variable_expression(identifier),
337            Variable::Field(field) => Self::visit_field_expression(field, processor),
338            Variable::Index(index) => Self::visit_index_expression(index, processor),
339        }
340    }
341
342    fn visit_if_expression(if_expression: &mut IfExpression, processor: &mut T) {
343        processor.process_if_expression(if_expression);
344
345        Self::visit_expression(if_expression.mutate_condition(), processor);
346        Self::visit_expression(if_expression.mutate_result(), processor);
347
348        for branch in if_expression.iter_mut_branches() {
349            Self::visit_expression(branch.mutate_condition(), processor);
350            Self::visit_expression(branch.mutate_result(), processor);
351        }
352
353        Self::visit_expression(if_expression.mutate_else_result(), processor);
354    }
355
356    fn visit_field_expression(field: &mut FieldExpression, processor: &mut T) {
357        processor.process_field_expression(field);
358
359        Self::visit_prefix_expression(field.mutate_prefix(), processor);
360    }
361
362    fn visit_index_expression(index: &mut IndexExpression, processor: &mut T) {
363        processor.process_index_expression(index);
364
365        Self::visit_prefix_expression(index.mutate_prefix(), processor);
366        Self::visit_expression(index.mutate_index(), processor);
367    }
368
369    fn visit_function_call(call: &mut FunctionCall, processor: &mut T) {
370        processor.process_function_call(call);
371
372        Self::visit_prefix_expression(call.mutate_prefix(), processor);
373        Self::visit_arguments(call.mutate_arguments(), processor);
374    }
375
376    fn visit_arguments(arguments: &mut Arguments, processor: &mut T) {
377        match arguments {
378            Arguments::String(string) => processor.process_string_expression(string),
379            Arguments::Table(table) => Self::visit_table(table, processor),
380            Arguments::Tuple(expressions) => expressions
381                .iter_mut_values()
382                .for_each(|expression| Self::visit_expression(expression, processor)),
383        }
384    }
385
386    fn visit_table(table: &mut TableExpression, processor: &mut T) {
387        processor.process_table_expression(table);
388
389        table.iter_mut_entries().for_each(|entry| match entry {
390            TableEntry::Field(entry) => Self::visit_expression(entry.mutate_value(), processor),
391            TableEntry::Index(entry) => {
392                Self::visit_expression(entry.mutate_key(), processor);
393                Self::visit_expression(entry.mutate_value(), processor);
394            }
395            TableEntry::Value(value) => Self::visit_expression(value, processor),
396        });
397    }
398
399    fn visit_prefix_expression(prefix: &mut Prefix, processor: &mut T) {
400        processor.process_prefix_expression(prefix);
401
402        match prefix {
403            Prefix::Call(call) => Self::visit_function_call(call, processor),
404            Prefix::Field(field) => Self::visit_field_expression(field, processor),
405            Prefix::Identifier(identifier) => processor.process_variable_expression(identifier),
406            Prefix::Index(index) => Self::visit_index_expression(index, processor),
407            Prefix::Parenthese(expression) => {
408                processor.process_parenthese_expression(expression);
409                Self::visit_expression(expression.mutate_inner_expression(), processor)
410            }
411        };
412    }
413
414    fn visit_type(r#type: &mut Type, processor: &mut T) {
415        processor.process_type(r#type);
416
417        match r#type {
418            Type::Name(type_name) => Self::visit_type_name(type_name, processor),
419            Type::Field(type_field) => {
420                processor.process_type_field(type_field);
421
422                Self::visit_type_name(type_field.mutate_type_name(), processor);
423            }
424            Type::Array(array) => {
425                processor.process_array_type(array);
426
427                Self::visit_type(array.mutate_element_type(), processor);
428            }
429            Type::Table(table) => {
430                processor.process_table_type(table);
431
432                for entry in table.iter_mut_entries() {
433                    match entry {
434                        TableEntryType::Property(property) => {
435                            Self::visit_type(property.mutate_type(), processor);
436                        }
437                        TableEntryType::Literal(property) => {
438                            processor.process_string_type(property.mutate_string());
439                            Self::visit_type(property.mutate_type(), processor);
440                        }
441                        TableEntryType::Indexer(indexer) => {
442                            Self::visit_type(indexer.mutate_key_type(), processor);
443                            Self::visit_type(indexer.mutate_value_type(), processor);
444                        }
445                    }
446                }
447            }
448            Type::TypeOf(expression_type) => {
449                processor.process_expression_type(expression_type);
450
451                Self::visit_expression(expression_type.mutate_expression(), processor);
452            }
453            Type::Parenthese(parenthese) => {
454                processor.process_parenthese_type(parenthese);
455
456                Self::visit_type(parenthese.mutate_inner_type(), processor);
457            }
458            Type::Function(function) => {
459                processor.process_function_type(function);
460
461                for argument in function.iter_mut_arguments() {
462                    Self::visit_type(argument.mutate_type(), processor);
463                }
464
465                if let Some(variadic_type) = function.mutate_variadic_argument_type() {
466                    Self::visit_variadic_argument_type(variadic_type, processor);
467                }
468
469                Self::visit_function_return_type(function.mutate_return_type(), processor);
470            }
471            Type::Optional(optional) => {
472                processor.process_optional_type(optional);
473
474                Self::visit_type(optional.mutate_inner_type(), processor);
475            }
476            Type::Intersection(intersection) => {
477                processor.process_intersection_type(intersection);
478
479                for r#type in intersection.iter_mut_types() {
480                    Self::visit_type(r#type, processor);
481                }
482            }
483            Type::Union(union) => {
484                processor.process_union_type(union);
485
486                for r#type in union.iter_mut_types() {
487                    Self::visit_type(r#type, processor);
488                }
489            }
490            Type::String(string) => {
491                processor.process_string_type(string);
492            }
493            Type::True(_) | Type::False(_) | Type::Nil(_) => {}
494        }
495    }
496
497    fn visit_type_name(type_name: &mut TypeName, processor: &mut T) {
498        processor.process_type_name(type_name);
499
500        if let Some(type_parameters) = type_name.mutate_type_parameters() {
501            for type_parameter in type_parameters {
502                match type_parameter {
503                    TypeParameter::Type(next_type) => {
504                        Self::visit_type(next_type, processor);
505                    }
506                    TypeParameter::TypePack(type_pack) => {
507                        Self::visit_type_pack(type_pack, processor);
508                    }
509                    TypeParameter::VariadicTypePack(variadic_type_pack) => {
510                        Self::visit_variadic_type_pack(variadic_type_pack, processor);
511                    }
512                    TypeParameter::GenericTypePack(generic_type_pack) => {
513                        processor.process_generic_type_pack(generic_type_pack);
514                    }
515                }
516            }
517        }
518    }
519
520    fn visit_type_pack(type_pack: &mut TypePack, processor: &mut T) {
521        processor.process_type_pack(type_pack);
522
523        for next_type in type_pack.into_iter() {
524            Self::visit_type(next_type, processor)
525        }
526        if let Some(variadic_type) = type_pack.mutate_variadic_type() {
527            Self::visit_variadic_argument_type(variadic_type, processor);
528        }
529    }
530
531    fn visit_variadic_type_pack(variadic_type_pack: &mut VariadicTypePack, processor: &mut T) {
532        processor.process_variadic_type_pack(variadic_type_pack);
533        Self::visit_type(variadic_type_pack.mutate_type(), processor);
534    }
535
536    fn visit_variadic_argument_type(variadic_type: &mut VariadicArgumentType, processor: &mut T) {
537        match variadic_type {
538            VariadicArgumentType::VariadicTypePack(variadic_type_pack) => {
539                Self::visit_variadic_type_pack(variadic_type_pack, processor);
540            }
541            VariadicArgumentType::GenericTypePack(generic_type_pack) => {
542                processor.process_generic_type_pack(generic_type_pack);
543            }
544        }
545    }
546
547    fn visit_function_return_type(
548        function_return_type: &mut FunctionReturnType,
549        processor: &mut T,
550    ) {
551        match function_return_type {
552            FunctionReturnType::Type(next_type) => {
553                Self::visit_type(next_type, processor);
554            }
555            FunctionReturnType::TypePack(type_pack) => Self::visit_type_pack(type_pack, processor),
556            FunctionReturnType::VariadicTypePack(variadic_type_pack) => {
557                Self::visit_variadic_type_pack(variadic_type_pack, processor);
558            }
559            FunctionReturnType::GenericTypePack(generic_type_pack) => {
560                processor.process_generic_type_pack(generic_type_pack);
561            }
562        }
563    }
564}
565
566/// The default node visitor.
567pub struct DefaultVisitor<T> {
568    _phantom: PhantomData<T>,
569}
570
571impl<T: NodeProcessor> NodeVisitor<T> for DefaultVisitor<T> {}
572
573#[cfg(test)]
574mod test {
575    use super::*;
576    use crate::process::NodeCounter;
577
578    #[test]
579    fn visit_do_statement() {
580        let mut counter = NodeCounter::new();
581        let mut block = Block::default().with_statement(DoStatement::default());
582
583        DefaultVisitor::visit_block(&mut block, &mut counter);
584
585        assert_eq!(counter.block_count, 2);
586        assert_eq!(counter.do_count, 1);
587    }
588
589    #[test]
590    fn visit_numeric_for_statement() {
591        let mut counter = NodeCounter::new();
592        let mut block = Block::default().with_statement(NumericForStatement::new(
593            "i".to_owned(),
594            Expression::from(true),
595            Expression::from(true),
596            None,
597            Block::default(),
598        ));
599
600        DefaultVisitor::visit_block(&mut block, &mut counter);
601
602        assert_eq!(counter.block_count, 2);
603        assert_eq!(counter.expression_count, 2);
604        assert_eq!(counter.numeric_for_count, 1);
605    }
606
607    #[test]
608    fn visit_generic_for_statement() {
609        let mut counter = NodeCounter::new();
610        let mut block = Block::default().with_statement(GenericForStatement::new(
611            vec!["k".into()],
612            vec![Expression::from(true)],
613            Block::default(),
614        ));
615
616        DefaultVisitor::visit_block(&mut block, &mut counter);
617
618        assert_eq!(counter.block_count, 2);
619        assert_eq!(counter.expression_count, 1);
620        assert_eq!(counter.generic_for_count, 1);
621    }
622
623    #[test]
624    fn visit_repeat_statement() {
625        let mut counter = NodeCounter::new();
626        let mut block =
627            Block::default().with_statement(RepeatStatement::new(Block::default(), true));
628
629        DefaultVisitor::visit_block(&mut block, &mut counter);
630
631        assert_eq!(counter.block_count, 2);
632        assert_eq!(counter.expression_count, 1);
633        assert_eq!(counter.repeat_count, 1);
634    }
635
636    #[test]
637    fn visit_while_statement() {
638        let mut counter = NodeCounter::new();
639        let mut block =
640            Block::default().with_statement(WhileStatement::new(Block::default(), true));
641
642        DefaultVisitor::visit_block(&mut block, &mut counter);
643
644        assert_eq!(counter.block_count, 2);
645        assert_eq!(counter.expression_count, 1);
646        assert_eq!(counter.while_count, 1);
647    }
648
649    #[test]
650    fn visit_if_statement() {
651        let mut counter = NodeCounter::new();
652        let mut block =
653            Block::default().with_statement(IfStatement::create(true, Block::default()));
654
655        DefaultVisitor::visit_block(&mut block, &mut counter);
656
657        assert_eq!(counter.block_count, 2);
658        assert_eq!(counter.expression_count, 1);
659        assert_eq!(counter.if_count, 1);
660    }
661
662    #[test]
663    fn visit_if_statement_with_else() {
664        let mut counter = NodeCounter::new();
665        let if_statement =
666            IfStatement::create(true, Block::default()).with_else_block(Block::default());
667
668        let mut block = Block::default().with_statement(if_statement);
669
670        DefaultVisitor::visit_block(&mut block, &mut counter);
671
672        assert_eq!(counter.block_count, 3);
673        assert_eq!(counter.expression_count, 1);
674        assert_eq!(counter.if_count, 1);
675    }
676
677    #[test]
678    fn visit_if_statement_with_elseif_and_else() {
679        let mut counter = NodeCounter::new();
680        let if_statement = IfStatement::create(true, Block::default())
681            .with_new_branch(false, Block::default())
682            .with_else_block(Block::default());
683
684        let mut block = Block::default().with_statement(if_statement);
685
686        DefaultVisitor::visit_block(&mut block, &mut counter);
687
688        assert_eq!(counter.block_count, 4);
689        assert_eq!(counter.expression_count, 2);
690        assert_eq!(counter.if_count, 1);
691    }
692
693    #[test]
694    fn visit_compound_assign_statement() {
695        let mut counter = NodeCounter::new();
696        let statement =
697            CompoundAssignStatement::new(CompoundOperator::Plus, Variable::new("var"), 1_f64);
698
699        let mut block = statement.into();
700
701        DefaultVisitor::visit_block(&mut block, &mut counter);
702
703        assert_eq!(counter.compound_assign, 1);
704        assert_eq!(counter.expression_count, 1);
705        assert_eq!(counter.variable_count, 1);
706    }
707
708    #[test]
709    fn visit_interpolated_string() {
710        let mut counter = NodeCounter::new();
711        let statement = LocalAssignStatement::from_variable("value")
712            .with_value(InterpolatedStringExpression::empty().with_segment(Expression::from(true)));
713
714        let mut block = statement.into();
715
716        DefaultVisitor::visit_block(&mut block, &mut counter);
717
718        assert_eq!(counter.interpolated_string_count, 1);
719        assert_eq!(counter.expression_count, 2);
720    }
721}