nff: LexError should include position for InvalidNumber; update diagnostics

This commit is contained in:
raf 2025-06-02 11:26:32 +03:00
commit c0002f5806
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
2 changed files with 49 additions and 24 deletions

View file

@ -453,7 +453,7 @@ impl AnalyzerModule for LexicalAnalyzer {
}
impl LexicalAnalyzer {
fn lex_error_to_diagnostic(error: &LexError, source: &str) -> Diagnostic {
pub fn lex_error_to_diagnostic(error: &LexError, source: &str) -> Diagnostic {
match error {
LexError::InvalidToken { position, text } => {
let pos = Position::from_text_size(TextSize::from(*position as u32), source);
@ -478,27 +478,17 @@ impl LexicalAnalyzer {
"Unterminated string literal".to_string(),
)
}
LexError::InvalidNumber { text } => {
if let Some(pos) = source.find(text) {
let start_pos = Position::from_text_size(TextSize::from(pos as u32), source);
let end_pos =
Position::new(start_pos.line, start_pos.character + text.len() as u32);
let range = Range::new(start_pos, end_pos);
Diagnostic::new(
range,
DiagnosticSeverity::Error,
DiagnosticCode::InvalidNumber,
format!("Invalid number: '{}'", text),
)
} else {
let range = Range::single_position(Position::new(0, 0));
Diagnostic::new(
range,
DiagnosticSeverity::Error,
DiagnosticCode::InvalidNumber,
format!("Invalid number: '{}'", text),
)
}
LexError::InvalidNumber { position, text } => {
let start_pos = Position::from_text_size(TextSize::from(*position as u32), source);
let end_pos =
Position::new(start_pos.line, start_pos.character + text.len() as u32);
let range = Range::new(start_pos, end_pos);
Diagnostic::new(
range,
DiagnosticSeverity::Error,
DiagnosticCode::InvalidNumber,
format!("Invalid number: '{}'", text),
)
}
}
}

View file

@ -10,8 +10,8 @@ pub enum LexError {
InvalidToken { position: usize, text: String },
#[error("Unterminated string literal starting at position {position}")]
UnterminatedString { position: usize },
#[error("Invalid numeric literal: {text}")]
InvalidNumber { text: String },
#[error("Invalid numeric literal at position {position}: {text}")]
InvalidNumber { position: usize, text: String },
}
/// Result type for lexical analysis
@ -356,6 +356,7 @@ impl<'a> NftablesLexer<'a> {
.any(|c| !c.is_ascii_digit() && c != '.' && c != 'x' && c != 'X')
{
return Err(LexError::InvalidNumber {
position: span.start,
text: text.to_owned(),
});
} else {
@ -448,4 +449,38 @@ mod tests {
panic!("Expected InvalidToken error");
}
}
#[test]
fn test_invalid_number_with_position() {
// Test that we can create a proper diagnostic with position information
use crate::diagnostic::LexicalAnalyzer;
// Create a source with the same invalid pattern at different positions
let source = "123abc normal 123abc end";
// Since normal tokenization splits "123abc" into "123" + "abc",
// let's test the diagnostic creation directly with a mock error
let error1 = LexError::InvalidNumber {
position: 0,
text: "123abc".to_string(),
};
let error2 = LexError::InvalidNumber {
position: 14,
text: "123abc".to_string(),
};
// Test that diagnostics are created with correct positions
let diagnostic1 = LexicalAnalyzer::lex_error_to_diagnostic(&error1, source);
let diagnostic2 = LexicalAnalyzer::lex_error_to_diagnostic(&error2, source);
// First occurrence should be at position 0
assert_eq!(diagnostic1.range.start.line, 0);
assert_eq!(diagnostic1.range.start.character, 0);
assert_eq!(diagnostic1.message, "Invalid number: '123abc'");
// Second occurrence should be at position 14 (not 0)
assert_eq!(diagnostic2.range.start.line, 0);
assert_eq!(diagnostic2.range.start.character, 14);
assert_eq!(diagnostic2.message, "Invalid number: '123abc'");
}
}