1e73685ebSopenharmony_ciuse codespan_reporting::diagnostic::{Diagnostic, Label}; 2e73685ebSopenharmony_ciuse codespan_reporting::files::SimpleFile; 3e73685ebSopenharmony_ciuse codespan_reporting::term::termcolor::StandardStream; 4e73685ebSopenharmony_ciuse codespan_reporting::term::{self, ColorArg}; 5e73685ebSopenharmony_ciuse std::ops::Range; 6e73685ebSopenharmony_ciuse structopt::StructOpt; 7e73685ebSopenharmony_ci 8e73685ebSopenharmony_ci#[derive(Debug, StructOpt)] 9e73685ebSopenharmony_ci#[structopt(name = "emit")] 10e73685ebSopenharmony_cipub struct Opts { 11e73685ebSopenharmony_ci #[structopt(long = "color", 12e73685ebSopenharmony_ci parse(try_from_str), 13e73685ebSopenharmony_ci default_value = "auto", 14e73685ebSopenharmony_ci possible_values = ColorArg::VARIANTS, 15e73685ebSopenharmony_ci case_insensitive = true 16e73685ebSopenharmony_ci )] 17e73685ebSopenharmony_ci color: ColorArg, 18e73685ebSopenharmony_ci} 19e73685ebSopenharmony_ci 20e73685ebSopenharmony_cifn main() -> anyhow::Result<()> { 21e73685ebSopenharmony_ci let file = SimpleFile::new( 22e73685ebSopenharmony_ci "main.rs", 23e73685ebSopenharmony_ci unindent::unindent( 24e73685ebSopenharmony_ci r#" 25e73685ebSopenharmony_ci fn main() { 26e73685ebSopenharmony_ci let foo: i32 = "hello, world"; 27e73685ebSopenharmony_ci foo += 1; 28e73685ebSopenharmony_ci } 29e73685ebSopenharmony_ci "#, 30e73685ebSopenharmony_ci ), 31e73685ebSopenharmony_ci ); 32e73685ebSopenharmony_ci 33e73685ebSopenharmony_ci let errors = [ 34e73685ebSopenharmony_ci Error::MismatchType( 35e73685ebSopenharmony_ci Item::new(20..23, "i32"), 36e73685ebSopenharmony_ci Item::new(31..45, "\"hello, world\""), 37e73685ebSopenharmony_ci ), 38e73685ebSopenharmony_ci Error::MutatingImmutable(Item::new(20..23, "foo"), Item::new(51..59, "foo += 1")), 39e73685ebSopenharmony_ci ]; 40e73685ebSopenharmony_ci 41e73685ebSopenharmony_ci let opts = Opts::from_args(); 42e73685ebSopenharmony_ci let writer = StandardStream::stderr(opts.color.into()); 43e73685ebSopenharmony_ci let config = codespan_reporting::term::Config::default(); 44e73685ebSopenharmony_ci for diagnostic in errors.iter().map(Error::report) { 45e73685ebSopenharmony_ci term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; 46e73685ebSopenharmony_ci } 47e73685ebSopenharmony_ci 48e73685ebSopenharmony_ci Ok(()) 49e73685ebSopenharmony_ci} 50e73685ebSopenharmony_ci 51e73685ebSopenharmony_ci/// An error enum that represent all possible errors within your program 52e73685ebSopenharmony_cienum Error { 53e73685ebSopenharmony_ci MismatchType(Item, Item), 54e73685ebSopenharmony_ci MutatingImmutable(Item, Item), 55e73685ebSopenharmony_ci} 56e73685ebSopenharmony_ci 57e73685ebSopenharmony_ciimpl Error { 58e73685ebSopenharmony_ci fn report(&self) -> Diagnostic<()> { 59e73685ebSopenharmony_ci match self { 60e73685ebSopenharmony_ci Error::MismatchType(left, right) => Diagnostic::error() 61e73685ebSopenharmony_ci .with_code("E0308") 62e73685ebSopenharmony_ci .with_message("mismatch types") 63e73685ebSopenharmony_ci .with_labels(vec![ 64e73685ebSopenharmony_ci Label::primary((), right.range.clone()).with_message(format!( 65e73685ebSopenharmony_ci "Expected `{}`, found: `{}`", 66e73685ebSopenharmony_ci left.content, right.content, 67e73685ebSopenharmony_ci )), 68e73685ebSopenharmony_ci Label::secondary((), left.range.clone()).with_message("expected due to this"), 69e73685ebSopenharmony_ci ]), 70e73685ebSopenharmony_ci Error::MutatingImmutable(original, mutating) => Diagnostic::error() 71e73685ebSopenharmony_ci .with_code("E0384") 72e73685ebSopenharmony_ci .with_message(format!( 73e73685ebSopenharmony_ci "cannot mutate immutable variable `{}`", 74e73685ebSopenharmony_ci original.content, 75e73685ebSopenharmony_ci )) 76e73685ebSopenharmony_ci .with_labels(vec![ 77e73685ebSopenharmony_ci Label::secondary((), original.range.clone()).with_message(unindent::unindent( 78e73685ebSopenharmony_ci &format!( 79e73685ebSopenharmony_ci r#" 80e73685ebSopenharmony_ci first assignment to `{0}` 81e73685ebSopenharmony_ci help: make this binding mutable: `mut {0}` 82e73685ebSopenharmony_ci "#, 83e73685ebSopenharmony_ci original.content, 84e73685ebSopenharmony_ci ), 85e73685ebSopenharmony_ci )), 86e73685ebSopenharmony_ci Label::primary((), mutating.range.clone()) 87e73685ebSopenharmony_ci .with_message("cannot assign twice to immutable variable"), 88e73685ebSopenharmony_ci ]), 89e73685ebSopenharmony_ci } 90e73685ebSopenharmony_ci } 91e73685ebSopenharmony_ci} 92e73685ebSopenharmony_ci 93e73685ebSopenharmony_ci/// An item in the source code to be used in the `Error` enum. 94e73685ebSopenharmony_ci/// In a more complex program it could also contain a `files::FileId` to handle errors that occur inside multiple files. 95e73685ebSopenharmony_cistruct Item { 96e73685ebSopenharmony_ci range: Range<usize>, 97e73685ebSopenharmony_ci content: String, 98e73685ebSopenharmony_ci} 99e73685ebSopenharmony_ci 100e73685ebSopenharmony_ciimpl Item { 101e73685ebSopenharmony_ci fn new(range: Range<usize>, content: impl Into<String>) -> Item { 102e73685ebSopenharmony_ci let content = content.into(); 103e73685ebSopenharmony_ci Item { range, content } 104e73685ebSopenharmony_ci } 105e73685ebSopenharmony_ci} 106