Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report implement Error, and a few more suggestions #87

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions examples/multifile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ fn main() {
.with_message(format!("Original definition of {} is here", "five".fg(a)))
.with_color(a))
.with_note(format!("{} is a number and can only be added to other numbers", "Nat".fg(a)))
.finish()
.print(sources(vec![
.finish(sources(vec![
("a.tao", include_str!("a.tao")),
("b.tao", include_str!("b.tao")),
]))
.print()
.unwrap();
}
4 changes: 2 additions & 2 deletions examples/multiline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() {
))
.with_color(out2))
.with_note(format!("Outputs of {} expressions must coerce to the same type", "match".fg(out)))
.finish()
.print(("sample.tao", Source::from(include_str!("sample.tao"))))
.finish(("sample.tao", Source::from(include_str!("sample.tao"))))
.print()
.unwrap();
}
8 changes: 4 additions & 4 deletions examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ fn main() {
.with_message("Incompatible types")
.with_label(Label::new(32..33).with_message("This is of type Nat"))
.with_label(Label::new(42..45).with_message("This is of type Str"))
.finish()
.print(Source::from(include_str!("sample.tao")))
.finish(Source::from(include_str!("sample.tao")))
.print()
.unwrap();

const SOURCE: &str = "a b c d e f";
Expand All @@ -19,7 +19,7 @@ fn main() {
.with_label(Label::new(2..3).with_color(Color::Blue).with_message("`b` for banana").with_order(1))
.with_label(Label::new(4..5).with_color(Color::Green))
.with_label(Label::new(7..9).with_color(Color::Cyan).with_message("`e` for emerald"))
.finish()
.print(Source::from(SOURCE))
.finish(Source::from(SOURCE))
.print()
.unwrap();
}
4 changes: 2 additions & 2 deletions examples/stresstest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn main() {
.with_compact(true)
.with_underlines(true)
.with_tab_width(4))
.finish()
.print(("stresstest.tao", Source::from(include_str!("stresstest.tao"))))
.finish(("stresstest.tao", Source::from(include_str!("stresstest.tao"))))
.print()
.unwrap();
}
42 changes: 35 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use std::{
cmp::{PartialEq, Eq},
fmt,
};
use std::fmt::Formatter;
use unicode_width::UnicodeWidthChar;

/// A trait implemented by spans within a character-based source.
Expand Down Expand Up @@ -152,6 +153,7 @@ pub struct Report<'a, S: Span = Range<usize>> {
location: (<S::SourceId as ToOwned>::Owned, usize),
labels: Vec<Label<S>>,
config: Config,
rendered: Option<String>
}

impl<S: Span> Report<'_, S> {
Expand All @@ -170,16 +172,23 @@ impl<S: Span> Report<'_, S> {
}

/// Write this diagnostic out to `stderr`.
pub fn eprint<C: Cache<S::SourceId>>(&self, cache: C) -> io::Result<()> {
self.write(cache, io::stderr())
pub fn eprint(&self) -> io::Result<()> {
write!(io::stderr(), "{}", self.rendered.as_ref().unwrap())
}

/// Write this diagnostic out to `stdout`.
///
/// In most cases, [`Report::eprint`] is the
/// ['more correct'](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)) function to use.
pub fn print<C: Cache<S::SourceId>>(&self, cache: C) -> io::Result<()> {
self.write_for_stdout(cache, io::stdout())
pub fn print(&self) -> io::Result<()> {
write!(io::stdout(), "{}", self.rendered.as_ref().unwrap())
}

/// TODO: Move the description from the fork
fn write_to_string<C: Cache<S::SourceId>>(&self, cache: C) -> String {
let mut vec = Vec::new();
self.write(cache, &mut vec).unwrap();
String::from_utf8(vec).unwrap()
}
}

Expand All @@ -195,6 +204,21 @@ impl<'a, S: Span> fmt::Debug for Report<'a, S> {
.finish()
}
}

impl<'a, S: Span> fmt::Display for Report<'a, S> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
assert!(
self.rendered.is_some(),
"A report render is necessary to do display"
);

write!(f, "{}", self.rendered.as_ref().unwrap())
}
}

impl<'a, S: Span> std::error::Error for Report<'a, S> {}


/// A type that defines the kind of report being produced.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ReportKind<'a> {
Expand Down Expand Up @@ -303,8 +327,8 @@ impl<'a, S: Span> ReportBuilder<'a, S> {
}

/// Finish building the [`Report`].
pub fn finish(self) -> Report<'a, S> {
Report {
pub fn finish<C: Cache<S::SourceId>>(self, cache: C) -> Report<'a, S> {
let mut report = Report {
kind: self.kind,
code: self.code,
msg: self.msg,
Expand All @@ -313,7 +337,11 @@ impl<'a, S: Span> ReportBuilder<'a, S> {
location: self.location,
labels: self.labels,
config: self.config,
}
rendered: None
};
report.rendered = Some(report.write_to_string(cache));

report
}
}

