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
use std::path::PathBuf; use steps::{CompilerMessage, MessageLocation}; #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum DiagnosticLevel { Error, Warning, Note, Help, #[serde(rename = "")] Empty, } #[derive(Debug, Deserialize)] pub struct Diagnostic { pub message: Option<DiagnosticMessage>, pub reason: String, } #[derive(Debug, Deserialize)] pub struct DiagnosticMessage { pub message: String, pub level: DiagnosticLevel, pub code: Option<DiagnosticCode>, pub spans: Vec<DiagnosticSpan>, } #[derive(Debug, Deserialize)] pub struct DiagnosticSpan { pub file_name: String, pub line_start: usize, pub is_primary: bool, } #[derive(Debug, Deserialize, Clone)] pub struct DiagnosticCode { pub code: String, } impl Default for DiagnosticSpan { fn default() -> Self { DiagnosticSpan { file_name: "unknown".into(), line_start: 1, is_primary: true, } } } impl<'a> From<&'a str> for DiagnosticLevel { fn from(text: &str) -> Self { match text { "ERROR" => DiagnosticLevel::Error, "WARNING" => DiagnosticLevel::Warning, "NOTE" => DiagnosticLevel::Note, "HELP" => DiagnosticLevel::Help, _ => DiagnosticLevel::Empty, } } } impl Into<CompilerMessage> for DiagnosticMessage { fn into(self) -> CompilerMessage { let span = self.spans .into_iter() .filter(|item| item.is_primary) .nth(0) .unwrap_or_default(); CompilerMessage { message: Some(self.message), level: self.level, code: self.code.map(|item| item.code), location: MessageLocation { file: PathBuf::from(span.file_name), line: span.line_start, }, } } }