From 42ba357302583ae83ffc5989a198376d75878a61 Mon Sep 17 00:00:00 2001 From: Jooris Hadeler Date: Tue, 21 Apr 2026 22:35:37 +0200 Subject: [PATCH] feat: add better diagnostic rendering --- Cargo.lock | 37 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + examples/simple.src | 6 +++++- src/frontend/token.rs | 8 +++++++- src/main.rs | 28 ++++++++++++++++++++++++---- 5 files changed, 74 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e62bf18..98ec4b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,6 +125,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "codespan-reporting" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + [[package]] name = "colorchoice" version = "1.0.5" @@ -136,6 +147,7 @@ name = "compiler" version = "0.1.0" dependencies = [ "clap", + "codespan-reporting", "cranelift-codegen", "cranelift-frontend", "cranelift-module", @@ -468,6 +480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -525,12 +538,27 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "utf8parse" version = "0.2.2" @@ -547,6 +575,15 @@ dependencies = [ "libm", ] +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + [[package]] name = "windows-link" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 7e6fc4a..fa14d35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ cranelift-frontend = "0.131.0" cranelift-module = "0.131.0" cranelift-object = "0.131.0" cranelift-native = "0.131.0" +codespan-reporting = "0.13.1" diff --git a/examples/simple.src b/examples/simple.src index 380035c..f2f636b 100644 --- a/examples/simple.src +++ b/examples/simple.src @@ -1,3 +1,7 @@ fn main() -> i8 { - return -1; + if 2 * 5 == 10 { + return -1; + } else { + return 45; + } } \ No newline at end of file diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 6d9309f..7594e9c 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -1,4 +1,4 @@ -use std::fmt::Display; +use std::{fmt::Display, ops::Range}; /// A half-open interval `[start, end)` representing a location in the source text. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -23,6 +23,12 @@ impl Span { } } +impl From for Range { + fn from(value: Span) -> Self { + value.start..value.end + } +} + /// A fundamental, categorized unit of source code produced during lexical analysis. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Token<'src> { diff --git a/src/main.rs b/src/main.rs index 7c5c490..f1a6ccd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,16 @@ use std::{fs::read_to_string, path::PathBuf, process::exit}; -use clap::Parser as ClapParser; +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term; +use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use crate::frontend::parser::Parser; use crate::frontend::sema::Sema; use crate::middle::builder::MirBuilder; use crate::middle::dce::eliminate_dead_code; use crate::middle::fold::fold_constants; +use clap::Parser as ClapParser; pub mod backend; pub mod frontend; @@ -37,12 +41,20 @@ fn main() { exit(1); }); + let writer = StandardStream::stderr(ColorChoice::Always); + let config = term::Config::default(); + let file = SimpleFile::new(&cli.input, &content); + let mut parser = Parser::new(&content); let module = parser.parse_module(); if let Some(errors) = parser.errors() { for error in errors { - eprintln!("{:?}", error); + let diagnostic = Diagnostic::error() + .with_message(error.message) + .with_label(Label::primary((), error.span)); + + term::emit_to_write_style(&mut writer.lock(), &config, &file, &diagnostic).unwrap(); } exit(1); @@ -53,7 +65,11 @@ fn main() { if let Some(errors) = sema.errors() { for error in errors { - eprintln!("{:?}", error); + let diagnostic = Diagnostic::error() + .with_message(error.message) + .with_label(Label::primary((), error.span)); + + term::emit_to_write_style(&mut writer.lock(), &config, &file, &diagnostic).unwrap(); } exit(1); @@ -64,7 +80,11 @@ fn main() { let warnings = eliminate_dead_code(&mut mir_module); for warning in warnings { - eprintln!("Warning: {} at {:?}", warning.message, warning.span); + let diagnostic = Diagnostic::warning() + .with_message(warning.message) + .with_label(Label::primary((), warning.span)); + + term::emit_to_write_style(&mut writer.lock(), &config, &file, &diagnostic).unwrap(); } let backend = CraneliftBackend::new();