1use std::{fmt::Display, ops::Range};
8
9#[derive(Debug, PartialEq, Eq)]
11pub enum PcodeErrorTy {
12 RangeOutOfBounds {
14 range: Range<usize>,
16 available: usize,
21 },
22
23 ArgumentCountMismatch {
25 expected: usize,
27 actual: usize,
29 },
30
31 UnknownSize,
33
34 UnknownMacro(Box<str>),
36
37 MultipleExports,
39
40 ExportNotLast,
42
43 FunctionStatement,
45
46 Unsupported(Box<str>),
48}
49
50#[derive(Debug)]
52pub struct PcodeError {
53 pub ty: PcodeErrorTy,
55 pub span: Option<(usize, usize)>,
57}
58
59pub type PcodeResult<T> = std::result::Result<T, PcodeError>;
61
62impl std::error::Error for PcodeError {}
63
64impl PartialEq for PcodeError {
67 fn eq(&self, other: &Self) -> bool {
68 self.ty == other.ty
69 }
70}
71
72impl Eq for PcodeError {}
73
74impl PcodeError {
75 pub fn new(ty: PcodeErrorTy, span: (usize, usize)) -> Self {
77 Self {
78 ty,
79 span: Some(span),
80 }
81 }
82
83 pub fn spanless(ty: PcodeErrorTy) -> Self {
85 Self { ty, span: None }
86 }
87
88 pub fn with_span(mut self, span: (usize, usize)) -> Self {
90 self.span = Some(span);
91 self
92 }
93
94 pub fn range_out_of_bounds(range: Range<usize>, span: (usize, usize)) -> Self {
96 Self::new(
97 PcodeErrorTy::RangeOutOfBounds {
98 range,
99 available: 0,
100 },
101 span,
102 )
103 }
104
105 pub fn argument_count_mismatch(expected: usize, actual: usize, span: (usize, usize)) -> Self {
107 Self::new(
108 PcodeErrorTy::ArgumentCountMismatch { expected, actual },
109 span,
110 )
111 }
112
113 pub fn unknown_size(span: (usize, usize)) -> Self {
115 Self::new(PcodeErrorTy::UnknownSize, span)
116 }
117
118 pub fn unknown_macro(name: &str, span: (usize, usize)) -> Self {
120 Self::new(PcodeErrorTy::UnknownMacro(name.into()), span)
121 }
122
123 pub fn multiple_exports(span: (usize, usize)) -> Self {
125 Self::new(PcodeErrorTy::MultipleExports, span)
126 }
127
128 pub fn export_not_last(span: (usize, usize)) -> Self {
130 Self::new(PcodeErrorTy::ExportNotLast, span)
131 }
132
133 pub fn function_is_a_statement(span: (usize, usize)) -> Self {
135 Self::new(PcodeErrorTy::FunctionStatement, span)
136 }
137}
138
139impl Display for PcodeError {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 let message = match &self.ty {
142 PcodeErrorTy::RangeOutOfBounds { range, available } => {
143 format!("Range {range:?} is out of bounds for available size {available}")
144 }
145
146 PcodeErrorTy::ArgumentCountMismatch { expected, actual } => {
147 format!("Expected {expected} arguments but got {actual}")
148 }
149
150 PcodeErrorTy::UnknownSize => {
151 "Could not determine the size of this expression".to_string()
152 }
153
154 PcodeErrorTy::UnknownMacro(name) => format!("Unknown macro: {name}"),
155
156 PcodeErrorTy::MultipleExports => {
157 "A macro definition contains multiple exports".to_string()
158 }
159
160 PcodeErrorTy::ExportNotLast => {
161 "The export statement is not the last statement in a macro definition".to_string()
162 }
163
164 PcodeErrorTy::FunctionStatement => {
165 "Attempted to use a function as an expression, but it is a statement".to_string()
166 }
167
168 PcodeErrorTy::Unsupported(what) => what.to_string(),
169 };
170
171 if let Some((start, end)) = self.span {
172 write!(f, "{message} (bytes {start}..{end})")
173 } else {
174 write!(f, "{message}")
175 }
176 }
177}