From 2e84d74b095c7cf0c493a250d765993309558bb8 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 +++++-- tests/frontend.rs | 13 +++++++++++++ 3 files changed, 27 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, 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(); diff --git a/tests/frontend.rs b/tests/frontend.rs index 1ce5c1a..2c359f4 100644 --- a/tests/frontend.rs +++ b/tests/frontend.rs @@ -167,6 +167,7 @@ fn lowercase_token() { assert_eq!(lines.next().unwrap(), "tests/frontend/lowercase_token.llw:1:7: error[E007]: token name starts with lower case letter"); assert_eq!(lines.next().unwrap(), "tests/frontend/lowercase_token.llw:1:9: error[E007]: token name starts with lower case letter"); + assert_eq!(lines.next().unwrap(), "tests/frontend/lowercase_token.llw:4:1: warning[W005]: empty rule"); assert_eq!(lines.next(), None); } @@ -239,6 +240,10 @@ fn redefinition() { assert_eq!(lines.next().unwrap(), "tests/frontend/redefinition.llw:14:1: error[E005]: redefinition of rule"); assert_eq!(lines.next().unwrap(), "tests/frontend/redefinition.llw:1:9: error[E005]: redefinition of token"); assert_eq!(lines.next().unwrap(), "tests/frontend/redefinition.llw:1:13: error[E005]: redefinition of token"); + assert_eq!(lines.next().unwrap(), "tests/frontend/redefinition.llw:6:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/redefinition.llw:9:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/redefinition.llw:12:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/redefinition.llw:14:1: warning[W005]: empty rule"); assert_eq!(lines.next().unwrap(), "error[E008]: missing start rule"); assert_eq!(lines.next(), None); } @@ -309,6 +314,9 @@ fn unused_element() { let diags = gen_diags("tests/frontend/unused_element.llw"); let mut lines = diags.lines(); + assert_eq!(lines.next().unwrap(), "tests/frontend/unused_element.llw:13:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/unused_element.llw:20:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/unused_element.llw:23:1: warning[W005]: empty rule"); assert_eq!(lines.next().unwrap(), "tests/frontend/unused_element.llw:9:1: warning[W001]: unused rule"); assert_eq!(lines.next().unwrap(), "tests/frontend/unused_element.llw:13:1: warning[W001]: unused rule"); assert_eq!(lines.next().unwrap(), "tests/frontend/unused_element.llw:23:1: warning[W001]: unused rule"); @@ -335,5 +343,10 @@ fn uppercase_rule() { assert_eq!(lines.next().unwrap(), "tests/frontend/uppercase_rule.llw:6:1: error[E006]: rule name starts with upper case letter"); assert_eq!(lines.next().unwrap(), "tests/frontend/uppercase_rule.llw:9:1: error[E006]: rule name starts with upper case letter"); + assert_eq!(lines.next().unwrap(), "tests/frontend/uppercase_rule.llw:3:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/uppercase_rule.llw:6:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/uppercase_rule.llw:9:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/uppercase_rule.llw:12:1: warning[W005]: empty rule"); + assert_eq!(lines.next().unwrap(), "tests/frontend/uppercase_rule.llw:15:1: warning[W005]: empty rule"); assert_eq!(lines.next(), None); }