1use std::{
62 convert::Infallible,
63 ffi::{NulError, c_void},
64 fmt::{self, Display, Formatter},
65 str::Utf8Error,
66 string::FromUtf8Error,
67};
68
69use crate::{
70 SourceInfo, TableGenParser,
71 raw::{
72 TableGenDiagKind::TABLEGEN_DK_ERROR, TableGenSourceLocationRef, tableGenPrintError,
73 tableGenSourceLocationClone, tableGenSourceLocationFree, tableGenSourceLocationNull,
74 },
75 string_ref::StringRef,
76 util::print_string_callback,
77};
78
79#[non_exhaustive]
81#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
82pub enum TableGenError {
83 #[error("invalid TableGen source")]
84 InvalidSource,
85 #[error("invalid TableGen source")]
86 InvalidSourceString(#[from] NulError),
87 #[error("invalid UTF-8 string")]
88 InvalidUtf8Str(#[from] Utf8Error),
89 #[error("invalid UTF-8 string")]
90 InvalidUtf8String(#[from] FromUtf8Error),
91 #[error("failed to parse TableGen source")]
92 Parse,
93 #[error("expected field {0} in record")]
94 MissingValue(String),
95 #[error("expected def {0}")]
96 MissingDef(String),
97 #[error("expected class {0}")]
98 MissingClass(String),
99 #[error("invalid conversion from {from} to {to}")]
100 InitConversion {
101 from: &'static str,
102 to: &'static str,
103 },
104 #[error("invalid source location")]
105 InvalidSourceLocation,
106 #[error("infallible")]
107 Infallible(#[from] Infallible),
108}
109
110#[derive(Debug, PartialEq, Eq)]
112pub struct SourceLocation {
113 raw: TableGenSourceLocationRef,
114}
115
116unsafe impl Sync for SourceLocation {}
118unsafe impl Send for SourceLocation {}
119
120impl SourceLocation {
121 pub unsafe fn from_raw(raw: TableGenSourceLocationRef) -> Self {
124 Self { raw }
125 }
126
127 pub fn none() -> Self {
130 unsafe {
131 Self {
132 raw: tableGenSourceLocationNull(),
133 }
134 }
135 }
136}
137
138impl Clone for SourceLocation {
139 fn clone(&self) -> Self {
140 unsafe { Self::from_raw(tableGenSourceLocationClone(self.raw)) }
141 }
142}
143
144impl Drop for SourceLocation {
145 fn drop(&mut self) {
146 unsafe { tableGenSourceLocationFree(self.raw) }
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq)]
158pub struct SourceError<E> {
159 location: SourceLocation,
160 message: Option<String>,
161 error: E,
162}
163
164impl<E: std::error::Error> SourceError<E> {
165 pub fn new(location: SourceLocation, error: E) -> Self {
167 Self {
168 location,
169 error,
170 message: None,
171 }
172 }
173
174 pub fn location(&self) -> &SourceLocation {
175 &self.location
176 }
177
178 pub fn error(&self) -> &E {
179 &self.error
180 }
181
182 pub fn set_error<F: std::error::Error>(self, error: F) -> SourceError<F> {
187 SourceError {
188 error,
189 message: None,
190 location: self.location,
191 }
192 }
193
194 pub fn set_location(mut self, location: impl SourceLoc) -> Self {
199 self.location = location.source_location();
200 self
201 }
202
203 pub fn add_source_info(mut self, info: SourceInfo) -> Self {
208 self.message = Some(Self::create_message(
209 info.0,
210 &self.location,
211 &format!("{}", self.error),
212 ));
213 self
214 }
215
216 fn create_message(parser: &TableGenParser, location: &SourceLocation, message: &str) -> String {
217 let mut data: (_, Result<_, TableGenError>) = (String::new(), Ok(()));
218 let res = unsafe {
219 tableGenPrintError(
220 parser.raw,
221 location.raw,
222 TABLEGEN_DK_ERROR,
223 StringRef::from(message).to_raw(),
224 Some(print_string_callback),
225 &mut data as *mut _ as *mut c_void,
226 )
227 };
228 if res == 0 {
229 data.1 = Err(TableGenError::InvalidSourceLocation);
230 }
231 if let Err(e) = data.1 {
232 data.0 = format!("{}\nfailed to print source information: {}", message, e);
233 }
234 data.0
235 }
236}
237
238impl<E: std::error::Error> Display for SourceError<E> {
239 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
240 if let Some(message) = self.message.as_ref() {
241 write!(f, "{}", message)
242 } else {
243 write!(f, "{}", self.error)
244 }
245 }
246}
247
248impl<E: std::error::Error + 'static> std::error::Error for SourceError<E> {
249 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
250 Some(&self.error)
251 }
252}
253
254impl From<TableGenError> for SourceError<TableGenError> {
255 fn from(value: TableGenError) -> Self {
256 value.with_location(SourceLocation::none())
257 }
258}
259
260pub trait WithLocation: std::error::Error + Sized {
261 fn with_location<L: SourceLoc>(self, location: L) -> SourceError<Self> {
263 SourceError::new(location.source_location(), self)
264 }
265}
266
267impl<E> WithLocation for E where E: std::error::Error {}
268
269pub trait SourceLoc {
270 fn source_location(self) -> SourceLocation;
272}
273
274impl SourceLoc for SourceLocation {
275 fn source_location(self) -> SourceLocation {
276 self
277 }
278}
279
280pub type Error = SourceError<TableGenError>;