From 4e488d20a08b565fe4a4ec740c4e13ff705fdd9e Mon Sep 17 00:00:00 2001
From: Daniel Pfister <80419299+0x2a-42@users.noreply.github.com>
Date: Tue, 31 Dec 2024 14:59:48 +0100
Subject: [PATCH] Add warning for empty rule

---
 src/frontend/diag.rs | 9 +++++++++
 src/frontend/sema.rs | 7 +++++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/frontend/diag.rs b/src/frontend/diag.rs
index bc821f0..0bb46a0 100644
--- a/src/frontend/diag.rs
+++ b/src/frontend/diag.rs
@@ -34,6 +34,7 @@ pub const UNUSED_RULE: &str = "W001";
 pub const UNUSED_TOKEN: &str = "W002";
 pub const UNUSED_OPEN_NODE: &str = "W003";
 pub const REDUNDANT_ELISION: &str = "W004";
+pub const EMPTY_RULE: &str = "W005";
 
 pub trait LanguageErrors {
     fn invalid_binding_pos(span: &Span) -> Self;
@@ -67,6 +68,7 @@ pub trait LanguageErrors {
     fn redundant_elision(span: &Span) -> Self;
     fn expected_rule(span: &Span) -> Self;
     fn missing_node_name(span: &Span) -> Self;
+    fn empty_rule(span: &Span) -> Self;
 }
 
 impl LanguageErrors for Diagnostic {
@@ -359,4 +361,11 @@ impl LanguageErrors for Diagnostic {
             .with_message("missing node name")
             .with_labels(vec![Label::primary((), span.clone())])
     }
+
+    fn empty_rule(span: &Span) -> Self {
+        Diagnostic::warning()
+            .with_code(EMPTY_RULE)
+            .with_message("empty rule")
+            .with_labels(vec![Label::primary((), span.clone())])
+    }
 }
diff --git a/src/frontend/sema.rs b/src/frontend/sema.rs
index 0c9b4c0..bbd6981 100644
--- a/src/frontend/sema.rs
+++ b/src/frontend/sema.rs
@@ -258,8 +258,11 @@ impl<'a> GeneralCheck<'a> {
         diags: &mut Vec<Diagnostic>,
         sema: &mut SemanticData<'a>,
     ) {
-        rule.regex(cst)
-            .map(|regex| self.check_regex(cst, rule, regex, diags, sema, false, false));
+        if let Some(regex) = rule.regex(cst) {
+            self.check_regex(cst, rule, regex, diags, sema, false, false);
+        } else {
+            diags.push(Diagnostic::empty_rule(&rule.span(cst)));
+        }
         self.check_recursive(cst, sema, rule, diags);
         if let Some(regex) = rule.regex(cst) {
             let mut open = HashSet::new();