1#![allow(unused_assignments)]
4
5use camino::{
6 Utf8Path,
7 Utf8PathBuf,
8};
9use miette::{
10 NamedSource,
11 SourceOffset,
12 SourceSpan,
13};
14use roxmltree::{
15 TextPos,
16};
17
18#[derive(Debug)]
19#[derive(miette::Diagnostic)]
20#[derive(thiserror::Error)]
21pub enum ParseErrors<E>
22where
23 E: std::fmt::Debug + miette::Diagnostic,
24{
25 #[error("Could not open '{path}'")]
26 Open {
27 path: Utf8PathBuf,
28
29 #[source]
30 error: std::io::Error,
31 },
32 #[error("Could not parse XML")]
33 Xml {
34 #[source_code]
35 src: NamedSource<String>,
36
37 #[diagnostic_source]
38 error: XmlError,
39 },
40 #[error("Could not parse")]
41 Parse {
42 #[source_code]
43 src: NamedSource<String>,
44
45 #[related]
46 errors: Vec<E>,
47 },
48}
49
50impl<E> ParseErrors<E>
51where
52 E: miette::Diagnostic,
53{
54 pub (crate) fn open(error: std::io::Error, path: &Utf8Path) -> Self {
55 ParseErrors::Open {
56 path: path.into(),
57 error,
58 }
59 }
60
61 pub (crate) fn xml(error: roxmltree::Error, path: &Utf8Path, source: String) -> Self {
62 let error = XmlError::from(error, &source);
63
64 ParseErrors::Xml {
65 src: NamedSource::new(path, source),
66 error,
67 }
68 }
69
70 pub (crate) fn parse(path: &Utf8Path, source: String, errors: Vec<E>) -> Self {
71 ParseErrors::Parse {
72 src: NamedSource::new(path, source),
73
74 errors,
75 }
76 }
77}
78
79#[derive(Debug)]
80#[derive(miette::Diagnostic)]
81#[derive(thiserror::Error)]
82pub enum XmlError {
83 #[error("Duplicate attribute")]
84 DuplicatedAttribute {
85 #[label]
86 span: SourceSpan,
87 },
88 #[error("Unexpected close tag")]
89 UnexpectedCloseTag {
90 #[label("expected </{expected}>")]
91 span: SourceSpan,
92
93 expected: String,
94 },
95 #[error("{0}")]
96 Other(String),
97}
98
99impl XmlError {
100 fn from(error: roxmltree::Error, source: &str) -> Self {
101 match error {
102 roxmltree::Error::DuplicatedAttribute(_name, position) =>
103 XmlError::DuplicatedAttribute {
104 span: from_text_pos(position, source),
105 },
106
107 roxmltree::Error::UnexpectedCloseTag(expected, _actual, position) =>
108 XmlError::UnexpectedCloseTag {
109 span: from_text_pos(position, source),
110 expected,
111 },
112
113 _ =>
114 XmlError::Other(error.to_string()),
115 }
116 }
117}
118
119fn from_text_pos(position: TextPos, source: &str) -> SourceSpan {
120 SourceOffset::from_location(
121 &source,
122 position.row as usize,
123 position.col as usize,
124 ).into()
125}
126
127#[derive(Debug)]
128#[derive(miette::Diagnostic)]
129#[derive(thiserror::Error)]
130pub enum ParseError {
131 #[error("Expecting one of 'yes', 'no', 'true' or 'false'")]
132 BooleanInvalid {
133 #[label]
134 value: SourceSpan,
135 },
136 #[error("Duplicate <{attribute}='...'>")]
137 DuplicateAttribute {
138 attribute: String,
139
140 #[label(primary, "duplicate")]
141 duplicate: SourceSpan,
142
143 #[label("existing")]
144 existing: SourceSpan,
145 },
146 #[error("Duplicate <{element}>")]
147 DuplicateElement {
148 element: String,
149
150 #[label(primary, "duplicate")]
151 duplicate: SourceSpan,
152
153 #[label("existing")]
154 existing: SourceSpan,
155 },
156 #[error("{message}")]
157 EnumValue {
158 message: String,
159 #[label]
160 value: SourceSpan,
161 },
162 #[error("Invalid length")]
168 LengthInvalid {
169 #[label]
170 value: SourceSpan,
171 },
172 #[error("Length must be between {min} and {max}")]
173 LengthRange {
174 min: usize,
175 max: usize,
176 #[label]
177 value: SourceSpan,
178 },
179 #[error("Missing <{element} {attribute}='...'>")]
180 MissingAttribute {
181 element: String,
182 attribute: String,
183
184 #[label]
185 parent: SourceSpan,
186 },
187 #[error("Missing <{element}>")]
188 MissingElement {
189 element: String,
190
191 #[label]
192 parent: SourceSpan,
193 },
194 #[error("Invalid number")]
195 NumberValue {
196 #[label]
197 value: SourceSpan,
198 },
199 #[error("Empty string")]
200 StringEmpty {
201 #[label]
202 value: SourceSpan,
203 },
204 #[error("Unexpected attribute")]
205 UnexpectedAttribute {
206 #[label]
207 unexpected: SourceSpan,
208 },
209 #[error("Unexpected element")]
210 UnexpectedElement {
211 #[label]
212 unexpected: SourceSpan,
213 },
214 #[error("Must be 'yes'")]
215 YesAttribute {
216 #[label]
217 value: SourceSpan,
218 },
219}