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 BindingsParse(String),
143 UnknownTargetKind(String),
145 InvalidStrategy(String),
147 MissingBindingsField { block: String, field: String },
149 InvalidEndianness(String),
151 MultipleTargetsAmbiguous(Vec<String>),
153 MultipleDecodersAmbiguous(Vec<String>),
156 UnknownDecoderInBinding {
159 name: String,
160 suggestion: Option<String>,
161 },
162 UnknownInstructionInGroup {
165 instruction: String,
166 suggestion: Option<String>,
167 },
168 UnknownInstructionInFlow {
170 instruction: String,
171 suggestion: Option<String>,
172 },
173 SegmentRegisterNotDeclared(String),
175 MissingInvalidHandler(String),
177 BindingsCircularInclude(String),
179 FlatDispatchAmbiguous {
182 raw: u64,
183 matches: Vec<(String, String)>,
184 },
185}
186
187#[derive(Debug, Clone)]
189pub struct Error {
190 pub kind: ErrorKind,
191 pub span: Span,
192 pub help: Option<String>,
193}
194
195impl Error {
196 pub fn new(kind: ErrorKind, span: Span) -> Self {
198 Error {
199 kind,
200 span,
201 help: None,
202 }
203 }
204
205 pub fn with_help(mut self, help: impl Into<String>) -> Self {
207 self.help = Some(help.into());
208 self
209 }
210}
211
212impl fmt::Display for Error {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 let msg = match &self.kind {
215 ErrorKind::UnexpectedChar(c) => format!("unexpected character '{}'", c),
216 ErrorKind::UnexpectedToken(t) => format!("unexpected token '{}'", t),
217 ErrorKind::InvalidBitPattern(p) => format!("invalid bit pattern '{}'", p),
218 ErrorKind::ExpectedToken(t) => format!("expected {}", t),
219 ErrorKind::InvalidRange => "invalid bit range".to_string(),
220 ErrorKind::InvalidWidth(w) => format!("invalid decoder width: {}", w),
221 ErrorKind::MissingDecoderBlock => "missing decoder block".to_string(),
222 ErrorKind::DuplicateInstructionName(n) => {
223 format!("duplicate instruction name '{}'", n)
224 }
225 ErrorKind::DuplicateTypeAlias(n) => format!("duplicate type alias '{}'", n),
226 ErrorKind::BitCoverageGap {
227 instruction,
228 missing_bits,
229 } => {
230 format!(
231 "instruction '{}' has uncovered bits: {:?}",
232 instruction, missing_bits
233 )
234 }
235 ErrorKind::OverlappingBits { instruction, bit } => {
236 format!(
237 "instruction '{}' has overlapping coverage at bit {}",
238 instruction, bit
239 )
240 }
241 ErrorKind::UnresolvedType(t) => format!("unresolved type '{}'", t),
242 ErrorKind::PatternConflict { a, b } => {
243 format!(
244 "instructions '{}' and '{}' have conflicting fixed bit patterns",
245 a, b
246 )
247 }
248 ErrorKind::PatternLengthMismatch {
249 instruction,
250 expected,
251 got,
252 } => {
253 format!(
254 "instruction '{}': fixed pattern length {} doesn't match range width {}",
255 instruction, got, expected
256 )
257 }
258 ErrorKind::UnusedImport(path) => format!("unused import '{}'", path),
259 ErrorKind::InvalidFormatString(msg) => format!("invalid format string: {}", msg),
260 ErrorKind::InvalidGuard(msg) => format!("invalid guard condition: {}", msg),
261 ErrorKind::UndefinedFieldInFormat { instruction, field } => {
262 format!(
263 "format string in '{}' references undefined field '{}'",
264 instruction, field
265 )
266 }
267 ErrorKind::UndefinedFieldInGuard { instruction, field } => {
268 format!(
269 "guard in '{}' references undefined field '{}'",
270 instruction, field
271 )
272 }
273 ErrorKind::UndefinedMap(name) => format!("undefined map '{}'", name),
274 ErrorKind::MapArgCountMismatch { map, expected, got } => {
275 format!(
276 "map '{}' expects {} arguments but got {}",
277 map, expected, got
278 )
279 }
280 ErrorKind::DuplicateMapEntry { map } => {
281 format!("duplicate entry in map '{}'", map)
282 }
283 ErrorKind::DuplicateMapName(name) => format!("duplicate map name '{}'", name),
284 ErrorKind::UnguardedNonLastFormatLine { instruction } => {
285 format!(
286 "non-last format line in '{}' must have a guard condition",
287 instruction
288 )
289 }
290 ErrorKind::UnknownBuiltinFunction(name) => {
291 format!("unknown builtin function '{}'", name)
292 }
293 ErrorKind::CrossUnitBoundary {
294 instruction,
295 range_start,
296 range_end,
297 width,
298 } => {
299 format!(
300 "instruction '{}': bit range [{}:{}] spans across unit boundary (width={})",
301 instruction, range_start, range_end, width
302 )
303 }
304 ErrorKind::ExceedsMaxUnits {
305 instruction,
306 required,
307 max_units,
308 } => {
309 format!(
310 "instruction '{}' requires {} units but decoder max_units is {}",
311 instruction, required, max_units
312 )
313 }
314 ErrorKind::InconsistentFragmentNames {
315 subdecoder,
316 instruction,
317 expected,
318 got,
319 } => {
320 format!(
321 "sub-decoder '{}': instruction '{}' has fragments {:?} but expected {:?}",
322 subdecoder, instruction, got, expected
323 )
324 }
325 ErrorKind::SubDecoderFieldTooWide {
326 field,
327 field_width,
328 subdecoder,
329 subdecoder_width,
330 } => {
331 format!(
332 "field '{}' is {} bits wide but sub-decoder '{}' is only {} bits",
333 field, field_width, subdecoder, subdecoder_width
334 )
335 }
336 ErrorKind::UndefinedSubDecoder(name) => {
337 format!("undefined sub-decoder '{}'", name)
338 }
339 ErrorKind::UndefinedFragment {
340 subdecoder,
341 fragment,
342 } => {
343 format!(
344 "sub-decoder '{}' has no fragment named '{}'",
345 subdecoder, fragment
346 )
347 }
348 ErrorKind::CircularInclude(path) => {
349 format!("circular include detected: '{}'", path)
350 }
351 ErrorKind::IncludeNotFound(path) => {
352 format!("included file not found: '{}'", path)
353 }
354
355 ErrorKind::BindingsParse(msg) => msg.clone(),
357 ErrorKind::UnknownTargetKind(name) => {
358 format!(
359 "unknown target kind '{}': expected one of rust, cpp, ida, binja",
360 name
361 )
362 }
363 ErrorKind::InvalidStrategy(name) => {
364 format!(
365 "unknown dispatch strategy '{}': expected one of fn_ptr_lut, jump_table, flat_lut, flat_match",
366 name
367 )
368 }
369 ErrorKind::MissingBindingsField { block, field } => {
370 format!("{} is missing required field '{}'", block, field)
371 }
372 ErrorKind::InvalidEndianness(value) => {
373 format!("invalid endianness '{}': expected 'big' or 'little'", value)
374 }
375 ErrorKind::MultipleTargetsAmbiguous(names) => {
376 let mut s = String::from("multiple targets found:");
377 for name in names {
378 s.push_str("\n ");
379 s.push_str(name);
380 }
381 s.push_str("\npass one explicitly with --target");
382 s
383 }
384 ErrorKind::MultipleDecodersAmbiguous(names) => {
385 let mut s = String::from("multiple dispatch targets found:");
386 for name in names {
387 s.push_str("\n ");
388 s.push_str(name);
389 }
390 s.push_str("\npass one explicitly with --decoder");
391 s
392 }
393 ErrorKind::UnknownDecoderInBinding { name, .. } => {
394 format!("unknown decoder '{}' in bindings block", name)
395 }
396 ErrorKind::UnknownInstructionInGroup { instruction, .. } => {
397 format!("unknown instruction '{}' in handler group", instruction)
398 }
399 ErrorKind::UnknownInstructionInFlow { instruction, .. } => {
400 format!("unknown instruction '{}' in flow block", instruction)
401 }
402 ErrorKind::SegmentRegisterNotDeclared(name) => {
403 format!(
404 "segment_registers entry '{}' is not declared in registers",
405 name
406 )
407 }
408 ErrorKind::MissingInvalidHandler(decoder) => {
409 format!(
410 "dispatch '{}' requires an `invalid_handler` directive",
411 decoder
412 )
413 }
414 ErrorKind::BindingsCircularInclude(path) => {
415 format!("circular bindings include detected: '{}'", path)
416 }
417 ErrorKind::FlatDispatchAmbiguous { raw, matches } => {
418 let mut s = format!(
419 "flat dispatch cannot resolve raw opcode {:#010x}\n matched instructions:",
420 raw
421 );
422 for (instr, handler) in matches {
423 s.push_str(&format!("\n {} -> {}", instr, handler));
424 }
425 s.push_str(
426 "\n flat dispatch requires each raw value to resolve to exactly one handler.",
427 );
428 s
429 }
430 };
431
432 write!(f, "error: {}", msg)?;
433 write!(f, "\n --> {}:{}", self.span.file, self.span.line)?;
434
435 let auto_help = if self.help.is_none() {
438 match &self.kind {
439 ErrorKind::UnknownDecoderInBinding {
440 suggestion: Some(s),
441 ..
442 }
443 | ErrorKind::UnknownInstructionInGroup {
444 suggestion: Some(s),
445 ..
446 }
447 | ErrorKind::UnknownInstructionInFlow {
448 suggestion: Some(s),
449 ..
450 } => Some(format!("did you mean \"{}\"?", s)),
451 _ => None,
452 }
453 } else {
454 None
455 };
456
457 if let Some(help) = self.help.as_ref().or(auto_help.as_ref()) {
458 write!(f, "\n = help: {}", help)?;
459 }
460
461 Ok(())
462 }
463}
464
465impl std::error::Error for Error {}
466
467#[derive(Debug)]
469pub struct Errors(pub Vec<Error>);
470
471impl fmt::Display for Errors {
472 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473 for (i, err) in self.0.iter().enumerate() {
474 if i > 0 {
475 writeln!(f)?;
476 }
477 write!(f, "{}", err)?;
478 }
479 Ok(())
480 }
481}
482
483impl std::error::Error for Errors {}