Error recovery

This commit is contained in:
2026-05-14 23:37:48 +02:00
parent 626990216c
commit 9b04a17fdd
13 changed files with 76 additions and 43 deletions
+36 -3
View File
@@ -1,14 +1,15 @@
use crate::Rule; use crate::Rule;
pub type ParseResult<'a, T> = Result<T, ParseError<'a>>; pub type ParseResult<'a, T, ET = T> = Result<T, ParseError<'a, ET>>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ParseError<'a> { pub enum ParseError<'a, T> {
PreAst(pest::error::Error<Rule>), PreAst(pest::error::Error<Rule>),
Ast { Ast {
span: pest::Span<'a>, span: pest::Span<'a>,
error_code: ErrorCode, error_code: ErrorCode,
error_message: String, error_message: String,
recovered: Option<T>,
}, },
} }
@@ -17,8 +18,40 @@ pub enum ErrorCode {
InvalidStatement = 200, InvalidStatement = 200,
} }
impl From<pest::error::Error<Rule>> for ParseError<'_> { impl<'a, F> ParseError<'a, F> {
pub fn get<T>(self) -> ParseError<'a, T> {
match self {
Self::Ast {
span,
error_code,
error_message,
..
} => ParseError::Ast {
span,
error_code,
error_message,
recovered: None,
},
Self::PreAst(pest_err) => ParseError::PreAst(pest_err),
}
}
}
impl<T> From<pest::error::Error<Rule>> for ParseError<'_, T> {
fn from(value: pest::error::Error<Rule>) -> Self { fn from(value: pest::error::Error<Rule>) -> Self {
Self::PreAst(value) Self::PreAst(value)
} }
} }
pub trait GetParseError<'a, F> {
fn get<T>(self) -> ParseResult<'a, F, T>;
}
impl<'a, F> GetParseError<'a, F> for ParseResult<'a, F> {
fn get<T>(self) -> ParseResult<'a, F, T> {
match self {
Ok(v) => Ok(v),
Err(e) => Err(e.get()),
}
}
}
+2 -2
View File
@@ -7,7 +7,7 @@ pub mod parser;
use ast::*; use ast::*;
use crate::error::ParseResult; use crate::error::{GetParseError, ParseResult};
#[derive(Parser)] #[derive(Parser)]
#[grammar = "./src/grammar.pest"] #[grammar = "./src/grammar.pest"]
@@ -20,7 +20,7 @@ pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec<TopLevel>> {
for pair in pairs.next().unwrap().into_inner() { for pair in pairs.next().unwrap().into_inner() {
if pair.as_rule() != Rule::EOI { if pair.as_rule() != Rule::EOI {
statements.push(TopLevel::try_from(pair)?); statements.push(TopLevel::try_from(pair).get()?);
} }
} }
+4 -4
View File
@@ -1,7 +1,7 @@
use crate::{Rule, ast::*, error::ParseError, parser::listen_rule}; use crate::{Rule, ast::*, error::ParseError, parser::listen_rule};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() { match pair.as_rule() {
@@ -21,7 +21,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDeclStmt { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDeclStmt {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() { match pair.as_rule() {
@@ -41,7 +41,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDeclStmt {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() { match pair.as_rule() {
@@ -76,7 +76,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDecl { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDecl {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() { match pair.as_rule() {
+11 -11
View File
@@ -1,11 +1,11 @@
use crate::{ use crate::{
Rule, Rule,
ast::*, ast::*,
error::{ParseError, ParseResult}, error::{GetParseError, ParseError, ParseResult},
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -19,7 +19,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
p.into_inner() p.into_inner()
.into_iter() .into_iter()
.map(Prefix::try_from) .map(Prefix::try_from)
.collect::<ParseResult<'a, Vec<_>>>() .collect::<ParseResult<'a, Vec<_>, _>>()
}) })
.transpose()? .transpose()?
.unwrap_or_default(); .unwrap_or_default();
@@ -47,7 +47,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(match pair.as_rule() { Ok(match pair.as_rule() {
@@ -63,7 +63,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -74,11 +74,11 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?),
Rule::call_px => Postfix::Call( Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::<ParseResult<
inner 'a,
.map(Expression::try_from) Vec<_>,
.collect::<ParseResult<'a, Vec<_>>>()?, _,
), >>()),
Rule::struct_px => Postfix::StructCall( Rule::struct_px => Postfix::StructCall(
inner inner
@@ -92,7 +92,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
.collect::<ParseResult<'a, Vec<_>>>()?, .collect::<ParseResult<'a, Vec<_>>>()?,
), ),
Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap()).get()?),
Rule::binary_px => { Rule::binary_px => {
let op_pair = inner.next().unwrap(); let op_pair = inner.next().unwrap();
+6 -6
View File
@@ -11,7 +11,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(Identifier(pair.as_str().to_string())) Ok(Identifier(pair.as_str().to_string()))
@@ -19,7 +19,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Path { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Path {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() { match pair.as_rule() {
@@ -34,7 +34,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Path {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -58,7 +58,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -97,11 +97,11 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern {
} }
impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result<Self, Self::Error> {
Ok(consume_rule(pairs, Rule::visibility) Ok(consume_rule(pairs, Rule::visibility)
.map(|pair| -> Result<Visibility, ParseError<'a>> { .map(|pair| -> Result<Visibility, ParseError<'a, Self>> {
if let Some(path) = pair.into_inner().next() { if let Some(path) = pair.into_inner().next() {
Ok(Visibility::PublicTarget(Path::try_from(path)?)) Ok(Visibility::PublicTarget(Path::try_from(path)?))
} else { } else {
+3 -3
View File
@@ -6,7 +6,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let statements = pair let statements = pair
@@ -25,7 +25,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -115,7 +115,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
+4 -4
View File
@@ -6,7 +6,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypePostfix { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypePostfix {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -39,7 +39,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypePostfix {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExprKind { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExprKind {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -69,7 +69,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExprKind {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -93,7 +93,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
+2 -2
View File
@@ -5,7 +5,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() { match pair.as_rule() {
@@ -41,7 +41,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
let items = next let items = next
.into_inner() .into_inner()
.map(Attribute::try_from) .map(Attribute::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?; .collect::<ParseResult<'a, Vec<_>, _>>()?;
Ok(Attribute::List { path, items }) Ok(Attribute::List { path, items })
} }
+2 -2
View File
@@ -1,7 +1,7 @@
use crate::{Rule, ast::*, error::ParseError, parser::consume_rule}; use crate::{Rule, ast::*, error::ParseError, parser::consume_rule};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
@@ -28,7 +28,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassItem { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassItem {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
+1 -1
View File
@@ -5,7 +5,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for EnumItem { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for EnumItem {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
+2 -2
View File
@@ -6,7 +6,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
@@ -72,7 +72,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(ParamList( Ok(ParamList(
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();
+2 -2
View File
@@ -12,7 +12,7 @@ use crate::{
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
@@ -35,7 +35,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel {
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
type Error = ParseError<'a>; type Error = ParseError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); let rule = pair.as_rule();