Expand Down
68 changes: 39 additions & 29 deletions src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,15 +805,7 @@ mod tests {

use insta::assert_snapshot;

use crate::{Cache, CharSet, Config, Label, Report, ReportKind, Source, Span};

impl<S: Span> Report<'_, S> {
fn write_to_string<C: Cache<S::SourceId>>(&self, cache: C) -> String {
let mut vec = Vec::new();
self.write(cache, &mut vec).unwrap();
String::from_utf8(vec).unwrap()
}
}
use crate::{CharSet, Config, Label, Report, ReportKind, Source};

fn no_color_and_ascii() -> Config {
Config::default()
Expand All @@ -828,8 +820,8 @@ mod tests {
let msg = Report::<Range<usize>>::build(ReportKind::Error, (), 0)
.with_config(no_color_and_ascii())
.with_message("can't compare apples with oranges")
.finish()
.write_to_string(Source::from(""));
.finish(Source::from(""))
.to_string();
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
"###)
Expand All @@ -843,8 +835,8 @@ mod tests {
.with_message("can't compare apples with oranges")
.with_label(Label::new(0..5))
.with_label(Label::new(9..15))
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
// TODO: it would be nice if these spans still showed up (like codespan-reporting does)
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
Expand All @@ -863,8 +855,8 @@ mod tests {
.with_message("can't compare apples with oranges")
.with_label(Label::new(0..5).with_message("This is an apple"))
.with_label(Label::new(9..15).with_message("This is an orange"))
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
// TODO: it would be nice if these lines didn't cross
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
Expand All @@ -888,8 +880,8 @@ mod tests {
.with_label(
Label::new(source.len() - 5..source.len()).with_message("This is an orange"),
)
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
// TODO: it would be nice if the start of long lines would be omitted (like rustc does)
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
Expand All @@ -908,8 +900,8 @@ mod tests {
let msg = Report::<Range<usize>>::build(ReportKind::Error, (), 0)
.with_config(no_color_and_ascii())
.with_label(Label::new(0..source.len()).with_message("illegal comparison"))
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
// TODO: it would be nice if the 2nd line wasn't omitted
assert_snapshot!(msg, @r###"
Error:
Expand All @@ -931,8 +923,8 @@ mod tests {
.with_config(no_color_and_ascii())
.with_label(Label::new(0..source.len()).with_message("URL"))
.with_label(Label::new(0..source.find(':').unwrap()).with_message("scheme"))
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
// TODO: it would be nice if you could tell where the spans start and end.
assert_snapshot!(msg, @r###"
Error:
Expand All @@ -959,8 +951,8 @@ mod tests {
.with_label(Label::new(9..15).with_message("This is an orange"))
.with_label(Label::new(9..15).with_message("Have I mentioned that this is an orange?"))
.with_label(Label::new(9..15).with_message("No really, have I mentioned that?"))
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
,-[<unknown>:1:1]
Expand Down Expand Up @@ -991,8 +983,8 @@ mod tests {
.with_label(Label::new(0..5).with_message("This is an apple"))
.with_label(Label::new(9..15).with_message("This is an orange"))
.with_note("stop trying ... this is a fruitless endeavor")
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
,-[<unknown>:1:1]
Expand All @@ -1017,8 +1009,8 @@ mod tests {
.with_label(Label::new(0..5).with_message("This is an apple"))
.with_label(Label::new(9..15).with_message("This is an orange"))
.with_help("have you tried peeling the orange?")
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
,-[<unknown>:1:1]
Expand All @@ -1044,8 +1036,8 @@ mod tests {
.with_label(Label::new(9..15).with_message("This is an orange"))
.with_help("have you tried peeling the orange?")
.with_note("stop trying ... this is a fruitless endeavor")
.finish()
.write_to_string(Source::from(source));
.finish(Source::from(source))
.to_string();
assert_snapshot!(msg, @r###"
Error: can't compare apples with oranges
,-[<unknown>:1:1]
Expand All @@ -1062,4 +1054,22 @@ mod tests {
---'
"###)
}

#[test]
fn report_to_error() {
let source = "apple == orange;";
let msg = Report::<Range<usize>>::build(ReportKind::Error, (), 0)
.with_config(no_color_and_ascii())
.with_message("can't compare apples with oranges")
.with_label(Label::new(0..5).with_message("This is an apple"))
.with_label(Label::new(9..15).with_message("This is an orange"))
.with_help("have you tried peeling the orange?")
.with_note("stop trying ... this is a fruitless endeavor")
.finish(Source::from(source));

let err: &dyn std::error::Error = &msg; // This bit compiling proves it is Error

println!("{err}");
println!("{err:?}");
}
}