diff --git a/src/xatu/ast.rs b/src/xatu/ast.rs index 5629ef5..3e22150 100644 --- a/src/xatu/ast.rs +++ b/src/xatu/ast.rs @@ -16,6 +16,12 @@ pub struct SourceRange { pub end: usize, } +impl std::fmt::Display for SourceRange { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "{}..{}", self.start, self.end) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Node { pub range: SourceRange, diff --git a/src/xatu/rules.rs b/src/xatu/rules.rs index 09684ed..28edf39 100644 --- a/src/xatu/rules.rs +++ b/src/xatu/rules.rs @@ -4,17 +4,29 @@ use crate::rules::empty_inherit::EmptyInherit; pub mod empty_inherit; +#[derive(Debug)] pub struct Finding { pub rule_id: &'static str, pub range: ast::SourceRange, pub message: &'static str, } +#[derive(Debug)] pub struct Diagnostic { pub file_id: FileId, pub finding: Finding, } +impl std::fmt::Display for Diagnostic { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + formatter, + "{}: {}: {}", + self.finding.range, self.finding.rule_id, self.finding.message, + ) + } +} + pub trait NodeRule { type Node; diff --git a/src/xatu/xatu.rs b/src/xatu/xatu.rs index b48ed5c..bc8b40f 100644 --- a/src/xatu/xatu.rs +++ b/src/xatu/xatu.rs @@ -4,9 +4,35 @@ mod parser; mod rules; pub use file_store::{FileId, FileStore, SourceFile}; +pub use rules::{Diagnostic, Finding}; -pub fn run(files: Vec) -> status::Result<()> { +#[derive(Debug)] +pub struct Report { + pub files: FileStore, + pub diagnostics: Vec, +} + +impl Report { + pub fn is_clean(&self) -> bool { + self.diagnostics.is_empty() + } +} + +impl std::fmt::Display for Report { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for diagnostic in &self.diagnostics { + let file = self.files.get(diagnostic.file_id); + writeln!(formatter, "{}:{diagnostic}", file.path.display())?; + } + + Ok(()) + } +} + +/// Analyzes source files and returns the diagnostics Xatu finds. +pub fn future_sight(files: Vec) -> status::Result { let mut store = FileStore::default(); + let mut diagnostics = Vec::new(); for file in files { let file_id = store.add(file); @@ -20,17 +46,11 @@ pub fn run(files: Vec) -> status::Result<()> { ))); } - for diagnostic in rules::run_rules(&parsed) { - println!( - "{}:{}..{}: {}: {}", - file.path.display(), - diagnostic.finding.range.start, - diagnostic.finding.range.end, - diagnostic.finding.rule_id, - diagnostic.finding.message, - ); - } + diagnostics.extend(rules::run_rules(&parsed)); } - Ok(()) + Ok(Report { + files: store, + diagnostics, + }) } diff --git a/src/xatu/xatu_main.rs b/src/xatu/xatu_main.rs index 24d519e..2a5c68c 100644 --- a/src/xatu/xatu_main.rs +++ b/src/xatu/xatu_main.rs @@ -82,5 +82,8 @@ fn main() -> status::Result<()> { .flatten() .collect(); - xatu::run(files) + let report = xatu::future_sight(files)?; + print!("{report}"); + + Ok(()) }