use anyhow::bail; use codespan_reporting::{ diagnostic::{Diagnostic, Label}, files::SimpleFiles, term::{ emit, termcolor::{ColorChoice, StandardStream}, }, }; use lalrpop_util::{lexer::Token, ParseError}; pub trait SpannedErr { // TODO: Give these a default, so that &str can be used as default. fn lo(&self) -> usize; fn hi(&self) -> usize; // TODO: Allow more controll fn message(&self) -> String; } pub fn report_error( tree: Result>, file_name: &str, file_contents: &str, ) -> anyhow::Result { match tree { Ok(x) => Ok(x), Err(e) => { let mut err_files = SimpleFiles::new(); let err_writer = StandardStream::stderr(ColorChoice::Auto); let err_config = codespan_reporting::term::Config::default(); let main_file_id = err_files.add(file_name, file_contents); let emit_err = |d| emit(&mut err_writer.lock(), &err_config, &err_files, d); let err = match e { ParseError::InvalidToken { location } => Diagnostic::error() .with_message("Invalid token") .with_labels(vec![Label::primary(main_file_id, location..location + 1)]), ParseError::UnrecognizedEOF { location, expected } => Diagnostic::error() .with_message("Unexpected end of file") .with_labels(vec![Label::primary(main_file_id, location..location + 1)]) .with_notes(expected.iter().map(|e| format!("Expected {}", e)).collect()), ParseError::UnrecognizedToken { token, expected } => Diagnostic::error() .with_message("Unrecognized token") .with_labels(vec![Label::primary(main_file_id, token.0..token.2)]) .with_notes(expected.iter().map(|e| format!("Expected {}", e)).collect()), ParseError::ExtraToken { token } => Diagnostic::error() .with_message("Extra token") .with_labels(vec![Label::primary(main_file_id, token.0..token.2)]), ParseError::User { error } => Diagnostic::error() .with_message(error.message()) .with_labels(vec![Label::primary(main_file_id, error.lo()..error.hi())]), }; emit_err(&err)?; bail!("Parse error"); } } }