Skip to content

Commit 3e7d5d8

Browse files
committed
Test removal of redundant errors
1 parent 4ca1b73 commit 3e7d5d8

File tree

1 file changed

+52
-12
lines changed

1 file changed

+52
-12
lines changed

src/parsing/parser.rs

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ pub fn parse_with_recovery<'i>(
2020
input.parse_collecting_errors()
2121
}
2222

23-
// Most general errors first, most specific last (for deduplication, we prefer
24-
// being able to give a more specific error message to the user)
23+
// Most general errors first, most specific last (when removing redundant
24+
// errors, we prefer being able to give a more specific error message to the
25+
// user)
2526
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
2627
pub enum ParsingError {
2728
// lowest priority
@@ -54,7 +55,7 @@ pub enum ParsingError {
5455
InvalidQuantityUncertainty(usize),
5556
InvalidQuantityMagnitude(usize),
5657
InvalidQuantitySymbol(usize),
57-
// highest priority when deduplicating
58+
// highest priority
5859
UnclosedInterpolation(usize),
5960
}
6061

@@ -94,11 +95,11 @@ impl ParsingError {
9495
}
9596
}
9697

97-
/// Deduplicate errors, preferring more specific errors over generic ones at the same offset.
98+
/// Remove redundant errors, keeping only the most specific error at each offset.
9899
/// When multiple errors occur at the same offset, keep only the most specific one.
99100
/// Since ParsingError derives Ord with general errors first and specific errors last,
100101
/// we use > to prefer the higher Ord value (more specific) errors.
101-
fn deduplicate_errors(errors: Vec<ParsingError>) -> Vec<ParsingError> {
102+
fn remove_redundant_errors(errors: Vec<ParsingError>) -> Vec<ParsingError> {
102103
let mut deduped = Vec::new();
103104

104105
for error in errors {
@@ -109,11 +110,11 @@ fn deduplicate_errors(errors: Vec<ParsingError>) -> Vec<ParsingError> {
109110
.iter()
110111
.position(|e: &ParsingError| e.offset() == error_offset)
111112
{
112-
// Keep the more specific error (higher Ord value, since specific errors come last)
113+
// Keep the more specific error
113114
if error > deduped[existing_idx] {
114115
deduped[existing_idx] = error;
115116
}
116-
// Otherwise, keep the existing more specific error
117+
// Otherwise, keep the existing error
117118
} else {
118119
// No error at this offset yet, add it
119120
deduped.push(error);
@@ -318,13 +319,12 @@ impl<'i> Parser<'i> {
318319
let document = Document { header, body };
319320
let errors = std::mem::take(&mut self.problems);
320321

321-
// Deduplicate errors, preferring more specific errors over generic
322-
// ones at the same offset
323-
let errors = deduplicate_errors(errors);
324-
325322
if errors.is_empty() {
326323
Ok(document)
327324
} else {
325+
// Remove redundant errors, keeping only the most specific error
326+
// at each offset
327+
let errors = remove_redundant_errors(errors);
328328
Err(errors)
329329
}
330330
}
@@ -4829,7 +4829,47 @@ broken_proc2 : -> B
48294829
}
48304830

48314831
#[test]
4832-
fn test_error_deduplication_unclosed_interpolation() {
4832+
fn test_redundant_error_removal_needed() {
4833+
use std::path::Path;
4834+
4835+
// Create a malformed procedure that could generate multiple errors at the same offset
4836+
let content = r#"
4837+
% technique v1
4838+
4839+
broken :
4840+
This is not a valid signature line
4841+
4842+
1. Step one
4843+
"#;
4844+
4845+
let result = parse_with_recovery(Path::new("test.tq"), content);
4846+
4847+
// Check that we get an error about the invalid signature
4848+
match result {
4849+
Err(errors) => {
4850+
// Debug: print what errors we actually get
4851+
eprintln!("Errors: {:?}", errors);
4852+
4853+
// Verify no redundant errors at the same offset
4854+
let mut offsets = errors
4855+
.iter()
4856+
.map(|e| e.offset())
4857+
.collect::<Vec<_>>();
4858+
offsets.sort();
4859+
let original_len = offsets.len();
4860+
offsets.dedup();
4861+
assert_eq!(
4862+
offsets.len(),
4863+
original_len,
4864+
"Found redundant errors at same offset"
4865+
);
4866+
}
4867+
Ok(_) => panic!("Expected errors for malformed content"),
4868+
}
4869+
}
4870+
4871+
#[test]
4872+
fn test_redundant_error_removal_unclosed_interpolation() {
48334873
let mut input = Parser::new();
48344874

48354875
// Test that UnclosedInterpolation error takes precedence over generic

0 commit comments

Comments
 (0)