1use serde::{de, ser};
2use std::fmt::Display;
3
4pub type Result<T> = std::result::Result<T, Error>;
5
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct LineColumn {
8 pub line: usize,
9 pub column: usize,
10}
11
12impl LineColumn {
13 pub fn from_pos(s: &str, pos: usize) -> Self {
14 let mut line = 1usize;
15 let mut col = 1usize;
16 let bytes = s.as_bytes();
17 let mut i = 0usize;
18 while i < pos && i < bytes.len() {
19 if bytes[i] == b'\n' {
20 line += 1;
21 col = 1;
22 } else {
23 col += 1;
24 }
25 i += 1;
26 }
27 LineColumn { line, column: col }
28 }
29}
30
31#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
32pub enum Error {
33 #[error("Unexpected character '{ch}' at line {}, column {}", .lc.line, .lc.column)]
34 UnexpectedChar { ch: char, lc: LineColumn },
35 #[error("Unterminated string at line {}, column {}", .lc.line, .lc.column)]
36 UnclosedString { lc: LineColumn },
37 #[error("Unterminated data block at line {}, column {}", .lc.line, .lc.column)]
38 UnclosedData { lc: LineColumn },
39 #[error("Data block did not contain valid paired hex digits")]
41 BadDataInternal,
42 #[error("Unknown escape code")]
43 UnknownEscapeInternal,
44 #[error("Invalid unicode escape sequence: '{seq}'")]
45 InvalidUnicodeEscapeInternal { seq: String },
46 #[error("Expected string, found '{token_name}'")]
47 NotAStringInternal { token_name: &'static str },
48 #[error("Data block did not contain valid paired hex digits at line {}, column {}", .lc.line, .lc.column)]
49 BadData { lc: LineColumn },
50 #[error("Unknown escape code at line {}, column {}", .lc.line, .lc.column)]
51 UnknownEscape { lc: LineColumn },
52 #[error("Invalid unicode escape sequence: '{seq}' at line {}, column {}", .lc.line, .lc.column)]
53 InvalidUnicodeEscape { seq: String, lc: LineColumn },
54 #[error("Expected string, found '{token_name}' at line {}, column {}", .lc.line, .lc.column)]
55 NotAString {
56 token_name: &'static str,
57 lc: LineColumn,
58 },
59 #[error("Missing '=' at line {}, column {}", .lc.line, .lc.column)]
60 ExpectedEquals { lc: LineColumn },
61 #[error("Missing ',' at line {}, column {}", .lc.line, .lc.column)]
62 ExpectedComma { lc: LineColumn },
63 #[error("Missing ';' at line {}, column {}", .lc.line, .lc.column)]
64 ExpectedSemicolon { lc: LineColumn },
65 #[error("Missing '{{' at line {}, column {}", .lc.line, .lc.column)]
66 ExpectedOpenBrace { lc: LineColumn },
67 #[error("Missing '}}' at line {}, column {}", .lc.line, .lc.column)]
68 ExpectedCloseBrace { lc: LineColumn },
69 #[error("Missing '(' at line {}, column {}", .lc.line, .lc.column)]
70 ExpectedOpenParen { lc: LineColumn },
71 #[error("Missing ')' at line {}, column {}", .lc.line, .lc.column)]
72 ExpectedCloseParen { lc: LineColumn },
73 #[error("Expected character '{ch}' at line {}, column {}", .lc.line, .lc.column)]
74 ExpectedChar { ch: char, lc: LineColumn },
75 #[error("Expected numeric value at line {}, column {}", .lc.line, .lc.column)]
76 ExpectedNumber { lc: LineColumn },
77 #[error("Expected string value at line {}, column {}", .lc.line, .lc.column)]
78 ExpectedString { lc: LineColumn },
79 #[error("Expected '{expected}', found '{found}'")]
80 UnexpectedDataType {
81 expected: &'static str,
82 found: &'static str,
83 },
84 #[error("Unexpected token '{name}' at line {}, column {}", .lc.line, .lc.column)]
85 UnexpectedToken { name: &'static str, lc: LineColumn },
86 #[error("parsing failed: '{0}'")]
87 Parse(String),
88 #[error("serializing failed: '{0}'")]
89 Serialize(String),
90}
91
92impl ser::Error for Error {
93 fn custom<T: Display>(msg: T) -> Self {
94 Error::Serialize(msg.to_string())
95 }
96}
97
98impl de::Error for Error {
99 fn custom<T: Display>(msg: T) -> Self {
100 Error::Parse(msg.to_string())
101 }
102}
103
104impl Error {
105 pub fn at(self, s: &str, pos: usize) -> Self {
106 let lc = LineColumn::from_pos(s, pos);
107 match self {
108 Error::BadDataInternal => Error::BadData { lc },
109 Error::UnknownEscapeInternal => Error::UnknownEscape { lc },
110 Error::InvalidUnicodeEscapeInternal { seq } => Error::InvalidUnicodeEscape { seq, lc },
111 Error::NotAStringInternal { token_name } => Error::NotAString { token_name, lc },
112 other => other,
113 }
114 }
115}