ast: Add metadata attributes on Items
TODO: decide what other places attributes belong
This commit is contained in:
parent
9806e95247
commit
325498ac8b
@ -8,7 +8,11 @@ Visibility = "pub"? ;
|
||||
File = Item* EOI ;
|
||||
|
||||
|
||||
Item = Visibility ItemKind ;
|
||||
Attrs = ('#' '[' (Meta ',') Meta? ']')* ;
|
||||
Meta = Identifier ('=' Literal | '(' (Literal ',')* Literal? ')')? ;
|
||||
|
||||
|
||||
Item = Attrs* Visibility ItemKind ;
|
||||
ItemKind = Const | Static | Module
|
||||
| Function | Struct | Enum
|
||||
| Alias | Impl ;
|
||||
|
@ -32,11 +32,31 @@ pub struct File {
|
||||
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
|
||||
/// Stores an [ItemKind] and associated metadata
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Item {
|
||||
pub extents: Span,
|
||||
pub attrs: Attrs,
|
||||
pub vis: Visibility,
|
||||
pub kind: ItemKind,
|
||||
}
|
||||
|
@ -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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.vis.fmt(f)?;
|
||||
match &self.kind {
|
||||
let Self { extents: _, attrs, vis, kind } = self;
|
||||
attrs.fmt(f)?;
|
||||
vis.fmt(f)?;
|
||||
match kind {
|
||||
ItemKind::Alias(v) => v.fmt(f),
|
||||
ItemKind::Const(v) => v.fmt(f),
|
||||
ItemKind::Static(v) => v.fmt(f),
|
||||
|
@ -68,6 +68,9 @@ pub mod error {
|
||||
pub enum Parsing {
|
||||
File,
|
||||
|
||||
Attrs,
|
||||
Meta,
|
||||
|
||||
Item,
|
||||
Visibility,
|
||||
Mutability,
|
||||
@ -161,6 +164,10 @@ pub mod error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Parsing::File => "a file",
|
||||
|
||||
Parsing::Attrs => "an attribute-set",
|
||||
Parsing::Meta => "an attribute",
|
||||
|
||||
Parsing::Item => "an item",
|
||||
Parsing::Visibility => "a visibility 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
|
||||
macro item_like() {
|
||||
Type::Keyword(
|
||||
Type::Hash
|
||||
| Type::Keyword(
|
||||
Keyword::Pub
|
||||
| Keyword::Type
|
||||
| Keyword::Const
|
||||
@ -406,6 +414,7 @@ impl<'t> Parser<'t> {
|
||||
let start = self.loc();
|
||||
Ok(Item {
|
||||
vis: self.visibility()?,
|
||||
attrs: self.attributes()?,
|
||||
kind: self.itemkind()?,
|
||||
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
|
||||
impl<'t> Parser<'t> {
|
||||
/// Parses an [ItemKind]
|
||||
|
Loading…
Reference in New Issue
Block a user