Separated classes, attributes, and types

This commit is contained in:
2026-05-14 21:35:41 +02:00
parent 50fa660392
commit 00e10d1097
6 changed files with 355 additions and 332 deletions
-295
View File
@@ -29,69 +29,6 @@ pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec<TopLevel>> {
Ok(statements) Ok(statements)
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypePostfix {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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<pest::iterators::Pair<'a, Rule>> for TypeExprKind {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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::<ParseResult<'a, _>>()?,
)),
Rule::path_type => {
let path = Path::try_from(inner.next().unwrap())?;
let params = inner
.map(TypeExpr::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?;
if params.len() == 0 {
Ok(TypeExprKind::Path(path))
} else {
Ok(TypeExprKind::PathParams(path, params))
}
}
_ => unimplemented!("{rule:#?}"),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList {
type Error = ParseError<'a>; type Error = ParseError<'a>;
@@ -104,94 +41,6 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList {
} }
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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::<ParseResult<'a, Vec<_>>>()?;
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::<Vec<_>>();
// 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<pest::iterators::Pair<'a, Rule>> for TopLevel {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner();
let attributes = inner
.next()
.unwrap()
.into_inner()
.map(Attribute::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?;
Ok(TopLevel(
inner
.next()
.map(TopLevelKind::try_from)
.unwrap_or(Ok(TopLevelKind::ModAttribute))?,
attributes,
))
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch {
type Error = ParseError<'a>; type Error = ParseError<'a>;
@@ -208,33 +57,6 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch {
} }
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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<pest::iterators::Pair<'a, Rule>> for Generics { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics {
type Error = ParseError<'a>; type Error = ParseError<'a>;
@@ -269,123 +91,6 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics {
} }
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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::<ParseResult<'a, Vec<_>>>()
})
.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::<ParseResult<'a, Vec<_>>>()?,
constructor: ClassConstructor::try_from(inner.next().unwrap())?,
items: inner
.into_iter()
.map(ClassItem::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?,
},
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::<ParseResult<'a, Vec<_>>>()?,
},
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::<ParseResult<'a, Vec<_>>>()
})
.transpose()?
.unwrap_or_default(),
items: inner
.map(FunctionDecl::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?,
},
_ => unimplemented!("{rule:#?}"),
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassItem {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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<pest::iterators::Pair<'a, Rule>> for ImplDecl { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl {
type Error = ParseError<'a>; type Error = ParseError<'a>;
@@ -1,3 +1,5 @@
pub mod types;
use crate::{ use crate::{
Rule, Rule,
ast::*, ast::*,
@@ -28,23 +30,6 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> 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<Self, Self::Error> {
Ok(consume_rule(pairs, Rule::visibility)
.map(|pair| -> Result<Visibility, ParseError<'a>> {
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<pest::iterators::Pair<'a, Rule>> for Literal { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal {
type Error = ParseError<'a>; type Error = ParseError<'a>;
@@ -69,26 +54,19 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal {
} }
} }
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr { impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility {
type Error = ParseError<'a>; type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> { fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule(); Ok(consume_rule(pairs, Rule::visibility)
let mut inner = pair.into_inner(); .map(|pair| -> Result<Visibility, ParseError<'a>> {
if let Some(path) = pair.into_inner().next() {
match rule { Ok(Visibility::PublicTarget(Path::try_from(path)?))
Rule::type_expr => Ok(TypeExpr( } else {
TypeExprKind::try_from(inner.next().unwrap())?, Ok(Visibility::Public)
inner
.map(TypePostfix::try_from)
.collect::<ParseResult<'a, _>>()?,
)),
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:#?}"),
} }
})
.transpose()?
.unwrap_or_else(|| Visibility::Private))
} }
} }
+93
View File
@@ -0,0 +1,93 @@
use crate::{
Rule,
ast::*,
error::{ParseError, ParseResult},
parser::{consume_rule, listen_rule},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypePostfix {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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<pest::iterators::Pair<'a, Rule>> for TypeExprKind {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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::<ParseResult<'a, _>>()?,
)),
Rule::path_type => {
let path = Path::try_from(inner.next().unwrap())?;
let params = inner
.map(TypeExpr::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?;
if params.len() == 0 {
Ok(TypeExprKind::Path(path))
} else {
Ok(TypeExprKind::PathParams(path, params))
}
}
_ => unimplemented!("{rule:#?}"),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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::<ParseResult<'a, _>>()?,
)),
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:#?}"),
}
}
}
+70
View File
@@ -0,0 +1,70 @@
use crate::{
Rule,
ast::*,
error::{ParseError, ParseResult},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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::<ParseResult<'a, Vec<_>>>()?;
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::<Vec<_>>();
// 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()),
}
}
}
+46
View File
@@ -0,0 +1,46 @@
use crate::{Rule, ast::*, error::ParseError, parser::consume_rule};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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<pest::iterators::Pair<'a, Rule>> for ClassItem {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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:#?}"),
}
}
}
+131
View File
@@ -1 +1,132 @@
pub mod attribute;
pub mod class;
pub mod function; pub mod function;
use crate::{
Rule,
ast::*,
error::{ParseError, ParseResult},
parser::consume_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner();
let attributes = inner
.next()
.unwrap()
.into_inner()
.map(Attribute::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?;
Ok(TopLevel(
inner
.next()
.map(TopLevelKind::try_from)
.unwrap_or(Ok(TopLevelKind::ModAttribute))?,
attributes,
))
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
type Error = ParseError<'a>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
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::<ParseResult<'a, Vec<_>>>()
})
.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::<ParseResult<'a, Vec<_>>>()?,
constructor: ClassConstructor::try_from(inner.next().unwrap())?,
items: inner
.into_iter()
.map(ClassItem::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?,
},
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::<ParseResult<'a, Vec<_>>>()?,
},
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::<ParseResult<'a, Vec<_>>>()
})
.transpose()?
.unwrap_or_default(),
items: inner
.map(FunctionDecl::try_from)
.collect::<ParseResult<'a, Vec<_>>>()?,
},
_ => unimplemented!("{rule:#?}"),
})
}
}