From c2ca65611c1b1f6071295f266459d444881d1179 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Wed, 6 Apr 2022 23:48:37 +0200 Subject: [PATCH] Make `ParseError` a `std::error::Error` Previously the `ParseError` struct did not implement `std::error::Error` or `std::fmt::Display`. This meant that `ParseError` was not boxable into an "any error" box like `anyhow::Error`. This commit adds Error and Display implementations for ParseError and friends. Fixes #247 Closes #298 Closes #262 --- src/parser.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 8484eb12..535e7895 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,6 +5,7 @@ use crate::cow_rc_str::CowRcStr; use crate::tokenizer::{SourceLocation, SourcePosition, Token, Tokenizer}; use smallvec::SmallVec; +use std::fmt; use std::ops::BitOr; use std::ops::Range; @@ -53,6 +54,24 @@ pub enum BasicParseErrorKind<'i> { QualifiedRuleInvalid, } +impl<'i> fmt::Display for BasicParseErrorKind<'i> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BasicParseErrorKind::UnexpectedToken(token) => { + write!(f, "unexpected token: {:?}", token) + } + BasicParseErrorKind::EndOfInput => write!(f, "unexpected end of input"), + BasicParseErrorKind::AtRuleInvalid(rule) => { + write!(f, "invalid @ rule encountered: '@{}'", rule) + } + BasicParseErrorKind::AtRuleBodyInvalid => write!(f, "invalid @ rule body encountered"), + BasicParseErrorKind::QualifiedRuleInvalid => { + write!(f, "invalid qualified rule encountered") + } + } + } +} + /// The fundamental parsing errors that can be triggered by built-in parsing routines. #[derive(Clone, Debug, PartialEq)] pub struct BasicParseError<'i> { @@ -123,6 +142,15 @@ impl<'i, T> ParseErrorKind<'i, T> { } } +impl<'i, E: fmt::Display> fmt::Display for ParseErrorKind<'i, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ParseErrorKind::Basic(ref basic) => basic.fmt(f), + ParseErrorKind::Custom(ref custom) => custom.fmt(f), + } + } +} + /// Extensible parse errors that can be encountered by client parsing implementations. #[derive(Clone, Debug, PartialEq)] pub struct ParseError<'i, E> { @@ -137,7 +165,7 @@ impl<'i, T> ParseError<'i, T> { pub fn basic(self) -> BasicParseError<'i> { match self.kind { ParseErrorKind::Basic(kind) => BasicParseError { - kind: kind, + kind, location: self.location, }, ParseErrorKind::Custom(_) => panic!("Not a basic parse error"), @@ -156,6 +184,14 @@ impl<'i, T> ParseError<'i, T> { } } +impl<'i, E: fmt::Display> fmt::Display for ParseError<'i, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.kind.fmt(f) + } +} + +impl<'i, E: fmt::Display + fmt::Debug> std::error::Error for ParseError<'i, E> {} + /// The owned input for a parser. pub struct ParserInput<'i> { tokenizer: Tokenizer<'i>, @@ -396,7 +432,7 @@ impl<'i: 't, 't> Parser<'i, 't> { #[inline] pub fn new_basic_error(&self, kind: BasicParseErrorKind<'i>) -> BasicParseError<'i> { BasicParseError { - kind: kind, + kind, location: self.current_source_location(), } }