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