1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#![feature(box_syntax, specialization, raw)]

#[macro_use]
extern crate kg_display_derive;
#[macro_use]
extern crate serde_derive;

pub use self::detail::{Detail, Severity};
pub use self::diag::{BasicDiag, Diag, ParseDiag, SimpleDiag};
pub use self::io::{
    ByteReader, CharReader, FileBuffer, FileType, IoError, IoResult, LexTerm, LexToken,
    MemByteReader, MemCharReader, OpType, ParseResult, Position, Quote, Reader, Span,
};
pub use self::multi::{Diags, Errors};
pub use self::stacktrace::Stacktrace;

mod detail;
mod diag;
pub mod io;
mod multi;
mod stacktrace;

#[macro_export]
macro_rules! basic_diag {
    ($kind: expr) => {{
        $crate::BasicDiag::from($kind)
    }};
    ($logger: expr, $kind: expr) => {{
        let e = $crate::BasicDiag::from($kind);
        slog_debug!($logger, "diagnostic created:\n{}", e);
        e
    }};
}

#[macro_export]
macro_rules! parse_diag {
    ($kind: expr) => {{
        $crate::ParseDiag::from($kind)
    }};
    ($kind: expr, $reader: expr, { $($p1: expr, $p2: expr => $msg: expr),+ $(,)* }) => {{
        let mut e = $crate::ParseDiag::from($kind);
        $(
        e.add_quote($reader.quote($p1, $p2, 2, 2, $msg.into()));
        )+
        e
    }};
    ($logger: expr, $kind: expr) => {{
        let e = $crate::ParseDiag::from($kind);
        slog_debug!("parse diagnostic created:\n{}", e);
        e
    }};
    ($logger: expr, $kind: expr, $reader: expr, { $($p1: expr, $p2: expr => $msg: expr),+ $(,)* }) => {{
        let mut e = $crate::ParseDiag::from($kind);
        $(
        e.add_quote($reader.quote($p1, $p2, 2, 2, $msg.into()));
        )+
        slog_debug!("parse diagnostic created:\n{}", e);
        e
    }};
}

pub trait ResultExt<T> {
    fn into_diag(self) -> Result<T, BasicDiag>;
}

impl<T, E: Detail> ResultExt<T> for Result<T, E> {
    fn into_diag(self) -> Result<T, BasicDiag> {
        self.map_err(|detail| BasicDiag::from(detail))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn detail_debug() {
        #[derive(Debug)]
        struct InvalidToken {
            expected: &'static [&'static str],
            found: String,
        }

        impl Detail for InvalidToken {
            fn severity(&self) -> Severity {
                Severity::Error
            }

            fn code(&self) -> u32 {
                101
            }
        }

        impl std::fmt::Display for InvalidToken {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(
                    f,
                    "invalid token '{}', expected one of {:?}",
                    self.found, self.expected
                )
            }
        }

        let err: ParseDiag = InvalidToken {
            expected: &["id", "num", "+", "-"],
            found: "*".into(),
        }
        .into();

        println!("{:#?}", err);
        println!("{}", err);
    }
}