From f4a14789c3bc6d11cf190aeef63269453b3fa71e Mon Sep 17 00:00:00 2001 From: Selimaj Dev Date: Tue, 5 May 2026 03:17:33 +0200 Subject: [PATCH] Attribute parsing and ast --- parser/src/ast.rs | 33 ++++++++----- parser/src/grammar.pest | 2 +- parser/src/lib.rs | 103 +++++++++++++++++++++++++++++++++++----- 3 files changed, 114 insertions(+), 24 deletions(-) diff --git a/parser/src/ast.rs b/parser/src/ast.rs index cdaa12c..e3e0bcf 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -20,22 +20,20 @@ pub enum TypePostfix { #[derive(Debug, Clone, Serialize)] pub struct Attribute { pub path: StaticPath, - pub args: Vec, + pub kind: MetaItemKind, } #[derive(Debug, Clone, Serialize)] -pub enum AttributeArg { - Named(String, Literal), - Positional(Literal), +pub enum MetaItemKind { + Word, + NameValue(Literal), + List(Vec), } #[derive(Debug, Clone, Serialize)] -pub enum Literal { - String(String), - Int(i64), - Float(f64), - Bool(bool), - Tuple(Vec), +pub enum NestedMetaItem { + Literal(Literal), + MetaItem(Attribute), } #[derive(Debug, Clone, Serialize)] @@ -67,7 +65,10 @@ pub enum BinaryOp { } #[derive(Debug, Clone, Serialize)] -pub enum TopLevel { +pub struct TopLevel(pub TopLevelKind, pub Vec); + +#[derive(Debug, Clone, Serialize)] +pub enum TopLevelKind { Include(StaticPath), StructDecl { export: bool, @@ -81,6 +82,7 @@ pub enum TopLevel { return_type: TypeExpr, body: Block, }, + EOI, } #[derive(Debug, Clone, Serialize)] @@ -166,3 +168,12 @@ pub enum Expression { postfixes: Vec, }, } + +#[derive(Debug, Clone, Serialize)] +pub enum Literal { + String(String), + Int(i64), + Float(f64), + Bool(bool), + Tuple(Vec), +} diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 3d74a98..b690bcf 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -37,7 +37,7 @@ structured_style = { identifier ~ "(" ~ pair ~ ("," ~ pair)* ~ ","? ~ ")" } pair = { identifier ~ "=" ~ primary } -top_level = _{ attribute* ~ (import | function_decl | struct_decl) } +top_level = { attribute* ~ (import | function_decl | struct_decl) } import = { sharp ~ "include" ~ "<" ~ static_path ~ ">" } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 525280b..caddf9d 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -18,9 +18,7 @@ pub fn parse(source: &str) -> Result, ParseError> { let mut statements = vec![]; for pair in pairs.next().unwrap().into_inner() { - if let Ok(stmt) = TopLevel::try_from(pair) { - statements.push(stmt); - } + statements.push(TopLevel::from(pair)); } Ok(statements) @@ -120,14 +118,79 @@ impl From> for ParamList { } } -impl TryFrom> for TopLevel { - type Error = (); - fn try_from(pair: pest::iterators::Pair) -> Result { +impl From> for Attribute { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + let rule = pair.as_rule(); + + // If we start at the top-level #[...], dive into the meta_item + if rule == Rule::attribute { + return Attribute::from(pair.into_inner().next().unwrap()); + } + + let mut inner = pair.into_inner(); + // Every style starts with an identifier (the path) + let path = StaticPath::from(inner.next().expect("Path identifier expected")); + + let kind = match rule { + Rule::simple_style => MetaItemKind::Word, + + Rule::key_value_style | Rule::pair => { + let lit = Literal::from(inner.next().unwrap()); + MetaItemKind::NameValue(lit) + } + + Rule::list_style => { + // derive(Debug, Clone) -> NestedMetaItem::MetaItem(Attribute { path: "Debug", kind: Word }) + let items = inner + .map(|p| { + NestedMetaItem::MetaItem(Attribute { + path: StaticPath::from(p), + kind: MetaItemKind::Word, + }) + }) + .collect(); + MetaItemKind::List(items) + } + + Rule::structured_style => { + // link(name = "readline") -> NestedMetaItem::MetaItem(Attribute { path: "name", kind: NameValue(...) }) + let items = inner + .map(|p| NestedMetaItem::MetaItem(Attribute::from(p))) + .collect(); + MetaItemKind::List(items) + } + + _ => unreachable!("Unexpected rule: {:?}", rule), + }; + + Attribute { path, kind } + } +} + +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())); + } + + TopLevel(inner.next().unwrap().into(), attributes) + } +} + +impl From> for TopLevelKind { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { let rule = pair.as_rule(); let mut inner = pair.into_inner(); match rule { - Rule::import => Ok(TopLevel::Include(StaticPath::from(inner.next().unwrap()))), + Rule::import => TopLevelKind::Include(StaticPath::from(inner.next().unwrap())), Rule::function_decl => { let export = if let Some(first) = inner.peek() { @@ -152,13 +215,13 @@ impl TryFrom> for TopLevel { let body = Block::from(inner.next().unwrap()); - Ok(TopLevel::FunctionDecl { + TopLevelKind::FunctionDecl { export, name, params, return_type, body, - }) + } } Rule::struct_decl => { @@ -176,14 +239,14 @@ impl TryFrom> for TopLevel { let fields_pair = inner.next().unwrap(); let fields = FieldList::from(fields_pair); - Ok(TopLevel::StructDecl { + TopLevelKind::StructDecl { export, name, fields, - }) + } } - Rule::EOI => Err(()), + Rule::EOI => TopLevelKind::EOI, _ => unimplemented!("{rule:#?}"), } } @@ -262,6 +325,22 @@ impl From> for Statement { } } +impl From> for Literal { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + let rule = pair.as_rule(); + let inner = pair.clone().into_inner(); + + match rule { + 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()), + _ => unimplemented!("{rule:#?}"), + } + } +} + impl From> for Expression { fn from(pair: pest::iterators::Pair) -> Self { let rule = pair.as_rule();