plotnik_compiler/analyze/validation/
empty_constructs.rs1use crate::SourceId;
6use crate::analyze::visitor::{Visitor, walk_alt_expr, walk_named_node, walk_seq_expr};
7use crate::diagnostics::{DiagnosticKind, Diagnostics};
8use crate::parser::{AltExpr, NamedNode, Root, SeqExpr};
9
10pub fn validate_empty_constructs(source_id: SourceId, ast: &Root, diag: &mut Diagnostics) {
11 let mut visitor = EmptyConstructsValidator { diag, source_id };
12 visitor.visit(ast);
13}
14
15struct EmptyConstructsValidator<'a> {
16 diag: &'a mut Diagnostics,
17 source_id: SourceId,
18}
19
20impl Visitor for EmptyConstructsValidator<'_> {
21 fn visit_named_node(&mut self, node: &NamedNode) {
22 if node.as_cst().children().next().is_none() && node.node_type().is_none() {
25 self.diag
26 .report(self.source_id, DiagnosticKind::EmptyTree, node.text_range())
27 .emit();
28 }
29 walk_named_node(self, node);
30 }
31
32 fn visit_seq_expr(&mut self, seq: &SeqExpr) {
33 if seq.children().next().is_none() {
34 self.diag
35 .report(
36 self.source_id,
37 DiagnosticKind::EmptySequence,
38 seq.text_range(),
39 )
40 .emit();
41 }
42 walk_seq_expr(self, seq);
43 }
44
45 fn visit_alt_expr(&mut self, alt: &AltExpr) {
46 if alt.branches().next().is_none() {
47 self.diag
48 .report(
49 self.source_id,
50 DiagnosticKind::EmptyAlternation,
51 alt.text_range(),
52 )
53 .emit();
54 }
55 walk_alt_expr(self, alt);
56 }
57}