From 5bf4a494cbb619a754e860293b6a3e7334aea0d7 Mon Sep 17 00:00:00 2001 From: Jooris Hadeler Date: Tue, 10 Mar 2026 18:42:40 +0100 Subject: [PATCH] Feat: add structured diagnostics with yansi colors Introduces fluxc/src/diagnostics.rs with Level (Critical, Error, Warning, Note), Label (Primary/Secondary with optional message), and Diagnostic types. Diagnostic::render(src, filename) produces rustc-style output: colored header, --> file:line:col pointer, source line with gutter, and ^ / - underlines aligned to the offending span. Replaces the flat ParseError struct in the parser; all five error sites now emit Diagnostic values with source-pointing labels. --- examples/invalid.flx | 4 + fluxc/Cargo.lock | 7 + fluxc/Cargo.toml | 1 + fluxc/src/diagnostics.rs | 323 +++++++++++++++++++++++++++++++++++++++ fluxc/src/lexer.rs | 4 +- fluxc/src/main.rs | 5 +- fluxc/src/parser.rs | 62 +++----- 7 files changed, 365 insertions(+), 41 deletions(-) create mode 100644 examples/invalid.flx create mode 100644 fluxc/src/diagnostics.rs diff --git a/examples/invalid.flx b/examples/invalid.flx new file mode 100644 index 0000000..b6f21f0 --- /dev/null +++ b/examples/invalid.flx @@ -0,0 +1,4 @@ +fn main() { + let a : 12 = 3; + return -; +} \ No newline at end of file diff --git a/fluxc/Cargo.lock b/fluxc/Cargo.lock index d867fb8..984f744 100644 --- a/fluxc/Cargo.lock +++ b/fluxc/Cargo.lock @@ -7,6 +7,7 @@ name = "fluxc" version = "0.1.0" dependencies = [ "unicode-xid", + "yansi", ] [[package]] @@ -14,3 +15,9 @@ name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/fluxc/Cargo.toml b/fluxc/Cargo.toml index a00b335..993a656 100644 --- a/fluxc/Cargo.toml +++ b/fluxc/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] unicode-xid = "0.2" +yansi = "1" diff --git a/fluxc/src/diagnostics.rs b/fluxc/src/diagnostics.rs new file mode 100644 index 0000000..6e8c67b --- /dev/null +++ b/fluxc/src/diagnostics.rs @@ -0,0 +1,323 @@ +use std::fmt::Write as _; + +use yansi::{Color, Paint as _}; + +use crate::token::Span; + +// ── Level ────────────────────────────────────────────────────────────────────── + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Level { + Critical, + Error, + Warning, + Note, +} + +impl Level { + fn label_str(self) -> &'static str { + match self { + Level::Critical => "critical", + Level::Error => "error", + Level::Warning => "warning", + Level::Note => "note", + } + } + + fn color(self) -> Color { + match self { + Level::Critical => Color::Magenta, + Level::Error => Color::Red, + Level::Warning => Color::Yellow, + Level::Note => Color::Cyan, + } + } +} + +// ── Label ────────────────────────────────────────────────────────────────────── + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LabelStyle { + Primary, + Secondary, +} + +#[derive(Debug, Clone)] +pub struct Label { + pub span: Span, + pub message: Option, + pub style: LabelStyle, +} + +impl Label { + pub fn primary(span: Span) -> Self { + Self { + span, + message: None, + style: LabelStyle::Primary, + } + } + + pub fn secondary(span: Span) -> Self { + Self { + span, + message: None, + style: LabelStyle::Secondary, + } + } + + pub fn with_message(mut self, msg: impl Into) -> Self { + self.message = Some(msg.into()); + self + } +} + +// ── Diagnostic ───────────────────────────────────────────────────────────────── + +#[derive(Debug, Clone)] +pub struct Diagnostic { + pub level: Level, + pub message: String, + pub labels: Vec