use crate::syntax::{Location, ParserError}; use codespan_reporting::diagnostic::Diagnostic; use codespan_reporting::files; use std::io; #[derive(Debug)] pub enum Error { IOError(io::Error), InternalFileDBError(files::Error), ParserError(ParserError), BindingSiteFailure(Location, String), UnboundVariable(Location, String), InternalError(Location, String), } fn display_expected(expected: &[String]) -> String { match expected.len() { 0 => "".to_string(), 1 => format!("; expected {}", expected[0]), 2 => format!("; expected {} or {}", expected[0], expected[1]), n => format!( "; expected {}or {}", comma_separate(&expected[0..n - 1]), expected[n - 1] ), } } fn comma_separate(strings: &[String]) -> String { let mut result = String::new(); for s in strings.iter() { result.push_str(s); result.push_str(", "); } result } impl From for Diagnostic { fn from(x: Error) -> Self { match &x { Error::IOError(e) => Diagnostic::error().with_message(format!("{}", e)), Error::InternalFileDBError(e) => Diagnostic::error().with_message(format!("{}", e)), Error::ParserError(pe) => match pe { // this was just a token we didn't understand ParserError::InvalidToken(location) => location .labelled_error("extremely odd token") .with_message("encountered extremely confusing token"), // unexpected EOF! ParserError::UnrecognizedEOF(location, expected) => location.error().with_message( format!("expected enf of file{}", display_expected(expected)), ), // encountered a token where it shouldn't be ParserError::UnrecognizedToken(start, end, token, expected) => { let expected_str = format!("unexpected token {}{}", token, display_expected(expected)); let unexpected_str = format!("unexpected token {}", token); let mut labels = start.range_label(end); Diagnostic::error() .with_labels( labels .drain(..) .map(|l| l.with_message(unexpected_str.clone())) .collect(), ) .with_message(expected_str) } // I think we get this when we get a token, but were expected EOF ParserError::ExtraToken(start, token, end) => { let expected_str = format!("unexpected token {} after the expected end of file", token); let unexpected_str = format!("unexpected token {}", token); let mut labels = start.range_label(end); Diagnostic::error() .with_labels( labels .drain(..) .map(|l| l.with_message(unexpected_str.clone())) .collect(), ) .with_message(expected_str) } // simple lexer errors ParserError::LexFailure(location) => { location.error().with_message("unexpected character") } }, Error::BindingSiteFailure(location, name) => location .labelled_error("discovered here") .with_message(format!( "Internal Error: Lost binding site for bound variable {}", name )), Error::UnboundVariable(location, name) => location .labelled_error("unbound here") .with_message(format!("Unbound variable '{}'", name)), Error::InternalError(location, string) => location .labelled_error("this is related") .with_message(format!("Internal error: {}", string)), } } }