use std;
use std::fmt::{self, Debug, Display};
use std::iter::FromIterator;
use std::slice;
use std::vec;
use proc_macro2::{
Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
#[cfg(feature = "printing")]
use quote::ToTokens;
#[cfg(feature = "parsing")]
use crate::buffer::Cursor;
use crate::thread::ThreadBound;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone)]
pub struct Error {
messages: Vec<ErrorMessage>,
}
struct ErrorMessage {
start_span: ThreadBound<Span>,
end_span: ThreadBound<Span>,
message: String,
}
#[cfg(test)]
struct _Test
where
Error: Send + Sync;
impl Error {
pub fn new<T: Display>(span: Span, message: T) -> Self {
Error {
messages: vec![ErrorMessage {
start_span: ThreadBound::new(span),
end_span: ThreadBound::new(span),
message: message.to_string(),
}],
}
}
#[cfg(feature = "printing")]
pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
let mut iter = tokens.into_token_stream().into_iter();
let start = iter.next().map_or_else(Span::call_site, |t| t.span());
let end = iter.last().map_or(start, |t| t.span());
Error {
messages: vec![ErrorMessage {
start_span: ThreadBound::new(start),
end_span: ThreadBound::new(end),
message: message.to_string(),
}],
}
}
pub fn span(&self) -> Span {
let start = match self.messages[0].start_span.get() {
Some(span) => *span,
None => return Span::call_site(),
};
let end = match self.messages[0].end_span.get() {
Some(span) => *span,
None => return Span::call_site(),
};
start.join(end).unwrap_or(start)
}
pub fn to_compile_error(&self) -> TokenStream {
self.messages
.iter()
.map(ErrorMessage::to_compile_error)
.collect()
}
pub fn combine(&mut self, another: Error) {
self.messages.extend(another.messages)
}
}
impl ErrorMessage {
fn to_compile_error(&self) -> TokenStream {
let start = self
.start_span
.get()
.cloned()
.unwrap_or_else(Span::call_site);
let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
TokenStream::from_iter(vec![
TokenTree::Ident(Ident::new("compile_error", start)),
TokenTree::Punct({
let mut punct = Punct::new('!', Spacing::Alone);
punct.set_span(start);
punct
}),
TokenTree::Group({
let mut group = Group::new(Delimiter::Brace, {
TokenStream::from_iter(vec![TokenTree::Literal({
let mut string = Literal::string(&self.message);
string.set_span(end);
string
})])
});
group.set_span(end);
group
}),
])
}
}
#[cfg(feature = "parsing")]
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
if cursor.eof() {
Error::new(scope, format!("unexpected end of input, {}", message))
} else {
let span = crate::buffer::open_span_of_group(cursor);
Error::new(span, message)
}
}
impl Debug for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
if self.messages.len() == 1 {
formatter
.debug_tuple("Error")
.field(&self.messages[0])
.finish()
} else {
formatter
.debug_tuple("Error")
.field(&self.messages)
.finish()
}
}
}
impl Debug for ErrorMessage {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.message, formatter)
}
}
impl Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&self.messages[0].message)
}
}
impl Clone for ErrorMessage {
fn clone(&self) -> Self {
let start = self
.start_span
.get()
.cloned()
.unwrap_or_else(Span::call_site);
let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
ErrorMessage {
start_span: ThreadBound::new(start),
end_span: ThreadBound::new(end),
message: self.message.clone(),
}
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
"parse error"
}
}
impl From<LexError> for Error {
fn from(err: LexError) -> Self {
Error::new(Span::call_site(), format!("{:?}", err))
}
}
impl IntoIterator for Error {
type Item = Error;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
messages: self.messages.into_iter(),
}
}
}
pub struct IntoIter {
messages: vec::IntoIter<ErrorMessage>,
}
impl Iterator for IntoIter {
type Item = Error;
fn next(&mut self) -> Option<Self::Item> {
Some(Error {
messages: vec![self.messages.next()?],
})
}
}
impl<'a> IntoIterator for &'a Error {
type Item = Error;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter {
messages: self.messages.iter(),
}
}
}
pub struct Iter<'a> {
messages: slice::Iter<'a, ErrorMessage>,
}
impl<'a> Iterator for Iter<'a> {
type Item = Error;
fn next(&mut self) -> Option<Self::Item> {
Some(Error {
messages: vec![self.messages.next()?.clone()],
})
}
}