shex_compact/
located_parse_error.rs1use crate::{shex_parser_error::ParseError as ShExParseError, Span};
2use nom::error::{ErrorKind, FromExternalError};
3use std::{
4 fmt::Debug,
5 num::{ParseFloatError, ParseIntError},
6};
7use thiserror::Error;
8
9#[derive(Debug, Error)]
11#[error("Parse error on line {}, column {}: {}\nat {}{}",
12 .line, .column,
13 .source,
14 .fragment,
15 format_parse_error_context(.context))]
16pub struct LocatedParseError {
17 #[source]
18 pub source: ShExParseError,
19 pub line: u32,
20 pub column: usize,
21 pub fragment: String,
22 pub context: Vec<LocatedParseError>,
23}
24
25impl LocatedParseError {
26 pub(crate) fn append(&mut self, other: LocatedParseError) {
28 self.context.push(other)
29 }
30}
31
32pub(crate) fn format_parse_error_context(context: &[LocatedParseError]) -> String {
33 let mut fragments = Vec::new();
34
35 for error in context {
36 let error_string = format!("{error}");
37 for line in error_string.split('\n') {
38 fragments.push(format!("{}{line}", " ".repeat(2)));
39 }
40 }
41
42 if fragments.is_empty() {
43 String::new()
44 } else {
45 format!("\nContext:\n{}", fragments.join("\n"))
46 }
47}
48
49impl nom::error::ParseError<Span<'_>> for LocatedParseError {
50 fn from_error_kind(input: Span, kind: ErrorKind) -> Self {
51 ShExParseError::SyntaxError(kind.description().to_string()).at(input)
52 }
53
54 fn append(input: Span, kind: ErrorKind, other: Self) -> Self {
55 let mut error = ShExParseError::SyntaxError(kind.description().to_string()).at(input);
56 error.append(other);
57 error
58 }
59}
60
61impl FromExternalError<Span<'_>, ParseIntError> for LocatedParseError {
62 fn from_external_error(input: Span, _kind: ErrorKind, e: ParseIntError) -> Self {
63 ShExParseError::ParseIntError {
64 str: input.fragment().to_string(),
65 err: e,
66 }
67 .at(input)
68 }
69}
70
71impl FromExternalError<Span<'_>, ParseFloatError> for LocatedParseError {
72 fn from_external_error(input: Span, _kind: ErrorKind, e: ParseFloatError) -> Self {
73 ShExParseError::ParseFloatError {
74 str: input.fragment().to_string(),
75 err: e,
76 }
77 .at(input)
78 }
79}