From 4d7454eeb6dd3f395d9b9fc3ac7d2b4d810de543 Mon Sep 17 00:00:00 2001 From: Christofer Nolander Date: Sun, 17 Jul 2022 13:36:21 +0200 Subject: [PATCH 1/4] add `emit_to_{stderr,string}` helpers to validation error --- src/front/wgsl/mod.rs | 59 ++++++++----------------------------------- src/span.rs | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index 2f68534cf2..2732c5b572 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -27,15 +27,10 @@ use codespan_reporting::{ files::SimpleFile, term::{ self, - termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor}, + termcolor::{ColorChoice, NoColor, StandardStream}, }, }; -use std::{ - borrow::Cow, - convert::TryFrom, - io::{self, Write}, - ops, -}; +use std::{borrow::Cow, convert::TryFrom, ops}; use thiserror::Error; type Span = ops::Range; @@ -1320,11 +1315,16 @@ impl ParseError { /// Emits a summary of the error to a string. pub fn emit_to_string(&self, source: &str) -> String { - let files = SimpleFile::new("wgsl", source); + self.emit_to_string_with_path(source, "wgsl") + } + + /// Emits a summary of the error to a string. + pub fn emit_to_string_with_path(&self, source: &str, path: &str) -> String { + let files = SimpleFile::new(path, source); let config = codespan_reporting::term::Config::default(); - let mut writer = StringErrorBuffer::new(); + let mut writer = NoColor::new(Vec::new()); term::emit(&mut writer, &config, &files, &self.diagnostic()).expect("cannot write error"); - writer.into_string() + String::from_utf8(writer.into_inner()).unwrap() } /// Returns a [`SourceLocation`] for the first label in the error message. @@ -4556,42 +4556,3 @@ impl Parser { pub fn parse_str(source: &str) -> Result { Parser::new().parse(source) } - -pub struct StringErrorBuffer { - buf: Vec, -} - -impl StringErrorBuffer { - pub const fn new() -> Self { - Self { buf: Vec::new() } - } - - pub fn into_string(self) -> String { - String::from_utf8(self.buf).unwrap() - } -} - -impl Write for StringErrorBuffer { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.buf.extend(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl WriteColor for StringErrorBuffer { - fn supports_color(&self) -> bool { - false - } - - fn set_color(&mut self, _spec: &ColorSpec) -> io::Result<()> { - Ok(()) - } - - fn reset(&mut self) -> io::Result<()> { - Ok(()) - } -} diff --git a/src/span.rs b/src/span.rs index 6f2583a5eb..ba8b70f1ca 100644 --- a/src/span.rs +++ b/src/span.rs @@ -236,6 +236,52 @@ impl WithSpan { pub fn location(&self, _source: &str) -> Option { None } + + fn diagnostic(&self) -> codespan_reporting::diagnostic::Diagnostic<()> { + use codespan_reporting::diagnostic::{Diagnostic, Label}; + let diagnostic = Diagnostic::error().with_labels( + self.spans() + .map(|&(span, ref desc)| { + Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned()) + }) + .collect(), + ); + diagnostic + } + + /// Emits a summary of the error to standard error stream. + pub fn emit_to_stderr(&self, source: &str) { + self.emit_to_stderr_with_path(source, "wgsl") + } + + /// Emits a summary of the error to standard error stream. + pub fn emit_to_stderr_with_path(&self, source: &str, path: &str) { + use codespan_reporting::{files, term}; + use term::termcolor::{ColorChoice, StandardStream}; + + let files = files::SimpleFile::new(path, source); + let config = term::Config::default(); + let writer = StandardStream::stderr(ColorChoice::Auto); + term::emit(&mut writer.lock(), &config, &files, &self.diagnostic()) + .expect("cannot write error"); + } + + /// Emits a summary of the error to a string. + pub fn emit_to_string(&self, source: &str) -> String { + self.emit_to_string_with_path(source, "wgsl") + } + + /// Emits a summary of the error to a string. + pub fn emit_to_string_with_path(&self, source: &str, path: &str) -> String { + use codespan_reporting::{files, term}; + use term::termcolor::NoColor; + + let files = files::SimpleFile::new(path, source); + let config = codespan_reporting::term::Config::default(); + let mut writer = NoColor::new(Vec::new()); + term::emit(&mut writer, &config, &files, &self.diagnostic()).expect("cannot write error"); + String::from_utf8(writer.into_inner()).unwrap() + } } /// Convenience trait for [`Error`] to be able to apply spans to anything. From 489d8a2e316d5bf32e81b57552e2fb4023b1ca28 Mon Sep 17 00:00:00 2001 From: Christofer Nolander Date: Sun, 17 Jul 2022 13:48:04 +0200 Subject: [PATCH 2/4] fix: only expose emit functions when using `span` fetaure --- src/span.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/span.rs b/src/span.rs index ba8b70f1ca..72fc75b027 100644 --- a/src/span.rs +++ b/src/span.rs @@ -237,6 +237,7 @@ impl WithSpan { None } + #[cfg(feature = "span")] fn diagnostic(&self) -> codespan_reporting::diagnostic::Diagnostic<()> { use codespan_reporting::diagnostic::{Diagnostic, Label}; let diagnostic = Diagnostic::error().with_labels( @@ -250,11 +251,13 @@ impl WithSpan { } /// Emits a summary of the error to standard error stream. + #[cfg(feature = "span")] pub fn emit_to_stderr(&self, source: &str) { self.emit_to_stderr_with_path(source, "wgsl") } /// Emits a summary of the error to standard error stream. + #[cfg(feature = "span")] pub fn emit_to_stderr_with_path(&self, source: &str, path: &str) { use codespan_reporting::{files, term}; use term::termcolor::{ColorChoice, StandardStream}; @@ -267,11 +270,13 @@ impl WithSpan { } /// Emits a summary of the error to a string. + #[cfg(feature = "span")] pub fn emit_to_string(&self, source: &str) -> String { self.emit_to_string_with_path(source, "wgsl") } /// Emits a summary of the error to a string. + #[cfg(feature = "span")] pub fn emit_to_string_with_path(&self, source: &str, path: &str) -> String { use codespan_reporting::{files, term}; use term::termcolor::NoColor; From 24d9b78c26bc46df217c0965dd9dee52b562b533 Mon Sep 17 00:00:00 2001 From: Christofer Nolander Date: Sun, 17 Jul 2022 14:59:37 +0200 Subject: [PATCH 3/4] add message to emitted error --- src/span.rs | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/span.rs b/src/span.rs index 72fc75b027..c0497172a0 100644 --- a/src/span.rs +++ b/src/span.rs @@ -238,27 +238,38 @@ impl WithSpan { } #[cfg(feature = "span")] - fn diagnostic(&self) -> codespan_reporting::diagnostic::Diagnostic<()> { + fn diagnostic(&self) -> codespan_reporting::diagnostic::Diagnostic<()> + where + E: std::fmt::Display, + { use codespan_reporting::diagnostic::{Diagnostic, Label}; - let diagnostic = Diagnostic::error().with_labels( - self.spans() - .map(|&(span, ref desc)| { - Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned()) - }) - .collect(), - ); + let diagnostic = Diagnostic::error() + .with_message(self.inner.to_string()) + .with_labels( + self.spans() + .map(|&(span, ref desc)| { + Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned()) + }) + .collect(), + ); diagnostic } /// Emits a summary of the error to standard error stream. #[cfg(feature = "span")] - pub fn emit_to_stderr(&self, source: &str) { + pub fn emit_to_stderr(&self, source: &str) + where + E: std::fmt::Display, + { self.emit_to_stderr_with_path(source, "wgsl") } /// Emits a summary of the error to standard error stream. #[cfg(feature = "span")] - pub fn emit_to_stderr_with_path(&self, source: &str, path: &str) { + pub fn emit_to_stderr_with_path(&self, source: &str, path: &str) + where + E: std::fmt::Display, + { use codespan_reporting::{files, term}; use term::termcolor::{ColorChoice, StandardStream}; @@ -271,13 +282,19 @@ impl WithSpan { /// Emits a summary of the error to a string. #[cfg(feature = "span")] - pub fn emit_to_string(&self, source: &str) -> String { + pub fn emit_to_string(&self, source: &str) -> String + where + E: std::fmt::Display, + { self.emit_to_string_with_path(source, "wgsl") } /// Emits a summary of the error to a string. #[cfg(feature = "span")] - pub fn emit_to_string_with_path(&self, source: &str, path: &str) -> String { + pub fn emit_to_string_with_path(&self, source: &str, path: &str) -> String + where + E: std::fmt::Display, + { use codespan_reporting::{files, term}; use term::termcolor::NoColor; From c98f503880e50234e2bc233428b539017263444b Mon Sep 17 00:00:00 2001 From: Christofer Nolander Date: Sun, 17 Jul 2022 15:09:49 +0200 Subject: [PATCH 4/4] add notes to emitted validation error --- src/span.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/span.rs b/src/span.rs index c0497172a0..a4670e2dad 100644 --- a/src/span.rs +++ b/src/span.rs @@ -240,7 +240,7 @@ impl WithSpan { #[cfg(feature = "span")] fn diagnostic(&self) -> codespan_reporting::diagnostic::Diagnostic<()> where - E: std::fmt::Display, + E: Error, { use codespan_reporting::diagnostic::{Diagnostic, Label}; let diagnostic = Diagnostic::error() @@ -251,7 +251,16 @@ impl WithSpan { Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned()) }) .collect(), - ); + ) + .with_notes({ + let mut notes = Vec::new(); + let mut source: &dyn Error = &self.inner; + while let Some(next) = Error::source(source) { + notes.push(next.to_string()); + source = next; + } + notes + }); diagnostic } @@ -259,7 +268,7 @@ impl WithSpan { #[cfg(feature = "span")] pub fn emit_to_stderr(&self, source: &str) where - E: std::fmt::Display, + E: Error, { self.emit_to_stderr_with_path(source, "wgsl") } @@ -268,7 +277,7 @@ impl WithSpan { #[cfg(feature = "span")] pub fn emit_to_stderr_with_path(&self, source: &str, path: &str) where - E: std::fmt::Display, + E: Error, { use codespan_reporting::{files, term}; use term::termcolor::{ColorChoice, StandardStream}; @@ -284,7 +293,7 @@ impl WithSpan { #[cfg(feature = "span")] pub fn emit_to_string(&self, source: &str) -> String where - E: std::fmt::Display, + E: Error, { self.emit_to_string_with_path(source, "wgsl") } @@ -293,7 +302,7 @@ impl WithSpan { #[cfg(feature = "span")] pub fn emit_to_string_with_path(&self, source: &str, path: &str) -> String where - E: std::fmt::Display, + E: Error, { use codespan_reporting::{files, term}; use term::termcolor::NoColor;