From 00e10d1097eb06dac810c31d698acdd8bf10306f Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 14 May 2026 21:35:41 +0200 Subject: [PATCH] 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:#?}"), + }) + } +}