use crate::Rule; pub type AstResult<'a, T, ET = T> = Result>; #[derive(Debug, Clone)] pub enum ParseError<'a, T> { PreAst(pest::error::Error), Ast(AstError<'a, T>), } #[derive(Debug, Clone)] pub struct AstError<'a, T> { pub span: pest::Span<'a>, pub error_code: ErrorCode, pub error_message: String, pub recovered: Option, } #[derive(Debug, Clone)] pub enum ErrorCode { InvalidStatement = 200, } impl From> for ParseError<'_, T> { fn from(value: pest::error::Error) -> Self { Self::PreAst(value) } } impl<'a, T> From> for ParseError<'a, T> { fn from(value: AstError<'a, T>) -> Self { Self::Ast(value) } } impl<'a, F> AstError<'a, F> { pub fn get(self) -> AstError<'a, T> { AstError { span: self.span, error_code: self.error_code, error_message: self.error_message, recovered: None, } } } pub trait GetParseError<'a, F> { fn get(self) -> AstResult<'a, F, T>; } impl<'a, F> GetParseError<'a, F> for AstResult<'a, F> { fn get(self) -> AstResult<'a, F, T> { match self { Ok(v) => Ok(v), Err(e) => Err(e.get()), } } } impl<'a, F> GetParseError<'a, Option> for Result, AstError<'a, F>> { fn get(self) -> AstResult<'a, Option, T> { match self { Ok(v) => Ok(v), Err(e) => Err(e.get()), } } } impl<'a, F> GetParseError<'a, Option>> for Result>, AstError<'a, F>> { fn get(self) -> AstResult<'a, Option>, T> { match self { Ok(v) => Ok(v), Err(e) => Err(e.get()), } } } pub fn collect_recovered<'a, T, ET>( pairs: impl Iterator>, ) -> AstResult<'a, Vec, Vec> where T: TryFrom, Error = AstError<'a, ET>>, { collect_recovered_map(pairs, T::try_from) } pub fn collect_recovered_map<'a, T, F, ET>( pairs: impl Iterator>, f: F, ) -> AstResult<'a, Vec, Vec> where F: Fn(pest::iterators::Pair<'a, Rule>) -> AstResult<'a, T, ET>, { let mut items = Vec::new(); let mut last_error: Option> = None; for pair in pairs { match f(pair) { Ok(item) => items.push(item), Err(e) => { last_error = Some(e); } } } match last_error { Some(ast_err) => Err(AstError { span: ast_err.span, error_code: ast_err.error_code, error_message: ast_err.error_message, recovered: None, }), None => Ok(items), } }