1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct Span {
8 pub file: String,
9 pub line: usize,
10 pub col: usize,
11 pub len: usize,
12}
13
14impl Span {
15 pub fn new(file: &str, line: usize, col: usize, len: usize) -> Self {
17 Span {
18 file: file.to_string(),
19 line,
20 col,
21 len,
22 }
23 }
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum ErrorKind {
29 UnexpectedChar(char),
32
33 UnexpectedToken(String),
36 InvalidBitPattern(String),
38 ExpectedToken(String),
40 InvalidRange,
42 InvalidWidth(u32),
44 MissingDecoderBlock,
46
47 DuplicateInstructionName(String),
50 DuplicateTypeAlias(String),
52 BitCoverageGap {
54 instruction: String,
55 missing_bits: Vec<u32>,
56 },
57 OverlappingBits { instruction: String, bit: u32 },
59 UnresolvedType(String),
61 PatternConflict { a: String, b: String },
63 PatternLengthMismatch {
65 instruction: String,
66 expected: u32,
67 got: u32,
68 },
69 UnusedImport(String),
71
72 InvalidFormatString(String),
75 InvalidGuard(String),
77 UndefinedFieldInFormat { instruction: String, field: String },
79 UndefinedFieldInGuard { instruction: String, field: String },
81 UndefinedMap(String),
83 MapArgCountMismatch {
85 map: String,
86 expected: usize,
87 got: usize,
88 },
89 DuplicateMapEntry { map: String },
91 DuplicateMapName(String),
93 UnguardedNonLastFormatLine { instruction: String },
95 UnknownBuiltinFunction(String),
97
98 CrossUnitBoundary {
101 instruction: String,
102 range_start: u32,
103 range_end: u32,
104 width: u32,
105 },
106 ExceedsMaxUnits {
108 instruction: String,
109 required: u32,
110 max_units: u32,
111 },
112
113 InconsistentFragmentNames {
116 subdecoder: String,
117 instruction: String,
118 expected: Vec<String>,
119 got: Vec<String>,
120 },
121 SubDecoderFieldTooWide {
123 field: String,
124 field_width: u32,
125 subdecoder: String,
126 subdecoder_width: u32,
127 },
128 UndefinedSubDecoder(String),
130 UndefinedFragment {
132 subdecoder: String,
133 fragment: String,
134 },
135 CircularInclude(String),
137 IncludeNotFound(String),
139}
140
141#[derive(Debug, Clone)]
143pub struct Error {
144 pub kind: ErrorKind,
145 pub span: Span,
146 pub help: Option<String>,
147}
148
149impl Error {
150 pub fn new(kind: ErrorKind, span: Span) -> Self {
152 Error {
153 kind,
154 span,
155 help: None,
156 }
157 }
158
159 pub fn with_help(mut self, help: impl Into<String>) -> Self {
161 self.help = Some(help.into());
162 self
163 }
164}
165
166impl fmt::Display for Error {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 let msg = match &self.kind {
169 ErrorKind::UnexpectedChar(c) => format!("unexpected character '{}'", c),
170 ErrorKind::UnexpectedToken(t) => format!("unexpected token '{}'", t),
171 ErrorKind::InvalidBitPattern(p) => format!("invalid bit pattern '{}'", p),
172 ErrorKind::ExpectedToken(t) => format!("expected {}", t),
173 ErrorKind::InvalidRange => "invalid bit range".to_string(),
174 ErrorKind::InvalidWidth(w) => format!("invalid decoder width: {}", w),
175 ErrorKind::MissingDecoderBlock => "missing decoder block".to_string(),
176 ErrorKind::DuplicateInstructionName(n) => {
177 format!("duplicate instruction name '{}'", n)
178 }
179 ErrorKind::DuplicateTypeAlias(n) => format!("duplicate type alias '{}'", n),
180 ErrorKind::BitCoverageGap {
181 instruction,
182 missing_bits,
183 } => {
184 format!(
185 "instruction '{}' has uncovered bits: {:?}",
186 instruction, missing_bits
187 )
188 }
189 ErrorKind::OverlappingBits { instruction, bit } => {
190 format!(
191 "instruction '{}' has overlapping coverage at bit {}",
192 instruction, bit
193 )
194 }
195 ErrorKind::UnresolvedType(t) => format!("unresolved type '{}'", t),
196 ErrorKind::PatternConflict { a, b } => {
197 format!(
198 "instructions '{}' and '{}' have conflicting fixed bit patterns",
199 a, b
200 )
201 }
202 ErrorKind::PatternLengthMismatch {
203 instruction,
204 expected,
205 got,
206 } => {
207 format!(
208 "instruction '{}': fixed pattern length {} doesn't match range width {}",
209 instruction, got, expected
210 )
211 }
212 ErrorKind::UnusedImport(path) => format!("unused import '{}'", path),
213 ErrorKind::InvalidFormatString(msg) => format!("invalid format string: {}", msg),
214 ErrorKind::InvalidGuard(msg) => format!("invalid guard condition: {}", msg),
215 ErrorKind::UndefinedFieldInFormat { instruction, field } => {
216 format!(
217 "format string in '{}' references undefined field '{}'",
218 instruction, field
219 )
220 }
221 ErrorKind::UndefinedFieldInGuard { instruction, field } => {
222 format!(
223 "guard in '{}' references undefined field '{}'",
224 instruction, field
225 )
226 }
227 ErrorKind::UndefinedMap(name) => format!("undefined map '{}'", name),
228 ErrorKind::MapArgCountMismatch { map, expected, got } => {
229 format!(
230 "map '{}' expects {} arguments but got {}",
231 map, expected, got
232 )
233 }
234 ErrorKind::DuplicateMapEntry { map } => {
235 format!("duplicate entry in map '{}'", map)
236 }
237 ErrorKind::DuplicateMapName(name) => format!("duplicate map name '{}'", name),
238 ErrorKind::UnguardedNonLastFormatLine { instruction } => {
239 format!(
240 "non-last format line in '{}' must have a guard condition",
241 instruction
242 )
243 }
244 ErrorKind::UnknownBuiltinFunction(name) => {
245 format!("unknown builtin function '{}'", name)
246 }
247 ErrorKind::CrossUnitBoundary {
248 instruction,
249 range_start,
250 range_end,
251 width,
252 } => {
253 format!(
254 "instruction '{}': bit range [{}:{}] spans across unit boundary (width={})",
255 instruction, range_start, range_end, width
256 )
257 }
258 ErrorKind::ExceedsMaxUnits {
259 instruction,
260 required,
261 max_units,
262 } => {
263 format!(
264 "instruction '{}' requires {} units but decoder max_units is {}",
265 instruction, required, max_units
266 )
267 }
268 ErrorKind::InconsistentFragmentNames {
269 subdecoder,
270 instruction,
271 expected,
272 got,
273 } => {
274 format!(
275 "sub-decoder '{}': instruction '{}' has fragments {:?} but expected {:?}",
276 subdecoder, instruction, got, expected
277 )
278 }
279 ErrorKind::SubDecoderFieldTooWide {
280 field,
281 field_width,
282 subdecoder,
283 subdecoder_width,
284 } => {
285 format!(
286 "field '{}' is {} bits wide but sub-decoder '{}' is only {} bits",
287 field, field_width, subdecoder, subdecoder_width
288 )
289 }
290 ErrorKind::UndefinedSubDecoder(name) => {
291 format!("undefined sub-decoder '{}'", name)
292 }
293 ErrorKind::UndefinedFragment {
294 subdecoder,
295 fragment,
296 } => {
297 format!(
298 "sub-decoder '{}' has no fragment named '{}'",
299 subdecoder, fragment
300 )
301 }
302 ErrorKind::CircularInclude(path) => {
303 format!("circular include detected: '{}'", path)
304 }
305 ErrorKind::IncludeNotFound(path) => {
306 format!("included file not found: '{}'", path)
307 }
308 };
309
310 write!(f, "error: {}", msg)?;
311 write!(f, "\n --> {}:{}", self.span.file, self.span.line)?;
312
313 if let Some(help) = &self.help {
314 write!(f, "\n = help: {}", help)?;
315 }
316
317 Ok(())
318 }
319}
320
321impl std::error::Error for Error {}
322
323#[derive(Debug)]
325pub struct Errors(pub Vec<Error>);
326
327impl fmt::Display for Errors {
328 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329 for (i, err) in self.0.iter().enumerate() {
330 if i > 0 {
331 writeln!(f)?;
332 }
333 write!(f, "{}", err)?;
334 }
335 Ok(())
336 }
337}
338
339impl std::error::Error for Errors {}