Skip to content

Commit c3588b9

Browse files
authored
Collect and display all detected errors in an input document (#76)
Until now we have just exited on detecting the first parsing or validation error, but the forthcoming language server will need to know where all the problems are. So the next step in maturing the parser is collecting more than a single error at a time when checking the validity of a document. The Parser state object is updated to include a Vec<ParsingError> that the parser (and subparsers) can contribute to. Finally, when reporting errors we deduplicate, with more specific messages overriding enclosing general ones. This is an admittedly rare occurrence, as usually fail-fast short-circuiting will cause a single error to propagate, but in the event nesting results in multiple errors at the same site we trim it down to a single message.
2 parents f8083ec + 3e7d5d8 commit c3588b9

File tree

10 files changed

+847
-299
lines changed

10 files changed

+847
-299
lines changed

Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "technique"
3-
version = "0.4.0"
3+
version = "0.4.1"
44
edition = "2021"
55
description = "A domain specific language for procedures."
66
authors = [ "Andrew Cowie" ]

src/main.rs

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,26 @@ fn main() {
160160
std::process::exit(1);
161161
}
162162
};
163+
163164
let technique = match parsing::parse(&filename, &content) {
164165
Ok(document) => document,
165-
Err(error) => {
166-
eprintln!(
167-
"{}",
168-
problem::full_parsing_error(&error, &filename, &content, &Terminal)
169-
);
166+
Err(errors) => {
167+
for (i, error) in errors
168+
.iter()
169+
.enumerate()
170+
{
171+
if i > 0 {
172+
eprintln!();
173+
}
174+
eprintln!(
175+
"{}",
176+
problem::full_parsing_error(&error, &filename, &content, &Terminal)
177+
);
178+
}
170179
std::process::exit(1);
171180
}
172181
};
182+
173183
// TODO continue with validation of the returned technique
174184

175185
eprintln!("{}", "ok".bright_green());
@@ -205,12 +215,26 @@ fn main() {
205215
std::process::exit(1);
206216
}
207217
};
218+
208219
let technique = match parsing::parse(&filename, &content) {
209220
Ok(document) => document,
210-
Err(error) => {
221+
Err(errors) => {
222+
for (i, error) in errors
223+
.iter()
224+
.enumerate()
225+
{
226+
if i > 0 {
227+
eprintln!();
228+
}
229+
eprintln!(
230+
"{}",
231+
problem::concise_parsing_error(&error, &filename, &content, &Terminal)
232+
);
233+
}
234+
211235
eprintln!(
212-
"{}",
213-
problem::concise_parsing_error(&error, &filename, &content, &Terminal)
236+
"\nUnable to parse input file. Try `technique check {}` for details.",
237+
&filename.to_string_lossy()
214238
);
215239
std::process::exit(1);
216240
}
@@ -251,16 +275,27 @@ fn main() {
251275
std::process::exit(1);
252276
}
253277
};
278+
254279
let technique = match parsing::parse(&filename, &content) {
255280
Ok(document) => document,
256-
Err(error) => {
281+
Err(errors) => {
257282
// It is possible that we will want to render the error
258283
// into the PDF document rather than crashing here. We'll
259284
// see in the future.
260-
eprintln!(
261-
"{}",
262-
problem::full_parsing_error(&error, &filename, &content, &Terminal)
263-
);
285+
286+
for (i, error) in errors
287+
.iter()
288+
.enumerate()
289+
{
290+
if i > 0 {
291+
eprintln!();
292+
}
293+
294+
eprintln!(
295+
"{}",
296+
problem::concise_parsing_error(&error, &filename, &content, &Terminal)
297+
);
298+
}
264299
std::process::exit(1);
265300
}
266301
};

src/parsing/mod.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ pub fn load(filename: &Path) -> Result<String, LoadingError<'_>> {
3535
}
3636
}
3737

38-
/// Parse text into a Technique object, or error out.
39-
pub fn parse<'i>(filename: &'i Path, content: &'i str) -> Result<Document<'i>, ParsingError<'i>> {
40-
let result = parser::parse_via_taking(filename, content);
38+
/// Parse text into a Document object, or return the list of errors
39+
/// encountered.
40+
pub fn parse<'i>(filename: &'i Path, content: &'i str) -> Result<Document<'i>, Vec<ParsingError>> {
41+
let result = parser::parse_with_recovery(filename, content);
4142

4243
match result {
4344
Ok(document) => {
@@ -66,9 +67,9 @@ pub fn parse<'i>(filename: &'i Path, content: &'i str) -> Result<Document<'i>, P
6667
}
6768
Ok(document)
6869
}
69-
Err(error) => {
70-
debug!("error: {:?}", error);
71-
Err(error)
70+
Err(errors) => {
71+
debug!("errors: {}", errors.len());
72+
Err(errors)
7273
}
7374
}
7475
}

0 commit comments

Comments
 (0)