dont store source in SpannedError

This commit is contained in:
Robin Appelman 2020-12-13 17:08:11 +01:00
commit 5e8ad8f513
3 changed files with 74 additions and 37 deletions

View file

@ -13,7 +13,9 @@ use std::num::ParseFloatError;
use std::str::ParseBoolError;
use thiserror::Error;
/// An error and related source span, will print out the problematic code fragment and error on `Display`
/// An error and related source span
///
/// You can pretty-print the error with the offending source by using `display_with_source`
///
/// ## Example
///
@ -28,19 +30,14 @@ use thiserror::Error;
/// ```
///
#[derive(Debug)]
pub struct SpannedError<'a, T: Error + Debug> {
pub struct SpannedError<T: Error + Debug> {
span: Span,
source: &'a str,
error: T,
}
impl<'a, T: Error + Debug> SpannedError<'a, T> {
pub fn new(error: T, span: Span, source: &'a str) -> Self {
SpannedError {
span,
source,
error,
}
impl<T: Error + Debug> SpannedError<T> {
pub fn new(error: T, span: Span) -> Self {
SpannedError { span, error }
}
pub fn error(&self) -> &T {
@ -48,23 +45,29 @@ impl<'a, T: Error + Debug> SpannedError<'a, T> {
}
}
impl<'a, T: Error + Debug + 'static> Error for SpannedError<'a, T> {
impl<T: Error + Debug + 'static> Error for SpannedError<T> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.error)
}
}
impl<T: Error + Debug> Display for SpannedError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as Display>::fmt(&self.error, f)
}
}
const METRICS: DefaultMetrics = DefaultMetrics::with_tab_stop(4);
impl<'a, T: Error + Debug> fmt::Display for SpannedError<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let start = get_position(self.source, self.span.start);
let end = get_position(self.source, self.span.end);
impl<T: Error + Debug> SpannedError<T> {
pub fn display_with_source(&self, source: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let start = get_position(source, self.span.start);
let end = get_position(source, self.span.end);
let span = SourceSpan::new(start, end, end.next_line());
let mut fmt = Formatter::with_margin_color(Color::Blue);
let buffer = SourceBuffer::new(
self.source.chars().map(|char| Result::<char, ()>::Ok(char)),
source.chars().map(|char| Result::<char, ()>::Ok(char)),
Position::default(),
METRICS,
);
@ -186,15 +189,14 @@ impl ExpectToken for Token {
}
}
pub trait ResultExt<'a, T, E: Error + Debug> {
fn with_span(self, span: Span, source: &'a str) -> Result<T, SpannedError<'a, E>>;
pub trait ResultExt<T, E: Error + Debug> {
fn with_span(self, span: Span) -> Result<T, SpannedError<E>>;
}
impl<'a, T, E: Into<ParseError>> ResultExt<'a, T, ParseError> for Result<T, E> {
fn with_span(self, span: Span, source: &'a str) -> Result<T, SpannedError<'a, ParseError>> {
impl<T, E: Into<ParseError>> ResultExt<T, ParseError> for Result<T, E> {
fn with_span(self, span: Span) -> Result<T, SpannedError<ParseError>> {
self.map_err(|error| SpannedError {
span,
source,
error: error.into(),
})
}

View file

@ -1,4 +1,4 @@
use logos::Logos;
use logos::{Lexer, Logos, Span};
#[derive(Logos, Debug, PartialEq, Clone)]
pub enum Token {
@ -165,3 +165,38 @@ fn test_lex_float() {
assert_eq!(lex.next(), Some(Token::Float));
assert_eq!(lex.next(), None);
}
pub struct SpannedToken<'source> {
pub token: Token,
pub span: Span,
pub source: &'source str,
}
impl<'source> SpannedToken<'source> {
pub fn slice(&self) -> &'source str {
&self.source[self.span.clone()]
}
}
pub struct TokenStream<'source> {
lexer: Lexer<'source, Token>,
}
impl<'source> TokenStream<'source> {
pub fn source(&self) -> &'source str {
self.lexer.source()
}
}
impl<'source> Iterator for TokenStream<'source> {
type Item = SpannedToken<'source>;
fn next(&mut self) -> Option<Self::Item> {
let token = self.lexer.next()?;
Some(SpannedToken {
token,
span: self.lexer.span(),
source: self.lexer.source(),
})
}
}

View file

@ -43,7 +43,7 @@ impl<'source> Parser<'source> {
}
}
pub fn parse(&mut self) -> Result<Value, SpannedError<'source, ParseError>> {
pub fn parse(&mut self) -> Result<Value, SpannedError<ParseError>> {
let token = self
.lexer
.next()
@ -56,24 +56,24 @@ impl<'source> Parser<'source> {
Token::Array,
Token::SquareOpen,
])
.with_span(self.lexer.span(), self.source)?;
.with_span(self.lexer.span())?;
let value = match token {
Token::Bool => Value::Bool(
self.lexer
.slice()
.to_ascii_lowercase()
.parse()
.with_span(self.lexer.span(), self.source)?,
.with_span(self.lexer.span())?,
),
Token::Integer => {
Value::Int(parse_int(self.lexer.slice()).with_span(self.lexer.span(), self.source)?)
Value::Int(parse_int(self.lexer.slice()).with_span(self.lexer.span())?)
}
Token::Float => {
Value::Float(parse_float(self.lexer.slice()).with_span(self.lexer.span())?)
}
Token::LiteralString => {
Value::String(parse_string(self.lexer.slice()).with_span(self.lexer.span())?)
}
Token::Float => Value::Float(
parse_float(self.lexer.slice()).with_span(self.lexer.span(), self.source)?,
),
Token::LiteralString => Value::String(
parse_string(self.lexer.slice()).with_span(self.lexer.span(), self.source)?,
),
Token::Null => Value::Null,
Token::Array => Value::Array(self.parse_array(ArraySyntax::Long)?),
Token::SquareOpen => Value::Array(self.parse_array(ArraySyntax::Short)?),
@ -86,14 +86,14 @@ impl<'source> Parser<'source> {
fn parse_array(
&mut self,
syntax: ArraySyntax,
) -> Result<HashMap<Key, Value>, SpannedError<'source, ParseError>> {
) -> Result<HashMap<Key, Value>, SpannedError<ParseError>> {
let mut builder = ArrayBuilder::default();
if syntax == ArraySyntax::Long {
self.lexer
.next()
.expect_token(&[Token::BracketOpen])
.with_span(self.lexer.span(), self.source)?;
.with_span(self.lexer.span())?;
}
loop {
@ -115,7 +115,7 @@ impl<'source> Parser<'source> {
.lexer
.next()
.expect_token(&[syntax.close_bracket(), Token::Comma, Token::Arrow])
.with_span(self.lexer.span(), self.source)?;
.with_span(self.lexer.span())?;
match next {
Token::BracketClose => {
@ -137,7 +137,7 @@ impl<'source> Parser<'source> {
Value::String(str) => Key::String(str),
value => {
let err = ParseError::InvalidArrayKey(InvalidArrayKeyError(value));
let span_err = SpannedError::new(err, key_or_value_span, self.source);
let span_err = SpannedError::new(err, key_or_value_span);
return Err(span_err);
}
};
@ -147,7 +147,7 @@ impl<'source> Parser<'source> {
.lexer
.next()
.expect_token(&[syntax.close_bracket(), Token::Comma])
.with_span(self.lexer.span(), self.source)?
.with_span(self.lexer.span())?
{
Token::BracketClose => {
break;