133d722a9Sopenharmony_ciuse crate::gen::fs; 233d722a9Sopenharmony_ciuse crate::syntax; 333d722a9Sopenharmony_ciuse codespan_reporting::diagnostic::{Diagnostic, Label}; 433d722a9Sopenharmony_ciuse codespan_reporting::files::SimpleFiles; 533d722a9Sopenharmony_ciuse codespan_reporting::term::termcolor::{ColorChoice, StandardStream, WriteColor}; 633d722a9Sopenharmony_ciuse codespan_reporting::term::{self, Config}; 733d722a9Sopenharmony_ciuse std::borrow::Cow; 833d722a9Sopenharmony_ciuse std::error::Error as StdError; 933d722a9Sopenharmony_ciuse std::fmt::{self, Display}; 1033d722a9Sopenharmony_ciuse std::io::{self, Write}; 1133d722a9Sopenharmony_ciuse std::ops::Range; 1233d722a9Sopenharmony_ciuse std::path::{Path, PathBuf}; 1333d722a9Sopenharmony_ciuse std::process; 1433d722a9Sopenharmony_ciuse std::str::Utf8Error; 1533d722a9Sopenharmony_ci 1633d722a9Sopenharmony_cipub(crate) type Result<T, E = Error> = std::result::Result<T, E>; 1733d722a9Sopenharmony_ci 1833d722a9Sopenharmony_ci#[derive(Debug)] 1933d722a9Sopenharmony_cipub(crate) enum Error { 2033d722a9Sopenharmony_ci NoBridgeMod, 2133d722a9Sopenharmony_ci Fs(fs::Error), 2233d722a9Sopenharmony_ci Utf8(PathBuf, Utf8Error), 2333d722a9Sopenharmony_ci Syn(syn::Error), 2433d722a9Sopenharmony_ci} 2533d722a9Sopenharmony_ci 2633d722a9Sopenharmony_ciimpl Display for Error { 2733d722a9Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 2833d722a9Sopenharmony_ci match self { 2933d722a9Sopenharmony_ci Error::NoBridgeMod => write!(f, "no #[cxx::bridge] module found"), 3033d722a9Sopenharmony_ci Error::Fs(err) => err.fmt(f), 3133d722a9Sopenharmony_ci Error::Utf8(path, _) => write!(f, "Failed to read file `{}`", path.display()), 3233d722a9Sopenharmony_ci Error::Syn(err) => err.fmt(f), 3333d722a9Sopenharmony_ci } 3433d722a9Sopenharmony_ci } 3533d722a9Sopenharmony_ci} 3633d722a9Sopenharmony_ci 3733d722a9Sopenharmony_ciimpl StdError for Error { 3833d722a9Sopenharmony_ci fn source(&self) -> Option<&(dyn StdError + 'static)> { 3933d722a9Sopenharmony_ci match self { 4033d722a9Sopenharmony_ci Error::Fs(err) => err.source(), 4133d722a9Sopenharmony_ci Error::Utf8(_, err) => Some(err), 4233d722a9Sopenharmony_ci Error::Syn(err) => err.source(), 4333d722a9Sopenharmony_ci _ => None, 4433d722a9Sopenharmony_ci } 4533d722a9Sopenharmony_ci } 4633d722a9Sopenharmony_ci} 4733d722a9Sopenharmony_ci 4833d722a9Sopenharmony_ciimpl From<fs::Error> for Error { 4933d722a9Sopenharmony_ci fn from(err: fs::Error) -> Self { 5033d722a9Sopenharmony_ci Error::Fs(err) 5133d722a9Sopenharmony_ci } 5233d722a9Sopenharmony_ci} 5333d722a9Sopenharmony_ci 5433d722a9Sopenharmony_ciimpl From<syn::Error> for Error { 5533d722a9Sopenharmony_ci fn from(err: syn::Error) -> Self { 5633d722a9Sopenharmony_ci Error::Syn(err) 5733d722a9Sopenharmony_ci } 5833d722a9Sopenharmony_ci} 5933d722a9Sopenharmony_ci 6033d722a9Sopenharmony_cipub(super) fn format_err(path: &Path, source: &str, error: Error) -> ! { 6133d722a9Sopenharmony_ci match error { 6233d722a9Sopenharmony_ci Error::Syn(syn_error) => { 6333d722a9Sopenharmony_ci let syn_error = sort_syn_errors(syn_error); 6433d722a9Sopenharmony_ci let writer = StandardStream::stderr(ColorChoice::Auto); 6533d722a9Sopenharmony_ci let ref mut stderr = writer.lock(); 6633d722a9Sopenharmony_ci for error in syn_error { 6733d722a9Sopenharmony_ci let _ = writeln!(stderr); 6833d722a9Sopenharmony_ci display_syn_error(stderr, path, source, error); 6933d722a9Sopenharmony_ci } 7033d722a9Sopenharmony_ci } 7133d722a9Sopenharmony_ci Error::NoBridgeMod => { 7233d722a9Sopenharmony_ci let _ = writeln!( 7333d722a9Sopenharmony_ci io::stderr(), 7433d722a9Sopenharmony_ci "cxxbridge: no #[cxx::bridge] module found in {}", 7533d722a9Sopenharmony_ci path.display(), 7633d722a9Sopenharmony_ci ); 7733d722a9Sopenharmony_ci } 7833d722a9Sopenharmony_ci _ => { 7933d722a9Sopenharmony_ci let _ = writeln!(io::stderr(), "cxxbridge: {}", report(error)); 8033d722a9Sopenharmony_ci } 8133d722a9Sopenharmony_ci } 8233d722a9Sopenharmony_ci process::exit(1); 8333d722a9Sopenharmony_ci} 8433d722a9Sopenharmony_ci 8533d722a9Sopenharmony_cipub(crate) fn report(error: impl StdError) -> impl Display { 8633d722a9Sopenharmony_ci struct Report<E>(E); 8733d722a9Sopenharmony_ci 8833d722a9Sopenharmony_ci impl<E: StdError> Display for Report<E> { 8933d722a9Sopenharmony_ci fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 9033d722a9Sopenharmony_ci write!(formatter, "{}", self.0)?; 9133d722a9Sopenharmony_ci let mut error: &dyn StdError = &self.0; 9233d722a9Sopenharmony_ci 9333d722a9Sopenharmony_ci while let Some(cause) = error.source() { 9433d722a9Sopenharmony_ci write!(formatter, "\n\nCaused by:\n {}", cause)?; 9533d722a9Sopenharmony_ci error = cause; 9633d722a9Sopenharmony_ci } 9733d722a9Sopenharmony_ci 9833d722a9Sopenharmony_ci Ok(()) 9933d722a9Sopenharmony_ci } 10033d722a9Sopenharmony_ci } 10133d722a9Sopenharmony_ci 10233d722a9Sopenharmony_ci Report(error) 10333d722a9Sopenharmony_ci} 10433d722a9Sopenharmony_ci 10533d722a9Sopenharmony_cifn sort_syn_errors(error: syn::Error) -> Vec<syn::Error> { 10633d722a9Sopenharmony_ci let mut errors: Vec<_> = error.into_iter().collect(); 10733d722a9Sopenharmony_ci errors.sort_by_key(|e| { 10833d722a9Sopenharmony_ci let start = e.span().start(); 10933d722a9Sopenharmony_ci (start.line, start.column) 11033d722a9Sopenharmony_ci }); 11133d722a9Sopenharmony_ci errors 11233d722a9Sopenharmony_ci} 11333d722a9Sopenharmony_ci 11433d722a9Sopenharmony_cifn display_syn_error(stderr: &mut dyn WriteColor, path: &Path, source: &str, error: syn::Error) { 11533d722a9Sopenharmony_ci let span = error.span(); 11633d722a9Sopenharmony_ci let start = span.start(); 11733d722a9Sopenharmony_ci let end = span.end(); 11833d722a9Sopenharmony_ci 11933d722a9Sopenharmony_ci let mut start_offset = 0; 12033d722a9Sopenharmony_ci for _ in 1..start.line { 12133d722a9Sopenharmony_ci start_offset += source[start_offset..].find('\n').unwrap() + 1; 12233d722a9Sopenharmony_ci } 12333d722a9Sopenharmony_ci let start_column = source[start_offset..] 12433d722a9Sopenharmony_ci .chars() 12533d722a9Sopenharmony_ci .take(start.column) 12633d722a9Sopenharmony_ci .map(char::len_utf8) 12733d722a9Sopenharmony_ci .sum::<usize>(); 12833d722a9Sopenharmony_ci start_offset += start_column; 12933d722a9Sopenharmony_ci 13033d722a9Sopenharmony_ci let mut end_offset = start_offset; 13133d722a9Sopenharmony_ci if start.line == end.line { 13233d722a9Sopenharmony_ci end_offset -= start_column; 13333d722a9Sopenharmony_ci } else { 13433d722a9Sopenharmony_ci for _ in 0..end.line - start.line { 13533d722a9Sopenharmony_ci end_offset += source[end_offset..].find('\n').unwrap() + 1; 13633d722a9Sopenharmony_ci } 13733d722a9Sopenharmony_ci } 13833d722a9Sopenharmony_ci end_offset += source[end_offset..] 13933d722a9Sopenharmony_ci .chars() 14033d722a9Sopenharmony_ci .take(end.column) 14133d722a9Sopenharmony_ci .map(char::len_utf8) 14233d722a9Sopenharmony_ci .sum::<usize>(); 14333d722a9Sopenharmony_ci 14433d722a9Sopenharmony_ci let mut path = path.to_string_lossy(); 14533d722a9Sopenharmony_ci if path == "-" { 14633d722a9Sopenharmony_ci path = Cow::Borrowed(if cfg!(unix) { "/dev/stdin" } else { "stdin" }); 14733d722a9Sopenharmony_ci } 14833d722a9Sopenharmony_ci 14933d722a9Sopenharmony_ci let mut files = SimpleFiles::new(); 15033d722a9Sopenharmony_ci let file = files.add(path, source); 15133d722a9Sopenharmony_ci 15233d722a9Sopenharmony_ci let diagnostic = diagnose(file, start_offset..end_offset, error); 15333d722a9Sopenharmony_ci 15433d722a9Sopenharmony_ci let config = Config::default(); 15533d722a9Sopenharmony_ci let _ = term::emit(stderr, &config, &files, &diagnostic); 15633d722a9Sopenharmony_ci} 15733d722a9Sopenharmony_ci 15833d722a9Sopenharmony_cifn diagnose(file: usize, range: Range<usize>, error: syn::Error) -> Diagnostic<usize> { 15933d722a9Sopenharmony_ci let message = error.to_string(); 16033d722a9Sopenharmony_ci let info = syntax::error::ERRORS 16133d722a9Sopenharmony_ci .iter() 16233d722a9Sopenharmony_ci .find(|e| message.contains(e.msg)); 16333d722a9Sopenharmony_ci let mut diagnostic = Diagnostic::error().with_message(&message); 16433d722a9Sopenharmony_ci let mut label = Label::primary(file, range); 16533d722a9Sopenharmony_ci if let Some(info) = info { 16633d722a9Sopenharmony_ci label.message = info.label.map_or(message, str::to_owned); 16733d722a9Sopenharmony_ci diagnostic.labels.push(label); 16833d722a9Sopenharmony_ci diagnostic.notes.extend(info.note.map(str::to_owned)); 16933d722a9Sopenharmony_ci } else { 17033d722a9Sopenharmony_ci label.message = message; 17133d722a9Sopenharmony_ci diagnostic.labels.push(label); 17233d722a9Sopenharmony_ci } 17333d722a9Sopenharmony_ci diagnostic.code = Some("cxxbridge".to_owned()); 17433d722a9Sopenharmony_ci diagnostic 17533d722a9Sopenharmony_ci} 176