From e421a81a3dc3b69760299e3f098f43a74c00004e Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Tue, 5 May 2026 14:43:14 +0200 Subject: [PATCH] Working parser for attributes --- parser/src/ast.rs | 1 - parser/src/grammar.pest | 4 +- parser/src/lib.rs | 83 +++++++++++++++++++++++++++++------------ src/codegen.rs | 1 - 4 files changed, 63 insertions(+), 26 deletions(-) diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 05a42f0..cbbc186 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -78,7 +78,6 @@ pub enum TopLevelKind { return_type: TypeExpr, body: Block, }, - EOI, } #[derive(Debug, Clone, Serialize)] diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 7b13504..5f73a47 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -31,7 +31,9 @@ meta_list = { 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 ~ ">" } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 0e00713..8b988fc 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -18,7 +18,9 @@ pub fn parse(source: &str) -> Result, ParseError> { let mut statements = vec![]; for pair in pairs.next().unwrap().into_inner() { - statements.push(TopLevel::from(pair)); + if pair.as_rule() != Rule::EOI { + statements.push(TopLevel::from(pair)); + } } Ok(statements) @@ -120,36 +122,73 @@ impl From> for ParamList { impl From> for Attribute { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); + match pair.as_rule() { + Rule::attribute => { + // unwrap #[ ... ] + Attribute::from(pair.into_inner().next().unwrap()) + } - // If we start at the top-level #[...], dive into the meta_item - if rule == Rule::attribute { - return Attribute::from(pair.into_inner().next().unwrap()); + Rule::meta => { + let mut inner = pair.into_inner(); + + // first item is always the path + let path = StaticPath::from(inner.next().unwrap()); + + // check what comes next + 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::>(); + + // 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()), } - - let mut inner = pair.into_inner(); - let path = StaticPath::from(inner.next().unwrap()); - - let kind = match rule { - _ => unimplemented!("{:?}", rule), - }; } } impl From> for TopLevel { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { let mut inner = pair.into_inner(); - let mut attributes = Vec::new(); - while inner - .peek() - .map(|v| v.as_rule() == Rule::attribute) - .unwrap_or_default() - { - attributes.push(Attribute::from(inner.next().unwrap())); - } + let attributes = inner + .next() + .unwrap() + .into_inner() + .map(Attribute::from) + .collect::>(); - TopLevel(inner.next().unwrap().into(), attributes) + TopLevel(TopLevelKind::from(inner.next().unwrap()), attributes) } } @@ -214,8 +253,6 @@ impl From> for TopLevelKind { fields, } } - - Rule::EOI => TopLevelKind::EOI, _ => unimplemented!("{rule:#?}"), } } diff --git a/src/codegen.rs b/src/codegen.rs index c37b6ea..4e1e848 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -285,7 +285,6 @@ impl ToRust for TopLevelKind { cg.indent -= 1; cg.addln("}\n"); } - Self::EOI => {} } } }