ast: Add metadata attributes on Items

TODO: decide what other places attributes belong
This commit is contained in:
John 2024-02-27 23:31:49 -06:00
parent 9806e95247
commit 325498ac8b
4 changed files with 102 additions and 5 deletions

View File

@ -8,9 +8,13 @@ Visibility = "pub"? ;
File = Item* EOI ; File = Item* EOI ;
Item = Visibility ItemKind ; Attrs = ('#' '[' (Meta ',') Meta? ']')* ;
Meta = Identifier ('=' Literal | '(' (Literal ',')* Literal? ')')? ;
Item = Attrs* Visibility ItemKind ;
ItemKind = Const | Static | Module ItemKind = Const | Static | Module
| Function | Struct | Enum | Function | Struct | Enum
| Alias | Impl ; | Alias | Impl ;

View File

@ -32,11 +32,31 @@ pub struct File {
pub items: Vec<Item>, pub items: Vec<Item>,
} }
// Metadata decorators
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Attrs {
pub meta: Vec<Meta>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Meta {
pub name: Identifier,
pub kind: MetaKind,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MetaKind {
Plain,
Equals(Literal),
Func(Vec<Literal>),
}
// Items // Items
/// Stores an [ItemKind] and associated metadata /// Stores an [ItemKind] and associated metadata
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Item { pub struct Item {
pub extents: Span, pub extents: Span,
pub attrs: Attrs,
pub vis: Visibility, pub vis: Visibility,
pub kind: ItemKind, pub kind: ItemKind,
} }

View File

@ -77,10 +77,39 @@ mod display {
} }
} }
impl Display for Attrs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { meta } = self;
if meta.is_empty() {
return Ok(());
}
"#".fmt(f)?;
delimit(separate(meta, ", "), INLINE_SQUARE)(f)?;
"\n".fmt(f)
}
}
impl Display for Meta {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, kind } = self;
write!(f, "{name}{kind}")
}
}
impl Display for MetaKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MetaKind::Plain => Ok(()),
MetaKind::Equals(v) => write!(f, " = {v}"),
MetaKind::Func(args) => delimit(separate(args, ", "), INLINE_PARENS)(f),
}
}
}
impl Display for Item { impl Display for Item {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.vis.fmt(f)?; let Self { extents: _, attrs, vis, kind } = self;
match &self.kind { attrs.fmt(f)?;
vis.fmt(f)?;
match kind {
ItemKind::Alias(v) => v.fmt(f), ItemKind::Alias(v) => v.fmt(f),
ItemKind::Const(v) => v.fmt(f), ItemKind::Const(v) => v.fmt(f),
ItemKind::Static(v) => v.fmt(f), ItemKind::Static(v) => v.fmt(f),

View File

@ -68,6 +68,9 @@ pub mod error {
pub enum Parsing { pub enum Parsing {
File, File,
Attrs,
Meta,
Item, Item,
Visibility, Visibility,
Mutability, Mutability,
@ -161,6 +164,10 @@ pub mod error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Parsing::File => "a file", Parsing::File => "a file",
Parsing::Attrs => "an attribute-set",
Parsing::Meta => "an attribute",
Parsing::Item => "an item", Parsing::Item => "an item",
Parsing::Visibility => "a visibility qualifier", Parsing::Visibility => "a visibility qualifier",
Parsing::Mutability => "a mutability qualifier", Parsing::Mutability => "a mutability qualifier",
@ -371,7 +378,8 @@ fn rep<'t, T>(
/// Expands to a pattern which matches item-like [Token] [Type]s /// Expands to a pattern which matches item-like [Token] [Type]s
macro item_like() { macro item_like() {
Type::Keyword( Type::Hash
| Type::Keyword(
Keyword::Pub Keyword::Pub
| Keyword::Type | Keyword::Type
| Keyword::Const | Keyword::Const
@ -406,6 +414,7 @@ impl<'t> Parser<'t> {
let start = self.loc(); let start = self.loc();
Ok(Item { Ok(Item {
vis: self.visibility()?, vis: self.visibility()?,
attrs: self.attributes()?,
kind: self.itemkind()?, kind: self.itemkind()?,
extents: Span(start, self.loc()), extents: Span(start, self.loc()),
}) })
@ -464,6 +473,41 @@ impl<'t> Parser<'t> {
} }
} }
/// Attribute parsing
impl<'t> Parser<'t> {
/// Parses an [attribute set](Attrs)
pub fn attributes(&mut self) -> PResult<Attrs> {
if self.match_type(Type::Hash, Parsing::Attrs).is_err() {
return Ok(Attrs { meta: vec![] });
}
let meta = delim(
sep(Self::meta, Type::Comma, BRACKETS.1, Parsing::Attrs),
BRACKETS,
Parsing::Attrs,
);
Ok(Attrs { meta: meta(self)? })
}
pub fn meta(&mut self) -> PResult<Meta> {
Ok(Meta { name: self.identifier()?, kind: self.meta_kind()? })
}
pub fn meta_kind(&mut self) -> PResult<MetaKind> {
const PARSING: Parsing = Parsing::Meta;
let lit_tuple = delim(
sep(Self::literal, Type::Comma, PARENS.1, PARSING),
PARENS,
PARSING,
);
Ok(match self.peek_type(PARSING) {
Ok(Type::Eq) => {
self.consume_peeked();
MetaKind::Equals(self.literal()?)
}
Ok(Type::LParen) => MetaKind::Func(lit_tuple(self)?),
_ => MetaKind::Plain,
})
}
}
/// Item parsing /// Item parsing
impl<'t> Parser<'t> { impl<'t> Parser<'t> {
/// Parses an [ItemKind] /// Parses an [ItemKind]