//! Diagnostic computation — wraps el-types TypeChecker output. use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Diagnostic { /// Human-readable message. pub message: String, /// "error" | "warning" | "info" pub severity: String, /// 1-based line number (if known). pub line: Option, /// 1-based column (if known). pub col: Option, } impl Diagnostic { pub fn error(message: impl Into) -> Self { Self { message: message.into(), severity: "error".into(), line: None, col: None } } pub fn warning(message: impl Into) -> Self { Self { message: message.into(), severity: "warning".into(), line: None, col: None } } } /// Parse and type-check `source`, returning all diagnostics. pub fn check(source: &str) -> Vec { let mut out = Vec::new(); let tokens = match el_lexer::tokenize(source) { Ok(t) => t, Err(e) => { out.push(Diagnostic { message: format!("Lex error: {}", e.kind), severity: "error".into(), line: Some(e.span.line), col: Some(e.span.col), }); return out; } }; let program = match el_parser::parse(tokens, source.to_string()) { Ok(p) => p, Err(e) => { out.push(Diagnostic { message: format!("Parse error: {}", e.kind), severity: "error".into(), line: Some(e.span.line), col: Some(e.span.col), }); return out; } }; let mut checker = el_types::TypeChecker::with_builtins(); checker.check(&program); for d in &checker.diagnostics { if d.is_error { out.push(Diagnostic::error(&d.message)); } else { out.push(Diagnostic::warning(&d.message)); } } out }