| 1 | use proc_macro2::Span; |
| 2 | |
| 3 | use std::{ |
| 4 | fmt::{self, Display}, |
| 5 | ops::Range, |
| 6 | }; |
| 7 | |
| 8 | #[derive (Debug, PartialEq)] |
| 9 | pub(crate) struct ParseError { |
| 10 | pub(crate) pos: usize, |
| 11 | pub(crate) kind: ParseErrorKind, |
| 12 | } |
| 13 | |
| 14 | #[derive (Debug, PartialEq)] |
| 15 | pub(crate) enum ParseErrorKind { |
| 16 | /// A `{` that wasn't closed. |
| 17 | UnclosedArg, |
| 18 | /// A `}` that doesn't close an argument. |
| 19 | InvalidClosedArg, |
| 20 | /// When parsing the number of a positional arguments |
| 21 | NotANumber { |
| 22 | what: String, |
| 23 | }, |
| 24 | /// When parsing the identifier of a named argument |
| 25 | NotAnIdent { |
| 26 | what: String, |
| 27 | }, |
| 28 | UnknownFormatting { |
| 29 | what: String, |
| 30 | }, |
| 31 | } |
| 32 | |
| 33 | #[allow (dead_code)] |
| 34 | impl ParseErrorKind { |
| 35 | pub fn not_a_number(what: &str) -> Self { |
| 36 | Self::NotANumber { |
| 37 | what: what.to_string(), |
| 38 | } |
| 39 | } |
| 40 | pub fn not_an_ident(what: &str) -> Self { |
| 41 | Self::NotAnIdent { |
| 42 | what: what.to_string(), |
| 43 | } |
| 44 | } |
| 45 | pub fn unknown_formatting(what: &str) -> Self { |
| 46 | Self::UnknownFormatting { |
| 47 | what: what.to_string(), |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | //////////////////////////////////////////////////////////////////////////////// |
| 53 | |
| 54 | #[derive (Debug, PartialEq)] |
| 55 | pub(crate) struct DisplayParseError<'a> { |
| 56 | pub(crate) str: &'a str, |
| 57 | pub(crate) error_span: Range<usize>, |
| 58 | pub(crate) kind: ParseErrorKind, |
| 59 | } |
| 60 | impl ParseError { |
| 61 | fn error_span(&self) -> Range<usize> { |
| 62 | let len: usize = match &self.kind { |
| 63 | ParseErrorKind::UnclosedArg => 0, |
| 64 | ParseErrorKind::InvalidClosedArg => 0, |
| 65 | ParseErrorKind::NotANumber { what: &String } => what.len(), |
| 66 | ParseErrorKind::NotAnIdent { what: &String } => what.len(), |
| 67 | ParseErrorKind::UnknownFormatting { what: &String } => what.len(), |
| 68 | }; |
| 69 | |
| 70 | self.pos..self.pos + len |
| 71 | } |
| 72 | |
| 73 | pub(crate) fn into_crate_err(self, span: Span, original_str: &str) -> crate::Error { |
| 74 | let display: DisplayParseError<'_> = DisplayParseError { |
| 75 | str: original_str, |
| 76 | error_span: self.error_span(), |
| 77 | kind: self.kind, |
| 78 | }; |
| 79 | |
| 80 | crate::Error::new(span, msg:display) |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | impl Display for ParseErrorKind { |
| 85 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 86 | match self { |
| 87 | ParseErrorKind::UnclosedArg => f.write_str(data:"unclosed argument" ), |
| 88 | ParseErrorKind::InvalidClosedArg => f.write_str(data:"`}` closing a nonexistent argument" ), |
| 89 | ParseErrorKind::NotANumber { what: &String } => writeln!(f, "not a number: \"{}\"" , what), |
| 90 | ParseErrorKind::NotAnIdent { what: &String } => { |
| 91 | writeln!(f, "not a valid identifier: \"{}\"" , what) |
| 92 | } |
| 93 | ParseErrorKind::UnknownFormatting { what: &String } => { |
| 94 | writeln!(f, "unknown formatting: \"{}\"" , what) |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | impl Display for DisplayParseError<'_> { |
| 101 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 102 | f.write_str(data:"failed to parse the format string " )?; |
| 103 | |
| 104 | // Gets the amount of chars up to the error, |
| 105 | // this is good enough for most cases, |
| 106 | // but doesn't acount for multi-char characters. |
| 107 | let chars: usize = self.str[..self.error_span.start].chars().count(); |
| 108 | writeln!(f, "at the character number {}, " , chars)?; |
| 109 | |
| 110 | Display::fmt(&self.kind, f)?; |
| 111 | |
| 112 | Ok(()) |
| 113 | } |
| 114 | } |
| 115 | |