diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/codespan-reporting/examples | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/codespan-reporting/examples')
5 files changed, 901 insertions, 0 deletions
diff --git a/third_party/rust/codespan-reporting/examples/custom_files.rs b/third_party/rust/codespan-reporting/examples/custom_files.rs new file mode 100644 index 0000000000..dbbacda591 --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/custom_files.rs @@ -0,0 +1,197 @@ +//! An example that shows how to implement a simple custom file database. +//! The database uses 32-bit file-ids, which could be useful for optimizing +//! memory usage. +//! +//! To run this example, execute the following command from the top level of +//! this repository: +//! +//! ```sh +//! cargo run --example custom_files +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::term; +use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; +use std::ops::Range; + +fn main() -> anyhow::Result<()> { + let mut files = files::Files::new(); + + let file_id0 = files.add("0.greeting", "hello world!").unwrap(); + let file_id1 = files.add("1.greeting", "bye world").unwrap(); + + let messages = vec![ + Message::UnwantedGreetings { + greetings: vec![(file_id0, 0..5), (file_id1, 0..3)], + }, + Message::OverTheTopExclamations { + exclamations: vec![(file_id0, 11..12)], + }, + ]; + + let writer = StandardStream::stderr(ColorChoice::Always); + let config = term::Config::default(); + for message in &messages { + let writer = &mut writer.lock(); + term::emit(writer, &config, &files, &message.to_diagnostic())?; + } + + Ok(()) +} + +/// A module containing the file implementation +mod files { + use codespan_reporting::files; + use std::ops::Range; + + /// A file that is backed by an `Arc<String>`. + #[derive(Debug, Clone)] + struct File { + /// The name of the file. + name: String, + /// The source code of the file. + source: String, + /// The starting byte indices in the source code. + line_starts: Vec<usize>, + } + + impl File { + fn line_start(&self, line_index: usize) -> Result<usize, files::Error> { + use std::cmp::Ordering; + + match line_index.cmp(&self.line_starts.len()) { + Ordering::Less => Ok(self + .line_starts + .get(line_index) + .expect("failed despite previous check") + .clone()), + Ordering::Equal => Ok(self.source.len()), + Ordering::Greater => Err(files::Error::LineTooLarge { + given: line_index, + max: self.line_starts.len() - 1, + }), + } + } + } + + /// An opaque file identifier. + #[derive(Copy, Clone, PartialEq, Eq)] + pub struct FileId(u32); + + #[derive(Debug, Clone)] + pub struct Files { + files: Vec<File>, + } + + impl Files { + /// Create a new files database. + pub fn new() -> Files { + Files { files: Vec::new() } + } + + /// Add a file to the database, returning the handle that can be used to + /// refer to it again. + pub fn add( + &mut self, + name: impl Into<String>, + source: impl Into<String>, + ) -> Option<FileId> { + use std::convert::TryFrom; + + let file_id = FileId(u32::try_from(self.files.len()).ok()?); + let name = name.into(); + let source = source.into(); + let line_starts = files::line_starts(&source).collect(); + + self.files.push(File { + name, + line_starts, + source, + }); + + Some(file_id) + } + + /// Get the file corresponding to the given id. + fn get(&self, file_id: FileId) -> Result<&File, files::Error> { + self.files + .get(file_id.0 as usize) + .ok_or(files::Error::FileMissing) + } + } + + impl<'files> files::Files<'files> for Files { + type FileId = FileId; + type Name = &'files str; + type Source = &'files str; + + fn name(&self, file_id: FileId) -> Result<&str, files::Error> { + Ok(self.get(file_id)?.name.as_ref()) + } + + fn source(&self, file_id: FileId) -> Result<&str, files::Error> { + Ok(&self.get(file_id)?.source) + } + + fn line_index(&self, file_id: FileId, byte_index: usize) -> Result<usize, files::Error> { + self.get(file_id)? + .line_starts + .binary_search(&byte_index) + .or_else(|next_line| Ok(next_line - 1)) + } + + fn line_range( + &self, + file_id: FileId, + line_index: usize, + ) -> Result<Range<usize>, files::Error> { + let file = self.get(file_id)?; + let line_start = file.line_start(line_index)?; + let next_line_start = file.line_start(line_index + 1)?; + + Ok(line_start..next_line_start) + } + } +} + +/// A Diagnostic message. +enum Message { + UnwantedGreetings { + greetings: Vec<(files::FileId, Range<usize>)>, + }, + OverTheTopExclamations { + exclamations: Vec<(files::FileId, Range<usize>)>, + }, +} + +impl Message { + fn to_diagnostic(&self) -> Diagnostic<files::FileId> { + match self { + Message::UnwantedGreetings { greetings } => Diagnostic::error() + .with_message("greetings are not allowed") + .with_labels( + greetings + .iter() + .map(|(file_id, range)| { + Label::primary(*file_id, range.clone()).with_message("a greeting") + }) + .collect(), + ) + .with_notes(vec![ + "found greetings!".to_owned(), + "pleas no greetings :(".to_owned(), + ]), + Message::OverTheTopExclamations { exclamations } => Diagnostic::error() + .with_message("over-the-top exclamations") + .with_labels( + exclamations + .iter() + .map(|(file_id, range)| { + Label::primary(*file_id, range.clone()).with_message("an exclamation") + }) + .collect(), + ) + .with_notes(vec!["ridiculous!".to_owned()]), + } + } +} diff --git a/third_party/rust/codespan-reporting/examples/peg_calculator.rs b/third_party/rust/codespan-reporting/examples/peg_calculator.rs new file mode 100644 index 0000000000..882ce6da8c --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/peg_calculator.rs @@ -0,0 +1,68 @@ +//! An example of using `peg` with `codespan_reporting`. +//! +//! To run this example, execute the following command from the top level of +//! this repository: +//! +//! ```sh +//! cargo run --example peg_calculator +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term; +use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; +use rustyline::error::ReadlineError; +use rustyline::Editor; + +peg::parser! { + grammar arithmetic() for str { + rule number() -> i64 + = n:$(['0'..='9']+) { n.parse().unwrap() } + + pub rule calculate() -> i64 = precedence!{ + x:(@) "+" y:@ { x + y } + x:(@) "-" y:@ { x - y } + "-" v:@ { - v } + -- + x:(@) "*" y:@ { x * y } + x:(@) "/" y:@ { x / y } + -- + x:@ "^" y:(@) { i64::pow(x, y as u32) } + v:@ "!" { (1..v+1).product() } + -- + "(" v:calculate() ")" { v } + n:number() { n } + } + } +} + +fn main() -> anyhow::Result<()> { + let writer = StandardStream::stderr(ColorChoice::Always); + let config = codespan_reporting::term::Config::default(); + let mut editor = Editor::<()>::new(); + + loop { + let line = match editor.readline("> ") { + Ok(line) => line, + Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => return Ok(()), + Err(error) => return Err(error.into()), + }; + + match arithmetic::calculate(&line) { + Ok(number) => println!("{}", number), + Err(error) => { + let file = SimpleFile::new("<repl>", line); + + let start = error.location.offset; + let diagnostic = Diagnostic::error() + .with_message("parse error") + .with_labels(vec![ + Label::primary((), start..start).with_message("parse error") + ]) + .with_notes(vec![format!("expected: {}", error.expected)]); + + term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; + } + } + } +} diff --git a/third_party/rust/codespan-reporting/examples/readme_preview.rs b/third_party/rust/codespan-reporting/examples/readme_preview.rs new file mode 100644 index 0000000000..2cf96f60cb --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/readme_preview.rs @@ -0,0 +1,356 @@ +//! Renders the preview SVG for the README. +//! +//! To update the preview, execute the following command from the top level of +//! the repository: +//! +//! ```sh +//! cargo run --example readme_preview svg > codespan-reporting/assets/readme_preview.svg +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term::termcolor::{Color, ColorSpec, StandardStream, WriteColor}; +use codespan_reporting::term::{self, ColorArg}; +use std::io::{self, Write}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "emit")] +pub enum Opts { + /// Render SVG output + Svg, + /// Render Stderr output + Stderr { + /// Configure coloring of output + #[structopt( + long = "color", + parse(try_from_str), + default_value = "auto", + possible_values = ColorArg::VARIANTS, + case_insensitive = true + )] + color: ColorArg, + }, +} + +fn main() -> anyhow::Result<()> { + let file = SimpleFile::new( + "FizzBuzz.fun", + unindent::unindent( + r#" + module FizzBuzz where + + fizz₁ : Nat → String + fizz₁ num = case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + + fizz₂ : Nat → String + fizz₂ num = + case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + "#, + ), + ); + + let diagnostics = [Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary((), 328..331).with_message("expected `String`, found `Nat`"), + Label::secondary((), 211..331).with_message("`case` clauses have incompatible types"), + Label::secondary((), 258..268).with_message("this is found to be of type `String`"), + Label::secondary((), 284..290).with_message("this is found to be of type `String`"), + Label::secondary((), 306..312).with_message("this is found to be of type `String`"), + Label::secondary((), 186..192).with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )])]; + + // let mut files = SimpleFiles::new(); + match Opts::from_args() { + Opts::Svg => { + let mut buffer = Vec::new(); + let mut writer = HtmlEscapeWriter::new(SvgWriter::new(&mut buffer)); + let config = codespan_reporting::term::Config { + styles: codespan_reporting::term::Styles::with_blue(Color::Blue), + ..codespan_reporting::term::Config::default() + }; + + for diagnostic in &diagnostics { + term::emit(&mut writer, &config, &file, &diagnostic)?; + } + + let num_lines = buffer.iter().filter(|byte| **byte == b'\n').count() + 1; + + let padding = 10; + let font_size = 12; + let line_spacing = 3; + let width = 882; + let height = padding + num_lines * (font_size + line_spacing) + padding; + + let stdout = std::io::stdout(); + let writer = &mut stdout.lock(); + + write!( + writer, + r#"<svg viewBox="0 0 {width} {height}" xmlns="http://www.w3.org/2000/svg"> + <style> + /* https://github.com/aaron-williamson/base16-alacritty/blob/master/colors/base16-tomorrow-night-256.yml */ + pre {{ + background: #1d1f21; + margin: 0; + padding: {padding}px; + border-radius: 6px; + color: #ffffff; + font: {font_size}px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + }} + + pre .bold {{ font-weight: bold; }} + + pre .fg.black {{ color: #1d1f21; }} + pre .fg.red {{ color: #cc6666; }} + pre .fg.green {{ color: #b5bd68; }} + pre .fg.yellow {{ color: #f0c674; }} + pre .fg.blue {{ color: #81a2be; }} + pre .fg.magenta {{ color: #b294bb; }} + pre .fg.cyan {{ color: #8abeb7; }} + pre .fg.white {{ color: #c5c8c6; }} + + pre .fg.black.bright {{ color: #969896; }} + pre .fg.red.bright {{ color: #cc6666; }} + pre .fg.green.bright {{ color: #b5bd68; }} + pre .fg.yellow.bright {{ color: #f0c674; }} + pre .fg.blue.bright {{ color: #81a2be; }} + pre .fg.magenta.bright {{ color: #b294bb; }} + pre .fg.cyan.bright {{ color: #8abeb7; }} + pre .fg.white.bright {{ color: #ffffff; }} + + pre .bg.black {{ background-color: #1d1f21; }} + pre .bg.red {{ background-color: #cc6666; }} + pre .bg.green {{ background-color: #b5bd68; }} + pre .bg.yellow {{ background-color: #f0c674; }} + pre .bg.blue {{ background-color: #81a2be; }} + pre .bg.magenta {{ background-color: #b294bb; }} + pre .bg.cyan {{ background-color: #8abeb7; }} + pre .bg.white {{ background-color: #c5c8c6; }} + + pre .bg.black.bright {{ background-color: #969896; }} + pre .bg.red.bright {{ background-color: #cc6666; }} + pre .bg.green.bright {{ background-color: #b5bd68; }} + pre .bg.yellow.bright {{ background-color: #f0c674; }} + pre .bg.blue.bright {{ background-color: #81a2be; }} + pre .bg.magenta.bright {{ background-color: #b294bb; }} + pre .bg.cyan.bright {{ background-color: #8abeb7; }} + pre .bg.white.bright {{ background-color: #ffffff; }} + </style> + + <foreignObject x="0" y="0" width="{width}" height="{height}"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <pre>"#, + padding = padding, + font_size = font_size, + width = width, + height = height, + )?; + + writer.write_all(&buffer)?; + + write!( + writer, + "</pre> + </div> + </foreignObject> +</svg> +" + )?; + } + Opts::Stderr { color } => { + let writer = StandardStream::stderr(color.into()); + let config = codespan_reporting::term::Config::default(); + for diagnostic in &diagnostics { + term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; + } + } + } + + Ok(()) +} + +/// Rudimentary HTML escaper which performs the following conversions: +/// +/// - `<` ⇒ `<` +/// - `>` ⇒ `>` +/// - `&` ⇒ `&` +pub struct HtmlEscapeWriter<W> { + upstream: W, +} + +impl<W> HtmlEscapeWriter<W> { + pub fn new(upstream: W) -> HtmlEscapeWriter<W> { + HtmlEscapeWriter { upstream } + } +} + +impl<W: Write> Write for HtmlEscapeWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let mut last_term = 0usize; + for (i, byte) in buf.iter().enumerate() { + let escape = match byte { + b'<' => &b"<"[..], + b'>' => &b">"[..], + b'&' => &b"&"[..], + _ => continue, + }; + self.upstream.write_all(&buf[last_term..i])?; + last_term = i + 1; + self.upstream.write_all(escape)?; + } + self.upstream.write_all(&buf[last_term..])?; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + self.upstream.flush() + } +} + +impl<W: WriteColor> WriteColor for HtmlEscapeWriter<W> { + fn supports_color(&self) -> bool { + self.upstream.supports_color() + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.upstream.set_color(spec) + } + + fn reset(&mut self) -> io::Result<()> { + self.upstream.reset() + } +} + +pub struct SvgWriter<W> { + upstream: W, + color: ColorSpec, +} + +impl<W> SvgWriter<W> { + pub fn new(upstream: W) -> SvgWriter<W> { + SvgWriter { + upstream, + color: ColorSpec::new(), + } + } +} + +impl<W: Write> Write for SvgWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.upstream.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.upstream.flush() + } +} + +impl<W: Write> WriteColor for SvgWriter<W> { + fn supports_color(&self) -> bool { + true + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + #![allow(unused_assignments)] + + if self.color == *spec { + return Ok(()); + } else { + if !self.color.is_none() { + write!(self, "</span>")?; + } + self.color = spec.clone(); + } + + if spec.is_none() { + write!(self, "</span>")?; + return Ok(()); + } else { + write!(self, "<span class=\"")?; + } + + let mut first = true; + + fn write_first<W: Write>(first: bool, writer: &mut SvgWriter<W>) -> io::Result<bool> { + if !first { + write!(writer, " ")?; + } + + Ok(false) + }; + + fn write_color<W: Write>(color: &Color, writer: &mut SvgWriter<W>) -> io::Result<()> { + match color { + Color::Black => write!(writer, "black"), + Color::Blue => write!(writer, "blue"), + Color::Green => write!(writer, "green"), + Color::Red => write!(writer, "red"), + Color::Cyan => write!(writer, "cyan"), + Color::Magenta => write!(writer, "magenta"), + Color::Yellow => write!(writer, "yellow"), + Color::White => write!(writer, "white"), + // TODO: other colors + _ => Ok(()), + } + }; + + if let Some(fg) = spec.fg() { + first = write_first(first, self)?; + write!(self, "fg ")?; + write_color(fg, self)?; + } + + if let Some(bg) = spec.bg() { + first = write_first(first, self)?; + write!(self, "bg ")?; + write_color(bg, self)?; + } + + if spec.bold() { + first = write_first(first, self)?; + write!(self, "bold")?; + } + + if spec.underline() { + first = write_first(first, self)?; + write!(self, "underline")?; + } + + if spec.intense() { + first = write_first(first, self)?; + write!(self, "bright")?; + } + + write!(self, "\">")?; + + Ok(()) + } + + fn reset(&mut self) -> io::Result<()> { + let color = self.color.clone(); + + if color != ColorSpec::new() { + write!(self, "</span>")?; + self.color = ColorSpec::new(); + } + + Ok(()) + } +} diff --git a/third_party/rust/codespan-reporting/examples/reusable_diagnostic.rs b/third_party/rust/codespan-reporting/examples/reusable_diagnostic.rs new file mode 100644 index 0000000000..d05dee8549 --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/reusable_diagnostic.rs @@ -0,0 +1,105 @@ +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term::termcolor::StandardStream; +use codespan_reporting::term::{self, ColorArg}; +use std::ops::Range; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "emit")] +pub struct Opts { + #[structopt(long = "color", + parse(try_from_str), + default_value = "auto", + possible_values = ColorArg::VARIANTS, + case_insensitive = true + )] + color: ColorArg, +} + +fn main() -> anyhow::Result<()> { + let file = SimpleFile::new( + "main.rs", + unindent::unindent( + r#" + fn main() { + let foo: i32 = "hello, world"; + foo += 1; + } + "#, + ), + ); + + let errors = [ + Error::MismatchType( + Item::new(20..23, "i32"), + Item::new(31..45, "\"hello, world\""), + ), + Error::MutatingImmutable(Item::new(20..23, "foo"), Item::new(51..59, "foo += 1")), + ]; + + let opts = Opts::from_args(); + let writer = StandardStream::stderr(opts.color.into()); + let config = codespan_reporting::term::Config::default(); + for diagnostic in errors.iter().map(Error::report) { + term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; + } + + Ok(()) +} + +/// An error enum that represent all possible errors within your program +enum Error { + MismatchType(Item, Item), + MutatingImmutable(Item, Item), +} + +impl Error { + fn report(&self) -> Diagnostic<()> { + match self { + Error::MismatchType(left, right) => Diagnostic::error() + .with_code("E0308") + .with_message("mismatch types") + .with_labels(vec![ + Label::primary((), right.range.clone()).with_message(format!( + "Expected `{}`, found: `{}`", + left.content, right.content, + )), + Label::secondary((), left.range.clone()).with_message("expected due to this"), + ]), + Error::MutatingImmutable(original, mutating) => Diagnostic::error() + .with_code("E0384") + .with_message(format!( + "cannot mutate immutable variable `{}`", + original.content, + )) + .with_labels(vec![ + Label::secondary((), original.range.clone()).with_message(unindent::unindent( + &format!( + r#" + first assignment to `{0}` + help: make this binding mutable: `mut {0}` + "#, + original.content, + ), + )), + Label::primary((), mutating.range.clone()) + .with_message("cannot assign twice to immutable variable"), + ]), + } + } +} + +/// An item in the source code to be used in the `Error` enum. +/// In a more complex program it could also contain a `files::FileId` to handle errors that occur inside multiple files. +struct Item { + range: Range<usize>, + content: String, +} + +impl Item { + fn new(range: Range<usize>, content: impl Into<String>) -> Item { + let content = content.into(); + Item { range, content } + } +} diff --git a/third_party/rust/codespan-reporting/examples/term.rs b/third_party/rust/codespan-reporting/examples/term.rs new file mode 100644 index 0000000000..19bf8503c0 --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/term.rs @@ -0,0 +1,175 @@ +//! To run this example, execute the following command from the top level of +//! this repository: +//! +//! ```sh +//! cargo run --example term +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFiles; +use codespan_reporting::term::termcolor::StandardStream; +use codespan_reporting::term::{self, ColorArg}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "emit")] +pub struct Opts { + /// Configure coloring of output + #[structopt( + long = "color", + parse(try_from_str), + default_value = "auto", + possible_values = ColorArg::VARIANTS, + case_insensitive = true + )] + pub color: ColorArg, +} + +fn main() -> anyhow::Result<()> { + let opts = Opts::from_args(); + let mut files = SimpleFiles::new(); + + let file_id1 = files.add( + "Data/Nat.fun", + unindent::unindent( + " + module Data.Nat where + + data Nat : Type where + zero : Nat + succ : Nat → Nat + + {-# BUILTIN NATRAL Nat #-} + + infixl 6 _+_ _-_ + + _+_ : Nat → Nat → Nat + zero + n₂ = n₂ + succ n₁ + n₂ = succ (n₁ + n₂) + + _-_ : Nat → Nat → Nat + n₁ - zero = n₁ + zero - succ n₂ = zero + succ n₁ - succ n₂ = n₁ - n₂ + ", + ), + ); + + let file_id2 = files.add( + "Test.fun", + unindent::unindent( + r#" + module Test where + + _ : Nat + _ = 123 + "hello" + "#, + ), + ); + + let file_id3 = files.add( + "FizzBuzz.fun", + unindent::unindent( + r#" + module FizzBuzz where + + fizz₁ : Nat → String + fizz₁ num = case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + + fizz₂ : Nat → String + fizz₂ num = + case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + "#, + ), + ); + + let diagnostics = [ + // Unknown builtin error + Diagnostic::error() + .with_message("unknown builtin: `NATRAL`") + .with_labels(vec![ + Label::primary(file_id1, 96..102).with_message("unknown builtin") + ]) + .with_notes(vec![ + "there is a builtin with a similar name: `NATURAL`".to_owned() + ]), + // Unused parameter warning + Diagnostic::warning() + .with_message("unused parameter pattern: `n₂`") + .with_labels(vec![ + Label::primary(file_id1, 285..289).with_message("unused parameter") + ]) + .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()]), + // Unexpected type error + Diagnostic::error() + .with_message("unexpected type in application of `_+_`") + .with_code("E0001") + .with_labels(vec![ + Label::primary(file_id2, 37..44).with_message("expected `Nat`, found `String`"), + Label::secondary(file_id1, 130..155) + .with_message("based on the definition of `_+_`"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `Nat` + found type `String` + ", + )]), + // Incompatible match clause error + Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary(file_id3, 163..166).with_message("expected `String`, found `Nat`"), + Label::secondary(file_id3, 62..166) + .with_message("`case` clauses have incompatible types"), + Label::secondary(file_id3, 41..47) + .with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )]), + // Incompatible match clause error + Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary(file_id3, 328..331).with_message("expected `String`, found `Nat`"), + Label::secondary(file_id3, 211..331) + .with_message("`case` clauses have incompatible types"), + Label::secondary(file_id3, 258..268) + .with_message("this is found to be of type `String`"), + Label::secondary(file_id3, 284..290) + .with_message("this is found to be of type `String`"), + Label::secondary(file_id3, 306..312) + .with_message("this is found to be of type `String`"), + Label::secondary(file_id3, 186..192) + .with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )]), + ]; + + let writer = StandardStream::stderr(opts.color.into()); + let config = codespan_reporting::term::Config::default(); + for diagnostic in &diagnostics { + term::emit(&mut writer.lock(), &config, &files, &diagnostic)?; + } + + Ok(()) +} |