Working parser for attributes

This commit is contained in:
2026-05-05 14:43:14 +02:00
parent ce7dc2b9ba
commit e421a81a3d
4 changed files with 63 additions and 26 deletions
-1
View File
@@ -78,7 +78,6 @@ pub enum TopLevelKind {
return_type: TypeExpr, return_type: TypeExpr,
body: Block, body: Block,
}, },
EOI,
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
+3 -1
View File
@@ -31,7 +31,9 @@ meta_list = {
meta ~ ("," ~ meta)* ~ ","? meta ~ ("," ~ meta)* ~ ","?
} }
top_level = { attribute* ~ (import | function_decl | struct_decl) } attributes = { attribute* }
top_level = { attributes ~ (import | function_decl | struct_decl) }
import = { sharp ~ "include" ~ "<" ~ static_path ~ ">" } import = { sharp ~ "include" ~ "<" ~ static_path ~ ">" }
+56 -19
View File
@@ -18,8 +18,10 @@ pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
let mut statements = vec![]; let mut statements = vec![];
for pair in pairs.next().unwrap().into_inner() { for pair in pairs.next().unwrap().into_inner() {
if pair.as_rule() != Rule::EOI {
statements.push(TopLevel::from(pair)); statements.push(TopLevel::from(pair));
} }
}
Ok(statements) Ok(statements)
} }
@@ -120,36 +122,73 @@ impl From<pest::iterators::Pair<'_, Rule>> for ParamList {
impl From<pest::iterators::Pair<'_, Rule>> for Attribute { impl From<pest::iterators::Pair<'_, Rule>> for Attribute {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule(); match pair.as_rule() {
Rule::attribute => {
// If we start at the top-level #[...], dive into the meta_item // unwrap #[ ... ]
if rule == Rule::attribute { Attribute::from(pair.into_inner().next().unwrap())
return Attribute::from(pair.into_inner().next().unwrap());
} }
Rule::meta => {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
// first item is always the path
let path = StaticPath::from(inner.next().unwrap()); let path = StaticPath::from(inner.next().unwrap());
let kind = match rule { // check what comes next
_ => unimplemented!("{:?}", rule), match inner.next() {
}; None => {
// #[path]
Attribute::Path(path)
}
Some(next) => match next.as_rule() {
Rule::primary => {
// #[path = literal]
Attribute::NameValue {
path,
value: Literal::from(next),
}
}
Rule::meta_list => {
// #[path(...)]
let items = next.into_inner().map(Attribute::from).collect();
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::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 From<pest::iterators::Pair<'_, Rule>> for TopLevel { impl From<pest::iterators::Pair<'_, Rule>> for TopLevel {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let mut attributes = Vec::new();
while inner let attributes = inner
.peek() .next()
.map(|v| v.as_rule() == Rule::attribute) .unwrap()
.unwrap_or_default() .into_inner()
{ .map(Attribute::from)
attributes.push(Attribute::from(inner.next().unwrap())); .collect::<Vec<_>>();
}
TopLevel(inner.next().unwrap().into(), attributes) TopLevel(TopLevelKind::from(inner.next().unwrap()), attributes)
} }
} }
@@ -214,8 +253,6 @@ impl From<pest::iterators::Pair<'_, Rule>> for TopLevelKind {
fields, fields,
} }
} }
Rule::EOI => TopLevelKind::EOI,
_ => unimplemented!("{rule:#?}"), _ => unimplemented!("{rule:#?}"),
} }
} }
-1
View File
@@ -285,7 +285,6 @@ impl ToRust for TopLevelKind {
cg.indent -= 1; cg.indent -= 1;
cg.addln("}\n"); cg.addln("}\n");
} }
Self::EOI => {}
} }
} }
} }