From ef7ccc5aed2a2ac72e428ed69f05956f5af1c430 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 19:07:36 +0200 Subject: [PATCH 01/27] Error recovery --- parser/src/grammar.pest | 10 +++++++++- parser/src/lib.rs | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 547e347..bcaf9d9 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -52,6 +52,14 @@ visibility = { "pub" ~ ("(" ~ static_path ~ ")")? } mutable = { "mut" } var = { "var" } +// ====================================================== +// ERROR RECOVERY +// ====================================================== + +unexpected_statement = { + (!(semicolon | "}" | statement) ~ ANY)+ +} + // ====================================================== // GENERICS // ====================================================== @@ -303,7 +311,7 @@ block = { } statement_list = { - statement* + (statement | unexpected_statement)* } statement = _{ diff --git a/parser/src/lib.rs b/parser/src/lib.rs index e536c67..d89ac1e 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -491,6 +491,12 @@ impl From> for Statement { .collect(), ), + Rule::unexpected_statement => { + let pos = pair.as_span().start_pos().line_col(); + + panic!("({}:{}) Invalid Statement: {}", pos.0, pos.1, pair.as_str()) + } + _ => unimplemented!("{rule:#?}"), } } From fd48d6c9c6ee498a9e0689ca798d1efd3b2d938b Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 19:25:29 +0200 Subject: [PATCH 02/27] Making better errors --- parser/src/lib.rs | 21 ++++++++++++++++++--- src/compiler.rs | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index d89ac1e..77e9a45 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -9,10 +9,19 @@ use ast::*; #[grammar = "./src/grammar.pest"] pub struct MistParser; -// convenience alias for pest errors -pub type ParseError = pest::error::Error; +#[derive(Debug, Clone)] +pub enum ParseError<'a> { + PreAst(pest::error::Error), + Ast { + span: pest::Span<'a>, + error_code: i32, + error_message: String, + }, +} -pub fn parse(source: &str) -> Result, ParseError> { +type ParseResult<'a, T> = Result>; + +pub fn parse<'a>(source: &str) -> ParseResult<'a, Vec> { let mut pairs = MistParser::parse(Rule::program, source)?; let mut statements = vec![]; @@ -26,6 +35,12 @@ pub fn parse(source: &str) -> Result, ParseError> { Ok(statements) } +impl From> for ParseError<'_> { + fn from(value: pest::error::Error) -> Self { + Self::PreAst(value) + } +} + impl From> for TypeExpr { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { let rule = pair.as_rule(); diff --git a/src/compiler.rs b/src/compiler.rs index f6e7d7e..7b8f585 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -100,7 +100,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { } }; - let parser_result = mist_parser::parse(&source).map_err(|e| e.to_string()); + let parser_result = mist_parser::parse(&source).map_err(|e| format!("{e:?}")); let ast = match parser_result { Ok(ast) => ast, From 03f97946712ab6131bfcf68dbfb0b9aee9aaa696 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 19:33:12 +0200 Subject: [PATCH 03/27] Mass rewrite --- parser/src/lib.rs | 148 +++++++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 53 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 77e9a45..2e844f8 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -41,28 +41,32 @@ impl From> for ParseError<'_> { } } -impl From> for TypeExpr { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for TypeExpr { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.into_inner(); match rule { - Rule::type_expr => TypeExpr( + Rule::type_expr => Ok(TypeExpr( TypeExprKind::from(inner.next().unwrap()), inner.map(TypePostfix::from).collect(), - ), - Rule::type_expr_param => TypeExpr::from(inner.next().unwrap()), - Rule::lifetime => TypeExpr( + )), + Rule::type_expr_param => Self::try_from(inner.next().unwrap()), + Rule::lifetime => Ok(TypeExpr( TypeExprKind::Lifetime(Identifier::from(inner.next().unwrap())), Vec::new(), - ), + )), _ => unimplemented!("{rule:#?}"), } } } -impl From> for TypePostfix { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for TypePostfix { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.into_inner(); @@ -91,8 +95,10 @@ impl From> for TypePostfix { } } -impl From> for TypeExprKind { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for TypeExprKind { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.into_inner(); @@ -113,8 +119,10 @@ impl From> for TypeExprKind { } } -impl From> for Path { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for Path { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::static_path => Path(pair.into_inner().map(Identifier::from).collect()), _ => unimplemented!("{pair:#?}"), @@ -122,14 +130,16 @@ impl From> for Path { } } -impl From> for ParamList { +impl<'a> TryFrom> for ParamList { fn from(pair: pest::iterators::Pair) -> Self { ParamList(pair.into_inner().map(VarDecl::from).collect()) } } -impl From> for Attribute { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for Attribute { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::attribute => { // unwrap #[ ... ] @@ -185,8 +195,10 @@ impl From> for Attribute { } } -impl From> for TopLevel { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for TopLevel { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); let attributes = inner @@ -206,8 +218,10 @@ impl From> for TopLevel { } } -impl From> for StatementBranch { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for StatementBranch { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); let condition = Expression::from(inner.next().unwrap()); @@ -220,8 +234,10 @@ impl From> for StatementBranch { } } -impl From> for ClassConstructor { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for ClassConstructor { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); let visibility = Visibility::from(&mut inner); @@ -243,8 +259,10 @@ impl From> for ClassConstructor { } } -impl From> for Generics { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for Generics { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let inner = pair.clone().into_inner(); @@ -269,8 +287,10 @@ impl From> for Generics { } } -impl From> for TopLevelKind { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for TopLevelKind { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -343,8 +363,10 @@ impl From> for TopLevelKind { } } -impl From> for ClassItem { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for ClassItem { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); match rule { @@ -357,8 +379,10 @@ impl From> for ClassItem { } } -impl From> for ImplDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for ImplDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -386,8 +410,10 @@ impl From> for ImplDecl { } } -impl From> for EnumItem { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for EnumItem { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -417,7 +443,7 @@ impl From> for EnumItem { } } -impl From> for Block { +impl<'a> TryFrom> for Block { fn from(pair: pest::iterators::Pair) -> Self { let statements = pair .into_inner() @@ -433,7 +459,7 @@ impl From> for Block { } } -impl From> for Statement { +impl<'a> TryFrom> for Statement { fn from(pair: pest::iterators::Pair) -> Self { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -517,8 +543,10 @@ impl From> for Statement { } } -impl From> for Literal { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for Literal { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -535,7 +563,7 @@ impl From> for Literal { } } -impl From> for Expression { +impl<'a> TryFrom> for Expression { fn from(pair: pest::iterators::Pair) -> Self { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -567,7 +595,7 @@ impl From> for Expression { } } -impl From> for Prefix { +impl<'a> TryFrom> for Prefix { fn from(pair: pest::iterators::Pair) -> Self { match pair.as_rule() { Rule::prefix => Self::from(pair.into_inner().next().unwrap()), @@ -581,7 +609,7 @@ impl From> for Prefix { } } -impl From> for Postfix { +impl<'a> TryFrom> for Postfix { fn from(pair: pest::iterators::Pair) -> Self { let rule = pair.as_rule(); let mut inner = pair.into_inner(); @@ -638,8 +666,10 @@ impl From> for Postfix { } } -impl From> for VarDeclStmt { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for VarDeclStmt { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::var_decl_statement => { let mut inner = pair.into_inner(); @@ -656,8 +686,10 @@ impl From> for VarDeclStmt { } } -impl From> for FieldDeclStmt { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for FieldDeclStmt { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::class_field => { let mut inner = pair.into_inner(); @@ -674,8 +706,10 @@ impl From> for FieldDeclStmt { } } -impl From> for Pattern { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for Pattern { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -703,8 +737,10 @@ impl From> for Pattern { } } -impl From> for VarDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for VarDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::var_decl => { let mut inner = pair.into_inner(); @@ -732,8 +768,10 @@ impl From> for VarDecl { } } -impl From> for FieldDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for FieldDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::field => { let mut inner = pair.into_inner(); @@ -754,8 +792,10 @@ impl From> for FieldDecl { } } -impl From> for FunctionDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for FunctionDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); let visibility = Visibility::from(&mut inner); let return_type = TypeExpr::from(inner.next().unwrap()); @@ -855,8 +895,10 @@ pub fn consume_rule<'a>( if consumed { pairs.next() } else { None } } -impl From> for Identifier { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { +impl<'a> TryFrom> for Identifier { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { Identifier(pair.as_str().to_string()) } } From 01532baf127ecb4d6e7df7484b83d4885c9c11ad Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 20:14:28 +0200 Subject: [PATCH 04/27] Mass improved error handling --- parser/src/lib.rs | 522 ++++++++++++++++++++++++++++------------------ 1 file changed, 318 insertions(+), 204 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 2e844f8..306ee4e 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -21,14 +21,14 @@ pub enum ParseError<'a> { type ParseResult<'a, T> = Result>; -pub fn parse<'a>(source: &str) -> ParseResult<'a, Vec> { +pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { let mut pairs = MistParser::parse(Rule::program, source)?; let mut statements = vec![]; for pair in pairs.next().unwrap().into_inner() { if pair.as_rule() != Rule::EOI { - statements.push(TopLevel::from(pair)); + statements.push(TopLevel::try_from(pair)?); } } @@ -50,12 +50,14 @@ impl<'a> TryFrom> for TypeExpr { match rule { Rule::type_expr => Ok(TypeExpr( - TypeExprKind::from(inner.next().unwrap()), - inner.map(TypePostfix::from).collect(), + TypeExprKind::try_from(inner.next().unwrap())?, + inner + .map(TypePostfix::try_from) + .collect::>()?, )), Rule::type_expr_param => Self::try_from(inner.next().unwrap()), Rule::lifetime => Ok(TypeExpr( - TypeExprKind::Lifetime(Identifier::from(inner.next().unwrap())), + TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), Vec::new(), )), _ => unimplemented!("{rule:#?}"), @@ -74,9 +76,10 @@ impl<'a> TryFrom> for TypePostfix { Rule::ref_type => { let mutable = listen_rule(&mut inner, Rule::mutable); let lifetime = consume_rule(&mut inner, Rule::lifetime) - .map(|pair| Identifier::from(pair.into_inner().next().unwrap())); + .map(|pair| Identifier::try_from(pair.into_inner().next().unwrap())) + .transpose()?; - if mutable { + Ok(if mutable { if let Some(lifetime) = lifetime { TypePostfix::RefMutLifetime(lifetime) } else { @@ -88,7 +91,7 @@ impl<'a> TryFrom> for TypePostfix { } else { TypePostfix::Ref } - } + }) } _ => unimplemented!("{rule:#?}"), } @@ -103,15 +106,21 @@ impl<'a> TryFrom> for TypeExprKind { let mut inner = pair.into_inner(); match rule { - Rule::tuple_type => TypeExprKind::Tuple(inner.map(TypeExpr::from).collect()), + Rule::tuple_type => Ok(TypeExprKind::Tuple( + inner + .map(TypeExpr::try_from) + .collect::>()?, + )), Rule::path_type => { - let path = Path::from(inner.next().unwrap()); - let params = inner.map(TypeExpr::from).collect::>(); + let path = Path::try_from(inner.next().unwrap())?; + let params = inner + .map(TypeExpr::try_from) + .collect::>>()?; if params.len() == 0 { - TypeExprKind::Path(path) + Ok(TypeExprKind::Path(path)) } else { - TypeExprKind::PathParams(path, params) + Ok(TypeExprKind::PathParams(path, params)) } } _ => unimplemented!("{rule:#?}"), @@ -124,15 +133,25 @@ impl<'a> TryFrom> for Path { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { - Rule::static_path => Path(pair.into_inner().map(Identifier::from).collect()), + Rule::static_path => Ok(Path( + pair.into_inner() + .map(Identifier::try_from) + .collect::>>()?, + )), _ => unimplemented!("{pair:#?}"), } } } impl<'a> TryFrom> for ParamList { - fn from(pair: pest::iterators::Pair) -> Self { - ParamList(pair.into_inner().map(VarDecl::from).collect()) + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(ParamList( + pair.into_inner() + .map(VarDecl::try_from) + .collect::>>()?, + )) } } @@ -143,36 +162,39 @@ impl<'a> TryFrom> for Attribute { match pair.as_rule() { Rule::attribute => { // unwrap #[ ... ] - Attribute::from(pair.into_inner().next().unwrap()) + Attribute::try_from(pair.into_inner().next().unwrap()) } Rule::meta => { let mut inner = pair.into_inner(); // first item is always the path - let path = Path::from(inner.next().unwrap()); + let path = Path::try_from(inner.next().unwrap())?; // check what comes next match inner.next() { None => { // #[path] - Attribute::Path(path) + Ok(Attribute::Path(path)) } Some(next) => match next.as_rule() { Rule::primary => { // #[path = literal] - Attribute::NameValue { + Ok(Attribute::NameValue { path, - value: Literal::from(next), - } + value: Literal::try_from(next)?, + }) } Rule::meta_list => { // #[path(...)] - let items = next.into_inner().map(Attribute::from).collect(); + let items = next + .into_inner() + .map(Attribute::try_from) + .collect::>>()?; - Attribute::List { path, items } + Ok(Attribute::List { path, items }) } _ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()), @@ -183,7 +205,10 @@ impl<'a> TryFrom> for Attribute { Rule::meta_list => { // This case usually won't be hit directly, // but it's nice to keep it safe if reused - let items = pair.into_inner().map(Attribute::from).collect::>(); + let items = pair + .into_inner() + .map(Attribute::try_from) + .collect::>(); // NOTE: this shouldn't normally construct an Attribute alone // but you can panic or wrap depending on your design @@ -205,16 +230,16 @@ impl<'a> TryFrom> for TopLevel { .next() .unwrap() .into_inner() - .map(Attribute::from) - .collect::>(); + .map(Attribute::try_from) + .collect::>>()?; - TopLevel( + Ok(TopLevel( inner .next() - .map(TopLevelKind::from) - .unwrap_or(TopLevelKind::ModAttribute), + .map(TopLevelKind::try_from) + .unwrap_or(Ok(TopLevelKind::ModAttribute))?, attributes, - ) + )) } } @@ -224,13 +249,13 @@ impl<'a> TryFrom> for StatementBranch { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let condition = Expression::from(inner.next().unwrap()); - let body = Statement::from(inner.next().unwrap()); + let condition = Expression::try_from(inner.next().unwrap())?; + let body = Statement::try_from(inner.next().unwrap())?; - StatementBranch { + Ok(StatementBranch { condition, body: Box::new(body), - } + }) } } @@ -243,19 +268,21 @@ impl<'a> TryFrom> for ClassConstructor { let visibility = Visibility::from(&mut inner); let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) + .transpose()? .unwrap_or_default(); let params = consume_rule(&mut inner, Rule::param_list) - .map(ParamList::from) - .unwrap_or_else(|| ParamList(Vec::new())); + .map(ParamList::try_from) + .transpose()? + .unwrap_or_default(); - Self { + Ok(Self { visibility, generics, params, - body: Block::from(inner.next().unwrap()), - } + body: Block::try_from(inner.next().unwrap())?, + }) } } @@ -267,21 +294,27 @@ impl<'a> TryFrom> for Generics { let inner = pair.clone().into_inner(); match rule { - Rule::generics => Generics( + Rule::generics => Ok(Generics( inner - .map(|pair| { + .map(|pair| -> ParseResult<'a, Generic> { let mut inner = pair.into_inner(); - if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { - Generic::Lifetime(Identifier::from(pair.into_inner().next().unwrap())) - } else { - Generic::Type( - Identifier::from(inner.next().unwrap()), - inner.map(TypeExpr::from).collect(), - ) - } + Ok( + if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { + Generic::Lifetime(Identifier::try_from( + pair.into_inner().next().unwrap(), + )?) + } else { + Generic::Type( + Identifier::try_from(inner.next().unwrap())?, + inner + .map(TypeExpr::try_from) + .collect::>>()?, + ) + }, + ) }) - .collect(), - ), + .collect::>>()?, + )), _ => unimplemented!("{rule:#?}"), } } @@ -294,72 +327,93 @@ impl<'a> TryFrom> for TopLevelKind { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); - match rule { + Ok(match rule { Rule::import => TopLevelKind::Import( Visibility::from(&mut inner), - Path::from(inner.next().unwrap()), + Path::try_from(inner.next().unwrap())?, ), - Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::from(pair)), + Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::try_from(pair)?), Rule::struct_decl => TopLevelKind::StructDecl { visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), + name: Identifier::try_from(inner.next().unwrap()), generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) .unwrap_or_default(), fields: inner .next() - .map(|pair| pair.into_inner().map(FieldDecl::from).collect()) + .map(|pair| { + pair.into_inner() + .map(FieldDecl::try_from) + .collect::>>()? + }) .unwrap_or_default(), }, Rule::class_decl => TopLevelKind::ClassDecl { visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), + name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) + .transpose()? .unwrap_or_default(), fields: inner .next() .unwrap() .into_inner() - .map(FieldDeclStmt::from) - .collect(), - constructor: ClassConstructor::from(inner.next().unwrap()), - items: inner.into_iter().map(ClassItem::from).collect(), + .map(FieldDeclStmt::try_from) + .collect::>>()?, + constructor: ClassConstructor::try_from(inner.next().unwrap())?, + items: inner + .into_iter() + .map(ClassItem::try_from) + .collect::>>()?, }, Rule::enum_decl => TopLevelKind::EnumDecl { visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), + name: Identifier::try_from(inner.next().unwrap()), generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) + .transpose()? .unwrap_or_default(), - fields: inner.map(EnumItem::from).collect(), + fields: inner + .map(EnumItem::try_from) + .collect::>>()?, }, Rule::mod_package => TopLevelKind::Mod( Visibility::from(&mut inner), - Identifier::from(inner.next().unwrap()), + Identifier::try_from(inner.next().unwrap())?, ), - Rule::impl_for_decl | Rule::impl_decl => TopLevelKind::ImplDecl(ImplDecl::from(pair)), + Rule::impl_for_decl | Rule::impl_decl => { + TopLevelKind::ImplDecl(ImplDecl::try_from(pair)?) + } Rule::trait_decl => TopLevelKind::TraitDecl { visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), + name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) + .transpose()? .unwrap_or_default(), requirements: consume_rule(&mut inner, Rule::trait_requirements) - .map(|pair| pair.into_inner().map(TypeExpr::from).collect()) + .map(|pair| { + pair.into_inner() + .map(TypeExpr::try_from) + .collect::>>() + }) + .transpose()? .unwrap_or_default(), - items: inner.map(FunctionDecl::from).collect(), + items: inner + .map(FunctionDecl::try_from) + .collect::>>()?, }, _ => unimplemented!("{rule:#?}"), - } + }) } } @@ -370,9 +424,11 @@ impl<'a> TryFrom> for ClassItem { let rule = pair.as_rule(); match rule { - Rule::impl_decl | Rule::impl_for_decl => ClassItem::ImplDecl(ImplDecl::from(pair)), + Rule::impl_decl | Rule::impl_for_decl => { + Ok(ClassItem::ImplDecl(ImplDecl::try_from(pair)?)) + } - Rule::method => ClassItem::Method(FunctionDecl::from(pair)), + Rule::method => Ok(ClassItem::Method(FunctionDecl::try_from(pair)?)), _ => unimplemented!("{rule:#?}"), } @@ -387,23 +443,29 @@ impl<'a> TryFrom> for ImplDecl { let mut inner = pair.clone().into_inner(); match rule { - Rule::impl_for_decl => ImplDecl { + Rule::impl_for_decl => Ok(ImplDecl { generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) + .transpose()? .unwrap_or_default(), - trait_: Some(TypeExpr::from(inner.next().unwrap())), - target: TypeExpr::from(inner.next().unwrap()), - methods: inner.map(FunctionDecl::from).collect(), - }, + trait_: Some(TypeExpr::try_from(inner.next().unwrap())?), + target: TypeExpr::try_from(inner.next().unwrap())?, + methods: inner + .map(FunctionDecl::try_from) + .collect::>>()?, + }), - Rule::impl_decl => ImplDecl { + Rule::impl_decl => Ok(ImplDecl { generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) + .transpose()? .unwrap_or_default(), trait_: None, - target: TypeExpr::from(inner.next().unwrap()), - methods: inner.map(FunctionDecl::from).collect(), - }, + target: TypeExpr::try_from(inner.next().unwrap())?, + methods: inner + .map(FunctionDecl::try_from) + .collect::>>()?, + }), _ => unimplemented!("{rule:#?}"), } @@ -418,25 +480,32 @@ impl<'a> TryFrom> for EnumItem { let mut inner = pair.clone().into_inner(); match rule { - Rule::enum_named => EnumItem::Named(Identifier::from(inner.next().unwrap())), + Rule::enum_named => Ok(EnumItem::Named(Identifier::try_from( + inner.next().unwrap(), + )?)), - Rule::enum_tuple => EnumItem::Tuple( - Identifier::from(inner.next().unwrap()), + Rule::enum_tuple => Ok(EnumItem::Tuple( + Identifier::try_from(inner.next().unwrap())?, inner .next() .unwrap() .into_inner() - .map(TypeExpr::from) - .collect(), - ), + .map(TypeExpr::try_from) + .collect::>>()?, + )), - Rule::enum_struct => EnumItem::Struct( - Identifier::from(inner.next().unwrap()), + Rule::enum_struct => Ok(EnumItem::Struct( + Identifier::try_from(inner.next().unwrap())?, inner .next() - .map(|pair| pair.into_inner().map(FieldDecl::from).collect()) + .map(|pair| { + pair.into_inner() + .map(FieldDecl::try_from) + .collect::>>() + }) + .transpose()? .unwrap_or_default(), - ), + )), _ => unimplemented!("{rule:#?}"), } @@ -444,39 +513,42 @@ impl<'a> TryFrom> for EnumItem { } impl<'a> TryFrom> for Block { - fn from(pair: pest::iterators::Pair) -> Self { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let statements = pair .into_inner() .flat_map(|pair| { if pair.as_rule() == Rule::statement_list { - pair.into_inner().map(Statement::from).collect() + pair.into_inner().map(Statement::try_from).collect() } else { - vec![Statement::from(pair)] + vec![Statement::try_from(pair)] } }) - .collect(); - Block(statements) + .collect::>>()?; + + Ok(Block(statements)) } } impl<'a> TryFrom> for Statement { - fn from(pair: pest::iterators::Pair) -> Self { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); - match rule { - Rule::statement => Statement::from(inner.next().unwrap()), + Ok(match rule { + Rule::statement => Statement::try_from(inner.next().unwrap())?, - Rule::expr_stmt => Statement::Expression(Expression::from(inner.next().unwrap())), + Rule::expr_stmt => Statement::Expression(Expression::try_from(inner.next().unwrap())?), - Rule::block => Statement::Block(Block::from(inner.next().unwrap())), + Rule::block => Statement::Block(Block::try_from(inner.next().unwrap())?), - Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::from(pair)), + Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair)?), Rule::return_stmt => { - let expr = inner.next().map(Expression::from); - - Statement::Return(expr) + Statement::Return(inner.next().map(Expression::try_from).transpose()?) } Rule::break_stmt => Statement::Break, @@ -487,49 +559,53 @@ impl<'a> TryFrom> for Statement { let mut inner = inner.skip(2); Statement::If { - initial: pair.into(), + initial: StatementBranch::try_from(pair)?, else_if: inner .next() .unwrap() .into_inner() - .map(StatementBranch::from) - .collect(), - else_branch: inner.next().map(Statement::from).map(Box::new), + .map(StatementBranch::try_from) + .collect::>>()?, + else_branch: inner + .next() + .map(Statement::try_from) + .transpose()? + .map(Box::new), } } - Rule::while_stmt => Statement::While(pair.into()), + Rule::while_stmt => Statement::While(pair.try_into()?), Rule::c_for_stmt => Statement::CStyleFor { - init: Box::new(Statement::from(inner.next().unwrap())), - condition: inner.next().unwrap().into(), - update: Box::new(Statement::from(inner.next().unwrap())), - body: Box::new(Statement::from(inner.next().unwrap())), + init: Box::new(Statement::try_from(inner.next().unwrap())?), + condition: inner.next().unwrap().try_into()?, + update: Box::new(Statement::try_from(inner.next().unwrap())?), + body: Box::new(Statement::try_from(inner.next().unwrap())?), }, Rule::for_stmt => Statement::For { mutable: listen_rule(&mut inner, Rule::mutable), - pattern: Pattern::from(inner.next().unwrap()), - iterator: inner.next().unwrap().into(), - body: Box::new(Statement::from(inner.next().unwrap())), + pattern: Pattern::try_from(inner.next().unwrap())?, + iterator: inner.next().unwrap().try_into()?, + body: Box::new(Statement::try_from(inner.next().unwrap())?), }, Rule::assign_statement => Statement::VarAssign(VarAssignStmt { - target: Expression::from(inner.next().unwrap()), - value: Expression::from(inner.next().unwrap()), + target: Expression::try_from(inner.next().unwrap())?, + value: Expression::try_from(inner.next().unwrap())?, }), Rule::match_stmt => Statement::Match( - Expression::from(inner.next().unwrap()), + Expression::try_from(inner.next().unwrap())?, inner .map(|match_itms| { let mut match_inner = match_itms.into_inner(); - ( - Pattern::from(match_inner.next().unwrap()), - Block::from(match_inner.next().unwrap()), - ) + Ok(( + Pattern::try_from(match_inner.next().unwrap())?, + Block::try_from(match_inner.next().unwrap())?, + )) }) - .collect(), + .collect::>>()?, ), Rule::unexpected_statement => { @@ -539,7 +615,7 @@ impl<'a> TryFrom> for Statement { } _ => unimplemented!("{rule:#?}"), - } + }) } } @@ -550,21 +626,27 @@ impl<'a> TryFrom> for Literal { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); - match rule { - Rule::primary => Self::from(inner.next().unwrap()), - Rule::literal => Self::from(inner.next().unwrap()), + Ok(match rule { + Rule::primary => Self::try_from(inner.next().unwrap())?, + Rule::literal => Self::try_from(inner.next().unwrap())?, Rule::integer => Literal::Int(pair.as_str().parse::().unwrap()), Rule::float => Literal::Float(pair.as_str().parse::().unwrap()), Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), Rule::string_lit => Literal::String(inner.as_str().to_string()), - Rule::tuple => Literal::Tuple(inner.map(Expression::from).collect()), + Rule::tuple => Literal::Tuple( + inner + .map(Expression::try_from) + .collect::>>()?, + ), _ => unimplemented!("{rule:#?}"), - } + }) } } impl<'a> TryFrom> for Expression { - fn from(pair: pest::iterators::Pair) -> Self { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); @@ -572,68 +654,84 @@ impl<'a> TryFrom> for Expression { Rule::expr => { let prefixes: Vec = inner .next() - .map(|p| p.into_inner().into_iter().map(Prefix::from).collect()) + .map(|p| { + p.into_inner() + .into_iter() + .map(Prefix::try_from) + .collect::>>() + }) + .transpose()? .unwrap_or_default(); - let exp = Expression::from(inner.next().unwrap()); + let exp = Expression::try_from(inner.next().unwrap())?; if inner.len() > 0 || prefixes.len() > 0 { - Expression::Fix { + Ok(Expression::Fix { initial: Box::new(exp), prefixes, - postfixes: inner.map(|p| Postfix::from(p)).collect(), - } + postfixes: inner + .map(|p| Postfix::try_from(p)) + .collect::>>()?, + }) } else { - exp + Ok(exp) } } - Rule::primary => Expression::from(inner.next().unwrap()), - Rule::static_path => Expression::Path(Path::from(pair)), - Rule::literal => Expression::Literal(Literal::from(pair)), + Rule::primary => Expression::try_from(inner.next().unwrap()), + Rule::static_path => Ok(Expression::Path(Path::try_from(pair)?)), + Rule::literal => Ok(Expression::Literal(Literal::try_from(pair)?)), _ => unimplemented!("{rule:#?}"), } } } impl<'a> TryFrom> for Prefix { - fn from(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::prefix => Self::from(pair.into_inner().next().unwrap()), + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(match pair.as_rule() { + Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?, Rule::deref_px => Self::Deref, Rule::mut_ref_px => Self::RefMut, Rule::ref_px => Self::Ref, Rule::new_px => Self::New, Rule::not_px => Self::Not, _ => unimplemented!("{pair:#?}"), - } + }) } } impl<'a> TryFrom> for Postfix { - fn from(pair: pest::iterators::Pair) -> Self { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); let mut inner = pair.into_inner(); - match rule { - Rule::postfix => Postfix::from(inner.next().unwrap()), + Ok(match rule { + Rule::postfix => Postfix::try_from(inner.next().unwrap())?, - Rule::field_px => Postfix::FieldAccess(Identifier::from(inner.next().unwrap())), + Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), - Rule::call_px => Postfix::Call(inner.map(Expression::from).collect()), + Rule::call_px => Postfix::Call( + inner + .map(Expression::try_from) + .collect::>>()?, + ), Rule::struct_px => Postfix::StructCall( inner .map(|p| { let mut pi = p.into_inner(); - ( - Identifier::from(pi.next().unwrap()), - Expression::from(pi.next().unwrap()), - ) + Ok(( + Identifier::try_from(pi.next().unwrap())?, + Expression::try_from(pi.next().unwrap())?, + )) }) - .collect(), + .collect::>>()?, ), - Rule::index_px => Postfix::Index(Expression::from(inner.next().unwrap())), + Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), Rule::binary_px => { let op_pair = inner.next().unwrap(); @@ -656,13 +754,13 @@ impl<'a> TryFrom> for Postfix { unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) } }; - Postfix::Binary(op, Expression::from(inner.next().unwrap())) + Postfix::Binary(op, Expression::try_from(inner.next().unwrap())?) } Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), _ => unimplemented!("{rule:#?}"), - } + }) } } @@ -674,9 +772,9 @@ impl<'a> TryFrom> for VarDeclStmt { Rule::var_decl_statement => { let mut inner = pair.into_inner(); - let decl = VarDecl::from(inner.next().unwrap()); + let decl = VarDecl::try_from(inner.next().unwrap()); - let init = inner.next().map(Expression::from); + let init = inner.next().map(Expression::try_from); VarDeclStmt { decl, init } } @@ -694,11 +792,11 @@ impl<'a> TryFrom> for FieldDeclStmt { Rule::class_field => { let mut inner = pair.into_inner(); - let decl = FieldDecl::from(inner.next().unwrap()); + let decl = FieldDecl::try_from(inner.next().unwrap())?; - let init = inner.next().map(Expression::from); + let init = inner.next().map(Expression::try_from).transpose()?; - FieldDeclStmt { decl, init } + Ok(FieldDeclStmt { decl, init }) } _ => unimplemented!(), @@ -713,27 +811,35 @@ impl<'a> TryFrom> for Pattern { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); - match rule { - Rule::tuple_pattern => Pattern::Tuple(inner.map(Identifier::from).collect()), + Ok(match rule { + Rule::tuple_pattern => Pattern::Tuple( + inner + .map(Identifier::try_from) + .collect::>>()?, + ), Rule::named_tuple_pattern => Pattern::NamedTuple( - Path::from(inner.next().unwrap()), - inner.map(Identifier::from).collect(), + Path::try_from(inner.next().unwrap())?, + inner + .map(Identifier::try_from) + .collect::>>()?, ), Rule::struct_pattern => Pattern::Struct( - Path::from(inner.next().unwrap()), - inner.map(Identifier::from).collect(), + Path::try_from(inner.next().unwrap())?, + inner + .map(Identifier::try_from) + .collect::>>()?, ), - Rule::literal => Pattern::Literal(Literal::from(pair)), + Rule::literal => Pattern::Literal(Literal::try_from(pair)?), - Rule::identifier => Pattern::Id(Identifier::from(pair)), + Rule::identifier => Pattern::Id(Identifier::try_from(pair)?), - Rule::static_path => Pattern::Path(Path::from(pair)), + Rule::static_path => Pattern::Path(Path::try_from(pair)?), _ => unimplemented!("{rule:?}"), - } + }) } } @@ -745,22 +851,26 @@ impl<'a> TryFrom> for VarDecl { Rule::var_decl => { let mut inner = pair.into_inner(); - let type_ = inner.next().and_then(|pair| { - if pair.as_str().trim() == "var" { - None - } else { - Some(TypeExpr::from(pair)) - } - }); + let type_ = inner + .next() + .and_then(|pair| { + if pair.as_str().trim() == "var" { + None + } else { + Some(TypeExpr::try_from(pair)) + } + }) + .transpose()?; + let mutable = listen_rule(&mut inner, Rule::mutable); - let name = Pattern::from(inner.next().unwrap()); + let name = Pattern::try_from(inner.next().unwrap())?; - VarDecl { + Ok(VarDecl { mutable, name, type_, - } + }) } _ => unimplemented!("{:?}", pair.as_rule()), @@ -777,14 +887,14 @@ impl<'a> TryFrom> for FieldDecl { let mut inner = pair.into_inner(); let visibility = Visibility::from(&mut inner); - let type_ = TypeExpr::from(inner.next().unwrap()); - let name = Identifier::from(inner.next().unwrap()); + let type_ = TypeExpr::try_from(inner.next().unwrap())?; + let name = Identifier::try_from(inner.next().unwrap())?; - FieldDecl { + Ok(FieldDecl { visibility, type_, name, - } + }) } _ => unimplemented!("{:?}", pair.as_rule()), @@ -798,10 +908,11 @@ impl<'a> TryFrom> for FunctionDecl { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); let visibility = Visibility::from(&mut inner); - let return_type = TypeExpr::from(inner.next().unwrap()); - let name = Identifier::from(inner.next().unwrap()); + let return_type = TypeExpr::try_from(inner.next().unwrap())?; + let name = Identifier::try_from(inner.next().unwrap())?; let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::from) + .map(Generics::try_from) + .transpose()? .unwrap_or_default(); let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { @@ -834,25 +945,26 @@ impl<'a> TryFrom> for FunctionDecl { .map({ let self_param = self_param.clone(); |params_pair| { - let mut params = ParamList::from(params_pair); + let mut params = ParamList::try_from(params_pair)?; if let Some(x) = self_param { params.0.insert(0, x); } - params + Ok(params) } }) + .transpose()? .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); - let body = inner.next().map(Block::from); + let body = inner.next().map(Block::try_from).transpose()?; - Self { + Ok(Self { visibility, name, generics, params, return_type, body, - } + }) } } @@ -861,11 +973,13 @@ impl From<&mut pest::iterators::Pairs<'_, Rule>> for Visibility { consume_rule(pairs, Rule::visibility) .map(|pair| { if let Some(path) = pair.into_inner().next() { - Visibility::PublicTarget(Path::from(path)) + Ok(Visibility::PublicTarget(Path::try_from(path)?)) } else { - Visibility::Public + Ok(Visibility::Public) } }) + .transpose() + .unwrap() .unwrap_or_else(|| Visibility::Private) } } From 5c732bb8d1008e24997365b96f8f9c0d49d1bb36 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 20:19:22 +0200 Subject: [PATCH 05/27] Finishing mass error rewrite --- parser/src/lib.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 306ee4e..2119075 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -337,17 +337,19 @@ impl<'a> TryFrom> for TopLevelKind { Rule::struct_decl => TopLevelKind::StructDecl { visibility: Visibility::from(&mut inner), - name: Identifier::try_from(inner.next().unwrap()), + name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) + .transpose()? .unwrap_or_default(), fields: inner .next() .map(|pair| { pair.into_inner() .map(FieldDecl::try_from) - .collect::>>()? + .collect::>>() }) + .transpose()? .unwrap_or_default(), }, @@ -373,7 +375,7 @@ impl<'a> TryFrom> for TopLevelKind { Rule::enum_decl => TopLevelKind::EnumDecl { visibility: Visibility::from(&mut inner), - name: Identifier::try_from(inner.next().unwrap()), + name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) .transpose()? @@ -772,11 +774,11 @@ impl<'a> TryFrom> for VarDeclStmt { Rule::var_decl_statement => { let mut inner = pair.into_inner(); - let decl = VarDecl::try_from(inner.next().unwrap()); + let decl = VarDecl::try_from(inner.next().unwrap())?; - let init = inner.next().map(Expression::try_from); + let init = inner.next().map(Expression::try_from).transpose()?; - VarDeclStmt { decl, init } + Ok(VarDeclStmt { decl, init }) } _ => unimplemented!(), @@ -944,7 +946,7 @@ impl<'a> TryFrom> for FunctionDecl { let params = consume_rule(&mut inner, Rule::param_list) .map({ let self_param = self_param.clone(); - |params_pair| { + |params_pair| -> ParseResult<'a, ParamList> { let mut params = ParamList::try_from(params_pair)?; if let Some(x) = self_param { params.0.insert(0, x); @@ -1013,6 +1015,6 @@ impl<'a> TryFrom> for Identifier { type Error = ParseError<'a>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Identifier(pair.as_str().to_string()) + Ok(Identifier(pair.as_str().to_string())) } } From d8d3b327dd5824d6d61e0714fe7f35b51b2828f1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 20:23:52 +0200 Subject: [PATCH 06/27] Visibility error stuff --- parser/src/lib.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 2119075..7bd2875 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -265,7 +265,7 @@ impl<'a> TryFrom> for ClassConstructor { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let visibility = Visibility::from(&mut inner); + let visibility = Visibility::try_from(&mut inner)?; let generics = consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) @@ -329,14 +329,14 @@ impl<'a> TryFrom> for TopLevelKind { Ok(match rule { Rule::import => TopLevelKind::Import( - Visibility::from(&mut inner), + Visibility::try_from(&mut inner)?, Path::try_from(inner.next().unwrap())?, ), Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::try_from(pair)?), Rule::struct_decl => TopLevelKind::StructDecl { - visibility: Visibility::from(&mut inner), + visibility: Visibility::try_from(&mut inner)?, name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) @@ -354,7 +354,7 @@ impl<'a> TryFrom> for TopLevelKind { }, Rule::class_decl => TopLevelKind::ClassDecl { - visibility: Visibility::from(&mut inner), + visibility: Visibility::try_from(&mut inner)?, name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) @@ -374,7 +374,7 @@ impl<'a> TryFrom> for TopLevelKind { }, Rule::enum_decl => TopLevelKind::EnumDecl { - visibility: Visibility::from(&mut inner), + visibility: Visibility::try_from(&mut inner)?, name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) @@ -386,7 +386,7 @@ impl<'a> TryFrom> for TopLevelKind { }, Rule::mod_package => TopLevelKind::Mod( - Visibility::from(&mut inner), + Visibility::try_from(&mut inner)?, Identifier::try_from(inner.next().unwrap())?, ), @@ -395,7 +395,7 @@ impl<'a> TryFrom> for TopLevelKind { } Rule::trait_decl => TopLevelKind::TraitDecl { - visibility: Visibility::from(&mut inner), + visibility: Visibility::try_from(&mut inner)?, name: Identifier::try_from(inner.next().unwrap())?, generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) @@ -888,7 +888,7 @@ impl<'a> TryFrom> for FieldDecl { Rule::field => { let mut inner = pair.into_inner(); - let visibility = Visibility::from(&mut inner); + let visibility = Visibility::try_from(&mut inner)?; let type_ = TypeExpr::try_from(inner.next().unwrap())?; let name = Identifier::try_from(inner.next().unwrap())?; @@ -909,7 +909,7 @@ impl<'a> TryFrom> for FunctionDecl { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let visibility = Visibility::from(&mut inner); + let visibility = Visibility::try_from(&mut inner)?; let return_type = TypeExpr::try_from(inner.next().unwrap())?; let name = Identifier::try_from(inner.next().unwrap())?; let generics = consume_rule(&mut inner, Rule::generics) @@ -969,20 +969,20 @@ impl<'a> TryFrom> for FunctionDecl { }) } } +impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { + type Error = ParseError<'a>; -impl From<&mut pest::iterators::Pairs<'_, Rule>> for Visibility { - fn from(pairs: &mut pest::iterators::Pairs<'_, Rule>) -> Self { - consume_rule(pairs, Rule::visibility) - .map(|pair| { + fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result { + Ok(consume_rule(pairs, Rule::visibility) + .map(|pair| -> Result> { if let Some(path) = pair.into_inner().next() { Ok(Visibility::PublicTarget(Path::try_from(path)?)) } else { Ok(Visibility::Public) } }) - .transpose() - .unwrap() - .unwrap_or_else(|| Visibility::Private) + .transpose()? + .unwrap_or_else(|| Visibility::Private)) } } From 5920a9f2365bc9ae2e6d5f46888621fa44cbb56e Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 20:36:15 +0200 Subject: [PATCH 07/27] Error returning --- parser/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 7bd2875..d85211d 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -14,13 +14,18 @@ pub enum ParseError<'a> { PreAst(pest::error::Error), Ast { span: pest::Span<'a>, - error_code: i32, + error_code: ErrorCode, error_message: String, }, } type ParseResult<'a, T> = Result>; +#[derive(Debug, Clone)] +pub enum ErrorCode { + InvalidStatement = 200, +} + pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { let mut pairs = MistParser::parse(Rule::program, source)?; @@ -611,9 +616,11 @@ impl<'a> TryFrom> for Statement { ), Rule::unexpected_statement => { - let pos = pair.as_span().start_pos().line_col(); - - panic!("({}:{}) Invalid Statement: {}", pos.0, pos.1, pair.as_str()) + return Err(ParseError::Ast { + span: pair.as_span(), + error_code: ErrorCode::InvalidStatement, + error_message: "Invalid Statement".to_string(), + }); } _ => unimplemented!("{rule:#?}"), From 192769c8ad655ee89730acb65fa22f2056236137 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 20:51:43 +0200 Subject: [PATCH 08/27] Separate error --- parser/src/error.rs | 18 ++++++++++++++++++ parser/src/lib.rs | 20 +++----------------- 2 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 parser/src/error.rs diff --git a/parser/src/error.rs b/parser/src/error.rs new file mode 100644 index 0000000..5b12dc7 --- /dev/null +++ b/parser/src/error.rs @@ -0,0 +1,18 @@ +use crate::Rule; + +pub type ParseResult<'a, T> = Result>; + +#[derive(Debug, Clone)] +pub enum ParseError<'a> { + PreAst(pest::error::Error), + Ast { + span: pest::Span<'a>, + error_code: ErrorCode, + error_message: String, + }, +} + +#[derive(Debug, Clone)] +pub enum ErrorCode { + InvalidStatement = 200, +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index d85211d..03e9347 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -2,30 +2,16 @@ use pest::Parser; use pest_derive::Parser; pub mod ast; +pub mod error; use ast::*; +use crate::error::{ErrorCode, ParseError, ParseResult}; + #[derive(Parser)] #[grammar = "./src/grammar.pest"] pub struct MistParser; -#[derive(Debug, Clone)] -pub enum ParseError<'a> { - PreAst(pest::error::Error), - Ast { - span: pest::Span<'a>, - error_code: ErrorCode, - error_message: String, - }, -} - -type ParseResult<'a, T> = Result>; - -#[derive(Debug, Clone)] -pub enum ErrorCode { - InvalidStatement = 200, -} - pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { let mut pairs = MistParser::parse(Rule::program, source)?; From 50fa6603927baa66c48a05ef66e853a810af6eb6 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 21:27:50 +0200 Subject: [PATCH 09/27] Separating ast implementations --- parser/src/error.rs | 6 + parser/src/lib.rs | 187 +--------------------------- parser/src/parser/common.rs | 94 ++++++++++++++ parser/src/parser/items/function.rs | 72 +++++++++++ parser/src/parser/items/mod.rs | 1 + parser/src/parser/mod.rs | 29 +++++ 6 files changed, 205 insertions(+), 184 deletions(-) create mode 100644 parser/src/parser/common.rs create mode 100644 parser/src/parser/items/function.rs create mode 100644 parser/src/parser/items/mod.rs create mode 100644 parser/src/parser/mod.rs diff --git a/parser/src/error.rs b/parser/src/error.rs index 5b12dc7..74974d1 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -16,3 +16,9 @@ pub enum ParseError<'a> { pub enum ErrorCode { InvalidStatement = 200, } + +impl From> for ParseError<'_> { + fn from(value: pest::error::Error) -> Self { + Self::PreAst(value) + } +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 03e9347..f72ada3 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -3,11 +3,14 @@ use pest_derive::Parser; pub mod ast; pub mod error; +pub mod parser; use ast::*; use crate::error::{ErrorCode, ParseError, ParseResult}; +use crate::parser::{consume_rule, listen_rule}; + #[derive(Parser)] #[grammar = "./src/grammar.pest"] pub struct MistParser; @@ -26,36 +29,6 @@ pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { Ok(statements) } -impl From> for ParseError<'_> { - fn from(value: pest::error::Error) -> Self { - Self::PreAst(value) - } -} - -impl<'a> TryFrom> for TypeExpr { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::type_expr => Ok(TypeExpr( - TypeExprKind::try_from(inner.next().unwrap())?, - inner - .map(TypePostfix::try_from) - .collect::>()?, - )), - Rule::type_expr_param => Self::try_from(inner.next().unwrap()), - Rule::lifetime => Ok(TypeExpr( - TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), - Vec::new(), - )), - _ => unimplemented!("{rule:#?}"), - } - } -} - impl<'a> TryFrom> for TypePostfix { type Error = ParseError<'a>; @@ -119,21 +92,6 @@ impl<'a> TryFrom> for TypeExprKind { } } -impl<'a> TryFrom> for Path { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - match pair.as_rule() { - Rule::static_path => Ok(Path( - pair.into_inner() - .map(Identifier::try_from) - .collect::>>()?, - )), - _ => unimplemented!("{pair:#?}"), - } - } -} - impl<'a> TryFrom> for ParamList { type Error = ParseError<'a>; @@ -614,30 +572,6 @@ impl<'a> TryFrom> for Statement { } } -impl<'a> TryFrom> for Literal { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - Ok(match rule { - Rule::primary => Self::try_from(inner.next().unwrap())?, - Rule::literal => Self::try_from(inner.next().unwrap())?, - Rule::integer => Literal::Int(pair.as_str().parse::().unwrap()), - Rule::float => Literal::Float(pair.as_str().parse::().unwrap()), - Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), - Rule::string_lit => Literal::String(inner.as_str().to_string()), - Rule::tuple => Literal::Tuple( - inner - .map(Expression::try_from) - .collect::>>()?, - ), - _ => unimplemented!("{rule:#?}"), - }) - } -} - impl<'a> TryFrom> for Expression { type Error = ParseError<'a>; @@ -896,118 +830,3 @@ impl<'a> TryFrom> for FieldDecl { } } } - -impl<'a> TryFrom> for FunctionDecl { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner)?; - let return_type = TypeExpr::try_from(inner.next().unwrap())?; - let name = Identifier::try_from(inner.next().unwrap())?; - let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(); - - let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { - let mut param_inner = param.into_inner(); - let name = Pattern::Id(Identifier(String::from("self"))); - - let mutable = listen_rule(&mut param_inner, Rule::mutable); - - let is_ref = listen_rule(&mut param_inner, Rule::deref_px); - - VarDecl { - mutable: mutable && !is_ref, - name: name.clone(), - type_: Some(TypeExpr( - TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])), - if is_ref { - vec![if mutable { - TypePostfix::RefMut - } else { - TypePostfix::Ref - }] - } else { - Vec::new() - }, - )), - } - }); - - let params = consume_rule(&mut inner, Rule::param_list) - .map({ - let self_param = self_param.clone(); - |params_pair| -> ParseResult<'a, ParamList> { - let mut params = ParamList::try_from(params_pair)?; - if let Some(x) = self_param { - params.0.insert(0, x); - } - Ok(params) - } - }) - .transpose()? - .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); - - let body = inner.next().map(Block::try_from).transpose()?; - - Ok(Self { - visibility, - name, - generics, - params, - return_type, - body, - }) - } -} -impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { - type Error = ParseError<'a>; - - fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result { - Ok(consume_rule(pairs, Rule::visibility) - .map(|pair| -> Result> { - if let Some(path) = pair.into_inner().next() { - Ok(Visibility::PublicTarget(Path::try_from(path)?)) - } else { - Ok(Visibility::Public) - } - }) - .transpose()? - .unwrap_or_else(|| Visibility::Private)) - } -} - -pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { - let consumed = pairs - .peek() - .map(|p| p.as_rule() == rule) - .unwrap_or_default(); - - if consumed { - pairs.next(); - } - - consumed -} - -pub fn consume_rule<'a>( - pairs: &mut pest::iterators::Pairs<'a, Rule>, - rule: Rule, -) -> Option> { - let consumed = pairs - .peek() - .map(|p| p.as_rule() == rule) - .unwrap_or_default(); - - if consumed { pairs.next() } else { None } -} - -impl<'a> TryFrom> for Identifier { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Ok(Identifier(pair.as_str().to_string())) - } -} diff --git a/parser/src/parser/common.rs b/parser/src/parser/common.rs new file mode 100644 index 0000000..d4d274c --- /dev/null +++ b/parser/src/parser/common.rs @@ -0,0 +1,94 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for Identifier { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(Identifier(pair.as_str().to_string())) + } +} + +impl<'a> TryFrom> for Path { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::static_path => Ok(Path( + pair.into_inner() + .map(Identifier::try_from) + .collect::>>()?, + )), + _ => unimplemented!("{pair:#?}"), + } + } +} + +impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { + type Error = ParseError<'a>; + + fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result { + Ok(consume_rule(pairs, Rule::visibility) + .map(|pair| -> Result> { + if let Some(path) = pair.into_inner().next() { + Ok(Visibility::PublicTarget(Path::try_from(path)?)) + } else { + Ok(Visibility::Public) + } + }) + .transpose()? + .unwrap_or_else(|| Visibility::Private)) + } +} + +impl<'a> TryFrom> for Literal { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::primary => Self::try_from(inner.next().unwrap())?, + Rule::literal => Self::try_from(inner.next().unwrap())?, + Rule::integer => Literal::Int(pair.as_str().parse::().unwrap()), + Rule::float => Literal::Float(pair.as_str().parse::().unwrap()), + Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), + Rule::string_lit => Literal::String(inner.as_str().to_string()), + Rule::tuple => Literal::Tuple( + inner + .map(Expression::try_from) + .collect::>>()?, + ), + _ => unimplemented!("{rule:#?}"), + }) + } +} + +impl<'a> TryFrom> for TypeExpr { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::type_expr => Ok(TypeExpr( + TypeExprKind::try_from(inner.next().unwrap())?, + inner + .map(TypePostfix::try_from) + .collect::>()?, + )), + Rule::type_expr_param => Self::try_from(inner.next().unwrap()), + Rule::lifetime => Ok(TypeExpr( + TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), + Vec::new(), + )), + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs new file mode 100644 index 0000000..4de9d45 --- /dev/null +++ b/parser/src/parser/items/function.rs @@ -0,0 +1,72 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, + parser::{consume_rule, listen_rule}, +}; + +impl<'a> TryFrom> for FunctionDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + let visibility = Visibility::try_from(&mut inner)?; + let return_type = TypeExpr::try_from(inner.next().unwrap())?; + let name = Identifier::try_from(inner.next().unwrap())?; + let generics = consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(); + + let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { + let mut param_inner = param.into_inner(); + let name = Pattern::Id(Identifier(String::from("self"))); + + let mutable = listen_rule(&mut param_inner, Rule::mutable); + + let is_ref = listen_rule(&mut param_inner, Rule::deref_px); + + VarDecl { + mutable: mutable && !is_ref, + name: name.clone(), + type_: Some(TypeExpr( + TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])), + if is_ref { + vec![if mutable { + TypePostfix::RefMut + } else { + TypePostfix::Ref + }] + } else { + Vec::new() + }, + )), + } + }); + + let params = consume_rule(&mut inner, Rule::param_list) + .map({ + let self_param = self_param.clone(); + |params_pair| -> ParseResult<'a, ParamList> { + let mut params = ParamList::try_from(params_pair)?; + if let Some(x) = self_param { + params.0.insert(0, x); + } + Ok(params) + } + }) + .transpose()? + .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); + + let body = inner.next().map(Block::try_from).transpose()?; + + Ok(Self { + visibility, + name, + generics, + params, + return_type, + body, + }) + } +} diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs new file mode 100644 index 0000000..7fd349b --- /dev/null +++ b/parser/src/parser/items/mod.rs @@ -0,0 +1 @@ +pub mod function; \ No newline at end of file diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs new file mode 100644 index 0000000..d7dad09 --- /dev/null +++ b/parser/src/parser/mod.rs @@ -0,0 +1,29 @@ +pub mod common; +pub mod items; + +use crate::Rule; + +pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { + let consumed = pairs + .peek() + .map(|p| p.as_rule() == rule) + .unwrap_or_default(); + + if consumed { + pairs.next(); + } + + consumed +} + +pub fn consume_rule<'a>( + pairs: &mut pest::iterators::Pairs<'a, Rule>, + rule: Rule, +) -> Option> { + let consumed = pairs + .peek() + .map(|p| p.as_rule() == rule) + .unwrap_or_default(); + + if consumed { pairs.next() } else { None } +} From 00e10d1097eb06dac810c31d698acdd8bf10306f Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 21:35:41 +0200 Subject: [PATCH 10/27] Separated classes, attributes, and types --- parser/src/lib.rs | 295 ------------------ .../src/parser/{common.rs => common/mod.rs} | 50 +-- parser/src/parser/common/types.rs | 93 ++++++ parser/src/parser/items/attribute.rs | 70 +++++ parser/src/parser/items/class.rs | 46 +++ parser/src/parser/items/mod.rs | 133 +++++++- 6 files changed, 355 insertions(+), 332 deletions(-) rename parser/src/parser/{common.rs => common/mod.rs} (74%) create mode 100644 parser/src/parser/common/types.rs create mode 100644 parser/src/parser/items/attribute.rs create mode 100644 parser/src/parser/items/class.rs diff --git a/parser/src/lib.rs b/parser/src/lib.rs index f72ada3..b95c367 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -29,69 +29,6 @@ pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { Ok(statements) } -impl<'a> TryFrom> for TypePostfix { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::ref_type => { - let mutable = listen_rule(&mut inner, Rule::mutable); - let lifetime = consume_rule(&mut inner, Rule::lifetime) - .map(|pair| Identifier::try_from(pair.into_inner().next().unwrap())) - .transpose()?; - - Ok(if mutable { - if let Some(lifetime) = lifetime { - TypePostfix::RefMutLifetime(lifetime) - } else { - TypePostfix::RefMut - } - } else { - if let Some(lifetime) = lifetime { - TypePostfix::RefLifetime(lifetime) - } else { - TypePostfix::Ref - } - }) - } - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl<'a> TryFrom> for TypeExprKind { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::tuple_type => Ok(TypeExprKind::Tuple( - inner - .map(TypeExpr::try_from) - .collect::>()?, - )), - Rule::path_type => { - let path = Path::try_from(inner.next().unwrap())?; - let params = inner - .map(TypeExpr::try_from) - .collect::>>()?; - - if params.len() == 0 { - Ok(TypeExprKind::Path(path)) - } else { - Ok(TypeExprKind::PathParams(path, params)) - } - } - _ => unimplemented!("{rule:#?}"), - } - } -} - impl<'a> TryFrom> for ParamList { type Error = ParseError<'a>; @@ -104,94 +41,6 @@ impl<'a> TryFrom> for ParamList { } } -impl<'a> TryFrom> for Attribute { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - match pair.as_rule() { - Rule::attribute => { - // unwrap #[ ... ] - Attribute::try_from(pair.into_inner().next().unwrap()) - } - - Rule::meta => { - let mut inner = pair.into_inner(); - - // first item is always the path - let path = Path::try_from(inner.next().unwrap())?; - - // check what comes next - match inner.next() { - None => { - // #[path] - Ok(Attribute::Path(path)) - } - - Some(next) => match next.as_rule() { - Rule::primary => { - // #[path = literal] - Ok(Attribute::NameValue { - path, - value: Literal::try_from(next)?, - }) - } - - Rule::meta_list => { - // #[path(...)] - let items = next - .into_inner() - .map(Attribute::try_from) - .collect::>>()?; - - Ok(Attribute::List { path, items }) - } - - _ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()), - }, - } - } - - Rule::meta_list => { - // This case usually won't be hit directly, - // but it's nice to keep it safe if reused - let items = pair - .into_inner() - .map(Attribute::try_from) - .collect::>(); - - // NOTE: this shouldn't normally construct an Attribute alone - // but you can panic or wrap depending on your design - panic!("meta_list should be handled inside meta: {:?}", items); - } - - _ => unreachable!("unexpected rule: {:?}", pair.as_rule()), - } - } -} - -impl<'a> TryFrom> for TopLevel { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let mut inner = pair.into_inner(); - - let attributes = inner - .next() - .unwrap() - .into_inner() - .map(Attribute::try_from) - .collect::>>()?; - - Ok(TopLevel( - inner - .next() - .map(TopLevelKind::try_from) - .unwrap_or(Ok(TopLevelKind::ModAttribute))?, - attributes, - )) - } -} - impl<'a> TryFrom> for StatementBranch { type Error = ParseError<'a>; @@ -208,33 +57,6 @@ impl<'a> TryFrom> for StatementBranch { } } -impl<'a> TryFrom> for ClassConstructor { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let mut inner = pair.into_inner(); - - let visibility = Visibility::try_from(&mut inner)?; - - let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(); - - let params = consume_rule(&mut inner, Rule::param_list) - .map(ParamList::try_from) - .transpose()? - .unwrap_or_default(); - - Ok(Self { - visibility, - generics, - params, - body: Block::try_from(inner.next().unwrap())?, - }) - } -} - impl<'a> TryFrom> for Generics { type Error = ParseError<'a>; @@ -269,123 +91,6 @@ impl<'a> TryFrom> for Generics { } } -impl<'a> TryFrom> for TopLevelKind { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - Ok(match rule { - Rule::import => TopLevelKind::Import( - Visibility::try_from(&mut inner)?, - Path::try_from(inner.next().unwrap())?, - ), - - Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::try_from(pair)?), - - Rule::struct_decl => TopLevelKind::StructDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(), - fields: inner - .next() - .map(|pair| { - pair.into_inner() - .map(FieldDecl::try_from) - .collect::>>() - }) - .transpose()? - .unwrap_or_default(), - }, - - Rule::class_decl => TopLevelKind::ClassDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(), - fields: inner - .next() - .unwrap() - .into_inner() - .map(FieldDeclStmt::try_from) - .collect::>>()?, - constructor: ClassConstructor::try_from(inner.next().unwrap())?, - items: inner - .into_iter() - .map(ClassItem::try_from) - .collect::>>()?, - }, - - Rule::enum_decl => TopLevelKind::EnumDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(), - fields: inner - .map(EnumItem::try_from) - .collect::>>()?, - }, - - Rule::mod_package => TopLevelKind::Mod( - Visibility::try_from(&mut inner)?, - Identifier::try_from(inner.next().unwrap())?, - ), - - Rule::impl_for_decl | Rule::impl_decl => { - TopLevelKind::ImplDecl(ImplDecl::try_from(pair)?) - } - - Rule::trait_decl => TopLevelKind::TraitDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(), - requirements: consume_rule(&mut inner, Rule::trait_requirements) - .map(|pair| { - pair.into_inner() - .map(TypeExpr::try_from) - .collect::>>() - }) - .transpose()? - .unwrap_or_default(), - items: inner - .map(FunctionDecl::try_from) - .collect::>>()?, - }, - - _ => unimplemented!("{rule:#?}"), - }) - } -} - -impl<'a> TryFrom> for ClassItem { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - - match rule { - Rule::impl_decl | Rule::impl_for_decl => { - Ok(ClassItem::ImplDecl(ImplDecl::try_from(pair)?)) - } - - Rule::method => Ok(ClassItem::Method(FunctionDecl::try_from(pair)?)), - - _ => unimplemented!("{rule:#?}"), - } - } -} - impl<'a> TryFrom> for ImplDecl { type Error = ParseError<'a>; diff --git a/parser/src/parser/common.rs b/parser/src/parser/common/mod.rs similarity index 74% rename from parser/src/parser/common.rs rename to parser/src/parser/common/mod.rs index d4d274c..a6acde1 100644 --- a/parser/src/parser/common.rs +++ b/parser/src/parser/common/mod.rs @@ -1,3 +1,5 @@ +pub mod types; + use crate::{ Rule, ast::*, @@ -28,23 +30,6 @@ impl<'a> TryFrom> for Path { } } -impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { - type Error = ParseError<'a>; - - fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result { - Ok(consume_rule(pairs, Rule::visibility) - .map(|pair| -> Result> { - if let Some(path) = pair.into_inner().next() { - Ok(Visibility::PublicTarget(Path::try_from(path)?)) - } else { - Ok(Visibility::Public) - } - }) - .transpose()? - .unwrap_or_else(|| Visibility::Private)) - } -} - impl<'a> TryFrom> for Literal { type Error = ParseError<'a>; @@ -69,26 +54,19 @@ impl<'a> TryFrom> for Literal { } } -impl<'a> TryFrom> for TypeExpr { +impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { type Error = ParseError<'a>; - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::type_expr => Ok(TypeExpr( - TypeExprKind::try_from(inner.next().unwrap())?, - inner - .map(TypePostfix::try_from) - .collect::>()?, - )), - Rule::type_expr_param => Self::try_from(inner.next().unwrap()), - Rule::lifetime => Ok(TypeExpr( - TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), - Vec::new(), - )), - _ => unimplemented!("{rule:#?}"), - } + fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result { + Ok(consume_rule(pairs, Rule::visibility) + .map(|pair| -> Result> { + if let Some(path) = pair.into_inner().next() { + Ok(Visibility::PublicTarget(Path::try_from(path)?)) + } else { + Ok(Visibility::Public) + } + }) + .transpose()? + .unwrap_or_else(|| Visibility::Private)) } } diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs new file mode 100644 index 0000000..08050b9 --- /dev/null +++ b/parser/src/parser/common/types.rs @@ -0,0 +1,93 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, + parser::{consume_rule, listen_rule}, +}; + +impl<'a> TryFrom> for TypePostfix { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::ref_type => { + let mutable = listen_rule(&mut inner, Rule::mutable); + let lifetime = consume_rule(&mut inner, Rule::lifetime) + .map(|pair| Identifier::try_from(pair.into_inner().next().unwrap())) + .transpose()?; + + Ok(if mutable { + if let Some(lifetime) = lifetime { + TypePostfix::RefMutLifetime(lifetime) + } else { + TypePostfix::RefMut + } + } else { + if let Some(lifetime) = lifetime { + TypePostfix::RefLifetime(lifetime) + } else { + TypePostfix::Ref + } + }) + } + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for TypeExprKind { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::tuple_type => Ok(TypeExprKind::Tuple( + inner + .map(TypeExpr::try_from) + .collect::>()?, + )), + Rule::path_type => { + let path = Path::try_from(inner.next().unwrap())?; + let params = inner + .map(TypeExpr::try_from) + .collect::>>()?; + + if params.len() == 0 { + Ok(TypeExprKind::Path(path)) + } else { + Ok(TypeExprKind::PathParams(path, params)) + } + } + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for TypeExpr { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::type_expr => Ok(TypeExpr( + TypeExprKind::try_from(inner.next().unwrap())?, + inner + .map(TypePostfix::try_from) + .collect::>()?, + )), + Rule::type_expr_param => Self::try_from(inner.next().unwrap()), + Rule::lifetime => Ok(TypeExpr( + TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), + Vec::new(), + )), + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/attribute.rs b/parser/src/parser/items/attribute.rs new file mode 100644 index 0000000..89ea34f --- /dev/null +++ b/parser/src/parser/items/attribute.rs @@ -0,0 +1,70 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, +}; + +impl<'a> TryFrom> for Attribute { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::attribute => { + // unwrap #[ ... ] + Attribute::try_from(pair.into_inner().next().unwrap()) + } + + Rule::meta => { + let mut inner = pair.into_inner(); + + // first item is always the path + let path = Path::try_from(inner.next().unwrap())?; + + // check what comes next + match inner.next() { + None => { + // #[path] + Ok(Attribute::Path(path)) + } + + Some(next) => match next.as_rule() { + Rule::primary => { + // #[path = literal] + Ok(Attribute::NameValue { + path, + value: Literal::try_from(next)?, + }) + } + + Rule::meta_list => { + // #[path(...)] + let items = next + .into_inner() + .map(Attribute::try_from) + .collect::>>()?; + + Ok(Attribute::List { path, items }) + } + + _ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()), + }, + } + } + + Rule::meta_list => { + // This case usually won't be hit directly, + // but it's nice to keep it safe if reused + let items = pair + .into_inner() + .map(Attribute::try_from) + .collect::>(); + + // NOTE: this shouldn't normally construct an Attribute alone + // but you can panic or wrap depending on your design + panic!("meta_list should be handled inside meta: {:?}", items); + } + + _ => unreachable!("unexpected rule: {:?}", pair.as_rule()), + } + } +} diff --git a/parser/src/parser/items/class.rs b/parser/src/parser/items/class.rs new file mode 100644 index 0000000..b80f566 --- /dev/null +++ b/parser/src/parser/items/class.rs @@ -0,0 +1,46 @@ +use crate::{Rule, ast::*, error::ParseError, parser::consume_rule}; + +impl<'a> TryFrom> for ClassConstructor { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + + let visibility = Visibility::try_from(&mut inner)?; + + let generics = consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(); + + let params = consume_rule(&mut inner, Rule::param_list) + .map(ParamList::try_from) + .transpose()? + .unwrap_or_default(); + + Ok(Self { + visibility, + generics, + params, + body: Block::try_from(inner.next().unwrap())?, + }) + } +} + +impl<'a> TryFrom> for ClassItem { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + + match rule { + Rule::impl_decl | Rule::impl_for_decl => { + Ok(ClassItem::ImplDecl(ImplDecl::try_from(pair)?)) + } + + Rule::method => Ok(ClassItem::Method(FunctionDecl::try_from(pair)?)), + + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 7fd349b..8db6a16 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -1 +1,132 @@ -pub mod function; \ No newline at end of file +pub mod attribute; +pub mod class; +pub mod function; + +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for TopLevel { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + + let attributes = inner + .next() + .unwrap() + .into_inner() + .map(Attribute::try_from) + .collect::>>()?; + + Ok(TopLevel( + inner + .next() + .map(TopLevelKind::try_from) + .unwrap_or(Ok(TopLevelKind::ModAttribute))?, + attributes, + )) + } +} + +impl<'a> TryFrom> for TopLevelKind { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::import => TopLevelKind::Import( + Visibility::try_from(&mut inner)?, + Path::try_from(inner.next().unwrap())?, + ), + + Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::try_from(pair)?), + + Rule::struct_decl => TopLevelKind::StructDecl { + visibility: Visibility::try_from(&mut inner)?, + name: Identifier::try_from(inner.next().unwrap())?, + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(), + fields: inner + .next() + .map(|pair| { + pair.into_inner() + .map(FieldDecl::try_from) + .collect::>>() + }) + .transpose()? + .unwrap_or_default(), + }, + + Rule::class_decl => TopLevelKind::ClassDecl { + visibility: Visibility::try_from(&mut inner)?, + name: Identifier::try_from(inner.next().unwrap())?, + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(), + fields: inner + .next() + .unwrap() + .into_inner() + .map(FieldDeclStmt::try_from) + .collect::>>()?, + constructor: ClassConstructor::try_from(inner.next().unwrap())?, + items: inner + .into_iter() + .map(ClassItem::try_from) + .collect::>>()?, + }, + + Rule::enum_decl => TopLevelKind::EnumDecl { + visibility: Visibility::try_from(&mut inner)?, + name: Identifier::try_from(inner.next().unwrap())?, + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(), + fields: inner + .map(EnumItem::try_from) + .collect::>>()?, + }, + + Rule::mod_package => TopLevelKind::Mod( + Visibility::try_from(&mut inner)?, + Identifier::try_from(inner.next().unwrap())?, + ), + + Rule::impl_for_decl | Rule::impl_decl => { + TopLevelKind::ImplDecl(ImplDecl::try_from(pair)?) + } + + Rule::trait_decl => TopLevelKind::TraitDecl { + visibility: Visibility::try_from(&mut inner)?, + name: Identifier::try_from(inner.next().unwrap())?, + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(), + requirements: consume_rule(&mut inner, Rule::trait_requirements) + .map(|pair| { + pair.into_inner() + .map(TypeExpr::try_from) + .collect::>>() + }) + .transpose()? + .unwrap_or_default(), + items: inner + .map(FunctionDecl::try_from) + .collect::>>()?, + }, + + _ => unimplemented!("{rule:#?}"), + }) + } +} From 5912032dfffe51ccdd26b734f0a9a3ba18ba39be Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 21:44:00 +0200 Subject: [PATCH 11/27] Enums and impl decl --- parser/src/lib.rs | 77 ---------------------------- parser/src/parser/items/enums.rs | 45 ++++++++++++++++ parser/src/parser/items/impl_decl.rs | 43 ++++++++++++++++ parser/src/parser/items/mod.rs | 2 + 4 files changed, 90 insertions(+), 77 deletions(-) create mode 100644 parser/src/parser/items/enums.rs create mode 100644 parser/src/parser/items/impl_decl.rs diff --git a/parser/src/lib.rs b/parser/src/lib.rs index b95c367..ee0a859 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -91,83 +91,6 @@ impl<'a> TryFrom> for Generics { } } -impl<'a> TryFrom> for ImplDecl { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::impl_for_decl => Ok(ImplDecl { - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(), - trait_: Some(TypeExpr::try_from(inner.next().unwrap())?), - target: TypeExpr::try_from(inner.next().unwrap())?, - methods: inner - .map(FunctionDecl::try_from) - .collect::>>()?, - }), - - Rule::impl_decl => Ok(ImplDecl { - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(), - trait_: None, - target: TypeExpr::try_from(inner.next().unwrap())?, - methods: inner - .map(FunctionDecl::try_from) - .collect::>>()?, - }), - - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl<'a> TryFrom> for EnumItem { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::enum_named => Ok(EnumItem::Named(Identifier::try_from( - inner.next().unwrap(), - )?)), - - Rule::enum_tuple => Ok(EnumItem::Tuple( - Identifier::try_from(inner.next().unwrap())?, - inner - .next() - .unwrap() - .into_inner() - .map(TypeExpr::try_from) - .collect::>>()?, - )), - - Rule::enum_struct => Ok(EnumItem::Struct( - Identifier::try_from(inner.next().unwrap())?, - inner - .next() - .map(|pair| { - pair.into_inner() - .map(FieldDecl::try_from) - .collect::>>() - }) - .transpose()? - .unwrap_or_default(), - )), - - _ => unimplemented!("{rule:#?}"), - } - } -} - impl<'a> TryFrom> for Block { type Error = ParseError<'a>; diff --git a/parser/src/parser/items/enums.rs b/parser/src/parser/items/enums.rs new file mode 100644 index 0000000..883ee77 --- /dev/null +++ b/parser/src/parser/items/enums.rs @@ -0,0 +1,45 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, +}; + +impl<'a> TryFrom> for EnumItem { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::enum_named => Ok(EnumItem::Named(Identifier::try_from( + inner.next().unwrap(), + )?)), + + Rule::enum_tuple => Ok(EnumItem::Tuple( + Identifier::try_from(inner.next().unwrap())?, + inner + .next() + .unwrap() + .into_inner() + .map(TypeExpr::try_from) + .collect::>>()?, + )), + + Rule::enum_struct => Ok(EnumItem::Struct( + Identifier::try_from(inner.next().unwrap())?, + inner + .next() + .map(|pair| { + pair.into_inner() + .map(FieldDecl::try_from) + .collect::>>() + }) + .transpose()? + .unwrap_or_default(), + )), + + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/impl_decl.rs b/parser/src/parser/items/impl_decl.rs new file mode 100644 index 0000000..76952a1 --- /dev/null +++ b/parser/src/parser/items/impl_decl.rs @@ -0,0 +1,43 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for ImplDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::impl_for_decl => Ok(ImplDecl { + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(), + trait_: Some(TypeExpr::try_from(inner.next().unwrap())?), + target: TypeExpr::try_from(inner.next().unwrap())?, + methods: inner + .map(FunctionDecl::try_from) + .collect::>>()?, + }), + + Rule::impl_decl => Ok(ImplDecl { + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .unwrap_or_default(), + trait_: None, + target: TypeExpr::try_from(inner.next().unwrap())?, + methods: inner + .map(FunctionDecl::try_from) + .collect::>>()?, + }), + + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 8db6a16..540dd2d 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -1,6 +1,8 @@ pub mod attribute; pub mod class; +pub mod enums; pub mod function; +pub mod impl_decl; use crate::{ Rule, From 78cac259f2cc90374d606993c06b84dc0e3a942a Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 21:52:56 +0200 Subject: [PATCH 12/27] Decl, Expr, and statement --- parser/src/lib.rs | 434 +------------------------- parser/src/parser/common/decl.rs | 100 ++++++ parser/src/parser/common/expr.rs | 165 ++++++++++ parser/src/parser/common/mod.rs | 3 + parser/src/parser/common/statement.rs | 131 ++++++++ parser/src/parser/common/types.rs | 34 ++ parser/src/parser/items/function.rs | 12 + 7 files changed, 446 insertions(+), 433 deletions(-) create mode 100644 parser/src/parser/common/decl.rs create mode 100644 parser/src/parser/common/expr.rs create mode 100644 parser/src/parser/common/statement.rs diff --git a/parser/src/lib.rs b/parser/src/lib.rs index ee0a859..9b99918 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -7,9 +7,7 @@ pub mod parser; use ast::*; -use crate::error::{ErrorCode, ParseError, ParseResult}; - -use crate::parser::{consume_rule, listen_rule}; +use crate::error::ParseResult; #[derive(Parser)] #[grammar = "./src/grammar.pest"] @@ -28,433 +26,3 @@ pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { Ok(statements) } - -impl<'a> TryFrom> for ParamList { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Ok(ParamList( - pair.into_inner() - .map(VarDecl::try_from) - .collect::>>()?, - )) - } -} - -impl<'a> TryFrom> for StatementBranch { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let mut inner = pair.into_inner(); - - let condition = Expression::try_from(inner.next().unwrap())?; - let body = Statement::try_from(inner.next().unwrap())?; - - Ok(StatementBranch { - condition, - body: Box::new(body), - }) - } -} - -impl<'a> TryFrom> for Generics { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let inner = pair.clone().into_inner(); - - match rule { - Rule::generics => Ok(Generics( - inner - .map(|pair| -> ParseResult<'a, Generic> { - let mut inner = pair.into_inner(); - Ok( - if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { - Generic::Lifetime(Identifier::try_from( - pair.into_inner().next().unwrap(), - )?) - } else { - Generic::Type( - Identifier::try_from(inner.next().unwrap())?, - inner - .map(TypeExpr::try_from) - .collect::>>()?, - ) - }, - ) - }) - .collect::>>()?, - )), - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl<'a> TryFrom> for Block { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let statements = pair - .into_inner() - .flat_map(|pair| { - if pair.as_rule() == Rule::statement_list { - pair.into_inner().map(Statement::try_from).collect() - } else { - vec![Statement::try_from(pair)] - } - }) - .collect::>>()?; - - Ok(Block(statements)) - } -} - -impl<'a> TryFrom> for Statement { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - Ok(match rule { - Rule::statement => Statement::try_from(inner.next().unwrap())?, - - Rule::expr_stmt => Statement::Expression(Expression::try_from(inner.next().unwrap())?), - - Rule::block => Statement::Block(Block::try_from(inner.next().unwrap())?), - - Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair)?), - - Rule::return_stmt => { - Statement::Return(inner.next().map(Expression::try_from).transpose()?) - } - - Rule::break_stmt => Statement::Break, - - Rule::continue_stmt => Statement::Continue, - - Rule::if_stmt => { - let mut inner = inner.skip(2); - - Statement::If { - initial: StatementBranch::try_from(pair)?, - else_if: inner - .next() - .unwrap() - .into_inner() - .map(StatementBranch::try_from) - .collect::>>()?, - else_branch: inner - .next() - .map(Statement::try_from) - .transpose()? - .map(Box::new), - } - } - - Rule::while_stmt => Statement::While(pair.try_into()?), - - Rule::c_for_stmt => Statement::CStyleFor { - init: Box::new(Statement::try_from(inner.next().unwrap())?), - condition: inner.next().unwrap().try_into()?, - update: Box::new(Statement::try_from(inner.next().unwrap())?), - body: Box::new(Statement::try_from(inner.next().unwrap())?), - }, - - Rule::for_stmt => Statement::For { - mutable: listen_rule(&mut inner, Rule::mutable), - pattern: Pattern::try_from(inner.next().unwrap())?, - iterator: inner.next().unwrap().try_into()?, - body: Box::new(Statement::try_from(inner.next().unwrap())?), - }, - - Rule::assign_statement => Statement::VarAssign(VarAssignStmt { - target: Expression::try_from(inner.next().unwrap())?, - value: Expression::try_from(inner.next().unwrap())?, - }), - - Rule::match_stmt => Statement::Match( - Expression::try_from(inner.next().unwrap())?, - inner - .map(|match_itms| { - let mut match_inner = match_itms.into_inner(); - Ok(( - Pattern::try_from(match_inner.next().unwrap())?, - Block::try_from(match_inner.next().unwrap())?, - )) - }) - .collect::>>()?, - ), - - Rule::unexpected_statement => { - return Err(ParseError::Ast { - span: pair.as_span(), - error_code: ErrorCode::InvalidStatement, - error_message: "Invalid Statement".to_string(), - }); - } - - _ => unimplemented!("{rule:#?}"), - }) - } -} - -impl<'a> TryFrom> for Expression { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::expr => { - let prefixes: Vec = inner - .next() - .map(|p| { - p.into_inner() - .into_iter() - .map(Prefix::try_from) - .collect::>>() - }) - .transpose()? - .unwrap_or_default(); - - let exp = Expression::try_from(inner.next().unwrap())?; - - if inner.len() > 0 || prefixes.len() > 0 { - Ok(Expression::Fix { - initial: Box::new(exp), - prefixes, - postfixes: inner - .map(|p| Postfix::try_from(p)) - .collect::>>()?, - }) - } else { - Ok(exp) - } - } - Rule::primary => Expression::try_from(inner.next().unwrap()), - Rule::static_path => Ok(Expression::Path(Path::try_from(pair)?)), - Rule::literal => Ok(Expression::Literal(Literal::try_from(pair)?)), - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl<'a> TryFrom> for Prefix { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Ok(match pair.as_rule() { - Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?, - Rule::deref_px => Self::Deref, - Rule::mut_ref_px => Self::RefMut, - Rule::ref_px => Self::Ref, - Rule::new_px => Self::New, - Rule::not_px => Self::Not, - _ => unimplemented!("{pair:#?}"), - }) - } -} - -impl<'a> TryFrom> for Postfix { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - Ok(match rule { - Rule::postfix => Postfix::try_from(inner.next().unwrap())?, - - Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), - - Rule::call_px => Postfix::Call( - inner - .map(Expression::try_from) - .collect::>>()?, - ), - - Rule::struct_px => Postfix::StructCall( - inner - .map(|p| { - let mut pi = p.into_inner(); - Ok(( - Identifier::try_from(pi.next().unwrap())?, - Expression::try_from(pi.next().unwrap())?, - )) - }) - .collect::>>()?, - ), - - Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), - - Rule::binary_px => { - let op_pair = inner.next().unwrap(); - let op = match op_pair.as_str() { - "+" => BinaryOp::Plus, - "-" => BinaryOp::Minus, - "*" => BinaryOp::Multiply, - "/" => BinaryOp::Divide, - "%" => BinaryOp::Modulo, - "==" => BinaryOp::Equal, - "!=" => BinaryOp::NotEqual, - "<" => BinaryOp::LessThan, - ">" => BinaryOp::GreaterThan, - "<=" => BinaryOp::LessThanOrEqual, - ">=" => BinaryOp::GreaterThanOrEqual, - "&&" => BinaryOp::And, - "||" => BinaryOp::Or, - - _ => { - unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) - } - }; - Postfix::Binary(op, Expression::try_from(inner.next().unwrap())?) - } - - Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), - - _ => unimplemented!("{rule:#?}"), - }) - } -} - -impl<'a> TryFrom> for VarDeclStmt { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - match pair.as_rule() { - Rule::var_decl_statement => { - let mut inner = pair.into_inner(); - - let decl = VarDecl::try_from(inner.next().unwrap())?; - - let init = inner.next().map(Expression::try_from).transpose()?; - - Ok(VarDeclStmt { decl, init }) - } - - _ => unimplemented!(), - } - } -} - -impl<'a> TryFrom> for FieldDeclStmt { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - match pair.as_rule() { - Rule::class_field => { - let mut inner = pair.into_inner(); - - let decl = FieldDecl::try_from(inner.next().unwrap())?; - - let init = inner.next().map(Expression::try_from).transpose()?; - - Ok(FieldDeclStmt { decl, init }) - } - - _ => unimplemented!(), - } - } -} - -impl<'a> TryFrom> for Pattern { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - Ok(match rule { - Rule::tuple_pattern => Pattern::Tuple( - inner - .map(Identifier::try_from) - .collect::>>()?, - ), - - Rule::named_tuple_pattern => Pattern::NamedTuple( - Path::try_from(inner.next().unwrap())?, - inner - .map(Identifier::try_from) - .collect::>>()?, - ), - - Rule::struct_pattern => Pattern::Struct( - Path::try_from(inner.next().unwrap())?, - inner - .map(Identifier::try_from) - .collect::>>()?, - ), - - Rule::literal => Pattern::Literal(Literal::try_from(pair)?), - - Rule::identifier => Pattern::Id(Identifier::try_from(pair)?), - - Rule::static_path => Pattern::Path(Path::try_from(pair)?), - - _ => unimplemented!("{rule:?}"), - }) - } -} - -impl<'a> TryFrom> for VarDecl { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - match pair.as_rule() { - Rule::var_decl => { - let mut inner = pair.into_inner(); - - let type_ = inner - .next() - .and_then(|pair| { - if pair.as_str().trim() == "var" { - None - } else { - Some(TypeExpr::try_from(pair)) - } - }) - .transpose()?; - - let mutable = listen_rule(&mut inner, Rule::mutable); - - let name = Pattern::try_from(inner.next().unwrap())?; - - Ok(VarDecl { - mutable, - name, - type_, - }) - } - - _ => unimplemented!("{:?}", pair.as_rule()), - } - } -} - -impl<'a> TryFrom> for FieldDecl { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - match pair.as_rule() { - Rule::field => { - let mut inner = pair.into_inner(); - - let visibility = Visibility::try_from(&mut inner)?; - let type_ = TypeExpr::try_from(inner.next().unwrap())?; - let name = Identifier::try_from(inner.next().unwrap())?; - - Ok(FieldDecl { - visibility, - type_, - name, - }) - } - - _ => unimplemented!("{:?}", pair.as_rule()), - } - } -} diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs new file mode 100644 index 0000000..9ffafdb --- /dev/null +++ b/parser/src/parser/common/decl.rs @@ -0,0 +1,100 @@ +use crate::{Rule, ast::*, error::ParseError, parser::listen_rule}; + +impl<'a> TryFrom> for VarDeclStmt { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::var_decl_statement => { + let mut inner = pair.into_inner(); + + let decl = VarDecl::try_from(inner.next().unwrap())?; + + let init = inner.next().map(Expression::try_from).transpose()?; + + Ok(VarDeclStmt { decl, init }) + } + + _ => unimplemented!(), + } + } +} + +impl<'a> TryFrom> for FieldDeclStmt { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::class_field => { + let mut inner = pair.into_inner(); + + let decl = FieldDecl::try_from(inner.next().unwrap())?; + + let init = inner.next().map(Expression::try_from).transpose()?; + + Ok(FieldDeclStmt { decl, init }) + } + + _ => unimplemented!(), + } + } +} + +impl<'a> TryFrom> for VarDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::var_decl => { + let mut inner = pair.into_inner(); + + let type_ = inner + .next() + .and_then(|pair| { + if pair.as_str().trim() == "var" { + None + } else { + Some(TypeExpr::try_from(pair)) + } + }) + .transpose()?; + + let mutable = listen_rule(&mut inner, Rule::mutable); + + let name = Pattern::try_from(inner.next().unwrap())?; + + Ok(VarDecl { + mutable, + name, + type_, + }) + } + + _ => unimplemented!("{:?}", pair.as_rule()), + } + } +} + +impl<'a> TryFrom> for FieldDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::field => { + let mut inner = pair.into_inner(); + + let visibility = Visibility::try_from(&mut inner)?; + let type_ = TypeExpr::try_from(inner.next().unwrap())?; + let name = Identifier::try_from(inner.next().unwrap())?; + + Ok(FieldDecl { + visibility, + type_, + name, + }) + } + + _ => unimplemented!("{:?}", pair.as_rule()), + } + } +} diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs new file mode 100644 index 0000000..0ff9be8 --- /dev/null +++ b/parser/src/parser/common/expr.rs @@ -0,0 +1,165 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, +}; + +impl<'a> TryFrom> for Expression { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::expr => { + let prefixes: Vec = inner + .next() + .map(|p| { + p.into_inner() + .into_iter() + .map(Prefix::try_from) + .collect::>>() + }) + .transpose()? + .unwrap_or_default(); + + let exp = Expression::try_from(inner.next().unwrap())?; + + if inner.len() > 0 || prefixes.len() > 0 { + Ok(Expression::Fix { + initial: Box::new(exp), + prefixes, + postfixes: inner + .map(|p| Postfix::try_from(p)) + .collect::>>()?, + }) + } else { + Ok(exp) + } + } + Rule::primary => Expression::try_from(inner.next().unwrap()), + Rule::static_path => Ok(Expression::Path(Path::try_from(pair)?)), + Rule::literal => Ok(Expression::Literal(Literal::try_from(pair)?)), + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for Prefix { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(match pair.as_rule() { + Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?, + Rule::deref_px => Self::Deref, + Rule::mut_ref_px => Self::RefMut, + Rule::ref_px => Self::Ref, + Rule::new_px => Self::New, + Rule::not_px => Self::Not, + _ => unimplemented!("{pair:#?}"), + }) + } +} + +impl<'a> TryFrom> for Postfix { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + Ok(match rule { + Rule::postfix => Postfix::try_from(inner.next().unwrap())?, + + Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), + + Rule::call_px => Postfix::Call( + inner + .map(Expression::try_from) + .collect::>>()?, + ), + + Rule::struct_px => Postfix::StructCall( + inner + .map(|p| { + let mut pi = p.into_inner(); + Ok(( + Identifier::try_from(pi.next().unwrap())?, + Expression::try_from(pi.next().unwrap())?, + )) + }) + .collect::>>()?, + ), + + Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), + + Rule::binary_px => { + let op_pair = inner.next().unwrap(); + let op = match op_pair.as_str() { + "+" => BinaryOp::Plus, + "-" => BinaryOp::Minus, + "*" => BinaryOp::Multiply, + "/" => BinaryOp::Divide, + "%" => BinaryOp::Modulo, + "==" => BinaryOp::Equal, + "!=" => BinaryOp::NotEqual, + "<" => BinaryOp::LessThan, + ">" => BinaryOp::GreaterThan, + "<=" => BinaryOp::LessThanOrEqual, + ">=" => BinaryOp::GreaterThanOrEqual, + "&&" => BinaryOp::And, + "||" => BinaryOp::Or, + + _ => { + unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) + } + }; + Postfix::Binary(op, Expression::try_from(inner.next().unwrap())?) + } + + Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), + + _ => unimplemented!("{rule:#?}"), + }) + } +} + +impl<'a> TryFrom> for Pattern { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::tuple_pattern => Pattern::Tuple( + inner + .map(Identifier::try_from) + .collect::>>()?, + ), + + Rule::named_tuple_pattern => Pattern::NamedTuple( + Path::try_from(inner.next().unwrap())?, + inner + .map(Identifier::try_from) + .collect::>>()?, + ), + + Rule::struct_pattern => Pattern::Struct( + Path::try_from(inner.next().unwrap())?, + inner + .map(Identifier::try_from) + .collect::>>()?, + ), + + Rule::literal => Pattern::Literal(Literal::try_from(pair)?), + + Rule::identifier => Pattern::Id(Identifier::try_from(pair)?), + + Rule::static_path => Pattern::Path(Path::try_from(pair)?), + + _ => unimplemented!("{rule:?}"), + }) + } +} diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index a6acde1..1f1169f 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -1,3 +1,6 @@ +pub mod decl; +pub mod expr; +pub mod statement; pub mod types; use crate::{ diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs new file mode 100644 index 0000000..f78065d --- /dev/null +++ b/parser/src/parser/common/statement.rs @@ -0,0 +1,131 @@ +use crate::{ + Rule, + ast::*, + error::{ErrorCode, ParseError, ParseResult}, + parser::listen_rule, +}; + +impl<'a> TryFrom> for Block { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let statements = pair + .into_inner() + .flat_map(|pair| { + if pair.as_rule() == Rule::statement_list { + pair.into_inner().map(Statement::try_from).collect() + } else { + vec![Statement::try_from(pair)] + } + }) + .collect::>>()?; + + Ok(Block(statements)) + } +} + +impl<'a> TryFrom> for Statement { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::statement => Statement::try_from(inner.next().unwrap())?, + + Rule::expr_stmt => Statement::Expression(Expression::try_from(inner.next().unwrap())?), + + Rule::block => Statement::Block(Block::try_from(inner.next().unwrap())?), + + Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair)?), + + Rule::return_stmt => { + Statement::Return(inner.next().map(Expression::try_from).transpose()?) + } + + Rule::break_stmt => Statement::Break, + + Rule::continue_stmt => Statement::Continue, + + Rule::if_stmt => { + let mut inner = inner.skip(2); + + Statement::If { + initial: StatementBranch::try_from(pair)?, + else_if: inner + .next() + .unwrap() + .into_inner() + .map(StatementBranch::try_from) + .collect::>>()?, + else_branch: inner + .next() + .map(Statement::try_from) + .transpose()? + .map(Box::new), + } + } + + Rule::while_stmt => Statement::While(pair.try_into()?), + + Rule::c_for_stmt => Statement::CStyleFor { + init: Box::new(Statement::try_from(inner.next().unwrap())?), + condition: inner.next().unwrap().try_into()?, + update: Box::new(Statement::try_from(inner.next().unwrap())?), + body: Box::new(Statement::try_from(inner.next().unwrap())?), + }, + + Rule::for_stmt => Statement::For { + mutable: listen_rule(&mut inner, Rule::mutable), + pattern: Pattern::try_from(inner.next().unwrap())?, + iterator: inner.next().unwrap().try_into()?, + body: Box::new(Statement::try_from(inner.next().unwrap())?), + }, + + Rule::assign_statement => Statement::VarAssign(VarAssignStmt { + target: Expression::try_from(inner.next().unwrap())?, + value: Expression::try_from(inner.next().unwrap())?, + }), + + Rule::match_stmt => Statement::Match( + Expression::try_from(inner.next().unwrap())?, + inner + .map(|match_itms| { + let mut match_inner = match_itms.into_inner(); + Ok(( + Pattern::try_from(match_inner.next().unwrap())?, + Block::try_from(match_inner.next().unwrap())?, + )) + }) + .collect::>>()?, + ), + + Rule::unexpected_statement => { + return Err(ParseError::Ast { + span: pair.as_span(), + error_code: ErrorCode::InvalidStatement, + error_message: "Invalid Statement".to_string(), + }); + } + + _ => unimplemented!("{rule:#?}"), + }) + } +} + +impl<'a> TryFrom> for StatementBranch { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + + let condition = Expression::try_from(inner.next().unwrap())?; + let body = Statement::try_from(inner.next().unwrap())?; + + Ok(StatementBranch { + condition, + body: Box::new(body), + }) + } +} diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs index 08050b9..f5dc265 100644 --- a/parser/src/parser/common/types.rs +++ b/parser/src/parser/common/types.rs @@ -91,3 +91,37 @@ impl<'a> TryFrom> for TypeExpr { } } } + +impl<'a> TryFrom> for Generics { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let inner = pair.clone().into_inner(); + + match rule { + Rule::generics => Ok(Generics( + inner + .map(|pair| -> ParseResult<'a, Generic> { + let mut inner = pair.into_inner(); + Ok( + if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { + Generic::Lifetime(Identifier::try_from( + pair.into_inner().next().unwrap(), + )?) + } else { + Generic::Type( + Identifier::try_from(inner.next().unwrap())?, + inner + .map(TypeExpr::try_from) + .collect::>>()?, + ) + }, + ) + }) + .collect::>>()?, + )), + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs index 4de9d45..07520ad 100644 --- a/parser/src/parser/items/function.rs +++ b/parser/src/parser/items/function.rs @@ -70,3 +70,15 @@ impl<'a> TryFrom> for FunctionDecl { }) } } + +impl<'a> TryFrom> for ParamList { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(ParamList( + pair.into_inner() + .map(VarDecl::try_from) + .collect::>>()?, + )) + } +} From 626990216c32dd201bf6d4cf88839a17458f262e Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 21:55:32 +0200 Subject: [PATCH 13/27] Moved pattern to general common --- parser/src/parser/common/expr.rs | 39 -------------------------------- parser/src/parser/common/mod.rs | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 0ff9be8..1269b8a 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -124,42 +124,3 @@ impl<'a> TryFrom> for Postfix { }) } } - -impl<'a> TryFrom> for Pattern { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - Ok(match rule { - Rule::tuple_pattern => Pattern::Tuple( - inner - .map(Identifier::try_from) - .collect::>>()?, - ), - - Rule::named_tuple_pattern => Pattern::NamedTuple( - Path::try_from(inner.next().unwrap())?, - inner - .map(Identifier::try_from) - .collect::>>()?, - ), - - Rule::struct_pattern => Pattern::Struct( - Path::try_from(inner.next().unwrap())?, - inner - .map(Identifier::try_from) - .collect::>>()?, - ), - - Rule::literal => Pattern::Literal(Literal::try_from(pair)?), - - Rule::identifier => Pattern::Id(Identifier::try_from(pair)?), - - Rule::static_path => Pattern::Path(Path::try_from(pair)?), - - _ => unimplemented!("{rule:?}"), - }) - } -} diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 1f1169f..9504afd 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -57,6 +57,45 @@ impl<'a> TryFrom> for Literal { } } +impl<'a> TryFrom> for Pattern { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::tuple_pattern => Pattern::Tuple( + inner + .map(Identifier::try_from) + .collect::>>()?, + ), + + Rule::named_tuple_pattern => Pattern::NamedTuple( + Path::try_from(inner.next().unwrap())?, + inner + .map(Identifier::try_from) + .collect::>>()?, + ), + + Rule::struct_pattern => Pattern::Struct( + Path::try_from(inner.next().unwrap())?, + inner + .map(Identifier::try_from) + .collect::>>()?, + ), + + Rule::literal => Pattern::Literal(Literal::try_from(pair)?), + + Rule::identifier => Pattern::Id(Identifier::try_from(pair)?), + + Rule::static_path => Pattern::Path(Path::try_from(pair)?), + + _ => unimplemented!("{rule:?}"), + }) + } +} + impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { type Error = ParseError<'a>; From 9b04a17fdd9fca30cc215780b784df9da14315cf Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 23:37:48 +0200 Subject: [PATCH 14/27] Error recovery --- parser/src/error.rs | 39 ++++++++++++++++++++++++--- parser/src/lib.rs | 4 +-- parser/src/parser/common/decl.rs | 8 +++--- parser/src/parser/common/expr.rs | 22 +++++++-------- parser/src/parser/common/mod.rs | 12 ++++----- parser/src/parser/common/statement.rs | 6 ++--- parser/src/parser/common/types.rs | 8 +++--- parser/src/parser/items/attribute.rs | 4 +-- parser/src/parser/items/class.rs | 4 +-- parser/src/parser/items/enums.rs | 2 +- parser/src/parser/items/function.rs | 4 +-- parser/src/parser/items/impl_decl.rs | 2 +- parser/src/parser/items/mod.rs | 4 +-- 13 files changed, 76 insertions(+), 43 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 74974d1..43a0305 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -1,14 +1,15 @@ use crate::Rule; -pub type ParseResult<'a, T> = Result>; +pub type ParseResult<'a, T, ET = T> = Result>; #[derive(Debug, Clone)] -pub enum ParseError<'a> { +pub enum ParseError<'a, T> { PreAst(pest::error::Error), Ast { span: pest::Span<'a>, error_code: ErrorCode, error_message: String, + recovered: Option, }, } @@ -17,8 +18,40 @@ pub enum ErrorCode { InvalidStatement = 200, } -impl From> for ParseError<'_> { +impl<'a, F> ParseError<'a, F> { + pub fn get(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 From> for ParseError<'_, T> { fn from(value: pest::error::Error) -> Self { Self::PreAst(value) } } + +pub trait GetParseError<'a, F> { + fn get(self) -> ParseResult<'a, F, T>; +} + +impl<'a, F> GetParseError<'a, F> for ParseResult<'a, F> { + fn get(self) -> ParseResult<'a, F, T> { + match self { + Ok(v) => Ok(v), + Err(e) => Err(e.get()), + } + } +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 9b99918..86e8ea7 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -7,7 +7,7 @@ pub mod parser; use ast::*; -use crate::error::ParseResult; +use crate::error::{GetParseError, ParseResult}; #[derive(Parser)] #[grammar = "./src/grammar.pest"] @@ -20,7 +20,7 @@ pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { for pair in pairs.next().unwrap().into_inner() { if pair.as_rule() != Rule::EOI { - statements.push(TopLevel::try_from(pair)?); + statements.push(TopLevel::try_from(pair).get()?); } } diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index 9ffafdb..0cd3bcb 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,7 +1,7 @@ use crate::{Rule, ast::*, error::ParseError, parser::listen_rule}; impl<'a> TryFrom> for VarDeclStmt { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -21,7 +21,7 @@ impl<'a> TryFrom> for VarDeclStmt { } impl<'a> TryFrom> for FieldDeclStmt { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -41,7 +41,7 @@ impl<'a> TryFrom> for FieldDeclStmt { } impl<'a> TryFrom> for VarDecl { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -76,7 +76,7 @@ impl<'a> TryFrom> for VarDecl { } impl<'a> TryFrom> for FieldDecl { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 1269b8a..6c5b804 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,11 +1,11 @@ use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{GetParseError, ParseError, ParseResult}, }; impl<'a> TryFrom> for Expression { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -19,7 +19,7 @@ impl<'a> TryFrom> for Expression { p.into_inner() .into_iter() .map(Prefix::try_from) - .collect::>>() + .collect::, _>>() }) .transpose()? .unwrap_or_default(); @@ -47,7 +47,7 @@ impl<'a> TryFrom> for Expression { } impl<'a> TryFrom> for Prefix { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { Ok(match pair.as_rule() { @@ -63,7 +63,7 @@ impl<'a> TryFrom> for Prefix { } impl<'a> TryFrom> for Postfix { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -74,11 +74,11 @@ impl<'a> TryFrom> for Postfix { Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), - Rule::call_px => Postfix::Call( - inner - .map(Expression::try_from) - .collect::>>()?, - ), + Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::, + _, + >>()), Rule::struct_px => Postfix::StructCall( inner @@ -92,7 +92,7 @@ impl<'a> TryFrom> for Postfix { .collect::>>()?, ), - 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 => { let op_pair = inner.next().unwrap(); diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 9504afd..0dc5dfd 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -11,7 +11,7 @@ use crate::{ }; impl<'a> TryFrom> for Identifier { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { Ok(Identifier(pair.as_str().to_string())) @@ -19,7 +19,7 @@ impl<'a> TryFrom> for Identifier { } impl<'a> TryFrom> for Path { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -34,7 +34,7 @@ impl<'a> TryFrom> for Path { } impl<'a> TryFrom> for Literal { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -58,7 +58,7 @@ impl<'a> TryFrom> for Literal { } impl<'a> TryFrom> for Pattern { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -97,11 +97,11 @@ impl<'a> TryFrom> for Pattern { } 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 { Ok(consume_rule(pairs, Rule::visibility) - .map(|pair| -> Result> { + .map(|pair| -> Result> { if let Some(path) = pair.into_inner().next() { Ok(Visibility::PublicTarget(Path::try_from(path)?)) } else { diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index f78065d..a95d7e1 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -6,7 +6,7 @@ use crate::{ }; impl<'a> TryFrom> for Block { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let statements = pair @@ -25,7 +25,7 @@ impl<'a> TryFrom> for Block { } impl<'a> TryFrom> for Statement { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -115,7 +115,7 @@ impl<'a> TryFrom> for Statement { } impl<'a> TryFrom> for StatementBranch { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs index f5dc265..912f8ae 100644 --- a/parser/src/parser/common/types.rs +++ b/parser/src/parser/common/types.rs @@ -6,7 +6,7 @@ use crate::{ }; impl<'a> TryFrom> for TypePostfix { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -39,7 +39,7 @@ impl<'a> TryFrom> for TypePostfix { } impl<'a> TryFrom> for TypeExprKind { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -69,7 +69,7 @@ impl<'a> TryFrom> for TypeExprKind { } impl<'a> TryFrom> for TypeExpr { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -93,7 +93,7 @@ impl<'a> TryFrom> for TypeExpr { } impl<'a> TryFrom> for Generics { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); diff --git a/parser/src/parser/items/attribute.rs b/parser/src/parser/items/attribute.rs index 89ea34f..44bf9f3 100644 --- a/parser/src/parser/items/attribute.rs +++ b/parser/src/parser/items/attribute.rs @@ -5,7 +5,7 @@ use crate::{ }; impl<'a> TryFrom> for Attribute { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -41,7 +41,7 @@ impl<'a> TryFrom> for Attribute { let items = next .into_inner() .map(Attribute::try_from) - .collect::>>()?; + .collect::, _>>()?; Ok(Attribute::List { path, items }) } diff --git a/parser/src/parser/items/class.rs b/parser/src/parser/items/class.rs index b80f566..5517ec0 100644 --- a/parser/src/parser/items/class.rs +++ b/parser/src/parser/items/class.rs @@ -1,7 +1,7 @@ use crate::{Rule, ast::*, error::ParseError, parser::consume_rule}; impl<'a> TryFrom> for ClassConstructor { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); @@ -28,7 +28,7 @@ impl<'a> TryFrom> for ClassConstructor { } impl<'a> TryFrom> for ClassItem { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); diff --git a/parser/src/parser/items/enums.rs b/parser/src/parser/items/enums.rs index 883ee77..70e0d8a 100644 --- a/parser/src/parser/items/enums.rs +++ b/parser/src/parser/items/enums.rs @@ -5,7 +5,7 @@ use crate::{ }; impl<'a> TryFrom> for EnumItem { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs index 07520ad..c4d25cf 100644 --- a/parser/src/parser/items/function.rs +++ b/parser/src/parser/items/function.rs @@ -6,7 +6,7 @@ use crate::{ }; impl<'a> TryFrom> for FunctionDecl { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); @@ -72,7 +72,7 @@ impl<'a> TryFrom> for FunctionDecl { } impl<'a> TryFrom> for ParamList { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { Ok(ParamList( diff --git a/parser/src/parser/items/impl_decl.rs b/parser/src/parser/items/impl_decl.rs index 76952a1..6f66f9f 100644 --- a/parser/src/parser/items/impl_decl.rs +++ b/parser/src/parser/items/impl_decl.rs @@ -6,7 +6,7 @@ use crate::{ }; impl<'a> TryFrom> for ImplDecl { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 540dd2d..e098145 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -12,7 +12,7 @@ use crate::{ }; impl<'a> TryFrom> for TopLevel { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); @@ -35,7 +35,7 @@ impl<'a> TryFrom> for TopLevel { } impl<'a> TryFrom> for TopLevelKind { - type Error = ParseError<'a>; + type Error = ParseError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); From cdb34984db93bd2ec070caf54c7bbfec9ebc54c9 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 23:46:38 +0200 Subject: [PATCH 15/27] Error recovery --- parser/src/error.rs | 9 +++++++++ parser/src/parser/common/decl.rs | 26 ++++++++++++++++---------- parser/src/parser/common/expr.rs | 6 +++--- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 43a0305..5157482 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -55,3 +55,12 @@ impl<'a, F> GetParseError<'a, F> for ParseResult<'a, F> { } } } + +impl<'a, F> GetParseError<'a, Option> for Result, ParseError<'a, F>> { + fn get(self) -> ParseResult<'a, Option, T> { + match self { + Ok(v) => Ok(v), + Err(e) => Err(e.get()), + } + } +} diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index 0cd3bcb..5e4038d 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,4 +1,9 @@ -use crate::{Rule, ast::*, error::ParseError, parser::listen_rule}; +use crate::{ + Rule, + ast::*, + error::{GetParseError, ParseError}, + parser::listen_rule, +}; impl<'a> TryFrom> for VarDeclStmt { type Error = ParseError<'a, Self>; @@ -8,9 +13,9 @@ impl<'a> TryFrom> for VarDeclStmt { Rule::var_decl_statement => { let mut inner = pair.into_inner(); - let decl = VarDecl::try_from(inner.next().unwrap())?; + let decl = VarDecl::try_from(inner.next().unwrap()).get()?; - let init = inner.next().map(Expression::try_from).transpose()?; + let init = inner.next().map(Expression::try_from).transpose().get()?; Ok(VarDeclStmt { decl, init }) } @@ -28,9 +33,9 @@ impl<'a> TryFrom> for FieldDeclStmt { Rule::class_field => { let mut inner = pair.into_inner(); - let decl = FieldDecl::try_from(inner.next().unwrap())?; + let decl = FieldDecl::try_from(inner.next().unwrap()).get()?; - let init = inner.next().map(Expression::try_from).transpose()?; + let init = inner.next().map(Expression::try_from).transpose().get()?; Ok(FieldDeclStmt { decl, init }) } @@ -57,11 +62,12 @@ impl<'a> TryFrom> for VarDecl { Some(TypeExpr::try_from(pair)) } }) - .transpose()?; + .transpose() + .get()?; let mutable = listen_rule(&mut inner, Rule::mutable); - let name = Pattern::try_from(inner.next().unwrap())?; + let name = Pattern::try_from(inner.next().unwrap()).get()?; Ok(VarDecl { mutable, @@ -83,9 +89,9 @@ impl<'a> TryFrom> for FieldDecl { Rule::field => { let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner)?; - let type_ = TypeExpr::try_from(inner.next().unwrap())?; - let name = Identifier::try_from(inner.next().unwrap())?; + let visibility = Visibility::try_from(&mut inner).get()?; + let type_ = TypeExpr::try_from(inner.next().unwrap()).get()?; + let name = Identifier::try_from(inner.next().unwrap()).get()?; Ok(FieldDecl { visibility, diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 6c5b804..342e2a4 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{GetParseError, ParseError, ParseResult}, + error::{ParseError, ParseResult}, }; impl<'a> TryFrom> for Expression { @@ -78,7 +78,7 @@ impl<'a> TryFrom> for Postfix { 'a, Vec<_>, _, - >>()), + >>()?), Rule::struct_px => Postfix::StructCall( inner @@ -92,7 +92,7 @@ impl<'a> TryFrom> for Postfix { .collect::>>()?, ), - Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap()).get()?), + Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), Rule::binary_px => { let op_pair = inner.next().unwrap(); From 25f4b5470dd1571486bedaea9c0aa6942317ffee Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 00:03:04 +0200 Subject: [PATCH 16/27] Getting error handling to work --- parser/src/error.rs | 92 ++++++++++++++++++--------- parser/src/lib.rs | 4 +- parser/src/parser/common/decl.rs | 10 +-- parser/src/parser/common/expr.rs | 16 ++--- parser/src/parser/common/mod.rs | 24 +++---- parser/src/parser/common/statement.rs | 16 ++--- parser/src/parser/common/types.rs | 22 +++---- parser/src/parser/items/attribute.rs | 6 +- parser/src/parser/items/class.rs | 6 +- parser/src/parser/items/enums.rs | 8 +-- parser/src/parser/items/function.rs | 10 +-- parser/src/parser/items/impl_decl.rs | 8 +-- parser/src/parser/items/mod.rs | 20 +++--- 13 files changed, 136 insertions(+), 106 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 5157482..a5d50dc 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -1,16 +1,19 @@ use crate::Rule; -pub type ParseResult<'a, T, ET = T> = Result>; +pub type AstResult<'a, T, ET = T> = Result>; #[derive(Debug, Clone)] pub enum ParseError<'a, T> { PreAst(pest::error::Error), - Ast { - span: pest::Span<'a>, - error_code: ErrorCode, - error_message: String, - recovered: Option, - }, + Ast(AstError<'a, T>), +} + +#[derive(Debug, Clone)] +pub struct AstError<'a, T> { + span: pest::Span<'a>, + error_code: ErrorCode, + error_message: String, + recovered: Option, } #[derive(Debug, Clone)] @@ -18,37 +21,35 @@ pub enum ErrorCode { InvalidStatement = 200, } -impl<'a, F> ParseError<'a, F> { - pub fn get(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 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) -> ParseResult<'a, F, T>; + fn get(self) -> AstResult<'a, F, T>; } -impl<'a, F> GetParseError<'a, F> for ParseResult<'a, F> { - fn get(self) -> ParseResult<'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()), @@ -56,11 +57,40 @@ impl<'a, F> GetParseError<'a, F> for ParseResult<'a, F> { } } -impl<'a, F> GetParseError<'a, Option> for Result, ParseError<'a, F>> { - fn get(self) -> ParseResult<'a, Option, T> { +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>>, +{ + let mut items = Vec::new(); + let mut last_error: Option> = None; + + for pair in pairs { + match T::try_from(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), + } +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 86e8ea7..5ab2bbf 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -7,13 +7,13 @@ pub mod parser; use ast::*; -use crate::error::{GetParseError, ParseResult}; +use crate::error::{GetParseError, ParseError}; #[derive(Parser)] #[grammar = "./src/grammar.pest"] pub struct MistParser; -pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { +pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec>> { let mut pairs = MistParser::parse(Rule::program, source)?; let mut statements = vec![]; diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index 5e4038d..d9a3dc5 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,12 +1,12 @@ use crate::{ Rule, ast::*, - error::{GetParseError, ParseError}, + error::{AstError, GetParseError}, parser::listen_rule, }; impl<'a> TryFrom> for VarDeclStmt { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -26,7 +26,7 @@ impl<'a> TryFrom> for VarDeclStmt { } impl<'a> TryFrom> for FieldDeclStmt { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -46,7 +46,7 @@ impl<'a> TryFrom> for FieldDeclStmt { } impl<'a> TryFrom> for VarDecl { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -82,7 +82,7 @@ impl<'a> TryFrom> for VarDecl { } impl<'a> TryFrom> for FieldDecl { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 342e2a4..0d25e58 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,11 +1,11 @@ use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, }; impl<'a> TryFrom> for Expression { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -19,7 +19,7 @@ impl<'a> TryFrom> for Expression { p.into_inner() .into_iter() .map(Prefix::try_from) - .collect::, _>>() + .collect::, _>>() }) .transpose()? .unwrap_or_default(); @@ -32,7 +32,7 @@ impl<'a> TryFrom> for Expression { prefixes, postfixes: inner .map(|p| Postfix::try_from(p)) - .collect::>>()?, + .collect::>>()?, }) } else { Ok(exp) @@ -47,7 +47,7 @@ impl<'a> TryFrom> for Expression { } impl<'a> TryFrom> for Prefix { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { Ok(match pair.as_rule() { @@ -63,7 +63,7 @@ impl<'a> TryFrom> for Prefix { } impl<'a> TryFrom> for Postfix { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -74,7 +74,7 @@ impl<'a> TryFrom> for Postfix { Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), - Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect:: Postfix::Call(inner.map(Expression::try_from).collect::, _, @@ -89,7 +89,7 @@ impl<'a> TryFrom> for Postfix { Expression::try_from(pi.next().unwrap())?, )) }) - .collect::>>()?, + .collect::>>()?, ), Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 0dc5dfd..9f3cbb4 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -6,12 +6,12 @@ pub mod types; use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, parser::consume_rule, }; impl<'a> TryFrom> for Identifier { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { Ok(Identifier(pair.as_str().to_string())) @@ -19,14 +19,14 @@ impl<'a> TryFrom> for Identifier { } impl<'a> TryFrom> for Path { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::static_path => Ok(Path( pair.into_inner() .map(Identifier::try_from) - .collect::>>()?, + .collect::>>()?, )), _ => unimplemented!("{pair:#?}"), } @@ -34,7 +34,7 @@ impl<'a> TryFrom> for Path { } impl<'a> TryFrom> for Literal { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -50,7 +50,7 @@ impl<'a> TryFrom> for Literal { Rule::tuple => Literal::Tuple( inner .map(Expression::try_from) - .collect::>>()?, + .collect::>>()?, ), _ => unimplemented!("{rule:#?}"), }) @@ -58,7 +58,7 @@ impl<'a> TryFrom> for Literal { } impl<'a> TryFrom> for Pattern { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -68,21 +68,21 @@ impl<'a> TryFrom> for Pattern { Rule::tuple_pattern => Pattern::Tuple( inner .map(Identifier::try_from) - .collect::>>()?, + .collect::>>()?, ), Rule::named_tuple_pattern => Pattern::NamedTuple( Path::try_from(inner.next().unwrap())?, inner .map(Identifier::try_from) - .collect::>>()?, + .collect::>>()?, ), Rule::struct_pattern => Pattern::Struct( Path::try_from(inner.next().unwrap())?, inner .map(Identifier::try_from) - .collect::>>()?, + .collect::>>()?, ), Rule::literal => Pattern::Literal(Literal::try_from(pair)?), @@ -97,11 +97,11 @@ impl<'a> TryFrom> for Pattern { } impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result { Ok(consume_rule(pairs, Rule::visibility) - .map(|pair| -> Result> { + .map(|pair| -> Result> { if let Some(path) = pair.into_inner().next() { Ok(Visibility::PublicTarget(Path::try_from(path)?)) } else { diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index a95d7e1..d30c5d2 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -1,12 +1,12 @@ use crate::{ Rule, ast::*, - error::{ErrorCode, ParseError, ParseResult}, + error::{ErrorCode, AstError, AstResult}, parser::listen_rule, }; impl<'a> TryFrom> for Block { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let statements = pair @@ -18,14 +18,14 @@ impl<'a> TryFrom> for Block { vec![Statement::try_from(pair)] } }) - .collect::>>()?; + .collect::>>()?; Ok(Block(statements)) } } impl<'a> TryFrom> for Statement { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -58,7 +58,7 @@ impl<'a> TryFrom> for Statement { .unwrap() .into_inner() .map(StatementBranch::try_from) - .collect::>>()?, + .collect::>>()?, else_branch: inner .next() .map(Statement::try_from) @@ -98,11 +98,11 @@ impl<'a> TryFrom> for Statement { Block::try_from(match_inner.next().unwrap())?, )) }) - .collect::>>()?, + .collect::>>()?, ), Rule::unexpected_statement => { - return Err(ParseError::Ast { + return Err(AstError::Ast { span: pair.as_span(), error_code: ErrorCode::InvalidStatement, error_message: "Invalid Statement".to_string(), @@ -115,7 +115,7 @@ impl<'a> TryFrom> for Statement { } impl<'a> TryFrom> for StatementBranch { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs index 912f8ae..89493f3 100644 --- a/parser/src/parser/common/types.rs +++ b/parser/src/parser/common/types.rs @@ -1,12 +1,12 @@ use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, parser::{consume_rule, listen_rule}, }; impl<'a> TryFrom> for TypePostfix { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -39,7 +39,7 @@ impl<'a> TryFrom> for TypePostfix { } impl<'a> TryFrom> for TypeExprKind { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -49,13 +49,13 @@ impl<'a> TryFrom> for TypeExprKind { Rule::tuple_type => Ok(TypeExprKind::Tuple( inner .map(TypeExpr::try_from) - .collect::>()?, + .collect::>()?, )), Rule::path_type => { let path = Path::try_from(inner.next().unwrap())?; let params = inner .map(TypeExpr::try_from) - .collect::>>()?; + .collect::>>()?; if params.len() == 0 { Ok(TypeExprKind::Path(path)) @@ -69,7 +69,7 @@ impl<'a> TryFrom> for TypeExprKind { } impl<'a> TryFrom> for TypeExpr { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -80,7 +80,7 @@ impl<'a> TryFrom> for TypeExpr { TypeExprKind::try_from(inner.next().unwrap())?, inner .map(TypePostfix::try_from) - .collect::>()?, + .collect::>()?, )), Rule::type_expr_param => Self::try_from(inner.next().unwrap()), Rule::lifetime => Ok(TypeExpr( @@ -93,7 +93,7 @@ impl<'a> TryFrom> for TypeExpr { } impl<'a> TryFrom> for Generics { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -102,7 +102,7 @@ impl<'a> TryFrom> for Generics { match rule { Rule::generics => Ok(Generics( inner - .map(|pair| -> ParseResult<'a, Generic> { + .map(|pair| -> AstResult<'a, Generic> { let mut inner = pair.into_inner(); Ok( if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { @@ -114,12 +114,12 @@ impl<'a> TryFrom> for Generics { Identifier::try_from(inner.next().unwrap())?, inner .map(TypeExpr::try_from) - .collect::>>()?, + .collect::>>()?, ) }, ) }) - .collect::>>()?, + .collect::>>()?, )), _ => unimplemented!("{rule:#?}"), } diff --git a/parser/src/parser/items/attribute.rs b/parser/src/parser/items/attribute.rs index 44bf9f3..b75a864 100644 --- a/parser/src/parser/items/attribute.rs +++ b/parser/src/parser/items/attribute.rs @@ -1,11 +1,11 @@ use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, }; impl<'a> TryFrom> for Attribute { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { @@ -41,7 +41,7 @@ impl<'a> TryFrom> for Attribute { let items = next .into_inner() .map(Attribute::try_from) - .collect::, _>>()?; + .collect::, _>>()?; Ok(Attribute::List { path, items }) } diff --git a/parser/src/parser/items/class.rs b/parser/src/parser/items/class.rs index 5517ec0..09b13e8 100644 --- a/parser/src/parser/items/class.rs +++ b/parser/src/parser/items/class.rs @@ -1,7 +1,7 @@ -use crate::{Rule, ast::*, error::ParseError, parser::consume_rule}; +use crate::{Rule, ast::*, error::AstError, parser::consume_rule}; impl<'a> TryFrom> for ClassConstructor { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); @@ -28,7 +28,7 @@ impl<'a> TryFrom> for ClassConstructor { } impl<'a> TryFrom> for ClassItem { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); diff --git a/parser/src/parser/items/enums.rs b/parser/src/parser/items/enums.rs index 70e0d8a..2b4dc89 100644 --- a/parser/src/parser/items/enums.rs +++ b/parser/src/parser/items/enums.rs @@ -1,11 +1,11 @@ use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, }; impl<'a> TryFrom> for EnumItem { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -23,7 +23,7 @@ impl<'a> TryFrom> for EnumItem { .unwrap() .into_inner() .map(TypeExpr::try_from) - .collect::>>()?, + .collect::>>()?, )), Rule::enum_struct => Ok(EnumItem::Struct( @@ -33,7 +33,7 @@ impl<'a> TryFrom> for EnumItem { .map(|pair| { pair.into_inner() .map(FieldDecl::try_from) - .collect::>>() + .collect::>>() }) .transpose()? .unwrap_or_default(), diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs index c4d25cf..fde3a29 100644 --- a/parser/src/parser/items/function.rs +++ b/parser/src/parser/items/function.rs @@ -1,12 +1,12 @@ use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, parser::{consume_rule, listen_rule}, }; impl<'a> TryFrom> for FunctionDecl { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); @@ -47,7 +47,7 @@ impl<'a> TryFrom> for FunctionDecl { let params = consume_rule(&mut inner, Rule::param_list) .map({ let self_param = self_param.clone(); - |params_pair| -> ParseResult<'a, ParamList> { + |params_pair| -> AstResult<'a, ParamList> { let mut params = ParamList::try_from(params_pair)?; if let Some(x) = self_param { params.0.insert(0, x); @@ -72,13 +72,13 @@ impl<'a> TryFrom> for FunctionDecl { } impl<'a> TryFrom> for ParamList { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { Ok(ParamList( pair.into_inner() .map(VarDecl::try_from) - .collect::>>()?, + .collect::>>()?, )) } } diff --git a/parser/src/parser/items/impl_decl.rs b/parser/src/parser/items/impl_decl.rs index 6f66f9f..7d4fab2 100644 --- a/parser/src/parser/items/impl_decl.rs +++ b/parser/src/parser/items/impl_decl.rs @@ -1,12 +1,12 @@ use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, parser::consume_rule, }; impl<'a> TryFrom> for ImplDecl { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -22,7 +22,7 @@ impl<'a> TryFrom> for ImplDecl { target: TypeExpr::try_from(inner.next().unwrap())?, methods: inner .map(FunctionDecl::try_from) - .collect::>>()?, + .collect::>>()?, }), Rule::impl_decl => Ok(ImplDecl { @@ -34,7 +34,7 @@ impl<'a> TryFrom> for ImplDecl { target: TypeExpr::try_from(inner.next().unwrap())?, methods: inner .map(FunctionDecl::try_from) - .collect::>>()?, + .collect::>>()?, }), _ => unimplemented!("{rule:#?}"), diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index e098145..7e97ab0 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -7,12 +7,12 @@ pub mod impl_decl; use crate::{ Rule, ast::*, - error::{ParseError, ParseResult}, + error::{AstError, AstResult}, parser::consume_rule, }; impl<'a> TryFrom> for TopLevel { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); @@ -22,7 +22,7 @@ impl<'a> TryFrom> for TopLevel { .unwrap() .into_inner() .map(Attribute::try_from) - .collect::>>()?; + .collect::>>()?; Ok(TopLevel( inner @@ -35,7 +35,7 @@ impl<'a> TryFrom> for TopLevel { } impl<'a> TryFrom> for TopLevelKind { - type Error = ParseError<'a, Self>; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); @@ -61,7 +61,7 @@ impl<'a> TryFrom> for TopLevelKind { .map(|pair| { pair.into_inner() .map(FieldDecl::try_from) - .collect::>>() + .collect::>>() }) .transpose()? .unwrap_or_default(), @@ -79,12 +79,12 @@ impl<'a> TryFrom> for TopLevelKind { .unwrap() .into_inner() .map(FieldDeclStmt::try_from) - .collect::>>()?, + .collect::>>()?, constructor: ClassConstructor::try_from(inner.next().unwrap())?, items: inner .into_iter() .map(ClassItem::try_from) - .collect::>>()?, + .collect::>>()?, }, Rule::enum_decl => TopLevelKind::EnumDecl { @@ -96,7 +96,7 @@ impl<'a> TryFrom> for TopLevelKind { .unwrap_or_default(), fields: inner .map(EnumItem::try_from) - .collect::>>()?, + .collect::>>()?, }, Rule::mod_package => TopLevelKind::Mod( @@ -119,13 +119,13 @@ impl<'a> TryFrom> for TopLevelKind { .map(|pair| { pair.into_inner() .map(TypeExpr::try_from) - .collect::>>() + .collect::>>() }) .transpose()? .unwrap_or_default(), items: inner .map(FunctionDecl::try_from) - .collect::>>()?, + .collect::>>()?, }, _ => unimplemented!("{rule:#?}"), From 80e17ffafb80f8e9499993be5b09fc74cef40bd7 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 01:24:55 +0200 Subject: [PATCH 17/27] Ast expression macro --- parser/src/error.rs | 10 +++---- parser/src/lib.rs | 48 +++++++++++++++++++++++++++++++ parser/src/parser/common/decl.rs | 49 +++++++++++++------------------- parser/src/parser/common/expr.rs | 4 +-- parser/src/parser/mod.rs | 9 ++++-- 5 files changed, 81 insertions(+), 39 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index a5d50dc..9724c31 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -10,10 +10,10 @@ pub enum ParseError<'a, T> { #[derive(Debug, Clone)] pub struct AstError<'a, T> { - span: pest::Span<'a>, - error_code: ErrorCode, - error_message: String, - recovered: Option, + pub span: pest::Span<'a>, + pub error_code: ErrorCode, + pub error_message: String, + pub recovered: Option, } #[derive(Debug, Clone)] @@ -89,7 +89,7 @@ where span: ast_err.span, error_code: ast_err.error_code, error_message: ast_err.error_message, - recovered: None, + recovered: Some(items), }), None => Ok(items), } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 5ab2bbf..429daf8 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -26,3 +26,51 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec {{ + $( + let $name = $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $($val2)?)); + )* + + $item { $($name,)* } + }}; +} + +#[macro_export] +macro_rules! _ast_t { + (: $val:expr) => { + $val.get()? + }; + + (? $val:expr) => { + $val.or_else(|e| { + if let Some(recovered) = e.recovered { + Ok(recovered) + } else { + Err(e) + } + }) + .get()? + }; +} + +#[macro_export] +macro_rules! _ast_ti { + ($inner:ident, ! $val:ident) => { + $val::try_from(&mut $inner) + }; + + ($inner:ident, @ $val:ident) => { + $val::try_from($inner.next().unwrap()) + }; + + ($inner:ident, ? ($rule:path)) => { + $crate::parser::listen_rule(&mut $inner, $rule) + }; + + ($inner:ident, & $val:expr) => { + $val + }; +} diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index d9a3dc5..ca8d438 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,8 +1,8 @@ use crate::{ Rule, ast::*, + ast_expr, error::{AstError, GetParseError}, - parser::listen_rule, }; impl<'a> TryFrom> for VarDeclStmt { @@ -53,27 +53,22 @@ impl<'a> TryFrom> for VarDecl { Rule::var_decl => { let mut inner = pair.into_inner(); - let type_ = inner - .next() - .and_then(|pair| { - if pair.as_str().trim() == "var" { - None - } else { - Some(TypeExpr::try_from(pair)) - } - }) - .transpose() - .get()?; + Ok(ast_expr!(inner@VarDecl { + type_: & (inner + .next() + .and_then(|pair| { + if pair.as_str().trim() == "var" { + None + } else { + Some(TypeExpr::try_from(pair)) + } + }) + .transpose()), - let mutable = listen_rule(&mut inner, Rule::mutable); + mutable: ?(Rule::mutable), - let name = Pattern::try_from(inner.next().unwrap()).get()?; - - Ok(VarDecl { - mutable, - name, - type_, - }) + name: @Pattern + })) } _ => unimplemented!("{:?}", pair.as_rule()), @@ -89,15 +84,11 @@ impl<'a> TryFrom> for FieldDecl { Rule::field => { let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner).get()?; - let type_ = TypeExpr::try_from(inner.next().unwrap()).get()?; - let name = Identifier::try_from(inner.next().unwrap()).get()?; - - Ok(FieldDecl { - visibility, - type_, - name, - }) + Ok(ast_expr!(inner@FieldDecl { + visibility: !Visibility, + type_: @TypeExpr, + name: @Identifier + })) } _ => unimplemented!("{:?}", pair.as_rule()), diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 0d25e58..44a942f 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, AstResult, GetParseError}, }; impl<'a> TryFrom> for Expression { @@ -72,7 +72,7 @@ impl<'a> TryFrom> for Postfix { Ok(match rule { Rule::postfix => Postfix::try_from(inner.next().unwrap())?, - Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), + Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap()).get()?), Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::, rule: Rule) -> bool { +pub fn listen_rule<'a>( + pairs: &mut pest::iterators::Pairs<'_, Rule>, + rule: Rule, +) -> AstResult<'a, bool> { let consumed = pairs .peek() .map(|p| p.as_rule() == rule) @@ -13,7 +16,7 @@ pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> pairs.next(); } - consumed + Ok(consumed) } pub fn consume_rule<'a>( From 6fbc2a086ef94878e121f602ef9bfbe1288029eb Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 01:33:43 +0200 Subject: [PATCH 18/27] Decl using the ast macro --- parser/src/lib.rs | 4 ++ parser/src/parser/common/decl.rs | 64 +++++++++++++++++--------------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 429daf8..765e563 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -66,6 +66,10 @@ macro_rules! _ast_ti { $val::try_from($inner.next().unwrap()) }; + ($inner:ident, ? $val:ident) => { + $inner.next().map($val::try_from).transpose() + }; + ($inner:ident, ? ($rule:path)) => { $crate::parser::listen_rule(&mut $inner, $rule) }; diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index ca8d438..99cd76e 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -13,11 +13,12 @@ impl<'a> TryFrom> for VarDeclStmt { Rule::var_decl_statement => { let mut inner = pair.into_inner(); - let decl = VarDecl::try_from(inner.next().unwrap()).get()?; - - let init = inner.next().map(Expression::try_from).transpose().get()?; - - Ok(VarDeclStmt { decl, init }) + Ok(ast_expr!( + inner@VarDeclStmt { + decl: @VarDecl, + init: ?Expression + } + )) } _ => unimplemented!(), @@ -33,11 +34,12 @@ impl<'a> TryFrom> for FieldDeclStmt { Rule::class_field => { let mut inner = pair.into_inner(); - let decl = FieldDecl::try_from(inner.next().unwrap()).get()?; - - let init = inner.next().map(Expression::try_from).transpose().get()?; - - Ok(FieldDeclStmt { decl, init }) + Ok(ast_expr!( + inner@FieldDeclStmt { + decl: @FieldDecl, + init: ?Expression + } + )) } _ => unimplemented!(), @@ -53,22 +55,24 @@ impl<'a> TryFrom> for VarDecl { Rule::var_decl => { let mut inner = pair.into_inner(); - Ok(ast_expr!(inner@VarDecl { - type_: & (inner - .next() - .and_then(|pair| { - if pair.as_str().trim() == "var" { - None - } else { - Some(TypeExpr::try_from(pair)) - } - }) - .transpose()), + Ok(ast_expr!( + inner@VarDecl { + type_: & (inner + .next() + .and_then(|pair| { + if pair.as_str().trim() == "var" { + None + } else { + Some(TypeExpr::try_from(pair)) + } + }) + .transpose()), - mutable: ?(Rule::mutable), + mutable: ?(Rule::mutable), - name: @Pattern - })) + name: @Pattern + } + )) } _ => unimplemented!("{:?}", pair.as_rule()), @@ -84,11 +88,13 @@ impl<'a> TryFrom> for FieldDecl { Rule::field => { let mut inner = pair.into_inner(); - Ok(ast_expr!(inner@FieldDecl { - visibility: !Visibility, - type_: @TypeExpr, - name: @Identifier - })) + Ok(ast_expr!( + inner@FieldDecl { + visibility: !Visibility, + type_: @TypeExpr, + name: @Identifier + } + )) } _ => unimplemented!("{:?}", pair.as_rule()), From 933f1026800164b4ceb496d87c79598893dc01e9 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 02:02:43 +0200 Subject: [PATCH 19/27] Might consider removing ast_expr --- parser/src/lib.rs | 22 +++++++++++++++++++--- parser/src/parser/common/expr.rs | 30 +++++++++++++++--------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 765e563..f0ee50c 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -29,12 +29,16 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec {{ + ($inner:tt @ $($item:ident)::+ ( $($t:tt $val:tt $val2:tt),* )) => {{ + $($item)::+ ( $( $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $val2)) )* ) + }}; + + ($inner:tt @ $($item:ident)::+ { $($name:ident $t:tt $val:tt $val2:tt),*}) => {{ $( - let $name = $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $($val2)?)); + let $name = $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $val2)); )* - $item { $($name,)* } + $($item)::+ { $($name,)* } }}; } @@ -58,6 +62,18 @@ macro_rules! _ast_t { #[macro_export] macro_rules! _ast_ti { + ($inner:ident, !*) => { + $crate::error::collect_recovered($inner) + }; + + ($inner:ident, @*) => { + $crate::error::collect_recovered($inner.next.unwrap().into_inner()) + }; + + ($inner:ident, @ @) => { + $inner.next().unwrap().try_into() + }; + ($inner:ident, ! $val:ident) => { $val::try_from(&mut $inner) }; diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 44a942f..8a1dd53 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,7 +1,8 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult, GetParseError}, + ast_expr, + error::{AstError, AstResult, GetParseError, collect_recovered}, }; impl<'a> TryFrom> for Expression { @@ -32,15 +33,16 @@ impl<'a> TryFrom> for Expression { prefixes, postfixes: inner .map(|p| Postfix::try_from(p)) - .collect::>>()?, + .collect::>>() + .get()?, }) } else { Ok(exp) } } Rule::primary => Expression::try_from(inner.next().unwrap()), - Rule::static_path => Ok(Expression::Path(Path::try_from(pair)?)), - Rule::literal => Ok(Expression::Literal(Literal::try_from(pair)?)), + Rule::static_path => Ok(Expression::Path(Path::try_from(pair).get()?)), + Rule::literal => Ok(Expression::Literal(Literal::try_from(pair).get()?)), _ => unimplemented!("{rule:#?}"), } } @@ -72,27 +74,24 @@ impl<'a> TryFrom> for Postfix { Ok(match rule { Rule::postfix => Postfix::try_from(inner.next().unwrap())?, - Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap()).get()?), + Rule::field_px => ast_expr!(inner@Postfix::FieldAccess(:@@)), - Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::, - _, - >>()?), + Rule::call_px => ast_expr!(inner@Postfix::Call(:!*)), Rule::struct_px => Postfix::StructCall( inner .map(|p| { let mut pi = p.into_inner(); Ok(( - Identifier::try_from(pi.next().unwrap())?, - Expression::try_from(pi.next().unwrap())?, + Identifier::try_from(pi.next().unwrap()).get()?, + Expression::try_from(pi.next().unwrap()).get()?, )) }) - .collect::>>()?, + .collect::>>() + .get()?, ), - Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), + Rule::index_px => ast_expr!(inner@Postfix::Index(:@@)), Rule::binary_px => { let op_pair = inner.next().unwrap(); @@ -115,7 +114,8 @@ impl<'a> TryFrom> for Postfix { unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) } }; - Postfix::Binary(op, Expression::try_from(inner.next().unwrap())?) + + ast_expr!(inner@Postfix::Binary(:&op, :@@)) } Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), From 459c4b1ee01fc8338018af378f8b5c444b106aa0 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 02:23:54 +0200 Subject: [PATCH 20/27] Reverted back --- parser/src/error.rs | 10 ++--- parser/src/lib.rs | 68 ----------------------------- parser/src/parser/common/decl.rs | 75 +++++++++++++++++--------------- parser/src/parser/common/expr.rs | 30 ++++++------- parser/src/parser/mod.rs | 9 ++-- 5 files changed, 62 insertions(+), 130 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 9724c31..a5d50dc 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -10,10 +10,10 @@ pub enum ParseError<'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, + span: pest::Span<'a>, + error_code: ErrorCode, + error_message: String, + recovered: Option, } #[derive(Debug, Clone)] @@ -89,7 +89,7 @@ where span: ast_err.span, error_code: ast_err.error_code, error_message: ast_err.error_message, - recovered: Some(items), + recovered: None, }), None => Ok(items), } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index f0ee50c..5ab2bbf 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -26,71 +26,3 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec {{ - $($item)::+ ( $( $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $val2)) )* ) - }}; - - ($inner:tt @ $($item:ident)::+ { $($name:ident $t:tt $val:tt $val2:tt),*}) => {{ - $( - let $name = $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $val2)); - )* - - $($item)::+ { $($name,)* } - }}; -} - -#[macro_export] -macro_rules! _ast_t { - (: $val:expr) => { - $val.get()? - }; - - (? $val:expr) => { - $val.or_else(|e| { - if let Some(recovered) = e.recovered { - Ok(recovered) - } else { - Err(e) - } - }) - .get()? - }; -} - -#[macro_export] -macro_rules! _ast_ti { - ($inner:ident, !*) => { - $crate::error::collect_recovered($inner) - }; - - ($inner:ident, @*) => { - $crate::error::collect_recovered($inner.next.unwrap().into_inner()) - }; - - ($inner:ident, @ @) => { - $inner.next().unwrap().try_into() - }; - - ($inner:ident, ! $val:ident) => { - $val::try_from(&mut $inner) - }; - - ($inner:ident, @ $val:ident) => { - $val::try_from($inner.next().unwrap()) - }; - - ($inner:ident, ? $val:ident) => { - $inner.next().map($val::try_from).transpose() - }; - - ($inner:ident, ? ($rule:path)) => { - $crate::parser::listen_rule(&mut $inner, $rule) - }; - - ($inner:ident, & $val:expr) => { - $val - }; -} diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index 99cd76e..d9a3dc5 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,8 +1,8 @@ use crate::{ Rule, ast::*, - ast_expr, error::{AstError, GetParseError}, + parser::listen_rule, }; impl<'a> TryFrom> for VarDeclStmt { @@ -13,12 +13,11 @@ impl<'a> TryFrom> for VarDeclStmt { Rule::var_decl_statement => { let mut inner = pair.into_inner(); - Ok(ast_expr!( - inner@VarDeclStmt { - decl: @VarDecl, - init: ?Expression - } - )) + let decl = VarDecl::try_from(inner.next().unwrap()).get()?; + + let init = inner.next().map(Expression::try_from).transpose().get()?; + + Ok(VarDeclStmt { decl, init }) } _ => unimplemented!(), @@ -34,12 +33,11 @@ impl<'a> TryFrom> for FieldDeclStmt { Rule::class_field => { let mut inner = pair.into_inner(); - Ok(ast_expr!( - inner@FieldDeclStmt { - decl: @FieldDecl, - init: ?Expression - } - )) + let decl = FieldDecl::try_from(inner.next().unwrap()).get()?; + + let init = inner.next().map(Expression::try_from).transpose().get()?; + + Ok(FieldDeclStmt { decl, init }) } _ => unimplemented!(), @@ -55,24 +53,27 @@ impl<'a> TryFrom> for VarDecl { Rule::var_decl => { let mut inner = pair.into_inner(); - Ok(ast_expr!( - inner@VarDecl { - type_: & (inner - .next() - .and_then(|pair| { - if pair.as_str().trim() == "var" { - None - } else { - Some(TypeExpr::try_from(pair)) - } - }) - .transpose()), + let type_ = inner + .next() + .and_then(|pair| { + if pair.as_str().trim() == "var" { + None + } else { + Some(TypeExpr::try_from(pair)) + } + }) + .transpose() + .get()?; - mutable: ?(Rule::mutable), + let mutable = listen_rule(&mut inner, Rule::mutable); - name: @Pattern - } - )) + let name = Pattern::try_from(inner.next().unwrap()).get()?; + + Ok(VarDecl { + mutable, + name, + type_, + }) } _ => unimplemented!("{:?}", pair.as_rule()), @@ -88,13 +89,15 @@ impl<'a> TryFrom> for FieldDecl { Rule::field => { let mut inner = pair.into_inner(); - Ok(ast_expr!( - inner@FieldDecl { - visibility: !Visibility, - type_: @TypeExpr, - name: @Identifier - } - )) + let visibility = Visibility::try_from(&mut inner).get()?; + let type_ = TypeExpr::try_from(inner.next().unwrap()).get()?; + let name = Identifier::try_from(inner.next().unwrap()).get()?; + + Ok(FieldDecl { + visibility, + type_, + name, + }) } _ => unimplemented!("{:?}", pair.as_rule()), diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 8a1dd53..0d25e58 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,8 +1,7 @@ use crate::{ Rule, ast::*, - ast_expr, - error::{AstError, AstResult, GetParseError, collect_recovered}, + error::{AstError, AstResult}, }; impl<'a> TryFrom> for Expression { @@ -33,16 +32,15 @@ impl<'a> TryFrom> for Expression { prefixes, postfixes: inner .map(|p| Postfix::try_from(p)) - .collect::>>() - .get()?, + .collect::>>()?, }) } else { Ok(exp) } } Rule::primary => Expression::try_from(inner.next().unwrap()), - Rule::static_path => Ok(Expression::Path(Path::try_from(pair).get()?)), - Rule::literal => Ok(Expression::Literal(Literal::try_from(pair).get()?)), + Rule::static_path => Ok(Expression::Path(Path::try_from(pair)?)), + Rule::literal => Ok(Expression::Literal(Literal::try_from(pair)?)), _ => unimplemented!("{rule:#?}"), } } @@ -74,24 +72,27 @@ impl<'a> TryFrom> for Postfix { Ok(match rule { Rule::postfix => Postfix::try_from(inner.next().unwrap())?, - Rule::field_px => ast_expr!(inner@Postfix::FieldAccess(:@@)), + Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), - Rule::call_px => ast_expr!(inner@Postfix::Call(:!*)), + Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::, + _, + >>()?), Rule::struct_px => Postfix::StructCall( inner .map(|p| { let mut pi = p.into_inner(); Ok(( - Identifier::try_from(pi.next().unwrap()).get()?, - Expression::try_from(pi.next().unwrap()).get()?, + Identifier::try_from(pi.next().unwrap())?, + Expression::try_from(pi.next().unwrap())?, )) }) - .collect::>>() - .get()?, + .collect::>>()?, ), - Rule::index_px => ast_expr!(inner@Postfix::Index(:@@)), + Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap())?), Rule::binary_px => { let op_pair = inner.next().unwrap(); @@ -114,8 +115,7 @@ impl<'a> TryFrom> for Postfix { unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) } }; - - ast_expr!(inner@Postfix::Binary(:&op, :@@)) + Postfix::Binary(op, Expression::try_from(inner.next().unwrap())?) } Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index 6900d7b..d7dad09 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -1,12 +1,9 @@ pub mod common; pub mod items; -use crate::{Rule, error::AstResult}; +use crate::Rule; -pub fn listen_rule<'a>( - pairs: &mut pest::iterators::Pairs<'_, Rule>, - rule: Rule, -) -> AstResult<'a, bool> { +pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { let consumed = pairs .peek() .map(|p| p.as_rule() == rule) @@ -16,7 +13,7 @@ pub fn listen_rule<'a>( pairs.next(); } - Ok(consumed) + consumed } pub fn consume_rule<'a>( From 527e450f9ee6ec2ab54c7591666dc003f6596e05 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 08:44:01 +0200 Subject: [PATCH 21/27] Common error handling --- parser/src/error.rs | 29 +++++++++-- parser/src/parser/common/expr.rs | 46 ++++++++---------- parser/src/parser/common/mod.rs | 40 +++++---------- parser/src/parser/common/statement.rs | 70 ++++++++++++--------------- 4 files changed, 87 insertions(+), 98 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index a5d50dc..a3bf8cc 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -10,10 +10,10 @@ pub enum ParseError<'a, T> { #[derive(Debug, Clone)] pub struct AstError<'a, T> { - span: pest::Span<'a>, - error_code: ErrorCode, - error_message: String, - recovered: Option, + pub span: pest::Span<'a>, + pub error_code: ErrorCode, + pub error_message: String, + pub recovered: Option, } #[derive(Debug, Clone)] @@ -66,17 +66,36 @@ impl<'a, F> GetParseError<'a, Option> for Result, AstError<'a, F>> } } +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 T::try_from(pair) { + match f(pair) { Ok(item) => items.push(item), Err(e) => { last_error = Some(e); diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 0d25e58..ff0ccd9 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, AstResult, GetParseError, collect_recovered, collect_recovered_map}, }; impl<'a> TryFrom> for Expression { @@ -13,7 +13,7 @@ impl<'a> TryFrom> for Expression { match rule { Rule::expr => { - let prefixes: Vec = inner + let prefixes = inner .next() .map(|p| { p.into_inner() @@ -21,7 +21,8 @@ impl<'a> TryFrom> for Expression { .map(Prefix::try_from) .collect::, _>>() }) - .transpose()? + .transpose() + .get()? .unwrap_or_default(); let exp = Expression::try_from(inner.next().unwrap())?; @@ -30,17 +31,15 @@ impl<'a> TryFrom> for Expression { Ok(Expression::Fix { initial: Box::new(exp), prefixes, - postfixes: inner - .map(|p| Postfix::try_from(p)) - .collect::>>()?, + postfixes: collect_recovered(inner).get()?, }) } else { Ok(exp) } } Rule::primary => Expression::try_from(inner.next().unwrap()), - Rule::static_path => Ok(Expression::Path(Path::try_from(pair)?)), - Rule::literal => Ok(Expression::Literal(Literal::try_from(pair)?)), + Rule::static_path => Ok(Expression::Path(Path::try_from(pair).get()?)), + Rule::literal => Ok(Expression::Literal(Literal::try_from(pair).get()?)), _ => unimplemented!("{rule:#?}"), } } @@ -72,27 +71,24 @@ impl<'a> TryFrom> for Postfix { Ok(match rule { Rule::postfix => Postfix::try_from(inner.next().unwrap())?, - Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), + Rule::field_px => { + Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap()).get()?) + } - Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::, - _, - >>()?), + Rule::call_px => Postfix::Call(collect_recovered(inner).get()?), Rule::struct_px => Postfix::StructCall( - inner - .map(|p| { - let mut pi = p.into_inner(); - Ok(( - Identifier::try_from(pi.next().unwrap())?, - Expression::try_from(pi.next().unwrap())?, - )) - }) - .collect::>>()?, + collect_recovered_map(inner, |p| { + let mut pi = p.into_inner(); + Ok(( + Identifier::try_from(pi.next().unwrap())?, + Expression::try_from(pi.next().unwrap()).get()?, + )) + }) + .get()?, ), - 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 => { let op_pair = inner.next().unwrap(); @@ -115,7 +111,7 @@ impl<'a> TryFrom> for Postfix { unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) } }; - Postfix::Binary(op, Expression::try_from(inner.next().unwrap())?) + Postfix::Binary(op, Expression::try_from(inner.next().unwrap()).get()?) } Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 9f3cbb4..f7852de 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -6,7 +6,7 @@ pub mod types; use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, GetParseError, collect_recovered}, parser::consume_rule, }; @@ -23,11 +23,7 @@ impl<'a> TryFrom> for Path { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { - Rule::static_path => Ok(Path( - pair.into_inner() - .map(Identifier::try_from) - .collect::>>()?, - )), + Rule::static_path => Ok(Path(collect_recovered(pair.into_inner()).get()?)), _ => unimplemented!("{pair:#?}"), } } @@ -47,11 +43,7 @@ impl<'a> TryFrom> for Literal { Rule::float => Literal::Float(pair.as_str().parse::().unwrap()), Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), Rule::string_lit => Literal::String(inner.as_str().to_string()), - Rule::tuple => Literal::Tuple( - inner - .map(Expression::try_from) - .collect::>>()?, - ), + Rule::tuple => Literal::Tuple(collect_recovered(inner).get()?), _ => unimplemented!("{rule:#?}"), }) } @@ -65,31 +57,23 @@ impl<'a> TryFrom> for Pattern { let mut inner = pair.clone().into_inner(); Ok(match rule { - Rule::tuple_pattern => Pattern::Tuple( - inner - .map(Identifier::try_from) - .collect::>>()?, - ), + Rule::tuple_pattern => Pattern::Tuple(collect_recovered(pair.into_inner()).get()?), Rule::named_tuple_pattern => Pattern::NamedTuple( - Path::try_from(inner.next().unwrap())?, - inner - .map(Identifier::try_from) - .collect::>>()?, + Path::try_from(inner.next().unwrap()).get()?, + collect_recovered(pair.into_inner()).get()?, ), Rule::struct_pattern => Pattern::Struct( - Path::try_from(inner.next().unwrap())?, - inner - .map(Identifier::try_from) - .collect::>>()?, + Path::try_from(inner.next().unwrap()).get()?, + collect_recovered(pair.into_inner()).get()?, ), - Rule::literal => Pattern::Literal(Literal::try_from(pair)?), + Rule::literal => Pattern::Literal(Literal::try_from(pair).get()?), - Rule::identifier => Pattern::Id(Identifier::try_from(pair)?), + Rule::identifier => Pattern::Id(Identifier::try_from(pair).get()?), - Rule::static_path => Pattern::Path(Path::try_from(pair)?), + Rule::static_path => Pattern::Path(Path::try_from(pair).get()?), _ => unimplemented!("{rule:?}"), }) @@ -103,7 +87,7 @@ impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { Ok(consume_rule(pairs, Rule::visibility) .map(|pair| -> Result> { if let Some(path) = pair.into_inner().next() { - Ok(Visibility::PublicTarget(Path::try_from(path)?)) + Ok(Visibility::PublicTarget(Path::try_from(path).get()?)) } else { Ok(Visibility::Public) } diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index d30c5d2..c4e22e4 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{ErrorCode, AstError, AstResult}, + error::{AstError, AstResult, ErrorCode, GetParseError, collect_recovered}, parser::listen_rule, }; @@ -9,18 +9,9 @@ impl<'a> TryFrom> for Block { type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let statements = pair - .into_inner() - .flat_map(|pair| { - if pair.as_rule() == Rule::statement_list { - pair.into_inner().map(Statement::try_from).collect() - } else { - vec![Statement::try_from(pair)] - } - }) - .collect::>>()?; - - Ok(Block(statements)) + Ok(Block( + collect_recovered(pair.into_inner().next().unwrap().into_inner()).get()?, + )) } } @@ -34,14 +25,16 @@ impl<'a> TryFrom> for Statement { Ok(match rule { Rule::statement => Statement::try_from(inner.next().unwrap())?, - Rule::expr_stmt => Statement::Expression(Expression::try_from(inner.next().unwrap())?), + Rule::expr_stmt => { + Statement::Expression(Expression::try_from(inner.next().unwrap()).get()?) + } - Rule::block => Statement::Block(Block::try_from(inner.next().unwrap())?), + Rule::block => Statement::Block(Block::try_from(inner.next().unwrap()).get()?), - Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair)?), + Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair).get()?), Rule::return_stmt => { - Statement::Return(inner.next().map(Expression::try_from).transpose()?) + Statement::Return(inner.next().map(Expression::try_from).transpose().get()?) } Rule::break_stmt => Statement::Break, @@ -52,13 +45,8 @@ impl<'a> TryFrom> for Statement { let mut inner = inner.skip(2); Statement::If { - initial: StatementBranch::try_from(pair)?, - else_if: inner - .next() - .unwrap() - .into_inner() - .map(StatementBranch::try_from) - .collect::>>()?, + initial: StatementBranch::try_from(pair).get()?, + else_if: collect_recovered(inner.next().unwrap().into_inner()).get()?, else_branch: inner .next() .map(Statement::try_from) @@ -67,45 +55,47 @@ impl<'a> TryFrom> for Statement { } } - Rule::while_stmt => Statement::While(pair.try_into()?), + Rule::while_stmt => Statement::While(pair.try_into().get()?), Rule::c_for_stmt => Statement::CStyleFor { - init: Box::new(Statement::try_from(inner.next().unwrap())?), - condition: inner.next().unwrap().try_into()?, - update: Box::new(Statement::try_from(inner.next().unwrap())?), - body: Box::new(Statement::try_from(inner.next().unwrap())?), + init: Box::new(inner.next().unwrap().try_into().get()?), + condition: inner.next().unwrap().try_into().get()?, + update: Box::new(inner.next().unwrap().try_into().get()?), + body: Box::new(inner.next().unwrap().try_into().get()?), }, Rule::for_stmt => Statement::For { mutable: listen_rule(&mut inner, Rule::mutable), - pattern: Pattern::try_from(inner.next().unwrap())?, - iterator: inner.next().unwrap().try_into()?, + pattern: inner.next().unwrap().try_into().get()?, + iterator: inner.next().unwrap().try_into().get()?, body: Box::new(Statement::try_from(inner.next().unwrap())?), }, Rule::assign_statement => Statement::VarAssign(VarAssignStmt { - target: Expression::try_from(inner.next().unwrap())?, - value: Expression::try_from(inner.next().unwrap())?, + target: inner.next().unwrap().try_into().get()?, + value: inner.next().unwrap().try_into().get()?, }), Rule::match_stmt => Statement::Match( - Expression::try_from(inner.next().unwrap())?, + inner.next().unwrap().try_into().get()?, inner .map(|match_itms| { let mut match_inner = match_itms.into_inner(); Ok(( - Pattern::try_from(match_inner.next().unwrap())?, - Block::try_from(match_inner.next().unwrap())?, + Pattern::try_from(match_inner.next().unwrap()).get()?, + Block::try_from(match_inner.next().unwrap()).get()?, )) }) - .collect::>>()?, + .collect::>>() + .get()?, ), Rule::unexpected_statement => { - return Err(AstError::Ast { + return Err(AstError { span: pair.as_span(), error_code: ErrorCode::InvalidStatement, error_message: "Invalid Statement".to_string(), + recovered: None, }); } @@ -120,8 +110,8 @@ impl<'a> TryFrom> for StatementBranch { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let condition = Expression::try_from(inner.next().unwrap())?; - let body = Statement::try_from(inner.next().unwrap())?; + let condition = inner.next().unwrap().try_into().get()?; + let body = inner.next().unwrap().try_into().get()?; Ok(StatementBranch { condition, From f9c5fb4ec843961abe6f82e8c5c1f1c481df0563 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 08:54:48 +0200 Subject: [PATCH 22/27] types error handling --- parser/src/parser/common/types.rs | 66 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs index 89493f3..19a91c9 100644 --- a/parser/src/parser/common/types.rs +++ b/parser/src/parser/common/types.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, GetParseError, collect_recovered}, parser::{consume_rule, listen_rule}, }; @@ -17,7 +17,8 @@ impl<'a> TryFrom> for TypePostfix { let mutable = listen_rule(&mut inner, Rule::mutable); let lifetime = consume_rule(&mut inner, Rule::lifetime) .map(|pair| Identifier::try_from(pair.into_inner().next().unwrap())) - .transpose()?; + .transpose() + .get()?; Ok(if mutable { if let Some(lifetime) = lifetime { @@ -46,16 +47,10 @@ impl<'a> TryFrom> for TypeExprKind { let mut inner = pair.into_inner(); match rule { - Rule::tuple_type => Ok(TypeExprKind::Tuple( - inner - .map(TypeExpr::try_from) - .collect::>()?, - )), + Rule::tuple_type => Ok(TypeExprKind::Tuple(collect_recovered(inner).get()?)), Rule::path_type => { - let path = Path::try_from(inner.next().unwrap())?; - let params = inner - .map(TypeExpr::try_from) - .collect::>>()?; + let path = Path::try_from(inner.next().unwrap()).get()?; + let params = collect_recovered(inner).get()?; if params.len() == 0 { Ok(TypeExprKind::Path(path)) @@ -77,14 +72,12 @@ impl<'a> TryFrom> for TypeExpr { match rule { Rule::type_expr => Ok(TypeExpr( - TypeExprKind::try_from(inner.next().unwrap())?, - inner - .map(TypePostfix::try_from) - .collect::>()?, + inner.next().unwrap().try_into().get()?, + collect_recovered(inner).get()?, )), Rule::type_expr_param => Self::try_from(inner.next().unwrap()), Rule::lifetime => Ok(TypeExpr( - TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), + TypeExprKind::Lifetime(inner.next().unwrap().try_into().get()?), Vec::new(), )), _ => unimplemented!("{rule:#?}"), @@ -100,28 +93,27 @@ impl<'a> TryFrom> for Generics { let inner = pair.clone().into_inner(); match rule { - Rule::generics => Ok(Generics( - inner - .map(|pair| -> AstResult<'a, Generic> { - let mut inner = pair.into_inner(); - Ok( - if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { - Generic::Lifetime(Identifier::try_from( - pair.into_inner().next().unwrap(), - )?) - } else { - Generic::Type( - Identifier::try_from(inner.next().unwrap())?, - inner - .map(TypeExpr::try_from) - .collect::>>()?, - ) - }, - ) - }) - .collect::>>()?, - )), + Rule::generics => Ok(Generics(collect_recovered(inner).get()?)), _ => unimplemented!("{rule:#?}"), } } } + +impl<'a> TryFrom> for Generic { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.clone().into_inner(); + + if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { + Ok(Generic::Lifetime( + pair.into_inner().next().unwrap().try_into().get()?, + )) + } else { + Ok(Generic::Type( + inner.next().unwrap().try_into().get()?, + collect_recovered(inner).get()?, + )) + } + } +} From 8c89f9ff65abfa55b109b8e033d1a88a85f3481e Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 09:00:21 +0200 Subject: [PATCH 23/27] Attr and class error handling --- parser/src/parser/items/attribute.rs | 16 +++++------ parser/src/parser/items/class.rs | 42 +++++++++++++++------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/parser/src/parser/items/attribute.rs b/parser/src/parser/items/attribute.rs index b75a864..5f64605 100644 --- a/parser/src/parser/items/attribute.rs +++ b/parser/src/parser/items/attribute.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, GetParseError, collect_recovered}, }; impl<'a> TryFrom> for Attribute { @@ -18,7 +18,7 @@ impl<'a> TryFrom> for Attribute { let mut inner = pair.into_inner(); // first item is always the path - let path = Path::try_from(inner.next().unwrap())?; + let path = inner.next().unwrap().try_into().get()?; // check what comes next match inner.next() { @@ -32,18 +32,16 @@ impl<'a> TryFrom> for Attribute { // #[path = literal] Ok(Attribute::NameValue { path, - value: Literal::try_from(next)?, + value: inner.next().unwrap().try_into().get()?, }) } Rule::meta_list => { // #[path(...)] - let items = next - .into_inner() - .map(Attribute::try_from) - .collect::, _>>()?; - - Ok(Attribute::List { path, items }) + Ok(Attribute::List { + path, + items: collect_recovered(next.into_inner()).get()?, + }) } _ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()), diff --git a/parser/src/parser/items/class.rs b/parser/src/parser/items/class.rs index 09b13e8..88b2944 100644 --- a/parser/src/parser/items/class.rs +++ b/parser/src/parser/items/class.rs @@ -1,4 +1,9 @@ -use crate::{Rule, ast::*, error::AstError, parser::consume_rule}; +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError}, + parser::consume_rule, +}; impl<'a> TryFrom> for ClassConstructor { type Error = AstError<'a, Self>; @@ -6,23 +11,22 @@ impl<'a> TryFrom> for ClassConstructor { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner)?; - - let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .unwrap_or_default(); - - let params = consume_rule(&mut inner, Rule::param_list) - .map(ParamList::try_from) - .transpose()? - .unwrap_or_default(); - Ok(Self { - visibility, - generics, - params, - body: Block::try_from(inner.next().unwrap())?, + visibility: Visibility::try_from(&mut inner).get()?, + + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + params: consume_rule(&mut inner, Rule::param_list) + .map(ParamList::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + body: inner.next().unwrap().try_into().get()?, }) } } @@ -35,10 +39,10 @@ impl<'a> TryFrom> for ClassItem { match rule { Rule::impl_decl | Rule::impl_for_decl => { - Ok(ClassItem::ImplDecl(ImplDecl::try_from(pair)?)) + Ok(ClassItem::ImplDecl(pair.try_into().get()?)) } - Rule::method => Ok(ClassItem::Method(FunctionDecl::try_from(pair)?)), + Rule::method => Ok(ClassItem::Method(pair.try_into().get()?)), _ => unimplemented!("{rule:#?}"), } From 6c7692208d44d0467f5ab65a190df5811fee2737 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 09:11:17 +0200 Subject: [PATCH 24/27] enums, functions, impls error handling --- parser/src/parser/items/enums.rs | 26 ++++++++------------------ parser/src/parser/items/function.rs | 22 ++++++++++------------ parser/src/parser/items/impl_decl.rs | 22 ++++++++++------------ 3 files changed, 28 insertions(+), 42 deletions(-) diff --git a/parser/src/parser/items/enums.rs b/parser/src/parser/items/enums.rs index 2b4dc89..ad8c87e 100644 --- a/parser/src/parser/items/enums.rs +++ b/parser/src/parser/items/enums.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, GetParseError, collect_recovered}, }; impl<'a> TryFrom> for EnumItem { @@ -12,30 +12,20 @@ impl<'a> TryFrom> for EnumItem { let mut inner = pair.clone().into_inner(); match rule { - Rule::enum_named => Ok(EnumItem::Named(Identifier::try_from( - inner.next().unwrap(), - )?)), + Rule::enum_named => Ok(EnumItem::Named(inner.next().unwrap().try_into().get()?)), Rule::enum_tuple => Ok(EnumItem::Tuple( - Identifier::try_from(inner.next().unwrap())?, - inner - .next() - .unwrap() - .into_inner() - .map(TypeExpr::try_from) - .collect::>>()?, + inner.next().unwrap().try_into().get()?, + collect_recovered(inner.next().unwrap().into_inner()).get()?, )), Rule::enum_struct => Ok(EnumItem::Struct( - Identifier::try_from(inner.next().unwrap())?, + inner.next().unwrap().try_into().get()?, inner .next() - .map(|pair| { - pair.into_inner() - .map(FieldDecl::try_from) - .collect::>>() - }) - .transpose()? + .map(|pair| collect_recovered::(pair.into_inner())) + .transpose() + .get::()? .unwrap_or_default(), )), diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs index fde3a29..0787d52 100644 --- a/parser/src/parser/items/function.rs +++ b/parser/src/parser/items/function.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, AstResult, GetParseError, collect_recovered}, parser::{consume_rule, listen_rule}, }; @@ -10,12 +10,13 @@ impl<'a> TryFrom> for FunctionDecl { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner)?; - let return_type = TypeExpr::try_from(inner.next().unwrap())?; - let name = Identifier::try_from(inner.next().unwrap())?; + let visibility = Visibility::try_from(&mut inner).get()?; + let return_type = TypeExpr::try_from(inner.next().unwrap()).get()?; + let name = Identifier::try_from(inner.next().unwrap()).get()?; let generics = consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) - .transpose()? + .transpose() + .get()? .unwrap_or_default(); let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { @@ -55,10 +56,11 @@ impl<'a> TryFrom> for FunctionDecl { Ok(params) } }) - .transpose()? + .transpose() + .get()? .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); - let body = inner.next().map(Block::try_from).transpose()?; + let body = inner.next().map(Block::try_from).transpose().get()?; Ok(Self { visibility, @@ -75,10 +77,6 @@ impl<'a> TryFrom> for ParamList { type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Ok(ParamList( - pair.into_inner() - .map(VarDecl::try_from) - .collect::>>()?, - )) + Ok(ParamList(collect_recovered(pair.into_inner()).get()?)) } } diff --git a/parser/src/parser/items/impl_decl.rs b/parser/src/parser/items/impl_decl.rs index 7d4fab2..98aa43e 100644 --- a/parser/src/parser/items/impl_decl.rs +++ b/parser/src/parser/items/impl_decl.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, GetParseError, collect_recovered}, parser::consume_rule, }; @@ -16,25 +16,23 @@ impl<'a> TryFrom> for ImplDecl { Rule::impl_for_decl => Ok(ImplDecl { generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) - .transpose()? + .transpose() + .get()? .unwrap_or_default(), - trait_: Some(TypeExpr::try_from(inner.next().unwrap())?), - target: TypeExpr::try_from(inner.next().unwrap())?, - methods: inner - .map(FunctionDecl::try_from) - .collect::>>()?, + trait_: Some(inner.next().unwrap().try_into().get()?), + target: inner.next().unwrap().try_into().get()?, + methods: collect_recovered(inner).get()?, }), Rule::impl_decl => Ok(ImplDecl { generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) - .transpose()? + .transpose() + .get()? .unwrap_or_default(), trait_: None, - target: TypeExpr::try_from(inner.next().unwrap())?, - methods: inner - .map(FunctionDecl::try_from) - .collect::>>()?, + target: inner.next().unwrap().try_into().get()?, + methods: collect_recovered(inner).get()?, }), _ => unimplemented!("{rule:#?}"), From 3c5b030bdd73c240bccfe404133a9fed131c37d7 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 09:19:49 +0200 Subject: [PATCH 25/27] Finished error handling --- parser/src/parser/items/mod.rs | 109 ++++++++++++++++----------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 7e97ab0..9eba00e 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -7,7 +7,7 @@ pub mod impl_decl; use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, GetParseError, collect_recovered}, parser::consume_rule, }; @@ -17,18 +17,14 @@ impl<'a> TryFrom> for TopLevel { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let attributes = inner - .next() - .unwrap() - .into_inner() - .map(Attribute::try_from) - .collect::>>()?; + let attributes = collect_recovered(inner.next().unwrap().into_inner()).get()?; Ok(TopLevel( inner .next() .map(TopLevelKind::try_from) - .unwrap_or(Ok(TopLevelKind::ModAttribute))?, + .unwrap_or(Ok(TopLevelKind::ModAttribute)) + .get()?, attributes, )) } @@ -43,89 +39,88 @@ impl<'a> TryFrom> for TopLevelKind { Ok(match rule { Rule::import => TopLevelKind::Import( - Visibility::try_from(&mut inner)?, - Path::try_from(inner.next().unwrap())?, + Visibility::try_from(&mut inner).get()?, + Path::try_from(inner.next().unwrap()).get()?, ), - Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::try_from(pair)?), + Rule::function_decl => TopLevelKind::FunctionDecl(pair.try_into().get()?), Rule::struct_decl => TopLevelKind::StructDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) - .transpose()? + .transpose() + .get()? .unwrap_or_default(), + fields: inner .next() - .map(|pair| { - pair.into_inner() - .map(FieldDecl::try_from) - .collect::>>() - }) - .transpose()? + .map(|pair| collect_recovered::(pair.into_inner())) + .transpose() + .get()? .unwrap_or_default(), }, Rule::class_decl => TopLevelKind::ClassDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) - .transpose()? + .transpose() + .get()? .unwrap_or_default(), - fields: inner - .next() - .unwrap() - .into_inner() - .map(FieldDeclStmt::try_from) - .collect::>>()?, - constructor: ClassConstructor::try_from(inner.next().unwrap())?, - items: inner - .into_iter() - .map(ClassItem::try_from) - .collect::>>()?, + + fields: collect_recovered(inner.next().unwrap().into_inner()).get()?, + + constructor: inner.next().unwrap().try_into().get()?, + + items: collect_recovered(inner).get()?, }, Rule::enum_decl => TopLevelKind::EnumDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) - .transpose()? + .transpose() + .get()? .unwrap_or_default(), - fields: inner - .map(EnumItem::try_from) - .collect::>>()?, + + fields: collect_recovered(inner).get()?, }, Rule::mod_package => TopLevelKind::Mod( - Visibility::try_from(&mut inner)?, - Identifier::try_from(inner.next().unwrap())?, + Visibility::try_from(&mut inner).get()?, + inner.next().unwrap().try_into().get()?, ), - Rule::impl_for_decl | Rule::impl_decl => { - TopLevelKind::ImplDecl(ImplDecl::try_from(pair)?) - } + Rule::impl_for_decl | Rule::impl_decl => TopLevelKind::ImplDecl(pair.try_into().get()?), Rule::trait_decl => TopLevelKind::TraitDecl { - visibility: Visibility::try_from(&mut inner)?, - name: Identifier::try_from(inner.next().unwrap())?, + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) - .transpose()? + .transpose() + .get()? .unwrap_or_default(), + requirements: consume_rule(&mut inner, Rule::trait_requirements) - .map(|pair| { - pair.into_inner() - .map(TypeExpr::try_from) - .collect::>>() - }) - .transpose()? + .map(|pair| collect_recovered::(pair.into_inner())) + .transpose() + .get()? .unwrap_or_default(), - items: inner - .map(FunctionDecl::try_from) - .collect::>>()?, + + items: collect_recovered(inner).get()?, }, _ => unimplemented!("{rule:#?}"), From 0bb7146d136ec66674ab818ffe69a516a3a9175d Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 10:29:02 +0200 Subject: [PATCH 26/27] Fixed block bug --- parser/src/grammar.pest | 6 +----- parser/src/parser/common/statement.rs | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index bcaf9d9..13b699f 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -307,11 +307,7 @@ top_level = { // ====================================================== block = { - "{" ~ statement_list ~ "}" -} - -statement_list = { - (statement | unexpected_statement)* + "{" ~ (statement | unexpected_statement)* ~ "}" } statement = _{ diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index c4e22e4..3f5afd5 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -9,9 +9,19 @@ impl<'a> TryFrom> for Block { type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Ok(Block( - collect_recovered(pair.into_inner().next().unwrap().into_inner()).get()?, - )) + if pair.as_rule() == Rule::block { + Ok(Block(collect_recovered(pair.into_inner()).get()?)) + } else { + Err(AstError { + span: pair.as_span(), + error_code: ErrorCode::InvalidStatement, + error_message: format!( + "BUG: AST requires a block, this isn't a block, it's a {:?}", + pair.as_rule() + ), + recovered: None, + }) + } } } @@ -29,7 +39,7 @@ impl<'a> TryFrom> for Statement { Statement::Expression(Expression::try_from(inner.next().unwrap()).get()?) } - Rule::block => Statement::Block(Block::try_from(inner.next().unwrap()).get()?), + Rule::block => Statement::Block(pair.try_into().get()?), Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair).get()?), From fa2c0b26588032d27a3de69bc3be2478e53138b9 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 10:37:06 +0200 Subject: [PATCH 27/27] Fixed pattern bug --- parser/src/parser/common/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index f7852de..067dba2 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -61,12 +61,12 @@ impl<'a> TryFrom> for Pattern { Rule::named_tuple_pattern => Pattern::NamedTuple( Path::try_from(inner.next().unwrap()).get()?, - collect_recovered(pair.into_inner()).get()?, + collect_recovered(inner).get()?, ), Rule::struct_pattern => Pattern::Struct( Path::try_from(inner.next().unwrap()).get()?, - collect_recovered(pair.into_inner()).get()?, + collect_recovered(inner).get()?, ), Rule::literal => Pattern::Literal(Literal::try_from(pair).get()?),